diff options
| author | Alfred Perlstein <alfred@FreeBSD.org> | 2001-03-19 12:50:13 +0000 |
|---|---|---|
| committer | Alfred Perlstein <alfred@FreeBSD.org> | 2001-03-19 12:50:13 +0000 |
| commit | 8360efbd6c932013ffdb2f83d2f2de4278febb5e (patch) | |
| tree | b842b4bf2665ef953be005b10013a2f3daf323c3 | |
| parent | 1ac2b9fe972a0c73729565f8310fa6eba55718c4 (diff) | |
Notes
204 files changed, 31956 insertions, 12014 deletions
diff --git a/etc/Makefile b/etc/Makefile index 14814f5957e0..acc18d1a2afe 100644 --- a/etc/Makefile +++ b/etc/Makefile @@ -10,7 +10,7 @@ BIN1= amd.map apmd.conf auth.conf \ dhclient.conf dm.conf fbtab ftpusers gettytab group \ hosts hosts.allow hosts.equiv hosts.lpd \ inetd.conf login.access login.conf \ - motd modems networks newsyslog.conf \ + motd modems netconfig networks newsyslog.conf \ pam.conf phones pim6dd.conf pim6sd.conf \ printcap profile protocols \ rc rc.atm rc.devfs rc.diskless1 rc.diskless2 rc.firewall rc.firewall6 \ diff --git a/etc/defaults/rc.conf b/etc/defaults/rc.conf index 3865a43818a4..d05dc7779afb 100644 --- a/etc/defaults/rc.conf +++ b/etc/defaults/rc.conf @@ -101,7 +101,7 @@ ppp_nat="YES" # Use PPP's internal network address translation or NO. ppp_profile="papchap" # Which profile to use from /etc/ppp/ppp.conf. ppp_user="root" # Which user to run ppp as -### Network daemon (miscellaneous) & NFS options: ### +### Network daemon (miscellaneous) ### syslogd_enable="YES" # Run syslog daemon (or NO). syslogd_flags="-s" # Flags to syslogd (if enabled). inetd_enable="NO" # Run the network daemon dispatcher (YES/NO). @@ -121,6 +121,19 @@ kadmind_server_enable="NO" # Run kadmind (or NO) -- do not run on kerberos_stash="" # Is the kerberos master key stashed? rwhod_enable="NO" # Run the rwho daemon (or NO). rwhod_flags="" # Flags for rwhod +rarpd_enable="NO" # Run rarpd (or NO). +rarpd_flags="" # Flags to rarpd. +xtend_enable="NO" # Run the X-10 power controller daemon. +xtend_flags="" # Flags to xtend (if enabled). +pppoed_enable="NO" # Run the PPP over Ethernet daemon. +pppoed_provider="*" # Provider and ppp(8) config file entry. +pppoed_flags="-P /var/run/pppoed.pid" # Flags to pppoed (if enabled). +pppoed_interface="fxp0" # The interface that pppoed runs on. +sshd_enable="NO" # Enable sshd +sshd_program="/usr/sbin/sshd" # path to sshd, if you want a different one. +sshd_flags="" # Additional flags for sshd. + +### Network daemon (NFS) Need all portmap_enable="YES" ### amd_enable="NO" # Run amd service with $amd_flags (or NO). amd_flags="-a /.amd_mnt -l syslog /host /etc/amd.map /net /etc/amd.map" amd_map_program="NO" # Can be set to "ypcat -k amd.master" @@ -135,24 +148,13 @@ weak_mountd_authentication="NO" # Allow non-root mount requests to be served. nfs_reserved_port_only="NO" # Provide NFS only on secure port (or NO). nfs_bufpackets="DEFAULT" # bufspace (in packets) for client (or DEFAULT) rpc_lockd_enable="NO" # Run NFS rpc.lockd (*broken!*) if nfs_server. -rpc_statd_enable="YES" # Run NFS rpc.statd if nfs_server (or NO). +rpc_statd_enable="NO" # Run NFS rpc.statd if nfs_server (or NO). portmap_enable="NO" # Run the portmapper service (YES/NO). -portmap_program="/usr/sbin/portmap" # path to portmap, if you want a different one. +portmap_program="/usr/sbin/rpcbind" # path to portmap, if you want a different one. portmap_flags="" # Flags to portmap (if enabled). rpc_ypupdated_enable="NO" # Run if NIS master and SecureRPC (or NO). keyserv_enable="NO" # Run the SecureRPC keyserver (or NO). keyserv_flags="" # Flags to keyserv (if enabled). -rarpd_enable="NO" # Run rarpd (or NO). -rarpd_flags="" # Flags to rarpd. -xtend_enable="NO" # Run the X-10 power controller daemon. -xtend_flags="" # Flags to xtend (if enabled). -pppoed_enable="NO" # Run the PPP over Ethernet daemon. -pppoed_provider="*" # Provider and ppp(8) config file entry. -pppoed_flags="-P /var/run/pppoed.pid" # Flags to pppoed (if enabled). -pppoed_interface="fxp0" # The interface that pppoed runs on. -sshd_enable="NO" # Enable sshd -sshd_program="/usr/sbin/sshd" # path to sshd, if you want a different one. -sshd_flags="" # Additional flags for sshd. ### Network Time Services options: ### timed_enable="NO" # Run the time daemon (or NO). @@ -164,7 +166,7 @@ xntpd_enable="NO" # Run ntpd Network Time Protocol (or NO). xntpd_program="ntpd" # path to ntpd, if you want a different one. xntpd_flags="-p /var/run/ntpd.pid" # Flags to ntpd (if enabled). -# Network Information Services (NIS) options: ### +# Network Information Services (NIS) options: Need all portmap_enable="YES" ### nis_client_enable="NO" # We're an NIS client (or NO). nis_client_flags="" # Flags to ypbind (if enabled). nis_ypset_enable="NO" # Run ypset at boot time (or NO). diff --git a/etc/netconfig b/etc/netconfig new file mode 100644 index 000000000000..89234fed6c73 --- /dev/null +++ b/etc/netconfig @@ -0,0 +1,17 @@ +# The network configuration file. This file is currently only used in +# conjunction with the (TI-) RPC code in the C library, unlike its +# use in SVR4. +# +# Entries consist of: +# +# <network_id> <semantics> <flags> <protofamily> <protoname> \ +# <device> <nametoaddr_libs> +# +# The <device> and <nametoaddr_libs> fields are always empty in FreeBSD. +# +udp6 tpi_clts v inet6 udp - - +tcp6 tpi_cots_ord v inet6 tcp - - +udp tpi_clts v inet udp - - +tcp tpi_cots_ord v inet tcp - - +rawip tpi_raw - inet - - - +unix tpi_cots_ord - loopback - - - diff --git a/etc/network.subr b/etc/network.subr index ef6c6038b029..c1ffb3735a74 100644 --- a/etc/network.subr +++ b/etc/network.subr @@ -514,59 +514,61 @@ network_pass2() { case ${portmap_enable} in [Yy][Ee][Ss]) - echo -n ' portmap'; ${portmap_program:-/usr/sbin/portmap} ${portmap_flags} - ;; - esac + echo -n ' rpcbind'; ${portmap_program:-/usr/sbin/rpcbind} \ + ${portmap_flags} - # Start ypserv if we're an NIS server. - # Run rpc.ypxfrd and rpc.yppasswdd only on the NIS master server. - # - case ${nis_server_enable} in - [Yy][Ee][Ss]) - echo -n ' ypserv'; ypserv ${nis_server_flags} - - case ${nis_ypxfrd_enable} in + # Start ypserv if we're an NIS server. + # Run rpc.ypxfrd and rpc.yppasswdd only on the NIS master server. + # + case ${nis_server_enable} in [Yy][Ee][Ss]) - echo -n ' rpc.ypxfrd' - rpc.ypxfrd ${nis_ypxfrd_flags} + echo -n ' ypserv'; ypserv ${nis_server_flags} + + case ${nis_ypxfrd_enable} in + [Yy][Ee][Ss]) + echo -n ' rpc.ypxfrd' + rpc.ypxfrd ${nis_ypxfrd_flags} + ;; + esac + + case ${nis_yppasswdd_enable} in + [Yy][Ee][Ss]) + echo -n ' rpc.yppasswdd' + rpc.yppasswdd ${nis_yppasswdd_flags} + ;; + esac ;; esac - case ${nis_yppasswdd_enable} in + # Start ypbind if we're an NIS client + # + case ${nis_client_enable} in [Yy][Ee][Ss]) - echo -n ' rpc.yppasswdd' - rpc.yppasswdd ${nis_yppasswdd_flags} + echo -n ' ypbind'; ypbind ${nis_client_flags} + case ${nis_ypset_enable} in + [Yy][Ee][Ss]) + echo -n ' ypset'; ypset ${nis_ypset_flags} + ;; + esac ;; esac - ;; - esac - # Start ypbind if we're an NIS client - # - case ${nis_client_enable} in - [Yy][Ee][Ss]) - echo -n ' ypbind'; ypbind ${nis_client_flags} - case ${nis_ypset_enable} in + # Start keyserv if we are running Secure RPC + # + case ${keyserv_enable} in [Yy][Ee][Ss]) - echo -n ' ypset'; ypset ${nis_ypset_flags} + echo -n ' keyserv'; keyserv ${keyserv_flags} ;; esac - ;; - esac - # Start keyserv if we are running Secure RPC - # - case ${keyserv_enable} in - [Yy][Ee][Ss]) - echo -n ' keyserv'; keyserv ${keyserv_flags} - ;; - esac - - # Start ypupdated if we are running Secure RPC and we are NIS master - # - case ${rpc_ypupdated_enable} in - [Yy][Ee][Ss]) - echo -n ' rpc.ypupdated'; rpc.ypupdated + # Start ypupdated if we are running Secure RPC + # and we are NIS master + # + case ${rpc_ypupdated_enable} in + [Yy][Ee][Ss]) + echo -n ' rpc.ypupdated'; rpc.ypupdated + ;; + esac ;; esac @@ -582,99 +584,103 @@ network_pass2() { network_pass3() { echo -n 'Starting final network daemons:' - case ${nfs_server_enable} in + case ${portmap_enable} in [Yy][Ee][Ss]) - if [ -r /etc/exports ]; then - echo -n ' mountd' - - case ${weak_mountd_authentication} in - [Yy][Ee][Ss]) - mountd_flags="${mountd_flags} -n" - ;; - esac + case ${nfs_server_enable} in + [Yy][Ee][Ss]) + if [ -r /etc/exports ]; then + echo -n ' mountd' - mountd ${mountd_flags} + case ${weak_mountd_authentication} in + [Yy][Ee][Ss]) + mountd_flags="${mountd_flags} -n" + ;; + esac - case ${nfs_reserved_port_only} in - [Yy][Ee][Ss]) - echo -n ' NFS on reserved port only=YES' - sysctl -w vfs.nfs.nfs_privport=1 >/dev/null - ;; - esac + mountd ${mountd_flags} - echo -n ' nfsd'; nfsd ${nfs_server_flags} + case ${nfs_reserved_port_only} in + [Yy][Ee][Ss]) + echo -n ' NFS on reserved port only=YES' + sysctl -w vfs.nfs.nfs_privport=1 > /dev/null + ;; + esac - if [ -n "${nfs_bufpackets}" ]; then - sysctl -w vfs.nfs.bufpackets=${nfs_bufpackets} \ - > /dev/null - fi + echo -n ' nfsd'; nfsd ${nfs_server_flags} - case ${rpc_lockd_enable} in - [Yy][Ee][Ss]) - echo -n ' rpc.lockd'; rpc.lockd - ;; - esac + if [ -n "${nfs_bufpackets}" ]; then + sysctl -w vfs.nfs.bufpackets=${nfs_bufpackets} > /dev/null + fi - case ${rpc_statd_enable} in - [Yy][Ee][Ss]) - echo -n ' rpc.statd'; rpc.statd - ;; - esac - fi - ;; - *) - case ${single_mountd_enable} in - [Yy][Ee][Ss]) - if [ -r /etc/exports ]; then - echo -n ' mountd' + case ${rpc_lockd_enable} in + [Yy][Ee][Ss]) + echo -n ' rpc.lockd'; rpc.lockd + ;; + esac - case ${weak_mountd_authentication} in + case ${rpc_statd_enable} in [Yy][Ee][Ss]) - mountd_flags="-n" + echo -n ' rpc.statd'; rpc.statd ;; esac + fi + ;; + *) + case ${single_mountd_enable} in + [Yy][Ee][Ss]) + if [ -r /etc/exports ]; then + echo -n ' mountd' - mountd ${mountd_flags} + case ${weak_mountd_authentication} in + [Yy][Ee][Ss]) + mountd_flags="-n" + ;; + esac + + mountd ${mountd_flags} + fi + ;; + esac + ;; + esac + + case ${nfs_client_enable} in + [Yy][Ee][Ss]) + echo -n ' nfsiod'; nfsiod ${nfs_client_flags} + if [ -n "${nfs_access_cache}" ]; then + echo -n " NFS access cache time=${nfs_access_cache}" + sysctl -w vfs.nfs.access_cache_timeout=${nfs_access_cache} >/dev/null fi ;; esac - ;; - esac - case ${nfs_client_enable} in - [Yy][Ee][Ss]) - echo -n ' nfsiod'; nfsiod ${nfs_client_flags} - if [ -n "${nfs_access_cache}" ]; then - echo -n " NFS access cache time=${nfs_access_cache}" - sysctl -w vfs.nfs.access_cache_timeout=${nfs_access_cache} \ - >/dev/null + # If /var/db/mounttab exists, some nfs-server has not been + # sucessfully notified about a previous client shutdown. + # If there is no /var/db/mounttab, we do nothing. + if [ -f /var/db/mounttab ]; then + rpc.umntall -k fi - ;; - esac - # If /var/db/mounttab exists, some nfs-server has not been - # sucessfully notified about a previous client shutdown. - # If there is no /var/db/mounttab, we do nothing. - if [ -f /var/db/mounttab ]; then - rpc.umntall -k - fi + case ${amd_enable} in + [Yy][Ee][Ss]) + echo -n ' amd' + case ${amd_map_program} in + [Nn][Oo] | '') + ;; + *) + amd_flags="${amd_flags} `eval\ + ${amd_map_program}`" + ;; + esac - case ${amd_enable} in - [Yy][Ee][Ss]) - echo -n ' amd' - case ${amd_map_program} in - [Nn][Oo] | '') - ;; - *) - amd_flags="${amd_flags} `eval ${amd_map_program}`" + if [ -n "${amd_flags}" ]; then + amd -p ${amd_flags}\ + > /var/run/amd.pid 2> /dev/null + else + amd 2> /dev/null + fi ;; esac - - if [ -n "${amd_flags}" ]; then - amd -p ${amd_flags} > /var/run/amd.pid 2> /dev/null - else - amd 2> /dev/null - fi ;; esac diff --git a/etc/rc.d/netoptions b/etc/rc.d/netoptions index ef6c6038b029..c1ffb3735a74 100644 --- a/etc/rc.d/netoptions +++ b/etc/rc.d/netoptions @@ -514,59 +514,61 @@ network_pass2() { case ${portmap_enable} in [Yy][Ee][Ss]) - echo -n ' portmap'; ${portmap_program:-/usr/sbin/portmap} ${portmap_flags} - ;; - esac + echo -n ' rpcbind'; ${portmap_program:-/usr/sbin/rpcbind} \ + ${portmap_flags} - # Start ypserv if we're an NIS server. - # Run rpc.ypxfrd and rpc.yppasswdd only on the NIS master server. - # - case ${nis_server_enable} in - [Yy][Ee][Ss]) - echo -n ' ypserv'; ypserv ${nis_server_flags} - - case ${nis_ypxfrd_enable} in + # Start ypserv if we're an NIS server. + # Run rpc.ypxfrd and rpc.yppasswdd only on the NIS master server. + # + case ${nis_server_enable} in [Yy][Ee][Ss]) - echo -n ' rpc.ypxfrd' - rpc.ypxfrd ${nis_ypxfrd_flags} + echo -n ' ypserv'; ypserv ${nis_server_flags} + + case ${nis_ypxfrd_enable} in + [Yy][Ee][Ss]) + echo -n ' rpc.ypxfrd' + rpc.ypxfrd ${nis_ypxfrd_flags} + ;; + esac + + case ${nis_yppasswdd_enable} in + [Yy][Ee][Ss]) + echo -n ' rpc.yppasswdd' + rpc.yppasswdd ${nis_yppasswdd_flags} + ;; + esac ;; esac - case ${nis_yppasswdd_enable} in + # Start ypbind if we're an NIS client + # + case ${nis_client_enable} in [Yy][Ee][Ss]) - echo -n ' rpc.yppasswdd' - rpc.yppasswdd ${nis_yppasswdd_flags} + echo -n ' ypbind'; ypbind ${nis_client_flags} + case ${nis_ypset_enable} in + [Yy][Ee][Ss]) + echo -n ' ypset'; ypset ${nis_ypset_flags} + ;; + esac ;; esac - ;; - esac - # Start ypbind if we're an NIS client - # - case ${nis_client_enable} in - [Yy][Ee][Ss]) - echo -n ' ypbind'; ypbind ${nis_client_flags} - case ${nis_ypset_enable} in + # Start keyserv if we are running Secure RPC + # + case ${keyserv_enable} in [Yy][Ee][Ss]) - echo -n ' ypset'; ypset ${nis_ypset_flags} + echo -n ' keyserv'; keyserv ${keyserv_flags} ;; esac - ;; - esac - # Start keyserv if we are running Secure RPC - # - case ${keyserv_enable} in - [Yy][Ee][Ss]) - echo -n ' keyserv'; keyserv ${keyserv_flags} - ;; - esac - - # Start ypupdated if we are running Secure RPC and we are NIS master - # - case ${rpc_ypupdated_enable} in - [Yy][Ee][Ss]) - echo -n ' rpc.ypupdated'; rpc.ypupdated + # Start ypupdated if we are running Secure RPC + # and we are NIS master + # + case ${rpc_ypupdated_enable} in + [Yy][Ee][Ss]) + echo -n ' rpc.ypupdated'; rpc.ypupdated + ;; + esac ;; esac @@ -582,99 +584,103 @@ network_pass2() { network_pass3() { echo -n 'Starting final network daemons:' - case ${nfs_server_enable} in + case ${portmap_enable} in [Yy][Ee][Ss]) - if [ -r /etc/exports ]; then - echo -n ' mountd' - - case ${weak_mountd_authentication} in - [Yy][Ee][Ss]) - mountd_flags="${mountd_flags} -n" - ;; - esac + case ${nfs_server_enable} in + [Yy][Ee][Ss]) + if [ -r /etc/exports ]; then + echo -n ' mountd' - mountd ${mountd_flags} + case ${weak_mountd_authentication} in + [Yy][Ee][Ss]) + mountd_flags="${mountd_flags} -n" + ;; + esac - case ${nfs_reserved_port_only} in - [Yy][Ee][Ss]) - echo -n ' NFS on reserved port only=YES' - sysctl -w vfs.nfs.nfs_privport=1 >/dev/null - ;; - esac + mountd ${mountd_flags} - echo -n ' nfsd'; nfsd ${nfs_server_flags} + case ${nfs_reserved_port_only} in + [Yy][Ee][Ss]) + echo -n ' NFS on reserved port only=YES' + sysctl -w vfs.nfs.nfs_privport=1 > /dev/null + ;; + esac - if [ -n "${nfs_bufpackets}" ]; then - sysctl -w vfs.nfs.bufpackets=${nfs_bufpackets} \ - > /dev/null - fi + echo -n ' nfsd'; nfsd ${nfs_server_flags} - case ${rpc_lockd_enable} in - [Yy][Ee][Ss]) - echo -n ' rpc.lockd'; rpc.lockd - ;; - esac + if [ -n "${nfs_bufpackets}" ]; then + sysctl -w vfs.nfs.bufpackets=${nfs_bufpackets} > /dev/null + fi - case ${rpc_statd_enable} in - [Yy][Ee][Ss]) - echo -n ' rpc.statd'; rpc.statd - ;; - esac - fi - ;; - *) - case ${single_mountd_enable} in - [Yy][Ee][Ss]) - if [ -r /etc/exports ]; then - echo -n ' mountd' + case ${rpc_lockd_enable} in + [Yy][Ee][Ss]) + echo -n ' rpc.lockd'; rpc.lockd + ;; + esac - case ${weak_mountd_authentication} in + case ${rpc_statd_enable} in [Yy][Ee][Ss]) - mountd_flags="-n" + echo -n ' rpc.statd'; rpc.statd ;; esac + fi + ;; + *) + case ${single_mountd_enable} in + [Yy][Ee][Ss]) + if [ -r /etc/exports ]; then + echo -n ' mountd' - mountd ${mountd_flags} + case ${weak_mountd_authentication} in + [Yy][Ee][Ss]) + mountd_flags="-n" + ;; + esac + + mountd ${mountd_flags} + fi + ;; + esac + ;; + esac + + case ${nfs_client_enable} in + [Yy][Ee][Ss]) + echo -n ' nfsiod'; nfsiod ${nfs_client_flags} + if [ -n "${nfs_access_cache}" ]; then + echo -n " NFS access cache time=${nfs_access_cache}" + sysctl -w vfs.nfs.access_cache_timeout=${nfs_access_cache} >/dev/null fi ;; esac - ;; - esac - case ${nfs_client_enable} in - [Yy][Ee][Ss]) - echo -n ' nfsiod'; nfsiod ${nfs_client_flags} - if [ -n "${nfs_access_cache}" ]; then - echo -n " NFS access cache time=${nfs_access_cache}" - sysctl -w vfs.nfs.access_cache_timeout=${nfs_access_cache} \ - >/dev/null + # If /var/db/mounttab exists, some nfs-server has not been + # sucessfully notified about a previous client shutdown. + # If there is no /var/db/mounttab, we do nothing. + if [ -f /var/db/mounttab ]; then + rpc.umntall -k fi - ;; - esac - # If /var/db/mounttab exists, some nfs-server has not been - # sucessfully notified about a previous client shutdown. - # If there is no /var/db/mounttab, we do nothing. - if [ -f /var/db/mounttab ]; then - rpc.umntall -k - fi + case ${amd_enable} in + [Yy][Ee][Ss]) + echo -n ' amd' + case ${amd_map_program} in + [Nn][Oo] | '') + ;; + *) + amd_flags="${amd_flags} `eval\ + ${amd_map_program}`" + ;; + esac - case ${amd_enable} in - [Yy][Ee][Ss]) - echo -n ' amd' - case ${amd_map_program} in - [Nn][Oo] | '') - ;; - *) - amd_flags="${amd_flags} `eval ${amd_map_program}`" + if [ -n "${amd_flags}" ]; then + amd -p ${amd_flags}\ + > /var/run/amd.pid 2> /dev/null + else + amd 2> /dev/null + fi ;; esac - - if [ -n "${amd_flags}" ]; then - amd -p ${amd_flags} > /var/run/amd.pid 2> /dev/null - else - amd 2> /dev/null - fi ;; esac diff --git a/etc/rc.d/network1 b/etc/rc.d/network1 index ef6c6038b029..c1ffb3735a74 100644 --- a/etc/rc.d/network1 +++ b/etc/rc.d/network1 @@ -514,59 +514,61 @@ network_pass2() { case ${portmap_enable} in [Yy][Ee][Ss]) - echo -n ' portmap'; ${portmap_program:-/usr/sbin/portmap} ${portmap_flags} - ;; - esac + echo -n ' rpcbind'; ${portmap_program:-/usr/sbin/rpcbind} \ + ${portmap_flags} - # Start ypserv if we're an NIS server. - # Run rpc.ypxfrd and rpc.yppasswdd only on the NIS master server. - # - case ${nis_server_enable} in - [Yy][Ee][Ss]) - echo -n ' ypserv'; ypserv ${nis_server_flags} - - case ${nis_ypxfrd_enable} in + # Start ypserv if we're an NIS server. + # Run rpc.ypxfrd and rpc.yppasswdd only on the NIS master server. + # + case ${nis_server_enable} in [Yy][Ee][Ss]) - echo -n ' rpc.ypxfrd' - rpc.ypxfrd ${nis_ypxfrd_flags} + echo -n ' ypserv'; ypserv ${nis_server_flags} + + case ${nis_ypxfrd_enable} in + [Yy][Ee][Ss]) + echo -n ' rpc.ypxfrd' + rpc.ypxfrd ${nis_ypxfrd_flags} + ;; + esac + + case ${nis_yppasswdd_enable} in + [Yy][Ee][Ss]) + echo -n ' rpc.yppasswdd' + rpc.yppasswdd ${nis_yppasswdd_flags} + ;; + esac ;; esac - case ${nis_yppasswdd_enable} in + # Start ypbind if we're an NIS client + # + case ${nis_client_enable} in [Yy][Ee][Ss]) - echo -n ' rpc.yppasswdd' - rpc.yppasswdd ${nis_yppasswdd_flags} + echo -n ' ypbind'; ypbind ${nis_client_flags} + case ${nis_ypset_enable} in + [Yy][Ee][Ss]) + echo -n ' ypset'; ypset ${nis_ypset_flags} + ;; + esac ;; esac - ;; - esac - # Start ypbind if we're an NIS client - # - case ${nis_client_enable} in - [Yy][Ee][Ss]) - echo -n ' ypbind'; ypbind ${nis_client_flags} - case ${nis_ypset_enable} in + # Start keyserv if we are running Secure RPC + # + case ${keyserv_enable} in [Yy][Ee][Ss]) - echo -n ' ypset'; ypset ${nis_ypset_flags} + echo -n ' keyserv'; keyserv ${keyserv_flags} ;; esac - ;; - esac - # Start keyserv if we are running Secure RPC - # - case ${keyserv_enable} in - [Yy][Ee][Ss]) - echo -n ' keyserv'; keyserv ${keyserv_flags} - ;; - esac - - # Start ypupdated if we are running Secure RPC and we are NIS master - # - case ${rpc_ypupdated_enable} in - [Yy][Ee][Ss]) - echo -n ' rpc.ypupdated'; rpc.ypupdated + # Start ypupdated if we are running Secure RPC + # and we are NIS master + # + case ${rpc_ypupdated_enable} in + [Yy][Ee][Ss]) + echo -n ' rpc.ypupdated'; rpc.ypupdated + ;; + esac ;; esac @@ -582,99 +584,103 @@ network_pass2() { network_pass3() { echo -n 'Starting final network daemons:' - case ${nfs_server_enable} in + case ${portmap_enable} in [Yy][Ee][Ss]) - if [ -r /etc/exports ]; then - echo -n ' mountd' - - case ${weak_mountd_authentication} in - [Yy][Ee][Ss]) - mountd_flags="${mountd_flags} -n" - ;; - esac + case ${nfs_server_enable} in + [Yy][Ee][Ss]) + if [ -r /etc/exports ]; then + echo -n ' mountd' - mountd ${mountd_flags} + case ${weak_mountd_authentication} in + [Yy][Ee][Ss]) + mountd_flags="${mountd_flags} -n" + ;; + esac - case ${nfs_reserved_port_only} in - [Yy][Ee][Ss]) - echo -n ' NFS on reserved port only=YES' - sysctl -w vfs.nfs.nfs_privport=1 >/dev/null - ;; - esac + mountd ${mountd_flags} - echo -n ' nfsd'; nfsd ${nfs_server_flags} + case ${nfs_reserved_port_only} in + [Yy][Ee][Ss]) + echo -n ' NFS on reserved port only=YES' + sysctl -w vfs.nfs.nfs_privport=1 > /dev/null + ;; + esac - if [ -n "${nfs_bufpackets}" ]; then - sysctl -w vfs.nfs.bufpackets=${nfs_bufpackets} \ - > /dev/null - fi + echo -n ' nfsd'; nfsd ${nfs_server_flags} - case ${rpc_lockd_enable} in - [Yy][Ee][Ss]) - echo -n ' rpc.lockd'; rpc.lockd - ;; - esac + if [ -n "${nfs_bufpackets}" ]; then + sysctl -w vfs.nfs.bufpackets=${nfs_bufpackets} > /dev/null + fi - case ${rpc_statd_enable} in - [Yy][Ee][Ss]) - echo -n ' rpc.statd'; rpc.statd - ;; - esac - fi - ;; - *) - case ${single_mountd_enable} in - [Yy][Ee][Ss]) - if [ -r /etc/exports ]; then - echo -n ' mountd' + case ${rpc_lockd_enable} in + [Yy][Ee][Ss]) + echo -n ' rpc.lockd'; rpc.lockd + ;; + esac - case ${weak_mountd_authentication} in + case ${rpc_statd_enable} in [Yy][Ee][Ss]) - mountd_flags="-n" + echo -n ' rpc.statd'; rpc.statd ;; esac + fi + ;; + *) + case ${single_mountd_enable} in + [Yy][Ee][Ss]) + if [ -r /etc/exports ]; then + echo -n ' mountd' - mountd ${mountd_flags} + case ${weak_mountd_authentication} in + [Yy][Ee][Ss]) + mountd_flags="-n" + ;; + esac + + mountd ${mountd_flags} + fi + ;; + esac + ;; + esac + + case ${nfs_client_enable} in + [Yy][Ee][Ss]) + echo -n ' nfsiod'; nfsiod ${nfs_client_flags} + if [ -n "${nfs_access_cache}" ]; then + echo -n " NFS access cache time=${nfs_access_cache}" + sysctl -w vfs.nfs.access_cache_timeout=${nfs_access_cache} >/dev/null fi ;; esac - ;; - esac - case ${nfs_client_enable} in - [Yy][Ee][Ss]) - echo -n ' nfsiod'; nfsiod ${nfs_client_flags} - if [ -n "${nfs_access_cache}" ]; then - echo -n " NFS access cache time=${nfs_access_cache}" - sysctl -w vfs.nfs.access_cache_timeout=${nfs_access_cache} \ - >/dev/null + # If /var/db/mounttab exists, some nfs-server has not been + # sucessfully notified about a previous client shutdown. + # If there is no /var/db/mounttab, we do nothing. + if [ -f /var/db/mounttab ]; then + rpc.umntall -k fi - ;; - esac - # If /var/db/mounttab exists, some nfs-server has not been - # sucessfully notified about a previous client shutdown. - # If there is no /var/db/mounttab, we do nothing. - if [ -f /var/db/mounttab ]; then - rpc.umntall -k - fi + case ${amd_enable} in + [Yy][Ee][Ss]) + echo -n ' amd' + case ${amd_map_program} in + [Nn][Oo] | '') + ;; + *) + amd_flags="${amd_flags} `eval\ + ${amd_map_program}`" + ;; + esac - case ${amd_enable} in - [Yy][Ee][Ss]) - echo -n ' amd' - case ${amd_map_program} in - [Nn][Oo] | '') - ;; - *) - amd_flags="${amd_flags} `eval ${amd_map_program}`" + if [ -n "${amd_flags}" ]; then + amd -p ${amd_flags}\ + > /var/run/amd.pid 2> /dev/null + else + amd 2> /dev/null + fi ;; esac - - if [ -n "${amd_flags}" ]; then - amd -p ${amd_flags} > /var/run/amd.pid 2> /dev/null - else - amd 2> /dev/null - fi ;; esac diff --git a/etc/rc.d/network2 b/etc/rc.d/network2 index ef6c6038b029..c1ffb3735a74 100644 --- a/etc/rc.d/network2 +++ b/etc/rc.d/network2 @@ -514,59 +514,61 @@ network_pass2() { case ${portmap_enable} in [Yy][Ee][Ss]) - echo -n ' portmap'; ${portmap_program:-/usr/sbin/portmap} ${portmap_flags} - ;; - esac + echo -n ' rpcbind'; ${portmap_program:-/usr/sbin/rpcbind} \ + ${portmap_flags} - # Start ypserv if we're an NIS server. - # Run rpc.ypxfrd and rpc.yppasswdd only on the NIS master server. - # - case ${nis_server_enable} in - [Yy][Ee][Ss]) - echo -n ' ypserv'; ypserv ${nis_server_flags} - - case ${nis_ypxfrd_enable} in + # Start ypserv if we're an NIS server. + # Run rpc.ypxfrd and rpc.yppasswdd only on the NIS master server. + # + case ${nis_server_enable} in [Yy][Ee][Ss]) - echo -n ' rpc.ypxfrd' - rpc.ypxfrd ${nis_ypxfrd_flags} + echo -n ' ypserv'; ypserv ${nis_server_flags} + + case ${nis_ypxfrd_enable} in + [Yy][Ee][Ss]) + echo -n ' rpc.ypxfrd' + rpc.ypxfrd ${nis_ypxfrd_flags} + ;; + esac + + case ${nis_yppasswdd_enable} in + [Yy][Ee][Ss]) + echo -n ' rpc.yppasswdd' + rpc.yppasswdd ${nis_yppasswdd_flags} + ;; + esac ;; esac - case ${nis_yppasswdd_enable} in + # Start ypbind if we're an NIS client + # + case ${nis_client_enable} in [Yy][Ee][Ss]) - echo -n ' rpc.yppasswdd' - rpc.yppasswdd ${nis_yppasswdd_flags} + echo -n ' ypbind'; ypbind ${nis_client_flags} + case ${nis_ypset_enable} in + [Yy][Ee][Ss]) + echo -n ' ypset'; ypset ${nis_ypset_flags} + ;; + esac ;; esac - ;; - esac - # Start ypbind if we're an NIS client - # - case ${nis_client_enable} in - [Yy][Ee][Ss]) - echo -n ' ypbind'; ypbind ${nis_client_flags} - case ${nis_ypset_enable} in + # Start keyserv if we are running Secure RPC + # + case ${keyserv_enable} in [Yy][Ee][Ss]) - echo -n ' ypset'; ypset ${nis_ypset_flags} + echo -n ' keyserv'; keyserv ${keyserv_flags} ;; esac - ;; - esac - # Start keyserv if we are running Secure RPC - # - case ${keyserv_enable} in - [Yy][Ee][Ss]) - echo -n ' keyserv'; keyserv ${keyserv_flags} - ;; - esac - - # Start ypupdated if we are running Secure RPC and we are NIS master - # - case ${rpc_ypupdated_enable} in - [Yy][Ee][Ss]) - echo -n ' rpc.ypupdated'; rpc.ypupdated + # Start ypupdated if we are running Secure RPC + # and we are NIS master + # + case ${rpc_ypupdated_enable} in + [Yy][Ee][Ss]) + echo -n ' rpc.ypupdated'; rpc.ypupdated + ;; + esac ;; esac @@ -582,99 +584,103 @@ network_pass2() { network_pass3() { echo -n 'Starting final network daemons:' - case ${nfs_server_enable} in + case ${portmap_enable} in [Yy][Ee][Ss]) - if [ -r /etc/exports ]; then - echo -n ' mountd' - - case ${weak_mountd_authentication} in - [Yy][Ee][Ss]) - mountd_flags="${mountd_flags} -n" - ;; - esac + case ${nfs_server_enable} in + [Yy][Ee][Ss]) + if [ -r /etc/exports ]; then + echo -n ' mountd' - mountd ${mountd_flags} + case ${weak_mountd_authentication} in + [Yy][Ee][Ss]) + mountd_flags="${mountd_flags} -n" + ;; + esac - case ${nfs_reserved_port_only} in - [Yy][Ee][Ss]) - echo -n ' NFS on reserved port only=YES' - sysctl -w vfs.nfs.nfs_privport=1 >/dev/null - ;; - esac + mountd ${mountd_flags} - echo -n ' nfsd'; nfsd ${nfs_server_flags} + case ${nfs_reserved_port_only} in + [Yy][Ee][Ss]) + echo -n ' NFS on reserved port only=YES' + sysctl -w vfs.nfs.nfs_privport=1 > /dev/null + ;; + esac - if [ -n "${nfs_bufpackets}" ]; then - sysctl -w vfs.nfs.bufpackets=${nfs_bufpackets} \ - > /dev/null - fi + echo -n ' nfsd'; nfsd ${nfs_server_flags} - case ${rpc_lockd_enable} in - [Yy][Ee][Ss]) - echo -n ' rpc.lockd'; rpc.lockd - ;; - esac + if [ -n "${nfs_bufpackets}" ]; then + sysctl -w vfs.nfs.bufpackets=${nfs_bufpackets} > /dev/null + fi - case ${rpc_statd_enable} in - [Yy][Ee][Ss]) - echo -n ' rpc.statd'; rpc.statd - ;; - esac - fi - ;; - *) - case ${single_mountd_enable} in - [Yy][Ee][Ss]) - if [ -r /etc/exports ]; then - echo -n ' mountd' + case ${rpc_lockd_enable} in + [Yy][Ee][Ss]) + echo -n ' rpc.lockd'; rpc.lockd + ;; + esac - case ${weak_mountd_authentication} in + case ${rpc_statd_enable} in [Yy][Ee][Ss]) - mountd_flags="-n" + echo -n ' rpc.statd'; rpc.statd ;; esac + fi + ;; + *) + case ${single_mountd_enable} in + [Yy][Ee][Ss]) + if [ -r /etc/exports ]; then + echo -n ' mountd' - mountd ${mountd_flags} + case ${weak_mountd_authentication} in + [Yy][Ee][Ss]) + mountd_flags="-n" + ;; + esac + + mountd ${mountd_flags} + fi + ;; + esac + ;; + esac + + case ${nfs_client_enable} in + [Yy][Ee][Ss]) + echo -n ' nfsiod'; nfsiod ${nfs_client_flags} + if [ -n "${nfs_access_cache}" ]; then + echo -n " NFS access cache time=${nfs_access_cache}" + sysctl -w vfs.nfs.access_cache_timeout=${nfs_access_cache} >/dev/null fi ;; esac - ;; - esac - case ${nfs_client_enable} in - [Yy][Ee][Ss]) - echo -n ' nfsiod'; nfsiod ${nfs_client_flags} - if [ -n "${nfs_access_cache}" ]; then - echo -n " NFS access cache time=${nfs_access_cache}" - sysctl -w vfs.nfs.access_cache_timeout=${nfs_access_cache} \ - >/dev/null + # If /var/db/mounttab exists, some nfs-server has not been + # sucessfully notified about a previous client shutdown. + # If there is no /var/db/mounttab, we do nothing. + if [ -f /var/db/mounttab ]; then + rpc.umntall -k fi - ;; - esac - # If /var/db/mounttab exists, some nfs-server has not been - # sucessfully notified about a previous client shutdown. - # If there is no /var/db/mounttab, we do nothing. - if [ -f /var/db/mounttab ]; then - rpc.umntall -k - fi + case ${amd_enable} in + [Yy][Ee][Ss]) + echo -n ' amd' + case ${amd_map_program} in + [Nn][Oo] | '') + ;; + *) + amd_flags="${amd_flags} `eval\ + ${amd_map_program}`" + ;; + esac - case ${amd_enable} in - [Yy][Ee][Ss]) - echo -n ' amd' - case ${amd_map_program} in - [Nn][Oo] | '') - ;; - *) - amd_flags="${amd_flags} `eval ${amd_map_program}`" + if [ -n "${amd_flags}" ]; then + amd -p ${amd_flags}\ + > /var/run/amd.pid 2> /dev/null + else + amd 2> /dev/null + fi ;; esac - - if [ -n "${amd_flags}" ]; then - amd -p ${amd_flags} > /var/run/amd.pid 2> /dev/null - else - amd 2> /dev/null - fi ;; esac diff --git a/etc/rc.d/network3 b/etc/rc.d/network3 index ef6c6038b029..c1ffb3735a74 100644 --- a/etc/rc.d/network3 +++ b/etc/rc.d/network3 @@ -514,59 +514,61 @@ network_pass2() { case ${portmap_enable} in [Yy][Ee][Ss]) - echo -n ' portmap'; ${portmap_program:-/usr/sbin/portmap} ${portmap_flags} - ;; - esac + echo -n ' rpcbind'; ${portmap_program:-/usr/sbin/rpcbind} \ + ${portmap_flags} - # Start ypserv if we're an NIS server. - # Run rpc.ypxfrd and rpc.yppasswdd only on the NIS master server. - # - case ${nis_server_enable} in - [Yy][Ee][Ss]) - echo -n ' ypserv'; ypserv ${nis_server_flags} - - case ${nis_ypxfrd_enable} in + # Start ypserv if we're an NIS server. + # Run rpc.ypxfrd and rpc.yppasswdd only on the NIS master server. + # + case ${nis_server_enable} in [Yy][Ee][Ss]) - echo -n ' rpc.ypxfrd' - rpc.ypxfrd ${nis_ypxfrd_flags} + echo -n ' ypserv'; ypserv ${nis_server_flags} + + case ${nis_ypxfrd_enable} in + [Yy][Ee][Ss]) + echo -n ' rpc.ypxfrd' + rpc.ypxfrd ${nis_ypxfrd_flags} + ;; + esac + + case ${nis_yppasswdd_enable} in + [Yy][Ee][Ss]) + echo -n ' rpc.yppasswdd' + rpc.yppasswdd ${nis_yppasswdd_flags} + ;; + esac ;; esac - case ${nis_yppasswdd_enable} in + # Start ypbind if we're an NIS client + # + case ${nis_client_enable} in [Yy][Ee][Ss]) - echo -n ' rpc.yppasswdd' - rpc.yppasswdd ${nis_yppasswdd_flags} + echo -n ' ypbind'; ypbind ${nis_client_flags} + case ${nis_ypset_enable} in + [Yy][Ee][Ss]) + echo -n ' ypset'; ypset ${nis_ypset_flags} + ;; + esac ;; esac - ;; - esac - # Start ypbind if we're an NIS client - # - case ${nis_client_enable} in - [Yy][Ee][Ss]) - echo -n ' ypbind'; ypbind ${nis_client_flags} - case ${nis_ypset_enable} in + # Start keyserv if we are running Secure RPC + # + case ${keyserv_enable} in [Yy][Ee][Ss]) - echo -n ' ypset'; ypset ${nis_ypset_flags} + echo -n ' keyserv'; keyserv ${keyserv_flags} ;; esac - ;; - esac - # Start keyserv if we are running Secure RPC - # - case ${keyserv_enable} in - [Yy][Ee][Ss]) - echo -n ' keyserv'; keyserv ${keyserv_flags} - ;; - esac - - # Start ypupdated if we are running Secure RPC and we are NIS master - # - case ${rpc_ypupdated_enable} in - [Yy][Ee][Ss]) - echo -n ' rpc.ypupdated'; rpc.ypupdated + # Start ypupdated if we are running Secure RPC + # and we are NIS master + # + case ${rpc_ypupdated_enable} in + [Yy][Ee][Ss]) + echo -n ' rpc.ypupdated'; rpc.ypupdated + ;; + esac ;; esac @@ -582,99 +584,103 @@ network_pass2() { network_pass3() { echo -n 'Starting final network daemons:' - case ${nfs_server_enable} in + case ${portmap_enable} in [Yy][Ee][Ss]) - if [ -r /etc/exports ]; then - echo -n ' mountd' - - case ${weak_mountd_authentication} in - [Yy][Ee][Ss]) - mountd_flags="${mountd_flags} -n" - ;; - esac + case ${nfs_server_enable} in + [Yy][Ee][Ss]) + if [ -r /etc/exports ]; then + echo -n ' mountd' - mountd ${mountd_flags} + case ${weak_mountd_authentication} in + [Yy][Ee][Ss]) + mountd_flags="${mountd_flags} -n" + ;; + esac - case ${nfs_reserved_port_only} in - [Yy][Ee][Ss]) - echo -n ' NFS on reserved port only=YES' - sysctl -w vfs.nfs.nfs_privport=1 >/dev/null - ;; - esac + mountd ${mountd_flags} - echo -n ' nfsd'; nfsd ${nfs_server_flags} + case ${nfs_reserved_port_only} in + [Yy][Ee][Ss]) + echo -n ' NFS on reserved port only=YES' + sysctl -w vfs.nfs.nfs_privport=1 > /dev/null + ;; + esac - if [ -n "${nfs_bufpackets}" ]; then - sysctl -w vfs.nfs.bufpackets=${nfs_bufpackets} \ - > /dev/null - fi + echo -n ' nfsd'; nfsd ${nfs_server_flags} - case ${rpc_lockd_enable} in - [Yy][Ee][Ss]) - echo -n ' rpc.lockd'; rpc.lockd - ;; - esac + if [ -n "${nfs_bufpackets}" ]; then + sysctl -w vfs.nfs.bufpackets=${nfs_bufpackets} > /dev/null + fi - case ${rpc_statd_enable} in - [Yy][Ee][Ss]) - echo -n ' rpc.statd'; rpc.statd - ;; - esac - fi - ;; - *) - case ${single_mountd_enable} in - [Yy][Ee][Ss]) - if [ -r /etc/exports ]; then - echo -n ' mountd' + case ${rpc_lockd_enable} in + [Yy][Ee][Ss]) + echo -n ' rpc.lockd'; rpc.lockd + ;; + esac - case ${weak_mountd_authentication} in + case ${rpc_statd_enable} in [Yy][Ee][Ss]) - mountd_flags="-n" + echo -n ' rpc.statd'; rpc.statd ;; esac + fi + ;; + *) + case ${single_mountd_enable} in + [Yy][Ee][Ss]) + if [ -r /etc/exports ]; then + echo -n ' mountd' - mountd ${mountd_flags} + case ${weak_mountd_authentication} in + [Yy][Ee][Ss]) + mountd_flags="-n" + ;; + esac + + mountd ${mountd_flags} + fi + ;; + esac + ;; + esac + + case ${nfs_client_enable} in + [Yy][Ee][Ss]) + echo -n ' nfsiod'; nfsiod ${nfs_client_flags} + if [ -n "${nfs_access_cache}" ]; then + echo -n " NFS access cache time=${nfs_access_cache}" + sysctl -w vfs.nfs.access_cache_timeout=${nfs_access_cache} >/dev/null fi ;; esac - ;; - esac - case ${nfs_client_enable} in - [Yy][Ee][Ss]) - echo -n ' nfsiod'; nfsiod ${nfs_client_flags} - if [ -n "${nfs_access_cache}" ]; then - echo -n " NFS access cache time=${nfs_access_cache}" - sysctl -w vfs.nfs.access_cache_timeout=${nfs_access_cache} \ - >/dev/null + # If /var/db/mounttab exists, some nfs-server has not been + # sucessfully notified about a previous client shutdown. + # If there is no /var/db/mounttab, we do nothing. + if [ -f /var/db/mounttab ]; then + rpc.umntall -k fi - ;; - esac - # If /var/db/mounttab exists, some nfs-server has not been - # sucessfully notified about a previous client shutdown. - # If there is no /var/db/mounttab, we do nothing. - if [ -f /var/db/mounttab ]; then - rpc.umntall -k - fi + case ${amd_enable} in + [Yy][Ee][Ss]) + echo -n ' amd' + case ${amd_map_program} in + [Nn][Oo] | '') + ;; + *) + amd_flags="${amd_flags} `eval\ + ${amd_map_program}`" + ;; + esac - case ${amd_enable} in - [Yy][Ee][Ss]) - echo -n ' amd' - case ${amd_map_program} in - [Nn][Oo] | '') - ;; - *) - amd_flags="${amd_flags} `eval ${amd_map_program}`" + if [ -n "${amd_flags}" ]; then + amd -p ${amd_flags}\ + > /var/run/amd.pid 2> /dev/null + else + amd 2> /dev/null + fi ;; esac - - if [ -n "${amd_flags}" ]; then - amd -p ${amd_flags} > /var/run/amd.pid 2> /dev/null - else - amd 2> /dev/null - fi ;; esac diff --git a/etc/rc.d/routing b/etc/rc.d/routing index ef6c6038b029..c1ffb3735a74 100644 --- a/etc/rc.d/routing +++ b/etc/rc.d/routing @@ -514,59 +514,61 @@ network_pass2() { case ${portmap_enable} in [Yy][Ee][Ss]) - echo -n ' portmap'; ${portmap_program:-/usr/sbin/portmap} ${portmap_flags} - ;; - esac + echo -n ' rpcbind'; ${portmap_program:-/usr/sbin/rpcbind} \ + ${portmap_flags} - # Start ypserv if we're an NIS server. - # Run rpc.ypxfrd and rpc.yppasswdd only on the NIS master server. - # - case ${nis_server_enable} in - [Yy][Ee][Ss]) - echo -n ' ypserv'; ypserv ${nis_server_flags} - - case ${nis_ypxfrd_enable} in + # Start ypserv if we're an NIS server. + # Run rpc.ypxfrd and rpc.yppasswdd only on the NIS master server. + # + case ${nis_server_enable} in [Yy][Ee][Ss]) - echo -n ' rpc.ypxfrd' - rpc.ypxfrd ${nis_ypxfrd_flags} + echo -n ' ypserv'; ypserv ${nis_server_flags} + + case ${nis_ypxfrd_enable} in + [Yy][Ee][Ss]) + echo -n ' rpc.ypxfrd' + rpc.ypxfrd ${nis_ypxfrd_flags} + ;; + esac + + case ${nis_yppasswdd_enable} in + [Yy][Ee][Ss]) + echo -n ' rpc.yppasswdd' + rpc.yppasswdd ${nis_yppasswdd_flags} + ;; + esac ;; esac - case ${nis_yppasswdd_enable} in + # Start ypbind if we're an NIS client + # + case ${nis_client_enable} in [Yy][Ee][Ss]) - echo -n ' rpc.yppasswdd' - rpc.yppasswdd ${nis_yppasswdd_flags} + echo -n ' ypbind'; ypbind ${nis_client_flags} + case ${nis_ypset_enable} in + [Yy][Ee][Ss]) + echo -n ' ypset'; ypset ${nis_ypset_flags} + ;; + esac ;; esac - ;; - esac - # Start ypbind if we're an NIS client - # - case ${nis_client_enable} in - [Yy][Ee][Ss]) - echo -n ' ypbind'; ypbind ${nis_client_flags} - case ${nis_ypset_enable} in + # Start keyserv if we are running Secure RPC + # + case ${keyserv_enable} in [Yy][Ee][Ss]) - echo -n ' ypset'; ypset ${nis_ypset_flags} + echo -n ' keyserv'; keyserv ${keyserv_flags} ;; esac - ;; - esac - # Start keyserv if we are running Secure RPC - # - case ${keyserv_enable} in - [Yy][Ee][Ss]) - echo -n ' keyserv'; keyserv ${keyserv_flags} - ;; - esac - - # Start ypupdated if we are running Secure RPC and we are NIS master - # - case ${rpc_ypupdated_enable} in - [Yy][Ee][Ss]) - echo -n ' rpc.ypupdated'; rpc.ypupdated + # Start ypupdated if we are running Secure RPC + # and we are NIS master + # + case ${rpc_ypupdated_enable} in + [Yy][Ee][Ss]) + echo -n ' rpc.ypupdated'; rpc.ypupdated + ;; + esac ;; esac @@ -582,99 +584,103 @@ network_pass2() { network_pass3() { echo -n 'Starting final network daemons:' - case ${nfs_server_enable} in + case ${portmap_enable} in [Yy][Ee][Ss]) - if [ -r /etc/exports ]; then - echo -n ' mountd' - - case ${weak_mountd_authentication} in - [Yy][Ee][Ss]) - mountd_flags="${mountd_flags} -n" - ;; - esac + case ${nfs_server_enable} in + [Yy][Ee][Ss]) + if [ -r /etc/exports ]; then + echo -n ' mountd' - mountd ${mountd_flags} + case ${weak_mountd_authentication} in + [Yy][Ee][Ss]) + mountd_flags="${mountd_flags} -n" + ;; + esac - case ${nfs_reserved_port_only} in - [Yy][Ee][Ss]) - echo -n ' NFS on reserved port only=YES' - sysctl -w vfs.nfs.nfs_privport=1 >/dev/null - ;; - esac + mountd ${mountd_flags} - echo -n ' nfsd'; nfsd ${nfs_server_flags} + case ${nfs_reserved_port_only} in + [Yy][Ee][Ss]) + echo -n ' NFS on reserved port only=YES' + sysctl -w vfs.nfs.nfs_privport=1 > /dev/null + ;; + esac - if [ -n "${nfs_bufpackets}" ]; then - sysctl -w vfs.nfs.bufpackets=${nfs_bufpackets} \ - > /dev/null - fi + echo -n ' nfsd'; nfsd ${nfs_server_flags} - case ${rpc_lockd_enable} in - [Yy][Ee][Ss]) - echo -n ' rpc.lockd'; rpc.lockd - ;; - esac + if [ -n "${nfs_bufpackets}" ]; then + sysctl -w vfs.nfs.bufpackets=${nfs_bufpackets} > /dev/null + fi - case ${rpc_statd_enable} in - [Yy][Ee][Ss]) - echo -n ' rpc.statd'; rpc.statd - ;; - esac - fi - ;; - *) - case ${single_mountd_enable} in - [Yy][Ee][Ss]) - if [ -r /etc/exports ]; then - echo -n ' mountd' + case ${rpc_lockd_enable} in + [Yy][Ee][Ss]) + echo -n ' rpc.lockd'; rpc.lockd + ;; + esac - case ${weak_mountd_authentication} in + case ${rpc_statd_enable} in [Yy][Ee][Ss]) - mountd_flags="-n" + echo -n ' rpc.statd'; rpc.statd ;; esac + fi + ;; + *) + case ${single_mountd_enable} in + [Yy][Ee][Ss]) + if [ -r /etc/exports ]; then + echo -n ' mountd' - mountd ${mountd_flags} + case ${weak_mountd_authentication} in + [Yy][Ee][Ss]) + mountd_flags="-n" + ;; + esac + + mountd ${mountd_flags} + fi + ;; + esac + ;; + esac + + case ${nfs_client_enable} in + [Yy][Ee][Ss]) + echo -n ' nfsiod'; nfsiod ${nfs_client_flags} + if [ -n "${nfs_access_cache}" ]; then + echo -n " NFS access cache time=${nfs_access_cache}" + sysctl -w vfs.nfs.access_cache_timeout=${nfs_access_cache} >/dev/null fi ;; esac - ;; - esac - case ${nfs_client_enable} in - [Yy][Ee][Ss]) - echo -n ' nfsiod'; nfsiod ${nfs_client_flags} - if [ -n "${nfs_access_cache}" ]; then - echo -n " NFS access cache time=${nfs_access_cache}" - sysctl -w vfs.nfs.access_cache_timeout=${nfs_access_cache} \ - >/dev/null + # If /var/db/mounttab exists, some nfs-server has not been + # sucessfully notified about a previous client shutdown. + # If there is no /var/db/mounttab, we do nothing. + if [ -f /var/db/mounttab ]; then + rpc.umntall -k fi - ;; - esac - # If /var/db/mounttab exists, some nfs-server has not been - # sucessfully notified about a previous client shutdown. - # If there is no /var/db/mounttab, we do nothing. - if [ -f /var/db/mounttab ]; then - rpc.umntall -k - fi + case ${amd_enable} in + [Yy][Ee][Ss]) + echo -n ' amd' + case ${amd_map_program} in + [Nn][Oo] | '') + ;; + *) + amd_flags="${amd_flags} `eval\ + ${amd_map_program}`" + ;; + esac - case ${amd_enable} in - [Yy][Ee][Ss]) - echo -n ' amd' - case ${amd_map_program} in - [Nn][Oo] | '') - ;; - *) - amd_flags="${amd_flags} `eval ${amd_map_program}`" + if [ -n "${amd_flags}" ]; then + amd -p ${amd_flags}\ + > /var/run/amd.pid 2> /dev/null + else + amd 2> /dev/null + fi ;; esac - - if [ -n "${amd_flags}" ]; then - amd -p ${amd_flags} > /var/run/amd.pid 2> /dev/null - else - amd 2> /dev/null - fi ;; esac diff --git a/etc/rc.network b/etc/rc.network index ef6c6038b029..c1ffb3735a74 100644 --- a/etc/rc.network +++ b/etc/rc.network @@ -514,59 +514,61 @@ network_pass2() { case ${portmap_enable} in [Yy][Ee][Ss]) - echo -n ' portmap'; ${portmap_program:-/usr/sbin/portmap} ${portmap_flags} - ;; - esac + echo -n ' rpcbind'; ${portmap_program:-/usr/sbin/rpcbind} \ + ${portmap_flags} - # Start ypserv if we're an NIS server. - # Run rpc.ypxfrd and rpc.yppasswdd only on the NIS master server. - # - case ${nis_server_enable} in - [Yy][Ee][Ss]) - echo -n ' ypserv'; ypserv ${nis_server_flags} - - case ${nis_ypxfrd_enable} in + # Start ypserv if we're an NIS server. + # Run rpc.ypxfrd and rpc.yppasswdd only on the NIS master server. + # + case ${nis_server_enable} in [Yy][Ee][Ss]) - echo -n ' rpc.ypxfrd' - rpc.ypxfrd ${nis_ypxfrd_flags} + echo -n ' ypserv'; ypserv ${nis_server_flags} + + case ${nis_ypxfrd_enable} in + [Yy][Ee][Ss]) + echo -n ' rpc.ypxfrd' + rpc.ypxfrd ${nis_ypxfrd_flags} + ;; + esac + + case ${nis_yppasswdd_enable} in + [Yy][Ee][Ss]) + echo -n ' rpc.yppasswdd' + rpc.yppasswdd ${nis_yppasswdd_flags} + ;; + esac ;; esac - case ${nis_yppasswdd_enable} in + # Start ypbind if we're an NIS client + # + case ${nis_client_enable} in [Yy][Ee][Ss]) - echo -n ' rpc.yppasswdd' - rpc.yppasswdd ${nis_yppasswdd_flags} + echo -n ' ypbind'; ypbind ${nis_client_flags} + case ${nis_ypset_enable} in + [Yy][Ee][Ss]) + echo -n ' ypset'; ypset ${nis_ypset_flags} + ;; + esac ;; esac - ;; - esac - # Start ypbind if we're an NIS client - # - case ${nis_client_enable} in - [Yy][Ee][Ss]) - echo -n ' ypbind'; ypbind ${nis_client_flags} - case ${nis_ypset_enable} in + # Start keyserv if we are running Secure RPC + # + case ${keyserv_enable} in [Yy][Ee][Ss]) - echo -n ' ypset'; ypset ${nis_ypset_flags} + echo -n ' keyserv'; keyserv ${keyserv_flags} ;; esac - ;; - esac - # Start keyserv if we are running Secure RPC - # - case ${keyserv_enable} in - [Yy][Ee][Ss]) - echo -n ' keyserv'; keyserv ${keyserv_flags} - ;; - esac - - # Start ypupdated if we are running Secure RPC and we are NIS master - # - case ${rpc_ypupdated_enable} in - [Yy][Ee][Ss]) - echo -n ' rpc.ypupdated'; rpc.ypupdated + # Start ypupdated if we are running Secure RPC + # and we are NIS master + # + case ${rpc_ypupdated_enable} in + [Yy][Ee][Ss]) + echo -n ' rpc.ypupdated'; rpc.ypupdated + ;; + esac ;; esac @@ -582,99 +584,103 @@ network_pass2() { network_pass3() { echo -n 'Starting final network daemons:' - case ${nfs_server_enable} in + case ${portmap_enable} in [Yy][Ee][Ss]) - if [ -r /etc/exports ]; then - echo -n ' mountd' - - case ${weak_mountd_authentication} in - [Yy][Ee][Ss]) - mountd_flags="${mountd_flags} -n" - ;; - esac + case ${nfs_server_enable} in + [Yy][Ee][Ss]) + if [ -r /etc/exports ]; then + echo -n ' mountd' - mountd ${mountd_flags} + case ${weak_mountd_authentication} in + [Yy][Ee][Ss]) + mountd_flags="${mountd_flags} -n" + ;; + esac - case ${nfs_reserved_port_only} in - [Yy][Ee][Ss]) - echo -n ' NFS on reserved port only=YES' - sysctl -w vfs.nfs.nfs_privport=1 >/dev/null - ;; - esac + mountd ${mountd_flags} - echo -n ' nfsd'; nfsd ${nfs_server_flags} + case ${nfs_reserved_port_only} in + [Yy][Ee][Ss]) + echo -n ' NFS on reserved port only=YES' + sysctl -w vfs.nfs.nfs_privport=1 > /dev/null + ;; + esac - if [ -n "${nfs_bufpackets}" ]; then - sysctl -w vfs.nfs.bufpackets=${nfs_bufpackets} \ - > /dev/null - fi + echo -n ' nfsd'; nfsd ${nfs_server_flags} - case ${rpc_lockd_enable} in - [Yy][Ee][Ss]) - echo -n ' rpc.lockd'; rpc.lockd - ;; - esac + if [ -n "${nfs_bufpackets}" ]; then + sysctl -w vfs.nfs.bufpackets=${nfs_bufpackets} > /dev/null + fi - case ${rpc_statd_enable} in - [Yy][Ee][Ss]) - echo -n ' rpc.statd'; rpc.statd - ;; - esac - fi - ;; - *) - case ${single_mountd_enable} in - [Yy][Ee][Ss]) - if [ -r /etc/exports ]; then - echo -n ' mountd' + case ${rpc_lockd_enable} in + [Yy][Ee][Ss]) + echo -n ' rpc.lockd'; rpc.lockd + ;; + esac - case ${weak_mountd_authentication} in + case ${rpc_statd_enable} in [Yy][Ee][Ss]) - mountd_flags="-n" + echo -n ' rpc.statd'; rpc.statd ;; esac + fi + ;; + *) + case ${single_mountd_enable} in + [Yy][Ee][Ss]) + if [ -r /etc/exports ]; then + echo -n ' mountd' - mountd ${mountd_flags} + case ${weak_mountd_authentication} in + [Yy][Ee][Ss]) + mountd_flags="-n" + ;; + esac + + mountd ${mountd_flags} + fi + ;; + esac + ;; + esac + + case ${nfs_client_enable} in + [Yy][Ee][Ss]) + echo -n ' nfsiod'; nfsiod ${nfs_client_flags} + if [ -n "${nfs_access_cache}" ]; then + echo -n " NFS access cache time=${nfs_access_cache}" + sysctl -w vfs.nfs.access_cache_timeout=${nfs_access_cache} >/dev/null fi ;; esac - ;; - esac - case ${nfs_client_enable} in - [Yy][Ee][Ss]) - echo -n ' nfsiod'; nfsiod ${nfs_client_flags} - if [ -n "${nfs_access_cache}" ]; then - echo -n " NFS access cache time=${nfs_access_cache}" - sysctl -w vfs.nfs.access_cache_timeout=${nfs_access_cache} \ - >/dev/null + # If /var/db/mounttab exists, some nfs-server has not been + # sucessfully notified about a previous client shutdown. + # If there is no /var/db/mounttab, we do nothing. + if [ -f /var/db/mounttab ]; then + rpc.umntall -k fi - ;; - esac - # If /var/db/mounttab exists, some nfs-server has not been - # sucessfully notified about a previous client shutdown. - # If there is no /var/db/mounttab, we do nothing. - if [ -f /var/db/mounttab ]; then - rpc.umntall -k - fi + case ${amd_enable} in + [Yy][Ee][Ss]) + echo -n ' amd' + case ${amd_map_program} in + [Nn][Oo] | '') + ;; + *) + amd_flags="${amd_flags} `eval\ + ${amd_map_program}`" + ;; + esac - case ${amd_enable} in - [Yy][Ee][Ss]) - echo -n ' amd' - case ${amd_map_program} in - [Nn][Oo] | '') - ;; - *) - amd_flags="${amd_flags} `eval ${amd_map_program}`" + if [ -n "${amd_flags}" ]; then + amd -p ${amd_flags}\ + > /var/run/amd.pid 2> /dev/null + else + amd 2> /dev/null + fi ;; esac - - if [ -n "${amd_flags}" ]; then - amd -p ${amd_flags} > /var/run/amd.pid 2> /dev/null - else - amd 2> /dev/null - fi ;; esac @@ -1,8 +1,8 @@ # # $FreeBSD$ -# rpc 88/08/01 4.0 RPCSRC; from 1.12 88/02/07 SMI +# rpc 88/08/01 4.0 RPCSRC; from 1.12 99/07/25 SMI # -portmapper 100000 portmap sunrpc +rpcbind 100000 portmap sunrpc rpcbind rstatd 100001 rstat rstat_svc rup perfmeter rusersd 100002 rusers nfs 100003 nfsprog @@ -29,10 +29,39 @@ status 100024 bootparamd 100026 bootparam ypupdated 100028 ypupdate keyserv 100029 keyserver +sunlink_mapper 100033 tfsd 100037 nsed 100038 nsemntd 100039 -pcnfsd 150001 pcnfs -amd 300019 +showfhd 100043 showfh +ioadmd 100055 rpc.ioadmd +NETlicense 100062 +sunisamd 100065 +debug_svc 100066 dbsrv cmsd 100068 +bugtraqd 100071 +kerbd 100078 ttdbserver 100083 tooltalk +event 100101 na.event # SunNet Manager +logger 100102 na.logger # SunNet Manager +sync 100104 na.sync +hostperf 100107 na.hostperf +activity 100109 na.activity # SunNet Manager +hostmem 100112 na.hostmem +sample 100113 na.sample +x25 100114 na.x25 +ping 100115 na.ping +rpcnfs 100116 na.rpcnfs +hostif 100117 na.hostif +etherif 100118 na.etherif +iproutes 100120 na.iproutes +layers 100121 na.layers +snmp 100122 na.snmp snmp-cmc snmp-synoptics snmp-unisys snmp-utk +traffic 100123 na.traffic +nfs_acl 100227 +sadmind 100232 +nisd 100300 rpc.nisd +nispasswd 100303 rpc.nispasswdd +ufsd 100233 ufsd +pcnfsd 150001 pcnfs +amd 300019 diff --git a/include/Makefile b/include/Makefile index 1b2ac62bbddc..97788a14bdab 100644 --- a/include/Makefile +++ b/include/Makefile @@ -7,13 +7,13 @@ # links. CLEANFILES= osreldate.h version vers.c -SUBDIR= rpcsvc +SUBDIR= rpcsvc rpc FILES= a.out.h ar.h assert.h bitstring.h ctype.h db.h dirent.h disktab.h \ dlfcn.h elf.h err.h fnmatch.h fstab.h \ fts.h glob.h grp.h strhash.h \ hesiod.h histedit.h ieeefp.h ifaddrs.h iso646.h langinfo.h \ libgen.h limits.h link.h locale.h malloc.h memory.h mpool.h \ - ndbm.h netdb.h nl_types.h nlist.h nsswitch.h objformat.h \ + netconfig.h ndbm.h netdb.h nl_types.h nlist.h nsswitch.h objformat.h \ paths.h pthread.h pthread_np.h pwd.h \ ranlib.h regex.h regexp.h resolv.h rune.h runetype.h \ search.h setjmp.h sgtty.h \ @@ -28,10 +28,6 @@ ARPAFILES= ftp.h inet.h nameser.h nameser_compat.h telnet.h tftp.h PROTOFILES= dumprestore.h routed.h rwhod.h talkd.h timed.h -RPCFILES= auth.h auth_unix.h clnt.h pmap_clnt.h pmap_prot.h pmap_rmt.h \ - rpc.h rpc_com.h rpc_msg.h svc.h svc_auth.h types.h xdr.h \ - auth_des.h des.h des_crypt.h - MFILES= float.h floatingpoint.h stdarg.h varargs.h # posix4/aio.h conflicts with dysons and isn't installed: @@ -86,9 +82,6 @@ beforeinstall: ${SHARED} cd ${.CURDIR}/protocols; \ ${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 \ ${PROTOFILES} ${DESTDIR}/usr/include/protocols - cd ${.CURDIR}/rpc; \ - ${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 \ - ${RPCFILES} ${DESTDIR}/usr/include/rpc ${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 \ ${.OBJDIR}/osreldate.h \ ${DESTDIR}/usr/include diff --git a/include/netconfig.h b/include/netconfig.h new file mode 100644 index 000000000000..330a5ee281c0 --- /dev/null +++ b/include/netconfig.h @@ -0,0 +1,96 @@ +/* $NetBSD: netconfig.h,v 1.1 2000/06/02 22:57:54 fvdl Exp $ */ +/* $FreeBSD$ */ + + +#ifndef _NETCONFIG_H_ +#define _NETCONFIG_H_ + +#include <sys/cdefs.h> + +#define NETCONFIG "/etc/netconfig" +#define NETPATH "NETPATH" + +struct netconfig { + char *nc_netid; /* Network ID */ + unsigned long nc_semantics; /* Semantics (see below) */ + unsigned long nc_flag; /* Flags (see below) */ + char *nc_protofmly; /* Protocol family */ + char *nc_proto; /* Protocol name */ + char *nc_device; /* Network device pathname */ + unsigned long nc_nlookups; /* Number of directory lookup libs */ + char **nc_lookups; /* Names of the libraries */ + unsigned long nc_unused[9]; /* reserved */ +}; + +typedef struct { + struct netconfig **nc_head; + struct netconfig **nc_curr; +} NCONF_HANDLE; + +/* + * nc_semantics values + */ +#define NC_TPI_CLTS 1 +#define NC_TPI_COTS 2 +#define NC_TPI_COTS_ORD 3 +#define NC_TPI_RAW 4 + +/* + * nc_flag values + */ +#define NC_NOFLAG 0x00 +#define NC_VISIBLE 0x01 +#define NC_BROADCAST 0x02 + +/* + * nc_protofmly values + */ +#define NC_NOPROTOFMLY "-" +#define NC_LOOPBACK "loopback" +#define NC_INET "inet" +#define NC_INET6 "inet6" +#define NC_IMPLINK "implink" +#define NC_PUP "pup" +#define NC_CHAOS "chaos" +#define NC_NS "ns" +#define NC_NBS "nbs" +#define NC_ECMA "ecma" +#define NC_DATAKIT "datakit" +#define NC_CCITT "ccitt" +#define NC_SNA "sna" +#define NC_DECNET "decnet" +#define NC_DLI "dli" +#define NC_LAT "lat" +#define NC_HYLINK "hylink" +#define NC_APPLETALK "appletalk" +#define NC_NIT "nit" +#define NC_IEEE802 "ieee802" +#define NC_OSI "osi" +#define NC_X25 "x25" +#define NC_OSINET "osinet" +#define NC_GOSIP "gosip" + +/* + * nc_proto values + */ +#define NC_NOPROTO "-" +#define NC_TCP "tcp" +#define NC_UDP "udp" +#define NC_ICMP "icmp" + +__BEGIN_DECLS +void *setnetconfig __P((void)); +struct netconfig *getnetconfig __P((void *)); +struct netconfig *getnetconfigent __P((char *)); +void freenetconfigent __P((struct netconfig *)); +int endnetconfig __P((void *)); + +void *setnetpath __P((void)); +struct netconfig *getnetpath __P((void *)); +int endnetpath(void *); + +void nc_perror __P((const char *)); +char *nc_sperror __P((void)); +__END_DECLS + +#endif /* _NETCONFIG_H_ */ diff --git a/include/pthread_np.h b/include/pthread_np.h index 485048bee30c..f5ac7f5aeb7c 100644 --- a/include/pthread_np.h +++ b/include/pthread_np.h @@ -29,6 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * + * $FreeBSD$ */ #ifndef _PTHREAD_NP_H_ #define _PTHREAD_NP_H_ @@ -52,6 +53,7 @@ int pthread_mutexattr_setkind_np __P((pthread_mutexattr_t *, int)); void pthread_set_name_np __P((pthread_t, char *)); int pthread_switch_add_np __P((pthread_switch_routine_t)); int pthread_switch_delete_np __P((pthread_switch_routine_t)); +int pthread_main_np __P((void)); __END_DECLS #endif diff --git a/include/rpc/Makefile b/include/rpc/Makefile new file mode 100644 index 000000000000..1d159746eda4 --- /dev/null +++ b/include/rpc/Makefile @@ -0,0 +1,37 @@ +# from: @(#)Makefile 2.3 88/08/11 4.0 RPCSRC +# $FreeBSD$ + +.SUFFIXES: .x + +RPCCOM = rpcgen -C + +HDRS= rpcb_prot.h + +XFILES= rpcb_prot.x + +HFILES= auth.h auth_unix.h clnt.h clnt_soc.h clnt_stat.h \ + nettype.h pmap_clnt.h pmap_prot.h pmap_rmt.h raw.h \ + rpc.h rpc_msg.h rpcb_clnt.h rpcent.h rpc_com.h \ + svc.h svc_auth.h svc_soc.h svc_dg.h types.h xdr.h + +# Secure RPC +HFILES+= auth_des.h des.h des_crypt.h + +# Kerberos +HFILES+= auth_kerb.h + +CLEANFILES+= ${HDRS} + +all: ${HDRS} + +beforeinstall: + ${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 \ + ${HFILES:S;^;${.CURDIR}/;} \ + ${XFILES:S;^;${.CURDIR}/;} \ + ${HDRS} \ + ${DESTDIR}/usr/include/rpc + +.x.h: + ${RPCCOM} -h -DWANT_NFS3 ${.IMPSRC} -o ${.TARGET} + +.include <bsd.prog.mk> diff --git a/include/rpc/auth.h b/include/rpc/auth.h index 4d6c38dbac17..68e8827b910c 100644 --- a/include/rpc/auth.h +++ b/include/rpc/auth.h @@ -1,3 +1,5 @@ +/* $NetBSD: auth.h,v 1.15 2000/06/02 22:57:55 fvdl Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -28,6 +30,7 @@ * * from: @(#)auth.h 1.17 88/02/08 SMI * from: @(#)auth.h 2.3 88/08/07 4.0 RPCSRC + * from: @(#)auth.h 1.43 98/02/02 SMI * $FreeBSD$ */ @@ -43,6 +46,8 @@ #ifndef _RPC_AUTH_H #define _RPC_AUTH_H +#include <rpc/xdr.h> +#include <rpc/clnt_stat.h> #include <sys/cdefs.h> #include <sys/socket.h> @@ -50,6 +55,67 @@ #define MAXNETNAMELEN 255 /* maximum length of network user's name */ /* + * Client side authentication/security data + */ + +typedef struct sec_data { + u_int secmod; /* security mode number e.g. in nfssec.conf */ + u_int rpcflavor; /* rpc flavors:AUTH_UNIX,AUTH_DES,RPCSEC_GSS */ + int flags; /* AUTH_F_xxx flags */ + caddr_t data; /* opaque data per flavor */ +} sec_data_t; + +#ifdef _SYSCALL32_IMPL +struct sec_data32 { + uint32_t secmod; /* security mode number e.g. in nfssec.conf */ + uint32_t rpcflavor; /* rpc flavors:AUTH_UNIX,AUTH_DES,RPCSEC_GSS */ + int32_t flags; /* AUTH_F_xxx flags */ + caddr32_t data; /* opaque data per flavor */ +}; +#endif /* _SYSCALL32_IMPL */ + +/* + * AUTH_DES flavor specific data from sec_data opaque data field. + * AUTH_KERB has the same structure. + */ +typedef struct des_clnt_data { + struct netbuf syncaddr; /* time sync addr */ + struct knetconfig *knconf; /* knetconfig info that associated */ + /* with the syncaddr. */ + char *netname; /* server's netname */ + int netnamelen; /* server's netname len */ +} dh_k4_clntdata_t; + +#ifdef _SYSCALL32_IMPL +struct des_clnt_data32 { + struct netbuf32 syncaddr; /* time sync addr */ + caddr32_t knconf; /* knetconfig info that associated */ + /* with the syncaddr. */ + caddr32_t netname; /* server's netname */ + int32_t netnamelen; /* server's netname len */ +}; +#endif /* _SYSCALL32_IMPL */ + +#ifdef KERBEROS +/* + * flavor specific data to hold the data for AUTH_DES/AUTH_KERB(v4) + * in sec_data->data opaque field. + */ +typedef struct krb4_svc_data { + int window; /* window option value */ +} krb4_svcdata_t; + +typedef struct krb4_svc_data des_svcdata_t; +#endif /* KERBEROS */ + +/* + * authentication/security specific flags + */ +#define AUTH_F_RPCTIMESYNC 0x001 /* use RPC to do time sync */ +#define AUTH_F_TRYNONE 0x002 /* allow fall back to AUTH_NONE */ + + +/* * Status returned from authentication check */ enum auth_stat { @@ -67,18 +133,32 @@ enum auth_stat { */ AUTH_INVALIDRESP=6, /* bogus response verifier */ AUTH_FAILED=7 /* some unknown reason */ +#ifdef KERBEROS + /* + * kerberos errors + */ + AUTH_KERB_GENERIC = 8, /* kerberos generic error */ + AUTH_TIMEEXPIRE = 9, /* time of credential expired */ + AUTH_TKT_FILE = 10, /* something wrong with ticket file */ + AUTH_DECODE = 11, /* can't decode authenticator */ + AUTH_NET_ADDR = 12 /* wrong net address in ticket */ +#endif /* KERBEROS */ }; union des_block { struct { - u_int32_t high; - u_int32_t low; + uint32_t high; + uint32_t low; } key; char c[8]; }; typedef union des_block des_block; __BEGIN_DECLS -extern bool_t xdr_des_block __P((XDR *, des_block *)); +#ifdef __STDC__ +extern bool_t xdr_des_block(XDR *, des_block *); +#else +extern bool_t xdr_des_block(); +#endif __END_DECLS /* @@ -89,29 +169,26 @@ struct opaque_auth { caddr_t oa_base; /* address of more auth stuff */ u_int oa_length; /* not to exceed MAX_AUTH_BYTES */ }; -__BEGIN_DECLS -bool_t xdr_opaque_auth __P((XDR *xdrs, struct opaque_auth *ap)); -__END_DECLS /* * Auth handle, interface to client side authenticators. */ -typedef struct __rpc_auth { +typedef struct __auth { struct opaque_auth ah_cred; struct opaque_auth ah_verf; union des_block ah_key; struct auth_ops { - void (*ah_nextverf) __P((struct __rpc_auth *)); + void (*ah_nextverf) (struct __auth *); /* nextverf & serialize */ - int (*ah_marshal) __P((struct __rpc_auth *, XDR *)); + int (*ah_marshal) (struct __auth *, XDR *); /* validate verifier */ - int (*ah_validate) __P((struct __rpc_auth *, - struct opaque_auth *)); + int (*ah_validate) (struct __auth *, + struct opaque_auth *); /* refresh credentials */ - int (*ah_refresh) __P((struct __rpc_auth *)); + int (*ah_refresh) (struct __auth *, void *); /* destroy this structure */ - void (*ah_destroy) __P((struct __rpc_auth *)); + void (*ah_destroy) (struct __auth *); } *ah_ops; caddr_t ah_private; } AUTH; @@ -140,10 +217,10 @@ typedef struct __rpc_auth { #define auth_validate(auth, verfp) \ ((*((auth)->ah_ops->ah_validate))((auth), verfp)) -#define AUTH_REFRESH(auth) \ - ((*((auth)->ah_ops->ah_refresh))(auth)) -#define auth_refresh(auth) \ - ((*((auth)->ah_ops->ah_refresh))(auth)) +#define AUTH_REFRESH(auth, msg) \ + ((*((auth)->ah_ops->ah_refresh))(auth, msg)) +#define auth_refresh(auth, msg) \ + ((*((auth)->ah_ops->ah_refresh))(auth, msg)) #define AUTH_DESTROY(auth) \ ((*((auth)->ah_ops->ah_destroy))(auth)) @@ -151,14 +228,16 @@ typedef struct __rpc_auth { ((*((auth)->ah_ops->ah_destroy))(auth)) +__BEGIN_DECLS extern struct opaque_auth _null_auth; +__END_DECLS /* * These are the various implementations of client side authenticators. */ /* - * Unix style authentication + * System style authentication * AUTH *authunix_create(machname, uid, gid, len, aup_gids) * char *machname; * int uid; @@ -167,94 +246,105 @@ extern struct opaque_auth _null_auth; * int *aup_gids; */ __BEGIN_DECLS -struct sockaddr_in; -extern AUTH *authunix_create __P((char *, int, int, int, int *)); -extern AUTH *authunix_create_default __P((void)); -extern AUTH *authnone_create __P((void)); +extern AUTH *authunix_create(char *, int, int, int, + int *); +extern AUTH *authunix_create_default(void); /* takes no parameters */ +extern AUTH *authnone_create(void); /* takes no parameters */ __END_DECLS - -/* Forward compatibility with TI-RPC */ -#define authsys_create authunix_create -#define authsys_create_default authunix_create_default - /* * DES style authentication - * AUTH *authdes_create(servername, window, timehost, ckey) + * AUTH *authsecdes_create(servername, window, timehost, ckey) * char *servername; - network name of server * u_int window; - time to live - * struct sockaddr *timehost; - optional hostname to sync with + * const char *timehost; - optional hostname to sync with * des_block *ckey; - optional conversation key to use */ __BEGIN_DECLS -extern AUTH *authdes_create __P(( char *, u_int, struct sockaddr *, des_block * )); -#ifdef NOTYET -/* - * TI-RPC supports this call, but it requires the inclusion of - * NIS+-specific headers which would require the inclusion of other - * headers which would result in a tangled mess. For now, the NIS+ - * code prototypes this routine internally. - */ -extern AUTH *authdes_pk_create __P(( char *, netobj *, u_int, - struct sockaddr *, des_block *, - nis_server * )); -#endif +extern AUTH *authdes_create (char *, u_int, struct sockaddr *, des_block *); +extern AUTH *authdes_seccreate (const char *, const u_int, const char *, + const des_block *); +__END_DECLS + +__BEGIN_DECLS +extern bool_t xdr_opaque_auth __P((XDR *, struct opaque_auth *)); __END_DECLS +#define authsys_create(c,i1,i2,i3,ip) authunix_create((c),(i1),(i2),(i3),(ip)) +#define authsys_create_default() authunix_create_default() + /* * Netname manipulation routines. */ __BEGIN_DECLS -extern int netname2user __P(( char *, uid_t *, gid_t *, int *, gid_t *)); -extern int netname2host __P(( char *, char *, int )); -extern int getnetname __P(( char * )); -extern int user2netname __P(( char *, uid_t, char * )); -extern int host2netname __P(( char *, char *, char * )); -extern void passwd2des __P(( char *, char * )); +extern int getnetname(char *); +extern int host2netname(char *, const char *, const char *); +extern int user2netname(char *, const uid_t, const char *); +extern int netname2user(char *, uid_t *, gid_t *, int *, gid_t *); +extern int netname2host(char *, char *, const int); +extern void passwd2des ( char *, char * ); __END_DECLS /* - * Keyserv interface routines. - * XXX Should not be here. + * + * These routines interface to the keyserv daemon + * */ -#ifndef HEXKEYBYTES -#define HEXKEYBYTES 48 -#endif -typedef char kbuf[HEXKEYBYTES]; -typedef char *namestr; - -struct netstarg { - kbuf st_priv_key; - kbuf st_pub_key; - namestr st_netname; -}; +__BEGIN_DECLS +extern int key_decryptsession(const char *, des_block *); +extern int key_encryptsession(const char *, des_block *); +extern int key_gendes(des_block *); +extern int key_setsecret(const char *); +extern int key_secretkey_is_set(void); +__END_DECLS +#ifdef KERBEROS +/* + * Kerberos style authentication + * AUTH *authkerb_seccreate(service, srv_inst, realm, window, timehost, status) + * const char *service; - service name + * const char *srv_inst; - server instance + * const char *realm; - server realm + * const u_int window; - time to live + * const char *timehost; - optional hostname to sync with + * int *status; - kerberos status returned + */ __BEGIN_DECLS -extern int key_decryptsession __P(( const char *, des_block * )); -extern int key_decryptsession_pk __P(( char *, netobj *, des_block * )); -extern int key_encryptsession __P(( const char *, des_block * )); -extern int key_encryptsession_pk __P(( char *, netobj *, des_block * )); -extern int key_gendes __P(( des_block * )); -extern int key_setsecret __P(( const char * )); -extern int key_secretkey_is_set __P(( void )); -extern int key_setnet __P(( struct netstarg * )); -extern int key_get_conv __P(( char *, des_block * )); +extern AUTH *authkerb_seccreate(const char *, const char *, const char *, + const u_int, const char *, int *); __END_DECLS /* - * Publickey routines. + * Map a kerberos credential into a unix cred. + * + * authkerb_getucred(rqst, uid, gid, grouplen, groups) + * const struct svc_req *rqst; - request pointer + * uid_t *uid; + * gid_t *gid; + * short *grouplen; + * int *groups; + * */ __BEGIN_DECLS -extern int getpublickey __P(( char *, char * )); -extern int getpublicandprivatekey __P(( char *, char * )); -extern int getsecretkey __P(( char *, char *, char * )); +extern int authkerb_getucred(/* struct svc_req *, uid_t *, gid_t *, + short *, int * */); __END_DECLS +#endif /* KERBEROS */ +__BEGIN_DECLS +struct svc_req; +struct rpc_msg; +enum auth_stat _svcauth_null __P((struct svc_req *, struct rpc_msg *)); +enum auth_stat _svcauth_short __P((struct svc_req *, struct rpc_msg *)); +enum auth_stat _svcauth_unix __P((struct svc_req *, struct rpc_msg *)); +__END_DECLS #define AUTH_NONE 0 /* no authentication */ #define AUTH_NULL 0 /* backward compatibility */ -#define AUTH_UNIX 1 /* unix style (uid, gids) */ -#define AUTH_SYS 1 /* forward compatibility */ +#define AUTH_SYS 1 /* unix style (uid, gids) */ +#define AUTH_UNIX AUTH_SYS #define AUTH_SHORT 2 /* short hand unix style */ -#define AUTH_DES 3 /* des style (encrypted timestamps) */ +#define AUTH_DH 3 /* for Diffie-Hellman mechanism */ +#define AUTH_DES AUTH_DH /* for backward compatibility */ +#define AUTH_KERB 4 /* kerberos style */ #endif /* !_RPC_AUTH_H */ diff --git a/include/rpc/auth_des.h b/include/rpc/auth_des.h index a7635f87e17c..964e77480da7 100644 --- a/include/rpc/auth_des.h +++ b/include/rpc/auth_des.h @@ -1,4 +1,5 @@ /* @(#)auth_des.h 2.2 88/07/29 4.0 RPCSRC; from 1.3 88/02/08 SMI */ +/* $FreeBSD$ */ /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -26,10 +27,13 @@ * Sun Microsystems, Inc. * 2550 Garcia Avenue * Mountain View, California 94043 + * + * from: @(#)auth_des.h 2.2 88/07/29 4.0 RPCSRC + * from: @(#)auth_des.h 1.14 94/04/25 SMI */ /* - * Copyright (c) 1988 by Sun Microsystems, Inc. + * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. */ /* @@ -102,8 +106,21 @@ struct authdes_verf { #define adv_xtimeverf adv_time_u.adv_xtime #define adv_nickname adv_int_u +/* + * Map a des credential into a unix cred. + * + */ __BEGIN_DECLS extern int authdes_getucred __P(( struct authdes_cred *, uid_t *, gid_t *, int *, gid_t * )); __END_DECLS +__BEGIN_DECLS +extern bool_t xdr_authdes_cred(XDR *, struct authdes_cred *); +extern bool_t xdr_authdes_verf(XDR *, struct authdes_verf *); +extern int rtime(dev_t, struct netbuf *, int, struct timeval *, + struct timeval *); +extern void kgetnetname(char *); +extern enum auth_stat _svcauth_des(struct svc_req *, struct rpc_msg *); +__END_DECLS + #endif /* ndef _AUTH_DES_ */ diff --git a/include/rpc/auth_kerb.h b/include/rpc/auth_kerb.h new file mode 100644 index 000000000000..f0145bd4789d --- /dev/null +++ b/include/rpc/auth_kerb.h @@ -0,0 +1,143 @@ +/* $FreeBSD$ */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* + * auth_kerb.h, Protocol for Kerberos style authentication for RPC + * + * Copyright (C) 1986, Sun Microsystems, Inc. + */ + +#ifndef _RPC_AUTH_KERB_H +#define _RPC_AUTH_KERB_H + +#ifdef KERBEROS + +#pragma ident "@(#)auth_kerb.h 1.10 94/04/25 SMI" + +#include <kerberos/krb.h> +#include <sys/socket.h> +#include <sys/t_kuser.h> +#include <netinet/in.h> +#include <rpc/svc.h> + +/* + * There are two kinds of "names": fullnames and nicknames + */ +enum authkerb_namekind { + AKN_FULLNAME, + AKN_NICKNAME +}; +/* + * A fullname contains the ticket and the window + */ +struct authkerb_fullname { + KTEXT_ST ticket; + u_long window; /* associated window */ +}; + +/* + * cooked credential stored in rq_clntcred + */ +struct authkerb_clnt_cred { + /* start of AUTH_DAT */ + unsigned char k_flags; /* Flags from ticket */ + char pname[ANAME_SZ]; /* Principal's name */ + char pinst[INST_SZ]; /* His Instance */ + char prealm[REALM_SZ]; /* His Realm */ + unsigned long checksum; /* Data checksum (opt) */ + C_Block session; /* Session Key */ + int life; /* Life of ticket */ + unsigned long time_sec; /* Time ticket issued */ + unsigned long address; /* Address in ticket */ + /* KTEXT_ST reply; Auth reply (opt) */ + /* end of AUTH_DAT */ + unsigned long expiry; /* time the ticket is expiring */ + u_long nickname; /* Nickname into cache */ + u_long window; /* associated window */ +}; + +typedef struct authkerb_clnt_cred authkerb_clnt_cred; + +/* + * A credential + */ +struct authkerb_cred { + enum authkerb_namekind akc_namekind; + struct authkerb_fullname akc_fullname; + u_long akc_nickname; +}; + +/* + * A kerb authentication verifier + */ +struct authkerb_verf { + union { + struct timeval akv_ctime; /* clear time */ + des_block akv_xtime; /* crypt time */ + } akv_time_u; + u_long akv_int_u; +}; + +/* + * des authentication verifier: client variety + * + * akv_timestamp is the current time. + * akv_winverf is the credential window + 1. + * Both are encrypted using the conversation key. + */ +#ifndef akv_timestamp +#define akv_timestamp akv_time_u.akv_ctime +#define akv_xtimestamp akv_time_u.akv_xtime +#define akv_winverf akv_int_u +#endif +/* + * des authentication verifier: server variety + * + * akv_timeverf is the client's timestamp + client's window + * akv_nickname is the server's nickname for the client. + * akv_timeverf is encrypted using the conversation key. + */ +#ifndef akv_timeverf +#define akv_timeverf akv_time_u.akv_ctime +#define akv_xtimeverf akv_time_u.akv_xtime +#define akv_nickname akv_int_u +#endif + +/* + * Register the service name, instance and realm. + */ +extern int authkerb_create(char *, char *, char *, u_int, + struct netbuf *, int *, dev_t, int, AUTH **); +extern bool_t xdr_authkerb_cred(XDR *, struct authkerb_cred *); +extern bool_t xdr_authkerb_verf(XDR *, struct authkerb_verf *); +extern int svc_kerb_reg(SVCXPRT *, char *, char *, char *); +extern enum auth_stat _svcauth_kerb(struct svc_req *, struct rpc_msg *); + +#endif KERBEROS +#endif /* !_RPC_AUTH_KERB_H */ diff --git a/include/rpc/clnt.h b/include/rpc/clnt.h index cf2116d611fa..2b0587b169ef 100644 --- a/include/rpc/clnt.h +++ b/include/rpc/clnt.h @@ -1,3 +1,5 @@ +/* $NetBSD: clnt.h,v 1.14 2000/06/02 22:57:55 fvdl Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -26,7 +28,7 @@ * 2550 Garcia Avenue * Mountain View, California 94043 * - * from: @(#)clnt.h 1.31 88/02/08 SMI + * from: @(#)clnt.h 1.31 94/04/29 SMI * from: @(#)clnt.h 2.1 88/07/29 4.0 RPCSRC * $FreeBSD$ */ @@ -39,52 +41,28 @@ #ifndef _RPC_CLNT_H_ #define _RPC_CLNT_H_ +#include <rpc/clnt_stat.h> #include <sys/cdefs.h> +#include <netconfig.h> #include <sys/un.h> /* - * Rpc calls return an enum clnt_stat. This should be looked at more, - * since each implementation is required to live with this (implementation - * independent) list of errors. + * Well-known IPV6 RPC broadcast address. */ -enum clnt_stat { - RPC_SUCCESS=0, /* call succeeded */ - /* - * local errors - */ - RPC_CANTENCODEARGS=1, /* can't encode arguments */ - RPC_CANTDECODERES=2, /* can't decode results */ - RPC_CANTSEND=3, /* failure in sending call */ - RPC_CANTRECV=4, /* failure in receiving result */ - RPC_TIMEDOUT=5, /* call timed out */ - /* - * remote errors - */ - RPC_VERSMISMATCH=6, /* rpc versions not compatible */ - RPC_AUTHERROR=7, /* authentication error */ - RPC_PROGUNAVAIL=8, /* program not available */ - RPC_PROGVERSMISMATCH=9, /* program version mismatched */ - RPC_PROCUNAVAIL=10, /* procedure unavailable */ - RPC_CANTDECODEARGS=11, /* decode arguments error */ - RPC_SYSTEMERROR=12, /* generic "other problem" */ - - /* - * callrpc & clnt_create errors - */ - RPC_UNKNOWNHOST=13, /* unknown host name */ - RPC_UNKNOWNPROTO=17, /* unkown protocol */ - - /* - * _ create errors - */ - RPC_PMAPFAILURE=14, /* the pmapper failed in its call */ - RPC_PROGNOTREGISTERED=15, /* remote program is not registered */ - /* - * unspecified error - */ - RPC_FAILED=16 -}; +#define RPCB_MULTICAST_ADDR "ff02::202" +/* + * the following errors are in general unrecoverable. The caller + * should give up rather than retry. + */ +#define IS_UNRECOVERABLE_RPC(s) (((s) == RPC_AUTHERROR) || \ + ((s) == RPC_CANTENCODEARGS) || \ + ((s) == RPC_CANTDECODERES) || \ + ((s) == RPC_VERSMISMATCH) || \ + ((s) == RPC_PROCUNAVAIL) || \ + ((s) == RPC_PROGUNAVAIL) || \ + ((s) == RPC_PROGVERSMISMATCH) || \ + ((s) == RPC_CANTDECODEARGS)) /* * Error info. @@ -95,8 +73,8 @@ struct rpc_err { int RE_errno; /* related system error */ enum auth_stat RE_why; /* why the auth error occurred */ struct { - u_int32_t low; /* lowest verion supported */ - u_int32_t high; /* highest verion supported */ + rpcvers_t low; /* lowest version supported */ + rpcvers_t high; /* highest version supported */ } RE_vers; struct { /* maybe meaningful if RPC_FAILED */ int32_t s1; @@ -112,7 +90,7 @@ struct rpc_err { /* * Client rpc handle. - * Created by individual implementations, see e.g. rpc_udp.c. + * Created by individual implementations * Client is responsible for initializing auth, see e.g. auth_none.c. */ typedef struct __rpc_client { @@ -120,7 +98,7 @@ typedef struct __rpc_client { struct clnt_ops { /* call remote procedure */ enum clnt_stat (*cl_call) __P((struct __rpc_client *, - u_long, xdrproc_t, caddr_t, xdrproc_t, + rpcproc_t, xdrproc_t, caddr_t, xdrproc_t, caddr_t, struct timeval)); /* abort a call */ void (*cl_abort) __P((struct __rpc_client *)); @@ -134,13 +112,37 @@ typedef struct __rpc_client { void (*cl_destroy) __P((struct __rpc_client *)); /* the ioctl() of rpc */ bool_t (*cl_control) __P((struct __rpc_client *, u_int, - void *)); + char *)); } *cl_ops; - caddr_t cl_private; /* private stuff */ + void *cl_private; /* private stuff */ + char *cl_netid; /* network token */ + char *cl_tp; /* device name */ } CLIENT; /* + * Timers used for the pseudo-transport protocol when using datagrams + */ +struct rpc_timers { + u_short rt_srtt; /* smoothed round-trip time */ + u_short rt_deviate; /* estimated deviation */ + u_long rt_rtxcur; /* current (backed-off) rto */ +}; + +/* + * Feedback values used for possible congestion and rate control + */ +#define FEEDBACK_REXMIT1 1 /* first retransmit */ +#define FEEDBACK_OK 2 /* no retransmits */ + +/* Used to set version of portmapper used in broadcast */ + +#define CLCR_SET_LOWVERS 3 +#define CLCR_GET_LOWVERS 4 + +#define RPCSMALLMSGSIZE 400 /* a more reasonable packet size */ + +/* * client side rpc interface ops * * Parameter types are: @@ -151,19 +153,19 @@ typedef struct __rpc_client { * enum clnt_stat * CLNT_CALL(rh, proc, xargs, argsp, xres, resp, timeout) * CLIENT *rh; - * u_long proc; + * rpcproc_t proc; * xdrproc_t xargs; * caddr_t argsp; * xdrproc_t xres; * caddr_t resp; * struct timeval timeout; */ -#define CLNT_CALL(rh, proc, xargs, argsp, xres, resp, secs) \ - ((*(rh)->cl_ops->cl_call)(rh, proc, xargs, (caddr_t)argsp, \ - xres, (caddr_t)resp, secs)) -#define clnt_call(rh, proc, xargs, argsp, xres, resp, secs) \ - ((*(rh)->cl_ops->cl_call)(rh, proc, xargs, (caddr_t)argsp, \ - xres, (caddr_t)resp, secs)) +#define CLNT_CALL(rh, proc, xargs, argsp, xres, resp, secs) \ + ((*(rh)->cl_ops->cl_call)(rh, proc, xargs, \ + (caddr_t)(void *)argsp, xres, (caddr_t)(void *)resp, secs)) +#define clnt_call(rh, proc, xargs, argsp, xres, resp, secs) \ + ((*(rh)->cl_ops->cl_call)(rh, proc, xargs, \ + (caddr_t)(void *)argsp, xres, (caddr_t)(void *)resp, secs)) /* * void @@ -203,43 +205,31 @@ typedef struct __rpc_client { #define clnt_control(cl,rq,in) ((*(cl)->cl_ops->cl_control)(cl,rq,in)) /* - * control operations that apply to udp, tcp and unix transports - * - * Note: options marked XXX are no-ops in this implementation of RPC. - * The are present in TI-RPC but can't be implemented here since they - * depend on the presence of STREAMS/TLI, which we don't have. - * + * control operations that apply to both udp and tcp transports */ -#define CLSET_TIMEOUT 1 /* set timeout (timeval) */ -#define CLGET_TIMEOUT 2 /* get timeout (timeval) */ -#define CLGET_SERVER_ADDR 3 /* get server's address (sockaddr) */ -#define CLGET_FD 6 /* get connections file descriptor */ -#define CLGET_SVC_ADDR 7 /* get server's address (netbuf) XXX */ -#define CLSET_FD_CLOSE 8 /* close fd while clnt_destroy */ -#define CLSET_FD_NCLOSE 9 /* Do not close fd while clnt_destroy */ -#define CLGET_XID 10 /* Get xid */ -#define CLSET_XID 11 /* Set xid */ -#define CLGET_VERS 12 /* Get version number */ -#define CLSET_VERS 13 /* Set version number */ -#define CLGET_PROG 14 /* Get program number */ -#define CLSET_PROG 15 /* Set program number */ -#define CLSET_SVC_ADDR 16 /* get server's address (netbuf) XXX */ -#define CLSET_PUSH_TIMOD 17 /* push timod if not already present XXX */ -#define CLSET_POP_TIMOD 18 /* pop timod XXX */ - +#define CLSET_TIMEOUT 1 /* set timeout (timeval) */ +#define CLGET_TIMEOUT 2 /* get timeout (timeval) */ +#define CLGET_SERVER_ADDR 3 /* get server's address (sockaddr) */ +#define CLGET_FD 6 /* get connections file descriptor */ +#define CLGET_SVC_ADDR 7 /* get server's address (netbuf) */ +#define CLSET_FD_CLOSE 8 /* close fd while clnt_destroy */ +#define CLSET_FD_NCLOSE 9 /* Do not close fd while clnt_destroy */ +#define CLGET_XID 10 /* Get xid */ +#define CLSET_XID 11 /* Set xid */ +#define CLGET_VERS 12 /* Get version number */ +#define CLSET_VERS 13 /* Set version number */ +#define CLGET_PROG 14 /* Get program number */ +#define CLSET_PROG 15 /* Set program number */ +#define CLSET_SVC_ADDR 16 /* get server's address (netbuf) */ +#define CLSET_PUSH_TIMOD 17 /* push timod if not already present */ +#define CLSET_POP_TIMOD 18 /* pop timod */ /* - * udp only control operations + * Connectionless only control operations */ #define CLSET_RETRY_TIMEOUT 4 /* set retry timeout (timeval) */ #define CLGET_RETRY_TIMEOUT 5 /* get retry timeout (timeval) */ /* - * Operations which GSSAPI needs. (Bletch.) - */ -#define CLGET_LOCAL_ADDR 19 /* get local addr (sockaddr) */ - - -/* * void * CLNT_DESTROY(rh); * CLIENT *rh; @@ -254,16 +244,16 @@ typedef struct __rpc_client { * and network administration. */ -#define RPCTEST_PROGRAM ((u_long)1) -#define RPCTEST_VERSION ((u_long)1) -#define RPCTEST_NULL_PROC ((u_long)2) -#define RPCTEST_NULL_BATCH_PROC ((u_long)3) +#define RPCTEST_PROGRAM ((rpcprog_t)1) +#define RPCTEST_VERSION ((rpcvers_t)1) +#define RPCTEST_NULL_PROC ((rpcproc_t)2) +#define RPCTEST_NULL_BATCH_PROC ((rpcproc_t)3) /* * By convention, procedure 0 takes null arguments and returns them */ -#define NULLPROC ((u_long)0) +#define NULLPROC ((rpcproc_t)0) /* * Below are the client handle creation routines for the various @@ -272,108 +262,112 @@ typedef struct __rpc_client { */ /* - * Memory based rpc (for speed check and testing) + * Generic client creation routine. Supported protocols are those that + * belong to the nettype namespace (/etc/netconfig). * CLIENT * - * clntraw_create(prog, vers) - * u_long prog; - * u_long vers; + * clnt_create(host, prog, vers, prot); + * const char *host; -- hostname + * const rpcprog_t prog; -- program number + * const rpcvers_t vers; -- version number + * const char *prot; -- protocol */ __BEGIN_DECLS -extern CLIENT *clntraw_create __P((u_long, u_long)); -__END_DECLS - +extern CLIENT *clnt_create __P((const char *, const rpcprog_t, const rpcvers_t, + const char *)); +/* + * + * const char *hostname; -- hostname + * const rpcprog_t prog; -- program number + * const rpcvers_t vers; -- version number + * const char *nettype; -- network type + */ /* - * Generic client creation routine. Supported protocols are "udp", "tcp" - * and "unix". - * CLIENT * - * clnt_create(host, prog, vers, prot); - * char *host; -- hostname - * u_long prog; -- program number - * u_long vers; -- version number - * char *prot; -- protocol + * Generic client creation routine. Supported protocols are which belong + * to the nettype name space. + */ +extern CLIENT *clnt_create_vers __P((const char *, const rpcprog_t, rpcvers_t *, + const rpcvers_t, const rpcvers_t, + const char *)); +/* + * const char *host; -- hostname + * const rpcprog_t prog; -- program number + * rpcvers_t *vers_out; -- servers highest available version + * const rpcvers_t vers_low; -- low version number + * const rpcvers_t vers_high; -- high version number + * const char *nettype; -- network type */ -__BEGIN_DECLS -extern CLIENT *clnt_create __P((char *, u_long, u_long, char *)); -__END_DECLS /* - * TCP based rpc - * CLIENT * - * clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz) - * struct sockaddr_in *raddr; - * u_long prog; - * u_long version; - * register int *sockp; - * u_int sendsz; - * u_int recvsz; + * Generic client creation routine. It takes a netconfig structure + * instead of nettype + */ +extern CLIENT *clnt_tp_create __P((const char *, const rpcprog_t, + const rpcvers_t, const struct netconfig *)); +/* + * const char *hostname; -- hostname + * const rpcprog_t prog; -- program number + * const rpcvers_t vers; -- version number + * const struct netconfig *netconf; -- network config structure */ -__BEGIN_DECLS -extern CLIENT *clnttcp_create __P((struct sockaddr_in *, - u_long, - u_long, - int *, - u_int, - u_int)); -__END_DECLS +/* + * Generic TLI create routine. Only provided for compatibility. + */ +extern CLIENT *clnt_tli_create __P((const int, const struct netconfig *, + const struct netbuf *, const rpcprog_t, + const rpcvers_t, const u_int, const u_int)); /* - * UDP based rpc. - * CLIENT * - * clntudp_create(raddr, program, version, wait, sockp) - * struct sockaddr_in *raddr; - * u_long program; - * u_long version; - * struct timeval wait; - * int *sockp; - * - * Same as above, but you specify max packet sizes. - * CLIENT * - * clntudp_bufcreate(raddr, program, version, wait, sockp, sendsz, recvsz) - * struct sockaddr_in *raddr; - * u_long program; - * u_long version; - * struct timeval wait; - * int *sockp; - * u_int sendsz; - * u_int recvsz; + * const register int fd; -- fd + * const struct netconfig *nconf; -- netconfig structure + * const struct netbuf *svcaddr; -- servers address + * const u_long prog; -- program number + * const u_long vers; -- version number + * const u_int sendsz; -- send size + * const u_int recvsz; -- recv size + */ + +/* + * Low level clnt create routine for connectionful transports, e.g. tcp. + */ +extern CLIENT *clnt_vc_create __P((const int, const struct netbuf *, + const rpcprog_t, const rpcvers_t, + const u_int, const u_int)); +/* + * const int fd; -- open file descriptor + * const struct netbuf *svcaddr; -- servers address + * const rpcprog_t prog; -- program number + * const rpcvers_t vers; -- version number + * const u_int sendsz; -- buffer recv size + * const u_int recvsz; -- buffer send size */ -__BEGIN_DECLS -extern CLIENT *clntudp_create __P((struct sockaddr_in *, - u_long, - u_long, - struct timeval, - int *)); -extern CLIENT *clntudp_bufcreate __P((struct sockaddr_in *, - u_long, - u_long, - struct timeval, - int *, - u_int, - u_int)); -__END_DECLS +/* + * Low level clnt create routine for connectionless transports, e.g. udp. + */ +extern CLIENT *clnt_dg_create __P((const int, const struct netbuf *, + const rpcprog_t, const rpcvers_t, + const u_int, const u_int)); +/* + * const int fd; -- open file descriptor + * const struct netbuf *svcaddr; -- servers address + * const rpcprog_t program; -- program number + * const rpcvers_t version; -- version number + * const u_int sendsz; -- buffer recv size + * const u_int recvsz; -- buffer send size + */ /* - * AF_UNIX based rpc + * Memory based rpc (for speed check and testing) * CLIENT * - * clntunix_create(raddr, prog, vers, sockp, sendsz, recvsz) - * struct sockaddr_un *raddr; + * clnt_raw_create(prog, vers) * u_long prog; - * u_long version; - * register int *sockp; - * u_int sendsz; - * u_int recvsz; + * u_long vers; */ -__BEGIN_DECLS -extern CLIENT *clntunix_create __P((struct sockaddr_un *, - u_long, - u_long, - int *, - u_int, - u_int)); +extern CLIENT *clnt_raw_create __P((rpcprog_t, rpcvers_t)); + __END_DECLS @@ -381,8 +375,8 @@ __END_DECLS * Print why creation failed */ __BEGIN_DECLS -extern void clnt_pcreateerror __P((char *)); /* stderr */ -extern char *clnt_spcreateerror __P((char *)); /* string */ +extern void clnt_pcreateerror __P((const char *)); /* stderr */ +extern char *clnt_spcreateerror __P((const char *)); /* string */ __END_DECLS /* @@ -397,8 +391,8 @@ __END_DECLS * Print an English error message, given the client error code */ __BEGIN_DECLS -extern void clnt_perror __P((CLIENT *, char *)); /* stderr */ -extern char *clnt_sperror __P((CLIENT *, char *)); /* string */ +extern void clnt_perror __P((CLIENT *, const char *)); /* stderr */ +extern char *clnt_sperror __P((CLIENT *, const char *)); /* string */ __END_DECLS @@ -410,10 +404,94 @@ struct rpc_createerr { struct rpc_err cf_error; /* useful when cf_stat == RPC_PMAPFAILURE */ }; +#ifdef _THREAD_SAFE +__BEGIN_DECLS +extern struct rpc_createerr *__rpc_createerr __P((void)); +__END_DECLS +#define rpc_createerr (*(__rpc_createerr())) +#else extern struct rpc_createerr rpc_createerr; +#endif /* _THREAD_SAFE */ + +/* + * The simplified interface: + * enum clnt_stat + * rpc_call(host, prognum, versnum, procnum, inproc, in, outproc, out, nettype) + * const char *host; + * const rpcprog_t prognum; + * const rpcvers_t versnum; + * const rpcproc_t procnum; + * const xdrproc_t inproc, outproc; + * const char *in; + * char *out; + * const char *nettype; + */ +__BEGIN_DECLS +extern enum clnt_stat rpc_call __P((const char *, const rpcprog_t, + const rpcvers_t, const rpcproc_t, + const xdrproc_t, const char *, + const xdrproc_t, char *, const char *)); +__END_DECLS +/* + * RPC broadcast interface + * The call is broadcasted to all locally connected nets. + * + * extern enum clnt_stat + * rpc_broadcast(prog, vers, proc, xargs, argsp, xresults, resultsp, + * eachresult, nettype) + * const rpcprog_t prog; -- program number + * const rpcvers_t vers; -- version number + * const rpcproc_t proc; -- procedure number + * const xdrproc_t xargs; -- xdr routine for args + * caddr_t argsp; -- pointer to args + * const xdrproc_t xresults; -- xdr routine for results + * caddr_t resultsp; -- pointer to results + * const resultproc_t eachresult; -- call with each result + * const char *nettype; -- Transport type + * + * For each valid response received, the procedure eachresult is called. + * Its form is: + * done = eachresult(resp, raddr, nconf) + * bool_t done; + * caddr_t resp; + * struct netbuf *raddr; + * struct netconfig *nconf; + * where resp points to the results of the call and raddr is the + * address if the responder to the broadcast. nconf is the transport + * on which the response was received. + * + * extern enum clnt_stat + * rpc_broadcast_exp(prog, vers, proc, xargs, argsp, xresults, resultsp, + * eachresult, inittime, waittime, nettype) + * const rpcprog_t prog; -- program number + * const rpcvers_t vers; -- version number + * const rpcproc_t proc; -- procedure number + * const xdrproc_t xargs; -- xdr routine for args + * caddr_t argsp; -- pointer to args + * const xdrproc_t xresults; -- xdr routine for results + * caddr_t resultsp; -- pointer to results + * const resultproc_t eachresult; -- call with each result + * const int inittime; -- how long to wait initially + * const int waittime; -- maximum time to wait + * const char *nettype; -- Transport type + */ + +typedef bool_t (*resultproc_t) __P((caddr_t, ...)); + +__BEGIN_DECLS +extern enum clnt_stat rpc_broadcast __P((const rpcprog_t, const rpcvers_t, + const rpcproc_t, const xdrproc_t, + caddr_t, const xdrproc_t, caddr_t, + const resultproc_t, const char *)); +extern enum clnt_stat rpc_broadcast_exp __P((const rpcprog_t, const rpcvers_t, + const rpcproc_t, const xdrproc_t, + caddr_t, const xdrproc_t, caddr_t, + const resultproc_t, const int, + const int, const char *)); +__END_DECLS -#define UDPMSGSIZE 8800 /* rpc imposed limit on udp msg size */ -#define RPCSMALLMSGSIZE 400 /* a more reasonable packet size */ +/* For backward compatibility */ +#include <rpc/clnt_soc.h> -#endif /* !_RPC_CLNT_H */ +#endif /* !_RPC_CLNT_H_ */ diff --git a/include/rpc/clnt_soc.h b/include/rpc/clnt_soc.h new file mode 100644 index 000000000000..b6c1bd2300a8 --- /dev/null +++ b/include/rpc/clnt_soc.h @@ -0,0 +1,118 @@ +/* $NetBSD: clnt_soc.h,v 1.1 2000/06/02 22:57:55 fvdl Exp $ */ +/* $FreeBSD$ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* + * Copyright (c) 1984 - 1991 by Sun Microsystems, Inc. + */ + +/* + * clnt.h - Client side remote procedure call interface. + */ + +#ifndef _RPC_CLNT_SOC_H +#define _RPC_CLNT_SOC_H + +/* derived from clnt_soc.h 1.3 88/12/17 SMI */ + +/* + * All the following declarations are only for backward compatibility + * with TS-RPC. + */ + +#include <sys/cdefs.h> + +#define UDPMSGSIZE 8800 /* rpc imposed limit on udp msg size */ + +/* + * TCP based rpc + * CLIENT * + * clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz) + * struct sockaddr_in *raddr; + * u_long prog; + * u_long version; + * register int *sockp; + * u_int sendsz; + * u_int recvsz; + */ +__BEGIN_DECLS +extern CLIENT *clnttcp_create __P((struct sockaddr_in *, + u_long, + u_long, + int *, + u_int, + u_int)); +__END_DECLS + +/* + * Raw (memory) rpc. + */ +__BEGIN_DECLS +extern CLIENT *clntraw_create __P((u_long, u_long)); +__END_DECLS + + +/* + * UDP based rpc. + * CLIENT * + * clntudp_create(raddr, program, version, wait, sockp) + * struct sockaddr_in *raddr; + * u_long program; + * u_long version; + * struct timeval wait; + * int *sockp; + * + * Same as above, but you specify max packet sizes. + * CLIENT * + * clntudp_bufcreate(raddr, program, version, wait, sockp, sendsz, recvsz) + * struct sockaddr_in *raddr; + * u_long program; + * u_long version; + * struct timeval wait; + * int *sockp; + * u_int sendsz; + * u_int recvsz; + */ +__BEGIN_DECLS +extern CLIENT *clntudp_create __P((struct sockaddr_in *, + u_long, + u_long, + struct timeval, + int *)); +extern CLIENT *clntudp_bufcreate __P((struct sockaddr_in *, + u_long, + u_long, + struct timeval, + int *, + u_int, + u_int)); +__END_DECLS + +#endif /* _RPC_CLNT_SOC_H */ diff --git a/include/rpc/clnt_stat.h b/include/rpc/clnt_stat.h new file mode 100644 index 000000000000..26cb4ffff39c --- /dev/null +++ b/include/rpc/clnt_stat.h @@ -0,0 +1,83 @@ +/* $FreeBSD$ */ +/* + * Copyright (c) 1986 - 1991, 1994, 1996, 1997 by Sun Microsystems, Inc. + * All rights reserved. + */ + +/* + * clnt_stat.h - Client side remote procedure call enum + * + */ + +#ifndef _RPC_CLNT_STAT_H +#define _RPC_CLNT_STAT_H + +#pragma ident "@(#)clnt_stat.h 1.2 97/04/28 SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +enum clnt_stat { + RPC_SUCCESS = 0, /* call succeeded */ + /* + * local errors + */ + RPC_CANTENCODEARGS = 1, /* can't encode arguments */ + RPC_CANTDECODERES = 2, /* can't decode results */ + RPC_CANTSEND = 3, /* failure in sending call */ + RPC_CANTRECV = 4, + /* failure in receiving result */ + RPC_TIMEDOUT = 5, /* call timed out */ + RPC_INTR = 18, /* call interrupted */ + RPC_UDERROR = 23, /* recv got uderr indication */ + /* + * remote errors + */ + RPC_VERSMISMATCH = 6, /* rpc versions not compatible */ + RPC_AUTHERROR = 7, /* authentication error */ + RPC_PROGUNAVAIL = 8, /* program not available */ + RPC_PROGVERSMISMATCH = 9, /* program version mismatched */ + RPC_PROCUNAVAIL = 10, /* procedure unavailable */ + RPC_CANTDECODEARGS = 11, /* decode arguments error */ + RPC_SYSTEMERROR = 12, /* generic "other problem" */ + + /* + * rpc_call & clnt_create errors + */ + RPC_UNKNOWNHOST = 13, /* unknown host name */ + RPC_UNKNOWNPROTO = 17, /* unknown protocol */ + RPC_UNKNOWNADDR = 19, /* Remote address unknown */ + RPC_NOBROADCAST = 21, /* Broadcasting not supported */ + + /* + * rpcbind errors + */ + RPC_RPCBFAILURE = 14, /* the pmapper failed in its call */ +#define RPC_PMAPFAILURE RPC_RPCBFAILURE + RPC_PROGNOTREGISTERED = 15, /* remote program is not registered */ + RPC_N2AXLATEFAILURE = 22, + /* Name to address translation failed */ + /* + * Misc error in the TLI library + */ + RPC_TLIERROR = 20, + /* + * unspecified error + */ + RPC_FAILED = 16, + /* + * asynchronous errors + */ + RPC_INPROGRESS = 24, + RPC_STALERACHANDLE = 25, + RPC_CANTCONNECT = 26, /* couldn't make connection (cots) */ + RPC_XPRTFAILED = 27, /* received discon from remote (cots) */ + RPC_CANTCREATESTREAM = 28 /* can't push rpc module (cots) */ +}; + +#ifdef __cplusplus +} +#endif + +#endif /* !_RPC_CLNT_STAT_H */ diff --git a/include/rpc/des_crypt.h b/include/rpc/des_crypt.h index c223cd1b77f0..ce6c1bf44783 100644 --- a/include/rpc/des_crypt.h +++ b/include/rpc/des_crypt.h @@ -33,6 +33,16 @@ * 2550 Garcia Avenue * Mountain View, California 94043 */ +/* + * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. + */ + +/* + * des_crypt.h, des library routine interface + */ + +#ifndef _DES_DES_CRYPT_H +#define _DES_DES_CRYPT_H #include <sys/cdefs.h> #include <rpc/rpc.h> @@ -75,46 +85,22 @@ * Cipher Block Chaining mode */ __BEGIN_DECLS -#ifdef __STDC__ int cbc_crypt __P(( char *, char *, unsigned int, unsigned int, char *)); -#else -cbc_crypt(/* key, buf, len, mode, ivec */); /* - char *key; - char *buf; - unsigned len; - unsigned mode; - char *ivec; -*/ -#endif +__END_DECLS /* * Electronic Code Book mode */ -#ifdef __STDC__ +__BEGIN_DECLS int ecb_crypt __P(( char *, char *, unsigned int, unsigned int )); -#else -ecb_crypt(/* key, buf, len, mode */); /* - char *key; - char *buf; - unsigned len; - unsigned mode; -*/ -#endif __END_DECLS -#ifndef _KERNEL /* * Set des parity for a key. * DES parity is odd and in the low bit of each byte */ __BEGIN_DECLS -#ifdef __STDC__ void des_setparity __P(( char *)); -#else -void -des_setparity(/* key */); /* - char *key; -*/ -#endif __END_DECLS -#endif + +#endif /* _DES_DES_CRYPT_H */ diff --git a/include/rpc/nettype.h b/include/rpc/nettype.h new file mode 100644 index 000000000000..f53c445d6ee3 --- /dev/null +++ b/include/rpc/nettype.h @@ -0,0 +1,64 @@ +/* $NetBSD: nettype.h,v 1.2 2000/07/06 03:17:19 christos Exp $ */ +/* $FreeBSD$ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* + * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. + */ + +/* + * nettype.h, Nettype definitions. + * All for the topmost layer of rpc + * + */ + +#ifndef _RPC_NETTYPE_H +#define _RPC_NETTYPE_H + +#include <netconfig.h> + +#define _RPC_NONE 0 +#define _RPC_NETPATH 1 +#define _RPC_VISIBLE 2 +#define _RPC_CIRCUIT_V 3 +#define _RPC_DATAGRAM_V 4 +#define _RPC_CIRCUIT_N 5 +#define _RPC_DATAGRAM_N 6 +#define _RPC_TCP 7 +#define _RPC_UDP 8 + +__BEGIN_DECLS +extern void *__rpc_setconf __P((const char *)); +extern void __rpc_endconf __P((void *)); +extern struct netconfig *__rpc_getconf __P((void *)); +extern struct netconfig *__rpc_getconfip __P((const char *)); +__END_DECLS + +#endif /* !_RPC_NETTYPE_H */ diff --git a/include/rpc/pmap_clnt.h b/include/rpc/pmap_clnt.h index d4080cc2857a..a2beae5691ce 100644 --- a/include/rpc/pmap_clnt.h +++ b/include/rpc/pmap_clnt.h @@ -1,3 +1,5 @@ +/* $NetBSD: pmap_clnt.h,v 1.9 2000/06/02 22:57:55 fvdl Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -26,7 +28,7 @@ * 2550 Garcia Avenue * Mountain View, California 94043 * - * from: @(#)pmap_clnt.h 1.11 88/02/08 SMI + * from: @(#)pmap_clnt.h 1.11 88/02/08 SMI * from: @(#)pmap_clnt.h 2.1 88/07/29 4.0 RPCSRC * $FreeBSD$ */ @@ -60,8 +62,8 @@ * address if the responder to the broadcast. */ -#ifndef _RPC_PMAPCLNT_H -#define _RPC_PMAPCLNT_H +#ifndef _RPC_PMAP_CLNT_H_ +#define _RPC_PMAP_CLNT_H_ #include <sys/cdefs.h> __BEGIN_DECLS @@ -76,10 +78,9 @@ extern enum clnt_stat pmap_rmtcall __P((struct sockaddr_in *, extern enum clnt_stat clnt_broadcast __P((u_long, u_long, u_long, xdrproc_t, char *, xdrproc_t, char *, - bool_t (*) __P((caddr_t, - struct sockaddr_in *)))); + resultproc_t)); extern u_short pmap_getport __P((struct sockaddr_in *, u_long, u_long, u_int)); __END_DECLS -#endif /* !_RPC_PMAPCLNT_H */ +#endif /* !_RPC_PMAP_CLNT_H_ */ diff --git a/include/rpc/pmap_prot.h b/include/rpc/pmap_prot.h index 123ee159dfae..7dddab2e0d5b 100644 --- a/include/rpc/pmap_prot.h +++ b/include/rpc/pmap_prot.h @@ -1,3 +1,5 @@ +/* $NetBSD: pmap_prot.h,v 1.8 2000/06/02 22:57:55 fvdl Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -26,7 +28,7 @@ * 2550 Garcia Avenue * Mountain View, California 94043 * - * from: @(#)pmap_prot.h 1.14 88/02/08 SMI + * from: @(#)pmap_prot.h 1.14 88/02/08 SMI * from: @(#)pmap_prot.h 2.1 88/07/29 4.0 RPCSRC * $FreeBSD$ */ @@ -68,8 +70,8 @@ * The service supports remote procedure calls on udp/ip or tcp/ip socket 111. */ -#ifndef _RPC_PMAPPROT_H -#define _RPC_PMAPPROT_H +#ifndef _RPC_PMAP_PROT_H +#define _RPC_PMAP_PROT_H #include <sys/cdefs.h> #define PMAPPORT ((u_short)111) @@ -99,6 +101,7 @@ struct pmaplist { __BEGIN_DECLS extern bool_t xdr_pmap __P((XDR *, struct pmap *)); extern bool_t xdr_pmaplist __P((XDR *, struct pmaplist **)); +extern bool_t xdr_pmaplist_ptr __P((XDR *, struct pmaplist *)); __END_DECLS -#endif /* !_RPC_PMAPPROT_H */ +#endif /* !_RPC_PMAP_PROT_H */ diff --git a/include/rpc/pmap_rmt.h b/include/rpc/pmap_rmt.h index 845e815e0add..4361f0d0b4f7 100644 --- a/include/rpc/pmap_rmt.h +++ b/include/rpc/pmap_rmt.h @@ -1,3 +1,5 @@ +/* $NetBSD: pmap_rmt.h,v 1.7 1998/02/11 23:01:23 lukem Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -38,8 +40,8 @@ * Copyright (C) 1986, Sun Microsystems, Inc. */ -#ifndef _RPC_PMAPRMT_H -#define _RPC_PMAPRMT_H +#ifndef _RPC_PMAP_RMT_H +#define _RPC_PMAP_RMT_H #include <sys/cdefs.h> struct rmtcallargs { @@ -60,4 +62,4 @@ extern bool_t xdr_rmtcall_args __P((XDR *, struct rmtcallargs *)); extern bool_t xdr_rmtcallres __P((XDR *, struct rmtcallres *)); __END_DECLS -#endif /* !_RPC_PMAPRMT_H */ +#endif /* !_RPC_PMAP_RMT_H */ diff --git a/include/rpc/raw.h b/include/rpc/raw.h new file mode 100644 index 000000000000..0fea4ad087a2 --- /dev/null +++ b/include/rpc/raw.h @@ -0,0 +1,58 @@ +/* $NetBSD: raw.h,v 1.1 2000/06/02 22:57:56 fvdl Exp $ */ +/* $FreeBSD$ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* + * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. + */ + +#ifndef _RPC_RAW_H +#define _RPC_RAW_H + +/* from: @(#)raw.h 1.11 94/04/25 SMI */ +/* from: @(#)raw.h 1.2 88/10/25 SMI */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * raw.h + * + * Raw interface + * The common memory area over which they will communicate + */ +extern char *__rpc_rawcombuf; + +#ifdef __cplusplus +} +#endif + +#endif /* _RPC_RAW_H */ diff --git a/include/rpc/rpc.h b/include/rpc/rpc.h index 7fd4a7f85906..8a45c4928096 100644 --- a/include/rpc/rpc.h +++ b/include/rpc/rpc.h @@ -1,3 +1,5 @@ +/* $NetBSD: rpc.h,v 1.13 2000/06/02 22:57:56 fvdl Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -41,6 +43,7 @@ #define _RPC_RPC_H #include <rpc/types.h> /* some typedefs */ +#include <sys/socket.h> #include <netinet/in.h> /* external data representation interfaces */ @@ -65,30 +68,40 @@ #include <rpc/svc.h> /* service manager and multiplexer */ #include <rpc/svc_auth.h> /* service side authenticator */ -/* - * COMMENT OUT THE NEXT INCLUDE (or add to the #ifndef) IF RUNNING ON - * A VERSION OF UNIX THAT USES SUN'S NFS SOURCE. These systems will - * already have the structures defined by <rpc/netdb.h> included in <netdb.h>. - */ -/* routines for parsing /etc/rpc */ +/* Portmapper client, server, and protocol headers */ +#include <rpc/pmap_clnt.h> +#include <rpc/pmap_prot.h> -struct rpcent { - char *r_name; /* name of server for this rpc program */ - char **r_aliases; /* alias list */ - int r_number; /* rpc program number */ -}; +#include <rpc/rpcb_clnt.h> /* rpcbind interface functions */ -__BEGIN_DECLS -extern struct rpcent *getrpcbyname __P((char *)); -extern struct rpcent *getrpcbynumber __P((int)); -extern struct rpcent *getrpcent __P((void)); -extern int getrpcport __P((char *host, int prognum, int versnum, int proto)); -extern void setrpcent __P((int)); -extern void endrpcent __P((void)); +#include <rpc/rpcent.h> +__BEGIN_DECLS +extern int get_myaddress __P((struct sockaddr_in *)); extern int bindresvport __P((int, struct sockaddr_in *)); +extern int registerrpc __P((int, int, int, char *(*) __P((char [UDPMSGSIZE])), + xdrproc_t, xdrproc_t)); +extern int callrpc __P((char *, int, int, int, xdrproc_t, char *, + xdrproc_t , char *)); +extern int getrpcport __P((char *, int, int, int)); + +char *taddr2uaddr __P((const struct netconfig *, const struct netbuf *)); +struct netbuf *uaddr2taddr __P((const struct netconfig *, const char *)); + +struct sockaddr; extern int bindresvport_sa __P((int, struct sockaddr *)); -extern int get_myaddress __P((struct sockaddr_in *)); +__END_DECLS + +/* + * The following are not exported interfaces, they are for internal library + * and rpcbind use only. Do not use, they may change without notice. + */ +__BEGIN_DECLS +int __rpc_nconf2fd __P((const struct netconfig *)); +int __rpc_nconf2sockinfo __P((const struct netconfig *, + struct __rpc_sockinfo *)); +int __rpc_fd2sockinfo __P((int, struct __rpc_sockinfo *)); +u_int __rpc_get_t_size __P((int, int, int)); __END_DECLS #endif /* !_RPC_RPC_H */ diff --git a/include/rpc/rpc_com.h b/include/rpc/rpc_com.h index 2cf5995d2d70..8add5d4c6a03 100644 --- a/include/rpc/rpc_com.h +++ b/include/rpc/rpc_com.h @@ -1,3 +1,6 @@ +/* $NetBSD: rpc_com.h,v 1.3 2000/12/10 04:10:08 christos Exp $ */ +/* $FreeBSD$ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -39,40 +42,42 @@ #ifndef _RPC_RPCCOM_H #define _RPC_RPCCOM_H -/* From: #pragma ident "@(#)rpc_com.h 1.11 93/07/05 SMI" */ +#include <sys/cdefs.h> -#ifdef __cplusplus -extern "C" { -#endif +/* #pragma ident "@(#)rpc_com.h 1.11 93/07/05 SMI" */ /* - * File descriptor to be used on xxx_create calls to get default descriptor - */ -#define RPC_ANYSOCK -1 -#define RPC_ANYFD RPC_ANYSOCK -/* * The max size of the transport, if the size cannot be determined * by other means. */ #define RPC_MAXDATASIZE 9000 #define RPC_MAXADDRSIZE 1024 -#if defined(__STDC__) || defined(__cplusplus) -extern u_int __rpc_get_t_size (int, long); -extern u_int __rpc_get_a_size (long); -extern int __rpc_dtbsize (void); -extern int _rpc_dtablesize (void); -extern int _rpc_get_default_domain(char **); -#else -extern u_int __rpc_get_t_size (); -extern u_int __rpc_get_a_size (); -extern int __rpc_dtbsize (); -extern int _rpc_dtablesize (); -extern int _rpc_get_default_domain(); -#endif +#define __RPC_GETXID(now) ((u_int32_t)getpid() ^ (u_int32_t)(now)->tv_sec ^ \ + (u_int32_t)(now)->tv_usec) + +__BEGIN_DECLS +extern u_int __rpc_get_a_size __P((int)); +extern int __rpc_dtbsize __P((void)); +extern struct netconfig * __rpcgettp __P((int)); +extern int __rpc_get_default_domain __P((char **)); + +char *__rpc_taddr2uaddr_af __P((int, const struct netbuf *)); +struct netbuf *__rpc_uaddr2taddr_af __P((int, const char *)); +int __rpc_fixup_addr __P((struct netbuf *, const struct netbuf *)); +int __rpc_sockinfo2netid __P((struct __rpc_sockinfo *, const char **)); +int __rpc_seman2socktype __P((int)); +int __rpc_socktype2seman __P((int)); +void *rpc_nullproc __P((CLIENT *)); +int __rpc_sockisbound __P((int)); + +struct netbuf *__rpcb_findaddr __P((rpcprog_t, rpcvers_t, + const struct netconfig *, + const char *, CLIENT **)); +bool_t __rpc_control __P((int,void *)); + +char *_get_next_token __P((char *, int)); -#ifdef __cplusplus -} -#endif +__END_DECLS #endif /* _RPC_RPCCOM_H */ diff --git a/include/rpc/rpc_msg.h b/include/rpc/rpc_msg.h index 98f0f79aa881..ed634a180250 100644 --- a/include/rpc/rpc_msg.h +++ b/include/rpc/rpc_msg.h @@ -1,3 +1,5 @@ +/* $NetBSD: rpc_msg.h,v 1.11 2000/06/02 22:57:56 fvdl Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -38,10 +40,10 @@ * Copyright (C) 1984, Sun Microsystems, Inc. */ -#ifndef _RPC_RPCMSG_H -#define _RPC_RPCMSG_H +#ifndef _RPC_RPC_MSG_H +#define _RPC_RPC_MSG_H -#define RPC_MSG_VERSION ((u_long) 2) +#define RPC_MSG_VERSION ((u_int32_t) 2) #define RPC_SERVICE_PORT ((u_short) 2048) /* @@ -88,8 +90,8 @@ struct accepted_reply { enum accept_stat ar_stat; union { struct { - u_int32_t low; - u_int32_t high; + rpcvers_t low; + rpcvers_t high; } AR_versions; struct { caddr_t where; @@ -108,8 +110,8 @@ struct rejected_reply { enum reject_stat rj_stat; union { struct { - u_int32_t low; - u_int32_t high; + rpcvers_t low; + rpcvers_t high; } RJ_versions; enum auth_stat RJ_why; /* why authentication did not work */ } ru; @@ -134,10 +136,10 @@ struct reply_body { * Body of an rpc request call. */ struct call_body { - u_int32_t cb_rpcvers; /* must be equal to two */ - u_int32_t cb_prog; - u_int32_t cb_vers; - u_int32_t cb_proc; + rpcvers_t cb_rpcvers; /* must be equal to two */ + rpcprog_t cb_prog; + rpcvers_t cb_vers; + rpcproc_t cb_proc; struct opaque_auth cb_cred; struct opaque_auth cb_verf; /* protocol specific - provided by client */ }; @@ -183,14 +185,30 @@ extern bool_t xdr_callhdr __P((XDR *, struct rpc_msg *)); */ extern bool_t xdr_replymsg __P((XDR *, struct rpc_msg *)); + +/* + * XDR routine to handle a accepted rpc reply. + * xdr_accepted_reply(xdrs, rej) + * XDR *xdrs; + * struct accepted_reply *rej; + */ +extern bool_t xdr_accepted_reply __P((XDR *, struct accepted_reply *)); + +/* + * XDR routine to handle a rejected rpc reply. + * xdr_rejected_reply(xdrs, rej) + * XDR *xdrs; + * struct rejected_reply *rej; + */ +extern bool_t xdr_rejected_reply __P((XDR *, struct rejected_reply *)); + /* * Fills in the error part of a reply message. * _seterr_reply(msg, error) * struct rpc_msg *msg; * struct rpc_err *error; */ -struct rpc_err; extern void _seterr_reply __P((struct rpc_msg *, struct rpc_err *)); __END_DECLS -#endif /* !_RPC_RPCMSG_H */ +#endif /* !_RPC_RPC_MSG_H */ diff --git a/include/rpc/rpcb_clnt.h b/include/rpc/rpcb_clnt.h new file mode 100644 index 000000000000..0f081a47b0c3 --- /dev/null +++ b/include/rpc/rpcb_clnt.h @@ -0,0 +1,85 @@ +/* $NetBSD: rpcb_clnt.h,v 1.1 2000/06/02 22:57:56 fvdl Exp $ */ +/* $FreeBSD$ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* + * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. + */ + +/* + * rpcb_clnt.h + * Supplies C routines to get to rpcbid services. + * + */ + +/* + * Usage: + * success = rpcb_set(program, version, nconf, address); + * success = rpcb_unset(program, version, nconf); + * success = rpcb_getaddr(program, version, nconf, host); + * head = rpcb_getmaps(nconf, host); + * clnt_stat = rpcb_rmtcall(nconf, host, program, version, procedure, + * xdrargs, argsp, xdrres, resp, tout, addr_ptr) + * success = rpcb_gettime(host, timep) + * uaddr = rpcb_taddr2uaddr(nconf, taddr); + * taddr = rpcb_uaddr2uaddr(nconf, uaddr); + */ + +#ifndef _RPC_RPCB_CLNT_H +#define _RPC_RPCB_CLNT_H + +/* #pragma ident "@(#)rpcb_clnt.h 1.13 94/04/25 SMI" */ +/* rpcb_clnt.h 1.3 88/12/05 SMI */ + +#include <rpc/types.h> +#include <rpc/rpcb_prot.h> + +__BEGIN_DECLS +extern bool_t rpcb_set __P((const rpcprog_t, const rpcvers_t, + const struct netconfig *, const struct netbuf *)); +extern bool_t rpcb_unset __P((const rpcprog_t, const rpcvers_t, + const struct netconfig *)); +extern rpcblist *rpcb_getmaps __P((const struct netconfig *, const char *)); +extern enum clnt_stat rpcb_rmtcall __P((const struct netconfig *, + const char *, const rpcprog_t, + const rpcvers_t, const rpcproc_t, + const xdrproc_t, const caddr_t, + const xdrproc_t, const caddr_t, + const struct timeval, + const struct netbuf *)); +extern bool_t rpcb_getaddr __P((const rpcprog_t, const rpcvers_t, + const struct netconfig *, struct netbuf *, + const char *)); +extern bool_t rpcb_gettime __P((const char *, time_t *)); +extern char *rpcb_taddr2uaddr __P((struct netconfig *, struct netbuf *)); +extern struct netbuf *rpcb_uaddr2taddr __P((struct netconfig *, char *)); +__END_DECLS + +#endif /* !_RPC_RPCB_CLNT_H */ diff --git a/include/rpc/rpcb_prot.x b/include/rpc/rpcb_prot.x new file mode 100644 index 000000000000..b1ab096b40b0 --- /dev/null +++ b/include/rpc/rpcb_prot.x @@ -0,0 +1,554 @@ +%/* +% * $FreeBSD$ +% * +% * Sun RPC is a product of Sun Microsystems, Inc. and is provided for +% * unrestricted use provided that this legend is included on all tape +% * media and as a part of the software program in whole or part. Users +% * may copy or modify Sun RPC without charge, but are not authorized +% * to license or distribute it to anyone else except as part of a product or +% * program developed by the user. +% * +% * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE +% * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR +% * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. +% * +% * Sun RPC is provided with no support and without any obligation on the +% * part of Sun Microsystems, Inc. to assist in its use, correction, +% * modification or enhancement. +% * +% * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE +% * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC +% * OR ANY PART THEREOF. +% * +% * In no event will Sun Microsystems, Inc. be liable for any lost revenue +% * or profits or other special, indirect and consequential damages, even if +% * Sun has been advised of the possibility of such damages. +% * +% * Sun Microsystems, Inc. +% * 2550 Garcia Avenue +% * Mountain View, California 94043 +% */ +%/* +% * Copyright (c) 1988 by Sun Microsystems, Inc. +% */ + +%/* from rpcb_prot.x */ + +#ifdef RPC_HDR +% +%/* #pragma ident "@(#)rpcb_prot.x 1.5 94/04/29 SMI" */ +% +%#ifndef _KERNEL +% +#endif + +/* + * rpcb_prot.x + * rpcbind protocol, versions 3 and 4, in RPC Language + */ +% +%/* +% * The following procedures are supported by the protocol in version 3: +% * +% * RPCBPROC_NULL() returns () +% * takes nothing, returns nothing +% * +% * RPCBPROC_SET(rpcb) returns (bool_t) +% * TRUE is success, FALSE is failure. Registers the tuple +% * [prog, vers, address, owner, netid]. +% * Finds out owner and netid information on its own. +% * +% * RPCBPROC_UNSET(rpcb) returns (bool_t) +% * TRUE is success, FALSE is failure. Un-registers tuple +% * [prog, vers, netid]. addresses is ignored. +% * If netid is NULL, unregister all. +% * +% * RPCBPROC_GETADDR(rpcb) returns (string). +% * 0 is failure. Otherwise returns the universal address where the +% * triple [prog, vers, netid] is registered. Ignore address and owner. +% * +% * RPCBPROC_DUMP() RETURNS (rpcblist_ptr) +% * used to dump the entire rpcbind maps +% * +% * RPCBPROC_CALLIT(rpcb_rmtcallargs) +% * RETURNS (rpcb_rmtcallres); +% * Calls the procedure on the remote machine. If it is not registered, +% * this procedure is quiet; i.e. it does not return error information!!! +% * This routine only passes null authentication parameters. +% * It has no interface to xdr routines for RPCBPROC_CALLIT. +% * +% * RPCBPROC_GETTIME() returns (int). +% * Gets the remote machines time +% * +% * RPCBPROC_UADDR2TADDR(strint) RETURNS (struct netbuf) +% * Returns the netbuf address from universal address. +% * +% * RPCBPROC_TADDR2UADDR(struct netbuf) RETURNS (string) +% * Returns the universal address from netbuf address. +% * +% * END OF RPCBIND VERSION 3 PROCEDURES +% */ +%/* +% * Except for RPCBPROC_CALLIT, the procedures above are carried over to +% * rpcbind version 4. Those below are added or modified for version 4. +% * NOTE: RPCBPROC_BCAST HAS THE SAME FUNCTIONALITY AND PROCEDURE NUMBER +% * AS RPCBPROC_CALLIT. +% * +% * RPCBPROC_BCAST(rpcb_rmtcallargs) +% * RETURNS (rpcb_rmtcallres); +% * Calls the procedure on the remote machine. If it is not registered, +% * this procedure IS quiet; i.e. it DOES NOT return error information!!! +% * This routine should be used for broadcasting and nothing else. +% * +% * RPCBPROC_GETVERSADDR(rpcb) returns (string). +% * 0 is failure. Otherwise returns the universal address where the +% * triple [prog, vers, netid] is registered. Ignore address and owner. +% * Same as RPCBPROC_GETADDR except that if the given version number +% * is not available, the address is not returned. +% * +% * RPCBPROC_INDIRECT(rpcb_rmtcallargs) +% * RETURNS (rpcb_rmtcallres); +% * Calls the procedure on the remote machine. If it is not registered, +% * this procedure is NOT quiet; i.e. it DOES return error information!!! +% * as any normal application would expect. +% * +% * RPCBPROC_GETADDRLIST(rpcb) returns (rpcb_entry_list_ptr). +% * Same as RPCBPROC_GETADDR except that it returns a list of all the +% * addresses registered for the combination (prog, vers) (for all +% * transports). +% * +% * RPCBPROC_GETSTAT(void) returns (rpcb_stat_byvers) +% * Returns the statistics about the kind of requests received by rpcbind. +% */ +% +%/* +% * A mapping of (program, version, network ID) to address +% */ +struct rpcb { + rpcprog_t r_prog; /* program number */ + rpcvers_t r_vers; /* version number */ + string r_netid<>; /* network id */ + string r_addr<>; /* universal address */ + string r_owner<>; /* owner of this service */ +}; +#ifdef RPC_HDR +% +%typedef rpcb RPCB; +% +#endif +% +%/* +% * A list of mappings +% * +% * Below are two definitions for the rpcblist structure. This is done because +% * xdr_rpcblist() is specified to take a struct rpcblist **, rather than a +% * struct rpcblist * that rpcgen would produce. One version of the rpcblist +% * structure (actually called rp__list) is used with rpcgen, and the other is +% * defined only in the header file for compatibility with the specified +% * interface. +% */ + +struct rp__list { + rpcb rpcb_map; + struct rp__list *rpcb_next; +}; + +typedef rp__list *rpcblist_ptr; /* results of RPCBPROC_DUMP */ + +#ifdef RPC_HDR +% +%typedef struct rp__list rpcblist; +%typedef struct rp__list RPCBLIST; +% +%#ifndef __cplusplus +%struct rpcblist { +% RPCB rpcb_map; +% struct rpcblist *rpcb_next; +%}; +%#endif +% +%#ifdef __cplusplus +%extern "C" { +%#endif +%extern bool_t xdr_rpcblist(XDR *, rpcblist**); +%#ifdef __cplusplus +%} +%#endif +% +#endif + +% +%/* +% * Arguments of remote calls +% */ +struct rpcb_rmtcallargs { + rpcprog_t prog; /* program number */ + rpcvers_t vers; /* version number */ + rpcproc_t proc; /* procedure number */ + opaque args<>; /* argument */ +}; +#ifdef RPC_HDR +% +%/* +% * Client-side only representation of rpcb_rmtcallargs structure. +% * +% * The routine that XDRs the rpcb_rmtcallargs structure must deal with the +% * opaque arguments in the "args" structure. xdr_rpcb_rmtcallargs() needs to +% * be passed the XDR routine that knows the args' structure. This routine +% * doesn't need to go over-the-wire (and it wouldn't make sense anyway) since +% * the application being called already knows the args structure. So we use a +% * different "XDR" structure on the client side, r_rpcb_rmtcallargs, which +% * includes the args' XDR routine. +% */ +%struct r_rpcb_rmtcallargs { +% rpcprog_t prog; +% rpcvers_t vers; +% rpcproc_t proc; +% struct { +% u_int args_len; +% char *args_val; +% } args; +% xdrproc_t xdr_args; /* encodes args */ +%}; +% +#endif /* def RPC_HDR */ +% +%/* +% * Results of the remote call +% */ +struct rpcb_rmtcallres { + string addr<>; /* remote universal address */ + opaque results<>; /* result */ +}; +#ifdef RPC_HDR +% +%/* +% * Client-side only representation of rpcb_rmtcallres structure. +% */ +%struct r_rpcb_rmtcallres { +% char *addr; +% struct { +% u_int32_t results_len; +% char *results_val; +% } results; +% xdrproc_t xdr_res; /* decodes results */ +%}; +#endif RPC_HDR +% +%/* +% * rpcb_entry contains a merged address of a service on a particular +% * transport, plus associated netconfig information. A list of rpcb_entrys +% * is returned by RPCBPROC_GETADDRLIST. See netconfig.h for values used +% * in r_nc_* fields. +% */ +struct rpcb_entry { + string r_maddr<>; /* merged address of service */ + string r_nc_netid<>; /* netid field */ + unsigned int r_nc_semantics; /* semantics of transport */ + string r_nc_protofmly<>; /* protocol family */ + string r_nc_proto<>; /* protocol name */ +}; +% +%/* +% * A list of addresses supported by a service. +% */ +struct rpcb_entry_list { + rpcb_entry rpcb_entry_map; + struct rpcb_entry_list *rpcb_entry_next; +}; + +typedef rpcb_entry_list *rpcb_entry_list_ptr; + +% +%/* +% * rpcbind statistics +% */ +% +const rpcb_highproc_2 = RPCBPROC_CALLIT; +const rpcb_highproc_3 = RPCBPROC_TADDR2UADDR; +const rpcb_highproc_4 = RPCBPROC_GETSTAT; + +const RPCBSTAT_HIGHPROC = 13; /* # of procs in rpcbind V4 plus one */ +const RPCBVERS_STAT = 3; /* provide only for rpcbind V2, V3 and V4 */ +const RPCBVERS_4_STAT = 2; +const RPCBVERS_3_STAT = 1; +const RPCBVERS_2_STAT = 0; +% +%/* Link list of all the stats about getport and getaddr */ +struct rpcbs_addrlist { + rpcprog_t prog; + rpcvers_t vers; + int success; + int failure; + string netid<>; + struct rpcbs_addrlist *next; +}; +% +%/* Link list of all the stats about rmtcall */ +struct rpcbs_rmtcalllist { + rpcprog_t prog; + rpcvers_t vers; + rpcproc_t proc; + int success; + int failure; + int indirect; /* whether callit or indirect */ + string netid<>; + struct rpcbs_rmtcalllist *next; +}; + +typedef int rpcbs_proc[RPCBSTAT_HIGHPROC]; +typedef rpcbs_addrlist *rpcbs_addrlist_ptr; +typedef rpcbs_rmtcalllist *rpcbs_rmtcalllist_ptr; + +struct rpcb_stat { + rpcbs_proc info; + int setinfo; + int unsetinfo; + rpcbs_addrlist_ptr addrinfo; + rpcbs_rmtcalllist_ptr rmtinfo; +}; +% +%/* +% * One rpcb_stat structure is returned for each version of rpcbind +% * being monitored. +% */ + +typedef rpcb_stat rpcb_stat_byvers[RPCBVERS_STAT]; + +#ifdef RPC_HDR +% +%/* +% * We don't define netbuf in RPCL, since it would contain structure member +% * names that would conflict with the definition of struct netbuf in +% * <tiuser.h>. Instead we merely declare the XDR routine xdr_netbuf() here, +% * and implement it ourselves in rpc/rpcb_prot.c. +% */ +%#ifdef __cplusplus +%extern "C" bool_t xdr_netbuf(XDR *, struct netbuf *); +% +%#else __STDC__ +%extern bool_t xdr_netbuf(XDR *, struct netbuf *); +% +%#endif +#endif /* def RPC_HDR */ + +/* + * rpcbind procedures + */ +program RPCBPROG { + version RPCBVERS { + bool + RPCBPROC_SET(rpcb) = 1; + + bool + RPCBPROC_UNSET(rpcb) = 2; + + string + RPCBPROC_GETADDR(rpcb) = 3; + + rpcblist_ptr + RPCBPROC_DUMP(void) = 4; + + rpcb_rmtcallres + RPCBPROC_CALLIT(rpcb_rmtcallargs) = 5; + + unsigned int + RPCBPROC_GETTIME(void) = 6; + + struct netbuf + RPCBPROC_UADDR2TADDR(string) = 7; + + string + RPCBPROC_TADDR2UADDR(struct netbuf) = 8; + } = 3; + + version RPCBVERS4 { + bool + RPCBPROC_SET(rpcb) = 1; + + bool + RPCBPROC_UNSET(rpcb) = 2; + + string + RPCBPROC_GETADDR(rpcb) = 3; + + rpcblist_ptr + RPCBPROC_DUMP(void) = 4; + + /* + * NOTE: RPCBPROC_BCAST has the same functionality as CALLIT; + * the new name is intended to indicate that this + * procedure should be used for broadcast RPC, and + * RPCBPROC_INDIRECT should be used for indirect calls. + */ + rpcb_rmtcallres + RPCBPROC_BCAST(rpcb_rmtcallargs) = RPCBPROC_CALLIT; + + unsigned int + RPCBPROC_GETTIME(void) = 6; + + struct netbuf + RPCBPROC_UADDR2TADDR(string) = 7; + + string + RPCBPROC_TADDR2UADDR(struct netbuf) = 8; + + string + RPCBPROC_GETVERSADDR(rpcb) = 9; + + rpcb_rmtcallres + RPCBPROC_INDIRECT(rpcb_rmtcallargs) = 10; + + rpcb_entry_list_ptr + RPCBPROC_GETADDRLIST(rpcb) = 11; + + rpcb_stat_byvers + RPCBPROC_GETSTAT(void) = 12; + } = 4; +} = 100000; +#ifdef RPC_HDR +% +%#define RPCBVERS_3 RPCBVERS +%#define RPCBVERS_4 RPCBVERS4 +% +%#define _PATH_RPCBINDSOCK "/var/run/rpcbind.sock" +% +%#else /* ndef _KERNEL */ +%#ifdef __cplusplus +%extern "C" { +%#endif +% +%/* +% * A mapping of (program, version, network ID) to address +% */ +%struct rpcb { +% rpcprog_t r_prog; /* program number */ +% rpcvers_t r_vers; /* version number */ +% char *r_netid; /* network id */ +% char *r_addr; /* universal address */ +% char *r_owner; /* owner of the mapping */ +%}; +%typedef struct rpcb RPCB; +% +%/* +% * A list of mappings +% */ +%struct rpcblist { +% RPCB rpcb_map; +% struct rpcblist *rpcb_next; +%}; +%typedef struct rpcblist RPCBLIST; +%typedef struct rpcblist *rpcblist_ptr; +% +%/* +% * Remote calls arguments +% */ +%struct rpcb_rmtcallargs { +% rpcprog_t prog; /* program number */ +% rpcvers_t vers; /* version number */ +% rpcproc_t proc; /* procedure number */ +% u_int32_t arglen; /* arg len */ +% caddr_t args_ptr; /* argument */ +% xdrproc_t xdr_args; /* XDR routine for argument */ +%}; +%typedef struct rpcb_rmtcallargs rpcb_rmtcallargs; +% +%/* +% * Remote calls results +% */ +%struct rpcb_rmtcallres { +% char *addr_ptr; /* remote universal address */ +% u_int32_t resultslen; /* results length */ +% caddr_t results_ptr; /* results */ +% xdrproc_t xdr_results; /* XDR routine for result */ +%}; +%typedef struct rpcb_rmtcallres rpcb_rmtcallres; +% +%struct rpcb_entry { +% char *r_maddr; +% char *r_nc_netid; +% unsigned int r_nc_semantics; +% char *r_nc_protofmly; +% char *r_nc_proto; +%}; +%typedef struct rpcb_entry rpcb_entry; +% +%/* +% * A list of addresses supported by a service. +% */ +% +%struct rpcb_entry_list { +% rpcb_entry rpcb_entry_map; +% struct rpcb_entry_list *rpcb_entry_next; +%}; +%typedef struct rpcb_entry_list rpcb_entry_list; +% +%typedef rpcb_entry_list *rpcb_entry_list_ptr; +% +%/* +% * rpcbind statistics +% */ +% +%#define rpcb_highproc_2 RPCBPROC_CALLIT +%#define rpcb_highproc_3 RPCBPROC_TADDR2UADDR +%#define rpcb_highproc_4 RPCBPROC_GETSTAT +%#define RPCBSTAT_HIGHPROC 13 +%#define RPCBVERS_STAT 3 +%#define RPCBVERS_4_STAT 2 +%#define RPCBVERS_3_STAT 1 +%#define RPCBVERS_2_STAT 0 +% +%/* Link list of all the stats about getport and getaddr */ +% +%struct rpcbs_addrlist { +% rpcprog_t prog; +% rpcvers_t vers; +% int success; +% int failure; +% char *netid; +% struct rpcbs_addrlist *next; +%}; +%typedef struct rpcbs_addrlist rpcbs_addrlist; +% +%/* Link list of all the stats about rmtcall */ +% +%struct rpcbs_rmtcalllist { +% rpcprog_t prog; +% rpcvers_t vers; +% rpcproc_t proc; +% int success; +% int failure; +% int indirect; +% char *netid; +% struct rpcbs_rmtcalllist *next; +%}; +%typedef struct rpcbs_rmtcalllist rpcbs_rmtcalllist; +% +%typedef int rpcbs_proc[RPCBSTAT_HIGHPROC]; +% +%typedef rpcbs_addrlist *rpcbs_addrlist_ptr; +% +%typedef rpcbs_rmtcalllist *rpcbs_rmtcalllist_ptr; +% +%struct rpcb_stat { +% rpcbs_proc info; +% int setinfo; +% int unsetinfo; +% rpcbs_addrlist_ptr addrinfo; +% rpcbs_rmtcalllist_ptr rmtinfo; +%}; +%typedef struct rpcb_stat rpcb_stat; +% +%/* +% * One rpcb_stat structure is returned for each version of rpcbind +% * being monitored. +% */ +% +%typedef rpcb_stat rpcb_stat_byvers[RPCBVERS_STAT]; +% +%#ifdef __cplusplus +%} +%#endif +% +%#endif /* ndef _KERNEL */ +#endif /* RPC_HDR */ diff --git a/include/rpc/rpcent.h b/include/rpc/rpcent.h new file mode 100644 index 000000000000..234002ac6a9c --- /dev/null +++ b/include/rpc/rpcent.h @@ -0,0 +1,69 @@ +/* $NetBSD: rpcent.h,v 1.1 2000/06/02 22:57:56 fvdl Exp $ */ +/* $FreeBSD$ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* + * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. + */ + +/* + * rpcent.h, + * For converting rpc program numbers to names etc. + * + */ + +#ifndef _RPC_RPCENT_H +#define _RPC_RPCENT_H + +/* #pragma ident "@(#)rpcent.h 1.13 94/04/25 SMI" */ +/* @(#)rpcent.h 1.1 88/12/06 SMI */ + + +struct rpcent { + char *r_name; /* name of server for this rpc program */ + char **r_aliases; /* alias list */ + int r_number; /* rpc program number */ +}; + +__BEGIN_DECLS +extern struct rpcent *getrpcbyname_r __P((const char *, struct rpcent *, + char *, int)); +extern struct rpcent *getrpcbynumber_r __P((int, struct rpcent *, char *, int)); +extern struct rpcent *getrpcent_r __P((struct rpcent *, char *, int)); + +/* Old interfaces that return a pointer to a static area; MT-unsafe */ +extern struct rpcent *getrpcbyname __P((char *)); +extern struct rpcent *getrpcbynumber __P((int)); +extern struct rpcent *getrpcent __P((void)); +extern void setrpcent __P((int)); +extern void endrpcent __P((void)); +__END_DECLS + +#endif /* !_RPC_CENT_H */ diff --git a/include/rpc/svc.h b/include/rpc/svc.h index 9ef76cfb22d9..dc03f5934f71 100644 --- a/include/rpc/svc.h +++ b/include/rpc/svc.h @@ -1,3 +1,5 @@ +/* $NetBSD: svc.h,v 1.17 2000/06/02 22:57:56 fvdl Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -26,15 +28,15 @@ * 2550 Garcia Avenue * Mountain View, California 94043 * - * from: @(#)svc.h 1.20 88/02/08 SMI - * from: @(#)svc.h 2.2 88/07/29 4.0 RPCSRC + * from: @(#)svc.h 1.35 88/12/17 SMI + * from: @(#)svc.h 1.27 94/04/25 SMI * $FreeBSD$ */ /* * svc.h, Server-side remote procedure call interface. * - * Copyright (C) 1984, Sun Microsystems, Inc. + * Copyright (C) 1986-1993 by Sun Microsystems, Inc. */ #ifndef _RPC_SVC_H @@ -63,21 +65,26 @@ * parameters, struct svc_req * and SVCXPRT *, defined below. */ +/* + * Service control requests + */ +#define SVCGET_VERSQUIET 1 +#define SVCSET_VERSQUIET 2 + + enum xprt_stat { XPRT_DIED, XPRT_MOREREQS, XPRT_IDLE }; -struct rpc_msg; - /* * Server side transport handle */ typedef struct __rpc_svcxprt { - int xp_sock; + int xp_fd; u_short xp_port; /* associated port number */ - struct xp_ops { + const struct xp_ops { /* receive incoming requests */ bool_t (*xp_recv) __P((struct __rpc_svcxprt *, struct rpc_msg *)); @@ -96,16 +103,45 @@ typedef struct __rpc_svcxprt { void (*xp_destroy) __P((struct __rpc_svcxprt *)); } *xp_ops; int xp_addrlen; /* length of remote address */ - struct sockaddr_in xp_raddr; /* remote address */ + struct sockaddr_in xp_raddr; /* remote addr. (backward ABI compat) */ + /* XXX - fvdl stick this here for ABI backward compat reasons */ + const struct xp_ops2 { + /* catch-all function */ + bool_t (*xp_control) __P((struct __rpc_svcxprt *, const u_int, + void *)); + } *xp_ops2; + char *xp_tp; /* transport provider device name */ + char *xp_netid; /* network token */ + struct netbuf xp_ltaddr; /* local transport address */ + struct netbuf xp_rtaddr; /* remote transport address */ struct opaque_auth xp_verf; /* raw response verifier */ - caddr_t xp_p1; /* private */ - caddr_t xp_p2; /* private */ + void *xp_p1; /* private: for use by svc ops */ + void *xp_p2; /* private: for use by svc ops */ + void *xp_p3; /* private: for use by svc lib */ + int xp_type; /* transport type */ } SVCXPRT; /* + * Service request + */ +struct svc_req { + u_int32_t rq_prog; /* service program number */ + u_int32_t rq_vers; /* service protocol version */ + u_int32_t rq_proc; /* the desired procedure */ + struct opaque_auth rq_cred; /* raw creds from the wire */ + void *rq_clntcred; /* read only cooked cred */ + SVCXPRT *rq_xprt; /* associated transport */ +}; + +/* * Approved way of getting address of caller */ -#define svc_getcaller(x) (&(x)->xp_raddr) +#define svc_getrpccaller(x) (&(x)->xp_rtaddr) + +/* + * FreeBSD-only definition to get the creds of the caller (AF_LOCAL). + */ +#define __svc_getcallercreds(x) ((struct cmsgcred *)(x)->xp_p2) /* * Operations defined on an SVCXPRT handle @@ -145,44 +181,36 @@ typedef struct __rpc_svcxprt { #define svc_destroy(xprt) \ (*(xprt)->xp_ops->xp_destroy)(xprt) - -/* - * Service request - */ -struct svc_req { - u_int32_t rq_prog; /* service program number */ - u_int32_t rq_vers; /* service protocol version */ - u_int32_t rq_proc; /* the desired procedure */ - struct opaque_auth rq_cred; /* raw creds from the wire */ - caddr_t rq_clntcred; /* read only cooked cred */ - SVCXPRT *rq_xprt; /* associated transport */ -}; - +#define SVC_CONTROL(xprt, rq, in) \ + (*(xprt)->xp_ops2->xp_control)((xprt), (rq), (in)) /* * Service registration * - * svc_register(xprt, prog, vers, dispatch, protocol) - * SVCXPRT *xprt; - * u_long prog; - * u_long vers; - * void (*dispatch)(); - * int protocol; (like TCP or UDP, zero means do not register) + * svc_reg(xprt, prog, vers, dispatch, nconf) + * const SVCXPRT *xprt; + * const rpcprog_t prog; + * const rpcvers_t vers; + * const void (*dispatch)(); + * const struct netconfig *nconf; */ + __BEGIN_DECLS -extern bool_t svc_register __P((SVCXPRT *, u_long, u_long, - void (*) __P((struct svc_req *, SVCXPRT *)), int)); +extern bool_t svc_reg __P((SVCXPRT *, const rpcprog_t, const rpcvers_t, + void (*) __P((struct svc_req *, SVCXPRT *)), + const struct netconfig *)); __END_DECLS /* * Service un-registration * - * svc_unregister(prog, vers) - * u_long prog; - * u_long vers; + * svc_unreg(prog, vers) + * const rpcprog_t prog; + * const rpcvers_t vers; */ + __BEGIN_DECLS -extern void svc_unregister __P((u_long, u_long)); +extern void svc_unreg __P((const rpcprog_t, const rpcvers_t)); __END_DECLS /* @@ -206,8 +234,6 @@ extern void xprt_unregister __P((SVCXPRT *)); __END_DECLS - - /* * When the service routine is called, it must first check to see if it * knows about the procedure; if not, it should call svcerr_noproc @@ -239,10 +265,13 @@ extern bool_t svc_sendreply __P((SVCXPRT *, xdrproc_t, char *)); extern void svcerr_decode __P((SVCXPRT *)); extern void svcerr_weakauth __P((SVCXPRT *)); extern void svcerr_noproc __P((SVCXPRT *)); -extern void svcerr_progvers __P((SVCXPRT *, u_long, u_long)); +extern void svcerr_progvers __P((SVCXPRT *, rpcvers_t, rpcvers_t)); extern void svcerr_auth __P((SVCXPRT *, enum auth_stat)); extern void svcerr_noprog __P((SVCXPRT *)); extern void svcerr_systemerr __P((SVCXPRT *)); +extern int rpc_reg __P((rpcprog_t, rpcvers_t, rpcproc_t, + char *(*) __P((char *)), xdrproc_t, xdrproc_t, + char *)); __END_DECLS /* @@ -261,64 +290,130 @@ __END_DECLS * dynamic; must be inspected before each call to select */ extern int svc_maxfd; +#ifdef FD_SETSIZE extern fd_set svc_fdset; #define svc_fds svc_fdset.fds_bits[0] /* compatibility */ +#else +extern int svc_fds; +#endif /* def FD_SETSIZE */ -#ifndef _KERNEL /* * a small program implemented by the svc_rpc implementation itself; * also see clnt.h for protocol numbers. */ -extern void rpctest_service(); -#endif +__BEGIN_DECLS +extern void rpctest_service __P((void)); +__END_DECLS __BEGIN_DECLS extern void svc_getreq __P((int)); extern void svc_getreqset __P((fd_set *)); -extern void svc_getreqset2 __P((fd_set *, int)); /* XXX: nonstd, undoc */ +extern void svc_getreq_common __P((int)); +struct pollfd; +extern void svc_getreq_poll __P((struct pollfd *, int)); + extern void svc_run __P((void)); +extern void svc_exit __P((void)); __END_DECLS /* * Socket to use on svcxxx_create call to get default socket */ #define RPC_ANYSOCK -1 +#define RPC_ANYFD RPC_ANYSOCK /* * These are the existing service side transport implementations */ +__BEGIN_DECLS /* - * Memory based rpc for testing and timing. + * Transport independent svc_create routine. + */ +extern int svc_create __P((void (*) __P((struct svc_req *, SVCXPRT *)), + const rpcprog_t, const rpcvers_t, const char *)); +/* + * void (*dispatch)(); -- dispatch routine + * const rpcprog_t prognum; -- program number + * const rpcvers_t versnum; -- version number + * const char *nettype; -- network type */ -__BEGIN_DECLS -extern SVCXPRT *svcraw_create __P((void)); -__END_DECLS /* - * Udp based rpc. + * Generic server creation routine. It takes a netconfig structure + * instead of a nettype. */ -__BEGIN_DECLS -extern SVCXPRT *svcudp_create __P((int)); -extern SVCXPRT *svcudp_bufcreate __P((int, u_int, u_int)); -__END_DECLS + +extern SVCXPRT *svc_tp_create __P((void (*) __P((struct svc_req *, SVCXPRT *)), + const rpcprog_t, const rpcvers_t, + const struct netconfig *)); + /* + * void (*dispatch)(); -- dispatch routine + * const rpcprog_t prognum; -- program number + * const rpcvers_t versnum; -- version number + * const struct netconfig *nconf; -- netconfig structure + */ /* - * Tcp based rpc. + * Generic TLI create routine + */ +extern SVCXPRT *svc_tli_create __P((const int, const struct netconfig *, + const struct t_bind *, const u_int, + const u_int)); +/* + * const int fd; -- connection end point + * const struct netconfig *nconf; -- netconfig structure for network + * const struct t_bind *bindaddr; -- local bind address + * const u_int sendsz; -- max sendsize + * const u_int recvsz; -- max recvsize */ -__BEGIN_DECLS -extern SVCXPRT *svctcp_create __P((int, u_int, u_int)); -extern SVCXPRT *svcfd_create __P((int, u_int, u_int)); -__END_DECLS /* - * AF_UNIX socket based rpc. + * Connectionless and connectionful create routines */ -__BEGIN_DECLS -extern SVCXPRT *svcunix_create __P((int, u_int, u_int, char *)); -extern SVCXPRT *svcunixfd_create __P((int, u_int, u_int)); + +extern SVCXPRT *svc_vc_create __P((const int, const u_int, const u_int)); +/* + * const int fd; -- open connection end point + * const u_int sendsize; -- max send size + * const u_int recvsize; -- max recv size + */ + +extern SVCXPRT *svc_dg_create __P((const int, const u_int, const u_int)); + /* + * const int fd; -- open connection + * const u_int sendsize; -- max send size + * const u_int recvsize; -- max recv size + */ + + +/* + * the routine takes any *open* connection + * descriptor as its first input and is used for open connections. + */ +extern SVCXPRT *svc_fd_create __P((const int, const u_int, const u_int)); +/* + * const int fd; -- open connection end point + * const u_int sendsize; -- max send size + * const u_int recvsize; -- max recv size + */ + +/* + * Memory based rpc (for speed check and testing) + */ +extern SVCXPRT *svc_raw_create __P((void)); + +/* + * svc_dg_enable_cache() enables the cache on dg transports. + */ +int svc_dg_enablecache __P((SVCXPRT *, const u_int)); + __END_DECLS + +/* for backward compatibility */ +#include <rpc/svc_soc.h> + #endif /* !_RPC_SVC_H */ diff --git a/include/rpc/svc_auth.h b/include/rpc/svc_auth.h index 536d6a6481c6..8f55339968e2 100644 --- a/include/rpc/svc_auth.h +++ b/include/rpc/svc_auth.h @@ -1,3 +1,5 @@ +/* $NetBSD: svc_auth.h,v 1.8 2000/06/02 22:57:57 fvdl Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -27,7 +29,7 @@ * Mountain View, California 94043 * * from: @(#)svc_auth.h 1.6 86/07/16 SMI - * from: @(#)svc_auth.h 2.1 88/07/29 4.0 RPCSRC + * @(#)svc_auth.h 2.1 88/07/29 4.0 RPCSRC * $FreeBSD$ */ @@ -37,20 +39,17 @@ * Copyright (C) 1984, Sun Microsystems, Inc. */ -#ifndef _RPC_SVCAUTH_H -#define _RPC_SVCAUTH_H - -struct rpc_msg; -struct svc_req; +#ifndef _RPC_SVC_AUTH_H +#define _RPC_SVC_AUTH_H /* * Server side authenticator */ __BEGIN_DECLS extern enum auth_stat _authenticate __P((struct svc_req *, struct rpc_msg *)); -extern int svc_auth_reg __P((int, enum auth_stat (*)(struct svc_req *, - struct rpc_msg *))); -extern enum auth_stat _svcauth_des __P((struct svc_req *, struct rpc_msg *)); +extern int svc_auth_reg __P((int, enum auth_stat (*) __P((struct svc_req *, + struct rpc_msg *)))); + __END_DECLS -#endif /* !_RPC_SVCAUTH_H */ +#endif /* !_RPC_SVC_AUTH_H */ diff --git a/include/rpc/svc_dg.h b/include/rpc/svc_dg.h new file mode 100644 index 000000000000..3514745d2efd --- /dev/null +++ b/include/rpc/svc_dg.h @@ -0,0 +1,51 @@ +/* $NetBSD: svc_dg.h,v 1.1 2000/06/02 23:11:16 fvdl Exp $ */ +/* $FreeBSD$ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * XXX - this file exists only so that the rpcbind code can pull it in. + * This should go away. It should only be include by svc_dg.c and + * rpcb_svc_com.c in the rpcbind code. + */ + +/* + * kept in xprt->xp_p2 + */ +struct svc_dg_data { + /* XXX: optbuf should be the first field, used by ti_opts.c code */ + size_t su_iosz; /* size of send.recv buffer */ + u_int32_t su_xid; /* transaction id */ + XDR su_xdrs; /* XDR handle */ + char su_verfbody[MAX_AUTH_BYTES]; /* verifier body */ + void *su_cache; /* cached data, NULL if none */ +}; + +#define __rpcb_get_dg_xidp(x) (&((struct svc_dg_data *)(x)->xp_p2)->su_xid) diff --git a/include/rpc/svc_soc.h b/include/rpc/svc_soc.h new file mode 100644 index 000000000000..c3d16fec6341 --- /dev/null +++ b/include/rpc/svc_soc.h @@ -0,0 +1,116 @@ +/* $NetBSD: svc_soc.h,v 1.1 2000/06/02 22:57:57 fvdl Exp $ */ +/* $FreeBSD$ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* + * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. + */ + +/* + * svc.h, Server-side remote procedure call interface. + */ + +#ifndef _RPC_SVC_SOC_H +#define _RPC_SVC_SOC_H +#include <sys/cdefs.h> + +/* #pragma ident "@(#)svc_soc.h 1.11 94/04/25 SMI" */ +/* svc_soc.h 1.8 89/05/01 SMI */ + +/* + * All the following declarations are only for backward compatibility + * with TS-RPC + */ + +/* + * Approved way of getting address of caller + */ +#define svc_getcaller(x) (&(x)->xp_raddr) + +/* + * Service registration + * + * svc_register(xprt, prog, vers, dispatch, protocol) + * SVCXPRT *xprt; + * u_long prog; + * u_long vers; + * void (*dispatch)(); + * int protocol; like TCP or UDP, zero means do not register + */ +__BEGIN_DECLS +extern bool_t svc_register __P((SVCXPRT *, u_long, u_long, + void (*) __P((struct svc_req *, SVCXPRT *)), int)); +__END_DECLS + +/* + * Service un-registration + * + * svc_unregister(prog, vers) + * u_long prog; + * u_long vers; + */ +__BEGIN_DECLS +extern void svc_unregister __P((u_long, u_long)); +__END_DECLS + + +/* + * Memory based rpc for testing and timing. + */ +__BEGIN_DECLS +extern SVCXPRT *svcraw_create __P((void)); +__END_DECLS + + +/* + * Udp based rpc. + */ +__BEGIN_DECLS +extern SVCXPRT *svcudp_create __P((int)); +extern SVCXPRT *svcudp_bufcreate __P((int, u_int, u_int)); +extern int svcudp_enablecache __P((SVCXPRT *, u_long)); +__END_DECLS + + +/* + * Tcp based rpc. + */ +__BEGIN_DECLS +extern SVCXPRT *svctcp_create __P((int, u_int, u_int)); +__END_DECLS + +/* + * Fd based rpc. + */ +__BEGIN_DECLS +extern SVCXPRT *svcfd_create __P((int, u_int, u_int)); +__END_DECLS + +#endif /* !_RPC_SVC_SOC_H */ diff --git a/include/rpc/types.h b/include/rpc/types.h index e2ceec5b3df7..4a5c6564b270 100644 --- a/include/rpc/types.h +++ b/include/rpc/types.h @@ -1,3 +1,5 @@ +/* $NetBSD: types.h,v 1.13 2000/06/13 01:02:44 thorpej Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -37,8 +39,18 @@ #ifndef _RPC_TYPES_H #define _RPC_TYPES_H -#define bool_t int32_t -#define enum_t int32_t +#include <sys/types.h> + +typedef int32_t bool_t; +typedef int32_t enum_t; + +typedef u_int32_t rpcprog_t; +typedef u_int32_t rpcvers_t; +typedef u_int32_t rpcproc_t; +typedef u_int32_t rpcprot_t; +typedef u_int32_t rpcport_t; +typedef int32_t rpc_inline_t; + #define __dontcare__ -1 #ifndef FALSE @@ -51,12 +63,46 @@ # define NULL 0 #endif -#define mem_alloc(bsize) malloc(bsize) +#define mem_alloc(bsize) calloc(1, bsize) #define mem_free(ptr, bsize) free(ptr) -#ifndef makedev /* ie, we haven't already included it */ -#include <sys/types.h> -#endif #include <sys/time.h> +#include <netconfig.h> + +/* + * The netbuf structure is defined here, because FreeBSD / NetBSD only use + * it inside the RPC code. It's in <xti.h> on SVR4, but it would be confusing + * to have an xti.h, since FreeBSD / NetBSD does not support XTI/TLI. + */ + +/* + * The netbuf structure is used for transport-independent address storage. + */ +struct netbuf { + unsigned int maxlen; + unsigned int len; + void *buf; +}; + +/* + * The format of the addres and options arguments of the XTI t_bind call. + * Only provided for compatibility, it should not be used. + */ + +struct t_bind { + struct netbuf addr; + unsigned int qlen; +}; + +/* + * Internal library and rpcbind use. This is not an exported interface, do + * not use. + */ +struct __rpc_sockinfo { + int si_af; + int si_proto; + int si_socktype; + int si_alen; +}; #endif /* !_RPC_TYPES_H */ diff --git a/include/rpc/xdr.h b/include/rpc/xdr.h index 2ce9205422e6..90107ffc92ac 100644 --- a/include/rpc/xdr.h +++ b/include/rpc/xdr.h @@ -1,3 +1,5 @@ +/* $NetBSD: xdr.h,v 1.19 2000/07/17 05:00:45 matt Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -97,15 +99,15 @@ enum xdr_op { */ typedef struct __rpc_xdr { enum xdr_op x_op; /* operation; fast additional param */ - struct xdr_ops { + const struct xdr_ops { /* get a long from underlying stream */ bool_t (*x_getlong) __P((struct __rpc_xdr *, long *)); - /* put a long to underlying stream */ - bool_t (*x_putlong) __P((struct __rpc_xdr *, long *)); - /* get some bytes from underlying stream */ - bool_t (*x_getbytes) __P((struct __rpc_xdr *, caddr_t, u_int)); - /* put some bytes to underlying stream */ - bool_t (*x_putbytes) __P((struct __rpc_xdr *, caddr_t, u_int)); + /* put a long to " */ + bool_t (*x_putlong) __P((struct __rpc_xdr *, const long *)); + /* get some bytes from " */ + bool_t (*x_getbytes) __P((struct __rpc_xdr *, char *, u_int)); + /* put some bytes to " */ + bool_t (*x_putbytes) __P((struct __rpc_xdr *, const char *, u_int)); /* returns bytes off from beginning */ u_int (*x_getpostn) __P((struct __rpc_xdr *)); /* lets you reposition the stream */ @@ -114,10 +116,11 @@ typedef struct __rpc_xdr { int32_t *(*x_inline) __P((struct __rpc_xdr *, u_int)); /* free privates of this xdr_stream */ void (*x_destroy) __P((struct __rpc_xdr *)); + bool_t (*x_control) __P((struct __rpc_xdr *, int, void *)); } *x_ops; - caddr_t x_public; /* users' data */ - caddr_t x_private; /* pointer to private data */ - caddr_t x_base; /* private used for position info */ + char * x_public; /* users' data */ + void * x_private; /* pointer to private data */ + char * x_base; /* private used for position info */ int x_handy; /* extra private word */ } XDR; @@ -128,22 +131,17 @@ typedef struct __rpc_xdr { * The opaque pointer generally points to a structure of the data type * to be decoded. If this pointer is 0, then the type routines should * allocate dynamic storage of the appropriate size and return it. - */ -#ifdef _KERNEL -typedef bool_t (*xdrproc_t) __P((XDR *, void *, u_int)); -#else -/* - * XXX can't actually prototype it, because some take two args!!! + * + * XXX can't actually prototype it, because some take three args!!! */ typedef bool_t (*xdrproc_t) __P((/* XDR *, void *, u_int */)); -#endif /* * Operations defined on a XDR handle * * XDR *xdrs; * long *longp; - * caddr_t addr; + * char * addr; * u_int len; * u_int pos; */ @@ -157,6 +155,29 @@ typedef bool_t (*xdrproc_t) __P((/* XDR *, void *, u_int */)); #define xdr_putlong(xdrs, longp) \ (*(xdrs)->x_ops->x_putlong)(xdrs, longp) +static __inline int +xdr_getint32(XDR *xdrs, int32_t *ip) +{ + long l; + + if (!xdr_getlong(xdrs, &l)) + return (FALSE); + *ip = (int32_t)l; + return (TRUE); +} + +static __inline int +xdr_putint32(XDR *xdrs, int32_t *ip) +{ + long l; + + l = (long)*ip; + return xdr_putlong(xdrs, &l); +} + +#define XDR_GETINT32(xdrs, int32p) xdr_getint32(xdrs, int32p) +#define XDR_PUTINT32(xdrs, int32p) xdr_putint32(xdrs, int32p) + #define XDR_GETBYTES(xdrs, addr, len) \ (*(xdrs)->x_ops->x_getbytes)(xdrs, addr, len) #define xdr_getbytes(xdrs, addr, len) \ @@ -189,6 +210,21 @@ typedef bool_t (*xdrproc_t) __P((/* XDR *, void *, u_int */)); if ((xdrs)->x_ops->x_destroy) \ (*(xdrs)->x_ops->x_destroy)(xdrs) +#define XDR_CONTROL(xdrs, req, op) \ + if ((xdrs)->x_ops->x_control) \ + (*(xdrs)->x_ops->x_control)(xdrs, req, op) +#define xdr_control(xdrs, req, op) XDR_CONTROL(xdrs, req, op) + +/* + * Solaris strips the '_t' from these types -- not sure why. + * But, let's be compatible. + */ +#define xdr_rpcvers(xdrs, versp) xdr_u_int32(xdrs, versp) +#define xdr_rpcprog(xdrs, progp) xdr_u_int32(xdrs, progp) +#define xdr_rpcproc(xdrs, procp) xdr_u_int32(xdrs, procp) +#define xdr_rpcprot(xdrs, protp) xdr_u_int32(xdrs, protp) +#define xdr_rpcport(xdrs, portp) xdr_u_int32(xdrs, portp) + /* * Support struct for discriminated unions. * You create an array of xdrdiscrim structures, terminated with @@ -220,8 +256,13 @@ struct xdr_discrim { * N.B. and frozen for all time: each data type here uses 4 bytes * of external representation. */ -#define IXDR_GET_LONG(buf) ((long)ntohl((u_long)*(buf)++)) -#define IXDR_PUT_LONG(buf, v) (*(buf)++ = (long)htonl((u_long)v)) +#define IXDR_GET_INT32(buf) ((int32_t)ntohl((u_int32_t)*(buf)++)) +#define IXDR_PUT_INT32(buf, v) (*(buf)++ =(int32_t)htonl((u_int32_t)v)) +#define IXDR_GET_U_INT32(buf) ((u_int32_t)IXDR_GET_INT32(buf)) +#define IXDR_PUT_U_INT32(buf, v) IXDR_PUT_INT32((buf), ((int32_t)(v))) + +#define IXDR_GET_LONG(buf) ((long)ntohl((u_int32_t)*(buf)++)) +#define IXDR_PUT_LONG(buf, v) (*(buf)++ =(int32_t)htonl((u_int32_t)v)) #define IXDR_GET_BOOL(buf) ((bool_t)IXDR_GET_LONG(buf)) #define IXDR_GET_ENUM(buf, t) ((t)IXDR_GET_LONG(buf)) @@ -229,11 +270,11 @@ struct xdr_discrim { #define IXDR_GET_SHORT(buf) ((short)IXDR_GET_LONG(buf)) #define IXDR_GET_U_SHORT(buf) ((u_short)IXDR_GET_LONG(buf)) -#define IXDR_PUT_BOOL(buf, v) IXDR_PUT_LONG((buf), ((long)(v))) -#define IXDR_PUT_ENUM(buf, v) IXDR_PUT_LONG((buf), ((long)(v))) -#define IXDR_PUT_U_LONG(buf, v) IXDR_PUT_LONG((buf), ((long)(v))) -#define IXDR_PUT_SHORT(buf, v) IXDR_PUT_LONG((buf), ((long)(v))) -#define IXDR_PUT_U_SHORT(buf, v) IXDR_PUT_LONG((buf), ((long)(v))) +#define IXDR_PUT_BOOL(buf, v) IXDR_PUT_LONG((buf), (v)) +#define IXDR_PUT_ENUM(buf, v) IXDR_PUT_LONG((buf), (v)) +#define IXDR_PUT_U_LONG(buf, v) IXDR_PUT_LONG((buf), (v)) +#define IXDR_PUT_SHORT(buf, v) IXDR_PUT_LONG((buf), (v)) +#define IXDR_PUT_U_SHORT(buf, v) IXDR_PUT_LONG((buf), (v)) /* * These are the "generic" xdr routines. @@ -256,19 +297,23 @@ extern bool_t xdr_bool __P((XDR *, bool_t *)); extern bool_t xdr_enum __P((XDR *, enum_t *)); extern bool_t xdr_array __P((XDR *, char **, u_int *, u_int, u_int, xdrproc_t)); extern bool_t xdr_bytes __P((XDR *, char **, u_int *, u_int)); -extern bool_t xdr_opaque __P((XDR *, caddr_t, u_int)); +extern bool_t xdr_opaque __P((XDR *, char *, u_int)); extern bool_t xdr_string __P((XDR *, char **, u_int)); -extern bool_t xdr_union __P((XDR *, enum_t *, char *, struct xdr_discrim *, xdrproc_t)); -extern unsigned long xdr_sizeof __P((xdrproc_t, void *)); +extern bool_t xdr_union __P((XDR *, enum_t *, char *, const struct xdr_discrim *, xdrproc_t)); extern bool_t xdr_char __P((XDR *, char *)); extern bool_t xdr_u_char __P((XDR *, u_char *)); extern bool_t xdr_vector __P((XDR *, char *, u_int, u_int, xdrproc_t)); extern bool_t xdr_float __P((XDR *, float *)); extern bool_t xdr_double __P((XDR *, double *)); -extern bool_t xdr_reference __P((XDR *, caddr_t *, u_int, xdrproc_t)); -extern bool_t xdr_pointer __P((XDR *, caddr_t *, u_int, xdrproc_t)); +extern bool_t xdr_quadruple __P((XDR *, long double *)); +extern bool_t xdr_reference __P((XDR *, char **, u_int, xdrproc_t)); +extern bool_t xdr_pointer __P((XDR *, char **, u_int, xdrproc_t)); extern bool_t xdr_wrapstring __P((XDR *, char **)); extern void xdr_free __P((xdrproc_t, char *)); +extern bool_t xdr_hyper __P((XDR *, quad_t *)); +extern bool_t xdr_u_hyper __P((XDR *, u_quad_t *)); +extern bool_t xdr_longlong_t __P((XDR *, quad_t *)); +extern bool_t xdr_u_longlong_t __P((XDR *, u_quad_t *)); __END_DECLS /* @@ -291,15 +336,15 @@ __BEGIN_DECLS /* XDR using memory buffers */ extern void xdrmem_create __P((XDR *, char *, u_int, enum xdr_op)); -#ifdef _STDIO_H_ /* XDR using stdio library */ +#ifdef _STDIO_H_ extern void xdrstdio_create __P((XDR *, FILE *, enum xdr_op)); #endif /* XDR pseudo records for tcp */ extern void xdrrec_create __P((XDR *, u_int, u_int, char *, - int (*) __P((caddr_t, caddr_t, int)), - int (*) __P((caddr_t, caddr_t, int)))); + int (*) __P((char *, char *, int)), + int (*) __P((char *, char *, int)))); /* make end of xdr record */ extern bool_t xdrrec_endofrecord __P((XDR *, int)); @@ -309,6 +354,7 @@ extern bool_t xdrrec_skiprecord __P((XDR *)); /* true if no more input */ extern bool_t xdrrec_eof __P((XDR *)); +extern u_int xdrrec_readbytes __P((XDR *, caddr_t, u_int)); __END_DECLS #endif /* !_RPC_XDR_H */ diff --git a/include/rpcsvc/key_prot.x b/include/rpcsvc/key_prot.x index ab3196cfc04c..d87f39ccb910 100644 --- a/include/rpcsvc/key_prot.x +++ b/include/rpcsvc/key_prot.x @@ -44,7 +44,7 @@ */ %/* From: #pragma ident "@(#)key_prot.x 1.7 94/04/29 SMI" */ -% +%/* $FreeBSD$ */ %/* Copyright (c) 1990, 1991 Sun Microsystems, Inc. */ % %/* diff --git a/include/rpcsvc/nlm_prot.x b/include/rpcsvc/nlm_prot.x index 4c3ea7d8e8ec..ba0ccf33c6cf 100644 --- a/include/rpcsvc/nlm_prot.x +++ b/include/rpcsvc/nlm_prot.x @@ -1,6 +1,3 @@ -/* @(#)nlm_prot.x 2.1 88/08/01 4.0 RPCSRC */ -/* @(#)nlm_prot.x 1.8 87/09/21 Copyr 1987 Sun Micro */ - /* * Network lock manager protocol definition * Copyright (C) 1986 Sun Microsystems, Inc. @@ -12,9 +9,13 @@ %#define LM_MAXSTRLEN 1024 %#define MAXNAMELEN LM_MAXSTRLEN+1 #else +%#include <sys/cdefs.h> %#ifndef lint %static const char rcsid[] = % "$FreeBSD$"; +%/*static char sccsid[] = "from: @(#)nlm_prot.x 1.8 87/09/21 Copyr 1987 Sun Micro";*/ +%/*static char sccsid[] = "from: * @(#)nlm_prot.x 2.1 88/08/01 4.0 RPCSRC";*/ +%__RCSID("$NetBSD: nlm_prot.x,v 1.6 2000/06/07 14:30:15 bouyer Exp $"); %#endif /* not lint */ #endif @@ -77,20 +78,20 @@ struct nlm_lockargs { }; struct nlm_cancargs { - netobj cookie; + netobj cookie; bool block; bool exclusive; struct nlm_lock alock; }; struct nlm_testargs { - netobj cookie; + netobj cookie; bool exclusive; struct nlm_lock alock; }; struct nlm_unlockargs { - netobj cookie; + netobj cookie; struct nlm_lock alock; }; @@ -140,11 +141,127 @@ struct nlm_notify { long state; }; +#ifdef RPC_HDR +%/* definitions for NLM version 4 */ +#endif +enum nlm4_stats { + nlm4_granted = 0, + nlm4_denied = 1, + nlm4_denied_nolock = 2, + nlm4_blocked = 3, + nlm4_denied_grace_period = 4, + nlm4_deadlck = 5, + nlm4_rofs = 6, + nlm4_stale_fh = 7, + nlm4_fbig = 8, + nlm4_failed = 9 +}; + +struct nlm4_stat { + nlm4_stats stat; +}; + +struct nlm4_holder { + bool exclusive; + u_int32_t svid; + netobj oh; + u_int64_t l_offset; + u_int64_t l_len; +}; + +struct nlm4_lock { + string caller_name<MAXNAMELEN>; + netobj fh; + netobj oh; + u_int32_t svid; + u_int64_t l_offset; + u_int64_t l_len; +}; + +struct nlm4_share { + string caller_name<MAXNAMELEN>; + netobj fh; + netobj oh; + fsh_mode mode; + fsh_access access; +}; + +union nlm4_testrply switch (nlm4_stats stat) { + case nlm_denied: + struct nlm4_holder holder; + default: + void; +}; + +struct nlm4_testres { + netobj cookie; + nlm4_testrply stat; +}; + +struct nlm4_testargs { + netobj cookie; + bool exclusive; + struct nlm4_lock alock; +}; + +struct nlm4_res { + netobj cookie; + nlm4_stat stat; +}; + +struct nlm4_lockargs { + netobj cookie; + bool block; + bool exclusive; + struct nlm4_lock alock; + bool reclaim; /* used for recovering locks */ + int state; /* specify local status monitor state */ +}; + +struct nlm4_cancargs { + netobj cookie; + bool block; + bool exclusive; + struct nlm4_lock alock; +}; + +struct nlm4_unlockargs { + netobj cookie; + struct nlm4_lock alock; +}; + +struct nlm4_shareargs { + netobj cookie; + nlm4_share share; + bool reclaim; +}; + +struct nlm4_shareres { + netobj cookie; + nlm4_stats stat; + int sequence; +}; + +/* + * argument for the procedure called by rpc.statd when a monitored host + * status change. + * XXX assumes LM_MAXSTRLEN == SM_MAXSTRLEN + */ +struct nlm_sm_status { + string mon_name<LM_MAXSTRLEN>; /* name of host */ + int state; /* new state */ + opaque priv[16]; /* private data */ +}; + /* * Over-the-wire protocol used between the network lock managers */ program NLM_PROG { + version NLM_SM { + void NLM_SM_NOTIFY(struct nlm_sm_status) = 1; + } = 0; + version NLM_VERS { nlm_testres NLM_TEST(struct nlm_testargs) = 1; @@ -180,5 +297,25 @@ program NLM_PROG { void NLM_FREE_ALL(nlm_notify) = 23; } = 3; + version NLM_VERS4 { + nlm4_testres NLM4_TEST(nlm4_testargs) = 1; + nlm4_res NLM4_LOCK(nlm4_lockargs) = 2; + nlm4_res NLM4_CANCEL(nlm4_cancargs) = 3; + nlm4_res NLM4_UNLOCK(nlm4_unlockargs) = 4; + nlm4_res NLM4_GRANTED(nlm4_testargs) = 5; + void NLM4_TEST_MSG(nlm4_testargs) = 6; + void NLM4_LOCK_MSG(nlm4_lockargs) = 7; + void NLM4_CANCEL_MSG(nlm4_cancargs) = 8; + void NLM4_UNLOCK_MSG(nlm4_unlockargs) = 9; + void NLM4_GRANTED_MSG(nlm4_testargs) = 10; + void NLM4_TEST_RES(nlm4_testres) = 11; + void NLM4_LOCK_RES(nlm4_res) = 12; + void NLM4_CANCEL_RES(nlm4_res) = 13; + void NLM4_UNLOCK_RES(nlm4_res) = 14; + void NLM4_GRANTED_RES(nlm4_res) = 15; + nlm4_shareres NLM4_SHARE(nlm4_shareargs) = 20; + nlm4_shareres NLM4_UNSHARE(nlm4_shareargs) = 21; + nlm4_res NLM4_NM_LOCK(nlm4_lockargs) = 22; + void NLM4_FREE_ALL(nlm_notify) = 23; + } = 4; } = 100021; - diff --git a/include/rpcsvc/sm_inter.x b/include/rpcsvc/sm_inter.x index f5bf54524110..6e1862bf9fc5 100644 --- a/include/rpcsvc/sm_inter.x +++ b/include/rpcsvc/sm_inter.x @@ -62,6 +62,7 @@ program SM_PROG { struct sm_stat SM_UNMON_ALL(struct my_id) = 4; void SM_SIMU_CRASH(void) = 5; + void SM_NOTIFY(struct stat_chge) = 6; } = 1; } = 100024; @@ -90,6 +91,10 @@ struct mon{ opaque priv[16]; /* private information to store at monitor for requesting process */ }; +struct stat_chge { + string mon_name<SM_MAXSTRLEN>; /* name of the site that had the state change */ + int state; +}; /* * state # of status monitor monitonically increases each time diff --git a/lib/libc/gen/_pthread_stubs.c b/lib/libc/gen/_pthread_stubs.c index be6dab74635c..478335902297 100644 --- a/lib/libc/gen/_pthread_stubs.c +++ b/lib/libc/gen/_pthread_stubs.c @@ -26,7 +26,9 @@ * $FreeBSD$ */ +#include <signal.h> #include <pthread.h> +#include <pthread_np.h> /* * Weak symbols: All libc internal usage of these functions should @@ -37,9 +39,13 @@ * between application locks and libc locks (threads holding the * latter can't be allowed to exit/terminate). */ +#pragma weak _pthread_cond_init=_pthread_cond_init_stub +#pragma weak _pthread_cond_signal=_pthread_cond_signal_stub +#pragma weak _pthread_cond_wait=_pthread_cond_wait_stub #pragma weak _pthread_getspecific=_pthread_getspecific_stub #pragma weak _pthread_key_create=_pthread_key_create_stub #pragma weak _pthread_key_delete=_pthread_key_delete_stub +#pragma weak _pthread_main_np=_pthread_main_np_stub #pragma weak _pthread_mutex_destroy=_pthread_mutex_destroy_stub #pragma weak _pthread_mutex_init=_pthread_mutex_init_stub #pragma weak _pthread_mutex_lock=_pthread_mutex_lock_stub @@ -50,13 +56,40 @@ #pragma weak _pthread_mutexattr_settype=_pthread_mutexattr_settype_stub #pragma weak _pthread_once=_pthread_once_stub #pragma weak _pthread_self=_pthread_self_stub +#pragma weak _pthread_rwlock_init=_pthread_rwlock_init_stub +#pragma weak _pthread_rwlock_rdlock=_pthread_rwlock_rdlock_stub +#pragma weak _pthread_rwlock_tryrdlock=_pthread_rwlock_tryrdlock_stub +#pragma weak _pthread_rwlock_trywrloc=_pthread_rwlock_trywrlock_stub +#pragma weak _pthread_rwlock_unlock=_pthread_rwlock_unlock_stub +#pragma weak _pthread_rwlock_wrlock=_pthread_rwlock_wrlock_stub #pragma weak _pthread_setspecific=_pthread_setspecific_stub +#pragma weak _pthread_sigmask=_pthread_sigmask_stub +/* Define a null pthread structure just to satisfy _pthread_self. */ struct pthread { }; static struct pthread main_thread; +int +_pthread_cond_init_stub(pthread_cond_t *cond, + const pthread_condattr_t *cond_attr) +{ + return (0); +} + +int +_pthread_cond_signal_stub(pthread_cond_t *cond) +{ + return (0); +} + +int +_pthread_cond_wait_stub(pthread_cond_t *cond, + pthread_mutex_t *mutex) +{ + return (0); +} void * _pthread_getspecific_stub(pthread_key_t key) @@ -77,6 +110,12 @@ _pthread_key_delete_stub(pthread_key_t key) } int +_pthread_main_np_stub() +{ + return (-1); +} + +int _pthread_mutex_destroy_stub(pthread_mutex_t *mattr) { return (0); @@ -130,6 +169,49 @@ _pthread_once_stub(pthread_once_t *once_control, void (*init_routine) (void)) return (0); } +int +_pthread_rwlock_init_stub(pthread_rwlock_t *rwlock, + const pthread_rwlockattr_t *attr) +{ + return (0); +} + +int +_pthread_rwlock_destroy_stub(pthread_rwlock_t *rwlock) +{ + return (0); +} + +int +_pthread_rwlock_rdlock_stub(pthread_rwlock_t *rwlock) +{ + return (0); +} + +int +_pthread_rwlock_tryrdlock_stub(pthread_rwlock_t *rwlock) +{ + return (0); +} + +int +_pthread_rwlock_trywrlock_stub(pthread_rwlock_t *rwlock) +{ + return (0); +} + +int +_pthread_rwlock_unlock_stub(pthread_rwlock_t *rwlock) +{ + return (0); +} + +int +_pthread_rwlock_wrlock_stub(pthread_rwlock_t *rwlock) +{ + return (0); +} + pthread_t _pthread_self_stub(void) { @@ -141,3 +223,14 @@ _pthread_setspecific_stub(pthread_key_t key, const void *value) { return (0); } + +int +_pthread_sigmask_stub(int how, const sigset_t *set, sigset_t *oset) +{ + /* + * No need to use _sigprocmask, since we know that the threads + * library is not linked in. + * + */ + return (sigprocmask(how, set, oset)); +} diff --git a/lib/libc/include/namespace.h b/lib/libc/include/namespace.h index ddffa82e4025..cc15a692d987 100644 --- a/lib/libc/include/namespace.h +++ b/lib/libc/include/namespace.h @@ -58,9 +58,15 @@ #define listen _listen #define nanosleep _nanosleep #define open _open +#define poll _poll +#define pthread_cond_signal _pthread_cond_signal +#define pthread_cond_wait _pthread_cond_wait +#define pthread_cond_init _pthread_cond_init +#define pthread_exit _pthread_exit #define pthread_getspecific _pthread_getspecific #define pthread_key_create _pthread_key_create #define pthread_key_delete _pthread_key_delete +#define pthread_main_np _pthread_main_np #define pthread_mutex_destroy _pthread_mutex_destroy #define pthread_mutex_init _pthread_mutex_init #define pthread_mutex_lock _pthread_mutex_lock @@ -70,8 +76,13 @@ #define pthread_mutexattr_destroy _pthread_mutexattr_destroy #define pthread_mutexattr_settype _pthread_mutexattr_settype #define pthread_once _pthread_once +#define pthread_rwlock_init _pthread_rwlock_init +#define pthread_rwlock_rdlock _pthread_rwlock_rdlock +#define pthread_rwlock_wrlock _pthread_rwlock_wrlock +#define pthread_rwlock_unlock _pthread_rwlock_unlock #define pthread_self _pthread_self #define pthread_setspecific _pthread_setspecific +#define pthread_sigmask _pthread_sigmask #define read _read #define readv _readv #define recvfrom _recvfrom @@ -106,14 +117,9 @@ #define msync _msync #define nfssvc _nfssvc #define pause _pause -#define poll _poll #define pthread_rwlock_destroy _pthread_rwlock_destroy -#define pthread_rwlock_init _pthread_rwlock_init -#define pthread_rwlock_rdlock _pthread_rwlock_rdlock #define pthread_rwlock_tryrdlock _pthread_rwlock_tryrdlock #define pthread_rwlock_trywrlock _pthread_rwlock_trywrlock -#define pthread_rwlock_unlock _pthread_rwlock_unlock -#define pthread_rwlock_wrlock _pthread_rwlock_wrlock #define pthread_rwlockattr_init _pthread_rwlockattr_init #define pthread_rwlockattr_destroy _pthread_rwlockattr_destroy #define sched_yield _sched_yield diff --git a/lib/libc/include/reentrant.h b/lib/libc/include/reentrant.h new file mode 100644 index 000000000000..e6ceb5ba1413 --- /dev/null +++ b/lib/libc/include/reentrant.h @@ -0,0 +1,130 @@ +/*- + * Copyright (c) 1997,98 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by J.T. Conklin. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * Requirements: + * + * 1. The thread safe mechanism should be lightweight so the library can + * be used by non-threaded applications without unreasonable overhead. + * + * 2. There should be no dependency on a thread engine for non-threaded + * applications. + * + * 3. There should be no dependency on any particular thread engine. + * + * 4. The library should be able to be compiled without support for thread + * safety. + * + * + * Rationale: + * + * One approach for thread safety is to provide discrete versions of the + * library: one thread safe, the other not. The disadvantage of this is + * that libc is rather large, and two copies of a library which are 99%+ + * identical is not an efficent use of resources. + * + * Another approach is to provide a single thread safe library. However, + * it should not add significant run time or code size overhead to non- + * threaded applications. + * + * Since the NetBSD C library is used in other projects, it should be + * easy to replace the mutual exclusion primitives with ones provided by + * another system. Similarly, it should also be easy to remove all + * support for thread safety completely if the target environment does + * not support threads. + * + * + * Implementation Details: + * + * The mutex primitives used by the library (mutex_t, mutex_lock, etc.) + * are macros which expand to the cooresponding primitives provided by + * the thread engine or to nothing. The latter is used so that code is + * not unreasonably cluttered with #ifdefs when all thread safe support + * is removed. + * + * The mutex macros can be directly mapped to the mutex primitives from + * pthreads, however it should be reasonably easy to wrap another mutex + * implementation so it presents a similar interface. + * + * Stub implementations of the mutex functions are provided with *weak* + * linkage. These functions simply return success. When linked with a + * thread library (i.e. -lpthread), the functions will override the + * stubs. + */ + +#include <pthread.h> +#include <pthread_np.h> +#include "libc_private.h" + +#define mutex_t pthread_mutex_t +#define cond_t pthread_cond_t +#define rwlock_t pthread_rwlock_t + +#define thread_key_t pthread_key_t +#define MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER +#define RWLOCK_INITIALIZER PTHREAD_RWLOCK_INITIALIZER + +#define mutex_init(m, a) _pthread_mutex_init(m, a) +#define mutex_lock(m) if (__isthreaded) \ + _pthread_mutex_lock(m) +#define mutex_unlock(m) if (__isthreaded) \ + _pthread_mutex_unlock(m) +#define mutex_trylock(m) (__isthreaded ? 0 : _pthread_mutex_trylock(m)) + +#define cond_init(c, a, p) _pthread_cond_init(c, a) +#define cond_signal(m) if (__isthreaded) \ + _pthread_cond_signal(m) +#define cond_wait(c, m) if (__isthreaded) \ + _pthread_cond_wait(c, m) + +#define rwlock_init(l, a) _pthread_rwlock_init(l, a) +#define rwlock_rdlock(l) if (__isthreaded) \ + _pthread_rwlock_rdlock(l) +#define rwlock_wrlock(l) if (__isthreaded) \ + _pthread_rwlock_wrlock(l) +#define rwlock_unlock(l) if (__isthreaded) \ + _pthread_rwlock_unlock(l) + +#define thr_keycreate(k, d) _pthread_key_create(k, d) +#define thr_setspecific(k, p) _pthread_setspecific(k, p) +#define thr_getspecific(k) _pthread_getspecific(k) +#define thr_sigsetmask(f, n, o) _pthread_sigmask(f, n, o) + +#define thr_self() _pthread_self() +#define thr_exit(x) _pthread_exit(x) +#define thr_main() _pthread_main_np() diff --git a/lib/libc/rpc/DISCLAIMER b/lib/libc/rpc/DISCLAIMER index 1a66d5f4c9cd..9a3a99161ae8 100644 --- a/lib/libc/rpc/DISCLAIMER +++ b/lib/libc/rpc/DISCLAIMER @@ -1,3 +1,6 @@ +/* $NetBSD: DISCLAIMER,v 1.2 1998/01/09 04:11:51 perry Exp $ */ +/* $FreeBSD$ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape diff --git a/lib/libc/rpc/Makefile.inc b/lib/libc/rpc/Makefile.inc index f9471598931e..1247c808a657 100644 --- a/lib/libc/rpc/Makefile.inc +++ b/lib/libc/rpc/Makefile.inc @@ -1,25 +1,35 @@ -# @(#)Makefile 5.11 (Berkeley) 9/6/90 +# @(#)Makefile 5.11 (Berkeley) 9/6/90 # $FreeBSD$ .PATH: ${.CURDIR}/../libc/rpc ${.CURDIR}/. +SRCS+= auth_none.c auth_unix.c authunix_prot.c bindresvport.c clnt_bcast.c \ + clnt_dg.c clnt_generic.c clnt_perror.c clnt_raw.c clnt_simple.c \ + clnt_vc.c rpc_dtablesize.c getnetconfig.c getnetpath.c getrpcent.c \ + getrpcport.c mt_misc.c pmap_clnt.c pmap_getmaps.c pmap_getport.c \ + pmap_prot.c pmap_prot2.c pmap_rmt.c rpc_prot.c rpc_commondata.c \ + rpc_callmsg.c rpc_generic.c rpc_soc.c rpcb_clnt.c rpcb_prot.c \ + rpcb_st_xdr.c svc.c svc_auth.c svc_dg.c svc_auth_unix.c svc_generic.c \ + svc_raw.c svc_run.c svc_simple.c svc_vc.c -SRCS+= auth_des.c auth_none.c auth_time.c auth_unix.c \ - authdes_prot.c authunix_prot.c bindresvport.c \ - clnt_generic.c clnt_perror.c clnt_raw.c clnt_simple.c clnt_tcp.c \ - clnt_udp.c clnt_unix.c crypt_client.c des_crypt.c des_soft.c \ - get_myaddress.c getpublickey.c getrpcent.c getrpcport.c \ - key_call.c key_prot_xdr.c netname.c netnamer.c \ - pmap_clnt.c pmap_getmaps.c pmap_getport.c pmap_prot.c \ - pmap_prot2.c pmap_rmt.c rpc_callmsg.c rpc_commondata.c \ - rpc_dtablesize.c rpc_prot.c rpcdname.c rtime.c \ - svc.c svc_auth.c svc_auth_des.c svc_auth_unix.c \ - svc_raw.c svc_run.c svc_simple.c \ - svc_tcp.c svc_udp.c svc_unix.c +# XDR +SRCS+= xdr.c xdr_array.c xdr_float.c xdr_mem.c xdr_rec.c xdr_reference.c \ + xdr_stdio.c + +# Secure-RPC +SRCS+= auth_time.c auth_des.c authdes_prot.c des_crypt.c des_soft.c \ + crypt_client.c key_call.c key_prot_xdr.c getpublickey.c \ + svc_auth_des.c + +# Resolver stuff +SRCS+= netname.c netnamer.c rpcdname.c + +# Misc Source +SRCS+= rtime.c # generated sources -SRCS+= crypt_clnt.c crypt_xdr.c crypt.h +SRCS+= crypt_clnt.c crypt_xdr.c crypt.h -CFLAGS+= -DBROKEN_DES +CFLAGS+= -DBROKEN_DES -DPORTMAP -DDES_BUILTIN CLEANFILES+= crypt_clnt.c crypt_xdr.c crypt.h @@ -34,79 +44,113 @@ crypt_xdr.c: ${RPCDIR}/crypt.x crypt.h crypt.h: ${RPCDIR}/crypt.x ${RPCGEN} -h -o ${.TARGET} ${RPCDIR}/crypt.x - -.if ${LIB} == "c" - -MAN3+= bindresvport.3 des_crypt.3 getrpcent.3 getrpcport.3 publickey.3 rpc.3 \ - rpc_secure.3 rtime.3 -MAN5+= publickey.5 rpc.5 - +MAN3+= bindresvport.3 des_crypt.3 getnetconfig.3 getnetpath.3 getrpcent.3 \ + getrpcport.3 rpc.3 rpc_soc.3 rpc_clnt_auth.3 rpc_clnt_calls.3 \ + rpc_clnt_create.3 rpc_svc_calls.3 rpc_svc_create.3 rpc_svc_err.3 \ + rpc_svc_reg.3 rpc_xdr.3 rpcbind.3 xdr.3 publickey.3 rpc_secure.3 \ + rtime.3 +MAN5+= publickey.5 rpc.5 netconfig.5 MLINKS+= bindresvport.3 bindresvport_sa.3 \ - getrpcent.3 endrpcent.3 \ + getnetconfig.3 setnetconfig.3 \ + getnetconfig.3 getnetconfigent.3 \ + getnetconfig.3 endnetconfig.3 \ + getnetconfig.3 nc_perror.3 \ + getnetconfig.3 nc_sperror.3 \ + getnetpath.3 setnetpath.3 \ + getnetpath.3 endnetpath.3 \ getrpcent.3 getrpcbyname.3 \ getrpcent.3 getrpcbynumber.3 \ + getrpcent.3 endrpcent.3 \ getrpcent.3 setrpcent.3 \ - rpc.3 auth_destroy.3 \ - rpc.3 authnone_create.3 \ - rpc.3 authunix_create.3 \ - rpc.3 authunix_create_default.3 \ - rpc.3 callrpc.3 \ - rpc.3 clnt_broadcast.3 \ - rpc.3 clnt_call.3 \ - rpc.3 clnt_control.3 \ - rpc.3 clnt_create.3 \ - rpc.3 clnt_destroy.3 \ - rpc.3 clnt_freeres.3 \ - rpc.3 clnt_geterr.3 \ - rpc.3 clnt_pcreateerror.3 \ - rpc.3 clnt_perrno.3 \ - rpc.3 clnt_perror.3 \ - rpc.3 clnt_spcreateerror.3 \ - rpc.3 clnt_sperrno.3 \ - rpc.3 clnt_sperror.3 \ - rpc.3 clntraw_create.3 \ - rpc.3 clnttcp_create.3 \ - rpc.3 clntudp_bufcreate.3 \ - rpc.3 clntudp_create.3 \ - rpc.3 get_myaddress.3 \ - rpc.3 pmap_getmaps.3 \ - rpc.3 pmap_getport.3 \ - rpc.3 pmap_rmtcall.3 \ - rpc.3 pmap_set.3 \ - rpc.3 pmap_unset.3 \ - rpc.3 regsterrpc.3 \ - rpc.3 rpc_createerr.3 \ - rpc.3 svc_destroy.3 \ - rpc.3 svc_fds.3 \ - rpc.3 svc_fdset.3 \ - rpc.3 svc_getargs.3 \ - rpc.3 svc_getcaller.3 \ - rpc.3 svc_getreg.3 \ - rpc.3 svc_getregset.3 \ - rpc.3 svc_register.3 \ - rpc.3 svc_run.3 \ - rpc.3 svc_sendreply.3 \ - rpc.3 svc_unregister.3 \ - rpc.3 svcerr_auth.3 \ - rpc.3 svcerr_decode.3 \ - rpc.3 svcerr_noproc.3 \ - rpc.3 svcerr_noprog.3 \ - rpc.3 svcerr_progvers.3 \ - rpc.3 svcerr_systemerr.3 \ - rpc.3 svcerr_weakauth.3 \ - rpc.3 svcfd_create.3 \ - rpc.3 svcraw_create.3 \ - rpc.3 svctcp_create.3 \ - rpc.3 svcudp_bufcreate.3 \ - rpc.3 xdr_accepted_reply.3 \ - rpc.3 xdr_authunix_parms.3 \ - rpc.3 xdr_callhdr.3 \ - rpc.3 xdr_callmsg.3 \ - rpc.3 xdr_opaque_auth.3 \ - rpc.3 xdr_pmap.3 \ - rpc.3 xdr_pmaplist.3 \ - rpc.3 xdr_rejected_reply.3 \ - rpc.3 xdr_replymsg.3 \ - rpc.3 xprt_register.3 \ - rpc.3 xprt_unregister.3 -.endif + rpc_clnt_auth.3 auth_destroy.3 \ + rpc_clnt_auth.3 authnone_create.3 \ + rpc_clnt_auth.3 authsys_create.3 \ + rpc_clnt_auth.3 authsys_create_default.3 \ + rpc_clnt_calls.3 clnt_call.3 \ + rpc_clnt_calls.3 clnt_perrno.3 \ + rpc_clnt_calls.3 clnt_perror.3 \ + rpc_clnt_calls.3 clnt_sperrno.3 \ + rpc_clnt_calls.3 clnt_sperror.3 \ + rpc_clnt_calls.3 rpc_call.3 \ + rpc_clnt_calls.3 rpc_broadcast.3 \ + rpc_clnt_calls.3 rpc_broadcast_exp.3 \ + rpc_clnt_calls.3 clnt_freeres.3 \ + rpc_clnt_calls.3 clnt_geterr.3 \ + rpc_clnt_create.3 clnt_control.3 \ + rpc_clnt_create.3 clnt_create.3 \ + rpc_clnt_create.3 clnt_create_vers.3 \ + rpc_clnt_create.3 clnt_destroy.3 \ + rpc_clnt_create.3 clnt_pcreateerror.3 \ + rpc_clnt_create.3 clnt_spcreateerror.3 \ + rpc_clnt_create.3 clnt_dg_create.3 \ + rpc_clnt_create.3 clnt_raw_create.3 \ + rpc_clnt_create.3 clnt_tli_create.3 \ + rpc_clnt_create.3 clnt_tp_create.3 \ + rpc_clnt_create.3 clnt_vc_create.3 \ + rpc_svc_calls.3 svc_dg_enablecache.3 \ + rpc_svc_calls.3 svc_exit.3 \ + rpc_svc_calls.3 svc_freeargs.3 \ + rpc_svc_calls.3 svc_getargs.3 \ + rpc_svc_calls.3 svc_getreq_common.3 \ + rpc_svc_calls.3 svc_getreq_poll.3 \ + rpc_svc_calls.3 svc_getreqset.3 \ + rpc_svc_calls.3 svc_getrpccaller.3 \ + rpc_svc_calls.3 __svc_getcallercreds.3 \ + rpc_svc_calls.3 svc_pollset.3 \ + rpc_svc_calls.3 svc_run.3 \ + rpc_svc_calls.3 svc_sendreply.3 \ + rpc_svc_create.3 svc_control.3 \ + rpc_svc_create.3 svc_create.3 \ + rpc_svc_create.3 svc_dg_create.3 \ + rpc_svc_create.3 svc_destroy.3 \ + rpc_svc_create.3 svc_fd_create.3 \ + rpc_svc_create.3 svc_raw_create.3 \ + rpc_svc_create.3 svc_tli_create.3 \ + rpc_svc_create.3 svc_tp_create.3 \ + rpc_svc_create.3 svc_vc_create.3 \ + rpc_svc_err.3 svcerr_auth.3 \ + rpc_svc_err.3 svcerr_decode.3 \ + rpc_svc_err.3 svcerr_noproc.3 \ + rpc_svc_err.3 svcerr_noprog.3 \ + rpc_svc_err.3 svcerr_progvers.3 \ + rpc_svc_err.3 svcerr_systemerr.3 \ + rpc_svc_err.3 svcerr_weakauth.3 \ + rpc_svc_reg.3 rpc_reg.3 \ + rpc_svc_reg.3 svc_reg.3 \ + rpc_svc_reg.3 svc_unreg.3 \ + rpc_svc_reg.3 svc_auth_reg.3 \ + rpc_svc_reg.3 xprt_register.3 \ + rpc_svc_reg.3 xprt_unregister.3 \ + rpcbind.3 rpcb_getmaps.3 \ + rpcbind.3 rpcb_getaddr.3 \ + rpcbind.3 rpcb_gettime.3 \ + rpcbind.3 rpcb_rmtcall.3 \ + rpcbind.3 rpcb_set.3 \ + rpcbind.3 rpcb_unset.3 \ + rpc_soc.3 authunix_create.3 \ + rpc_soc.3 authunix_create_default.3 \ + rpc_soc.3 callrpc.3 \ + rpc_soc.3 clnt_broadcast.3 \ + rpc_soc.3 clntraw_create.3 \ + rpc_soc.3 clnttcp_create.3 \ + rpc_soc.3 clntudp_bufcreate.3 \ + rpc_soc.3 clntudp_create.3 \ + rpc_soc.3 get_myaddress.3 \ + rpc_soc.3 pmap_getmaps.3 \ + rpc_soc.3 pmap_getport.3 \ + rpc_soc.3 pmap_rmtcall.3 \ + rpc_soc.3 pmap_set.3 \ + rpc_soc.3 pmap_unset.3 \ + rpc_soc.3 registerrpc.3 \ + rpc_soc.3 rpc_createerr.3 \ + rpc_soc.3 svc_fds.3 \ + rpc_soc.3 svc_fdset.3 \ + rpc_soc.3 svc_getcaller.3 \ + rpc_soc.3 svc_register.3 \ + rpc_soc.3 svc_unregister.3 \ + rpc_soc.3 svcfd_create.3 \ + rpc_soc.3 svcraw_create.3 \ + rpc_soc.3 svctcp_create.3 \ + rpc_soc.3 svcudp_bufcreate.3 \ + rpc_soc.3 xdr_pmap.3 \ + rpc_soc.3 xdr_pmaplist.3 diff --git a/lib/libc/rpc/README b/lib/libc/rpc/README index ad9d70f99056..c915fad283c6 100644 --- a/lib/libc/rpc/README +++ b/lib/libc/rpc/README @@ -1,233 +1,176 @@ -RPCSRC 4.0 7/11/89 +$FreeBSD$ -This distribution contains Sun Microsystem's implementation of the -RPC and XDR protocols and is compatible with 4.2BSD and 4.3BSD. Also -included is complete documentation, utilities, RPC service -specification files, and demonstration services in the format used by -the RPC protocol compiler (rpcgen). See WHAT'S NEW below for -details. +PLEASE READ THE DISCLAIMER FILE. DO NOT CALL THE SUN MICROSYSTEMS SUPPORT +LINE WITH QUESTIONS ON THIS RELEASE. THEY CANNOT ANSWER QUESTIONS ABOUT THIS +UNSUPPORTED SOURCE RELEASE. -NOTE ABOUT SECURE RPC: +TIRPCSRC 2.3 29 Aug 1994 -This release of RPCSRC contains most of the code needed to implement -Secure RPC (see "DES Authentication" in the RPC Protocol Specification, -doc/rpc.rfc.ms). Due to legal considerations, we are unable to -distribute an implementation of DES, the Data Encryption Standard, which -Secure RPC requires. For this reason, all of the files, documentation, and -programs associated with Secure RPC have been placed into a separate -directory, secure_rpc. The RPC library contained in the main body of this -release *DOES NOT* support Secure RPC. See secure_rpc/README for more -details. (A DES library was posted in Volume 18 of comp.sources.unix.) +This distribution contains SunSoft's implementation of transport-independent +RPC (TI-RPC), External Data Representation (XDR), and various utilities and +documentation. These libraries and programs form the base of Open Network +Computing (ONC), and are derived directly from the Solaris 2.3 source. -If you wish to report bugs found in this release, send mail to: +Previous releases of RPC Source based on SunOS 4.x were ported to 4.2BSD and +used Sockets as the transport interface. These versions were +transport-specific RPC (TS-RPC). -Portable ONC/NFS -Sun Microsystems, Inc -MS 12-33 -2550 Garcia Avenue -Mountain View, CA 94043 +TI-RPC is an enhanced version of TS-RPC that requires the UNIX System V +Transport Layer Interface (TLI) or an equivalent X/Open Transport Interface +(XTI). TI-RPC is on-the-wire compatible with the TS-RPC, which is supported +by almost 70 vendors on all major operating systems. TS-RPC source code +(RPCSRC 4.0) remains available from several internet sites. -or send Email to nfsnet@sun.com (the Internet) or sun!nfsnet (Usenet). +This release is a native source release, that is, it is compatible for +building on Solaris 2.3. This release was built on Solaris 2.3 using SunPro +SPARCompiler 2.0.1. -ROADMAP +Solaris 2.3 is based on System V, Release 4 (SVR4), and while this release +should be mostly compatible with other SVR4 systems, some Solaris facilities +that are assumed may not be available. In particular, this release uses the +Makefile format supported by SparcCompiler 2.0.1. Second, the Secure RPC +routines use the Solaris Name Service Switch to access public-key credential +databases. This code will need to be ported if your system does not support +the Name Service Switch. Finally, this release uses the synchronization +interfaces of UI Threads to make certain interfaces thread-safe. These +interfaces are found in libthread in Solaris 2.3 and later. -The directory hierarchy is as follows: +Applications linked with this release's librpc must link with the United +States domestic version of libcrypt in order to resolve the cbc_crypt() and +ecb_crypt() functions. These routines are used with Secure RPC however all +RPC programs that link with this release's librpc will need to link with the +domestic libcrypt. Note that the Solaris 2.3 Encryption Kit is only available +within the United States. (PLEASE NOTE: The RPC implementation found in +Solaris 2.3's libnsl does *not* have this requirement; linking with libcrypt +is only a requirement for the TIRPCSRC 2.3 version of librpc.) - demo/ Various demonstration services - demo/dir Remote directory lister - demo/msg Remote console message delivery service - demo/sort Remote sort service - doc/ Documentation for RPC, XDR and NFS in "-ms" format. +DOCUMENTATION NOTE - etc/ Utilities (rpcinfo and portmap). portmap must be - started by root before any other RPC network services are - used. SEE BELOW FOR BUGFIX TO 4.3BSD COMPILER. +The documentation found in the doc directory are derived from the Solaris 2.3 +Network Interfaces Programming Guide. A small number of compile examples are +given, and these use libnsl to link in the RPC library. This release builds +the RPC library as librpc. To use this release's librpc, use the link command +"-lrpc -lnsl -lcrypt". This links the application with TIRPCSRC 2.3's librpc +for RPC routines, Solaris's libnsl for other networking functions, and +libcrypt for the cbc_crypt() and ecb_crypt functions. - man/ Manual pages for RPC library, rpcgen, and utilities. - rpc/ The RPC and XDR library. SEE BELOW - FOR BUGFIX TO 4.2BSD COMPILER. +WHY IS THIS RELEASE BEING DONE? - rpcgen/ The RPC Language compiler (for .x files) +This release is being distributed to make the Sun implementation of the ONC +technologies available for reference and porting to non-Solaris platforms. +The current release is a native source distribution, and provides services +that are already available on Solaris 2.3 (such as the RPC headers, the RPC +library in libnsl, rpcbind, rpcinfo, etc.). It is not our intention to +replace these services. See the DISCLAIMER for further information about the +legal status of this release. - rpcsvc/ Service definition files for various services and the - server and client code for the Remote Status service. - secure_rpc/ The files in this directory are used to build a version of - the RPC library with DES Authentication. See the README - file in that directory for more details. +WHAT'S NEW IN THIS RELEASE: TIRPCSRC 2.3 -BUILD INSTRUCTIONS +The previous release was TIRPCSRC 2.0. -Makefiles can be found in all directories except for man. The -Makefile in the top directory will cause these others to be invoked -(except for in the doc, man and demo directories), in turn building the -entire release. +1. This release is based on Solaris 2.3. The previous release was + based on Solaris 2.0. This release contains a siginificant number of + bug fixes and other enhancements over TIRPCSRC 2.0. -WARNING! THE DEFAULT INSTALLATION PROCEDURES WILL INSTALL FILES -IN /usr/include, /usr/lib, /usr/bin and /etc. +2. The RPC library is thread safe for all client-side interfaces + (clnt_create, clnt_call, etc.). The server-side interfaces + (svc_create, svc_run, etc.) are not thread safe in this release. The + server-side interfaces will be made thread safe in the next release of + TIRPCSRC. Please see the manual pages for details about which + interfaces are thread safe. -The master RPC include file, rpc/rpc.h, is used by all programs and -routines that use RPC. It includes other RPC and system include files -needed by the RPC system. PLEASE NOTE: If your system has NFS, it -may have been based on Sun's NFS Source. The include files installed -by this package may duplicate include files you will find on your NFS -system. The RPCSRC 4.0 include files are upwardly compatible to all -NFS Source include files as of the date of this distribution (not -including any new definitions or declarations added by your system -vendor). HOWEVER: Please read the comments towards the end of -rpc/rpc.h regarding rpc/netdb.h. You may need to uncomment the -inclusion of that file if the structures it defines are already -defined by your system's include files. +3. As part of the work to make the RPC library thread-safe, rpcgen has + been enhanced to generate thread-safe RPC stubs (the -M option). Note + that this modifies the call-signature for the stub functions; the + procedure calling the RPC stub must now pass to the stub a pointer to + an allocated structure where results will be placed by the stub. See + the rpcgen manual page and the rpcgen Programming Guide for details. -After making any compiler fixes that are needed (see below), at -the top directory, type: +4. The Remote Asynchronous Calls (RAC) library is now included. RAC was + first introduced in TIRPCSRC 1.0, and was bundled with librpc. It is + now a separate library. The asynchronous call model that RAC provides + can be achieved by using threads for making client-side RPC calls. + The ONC Technology group recommends using threads (where possible) to + achieve asynchrony rather than RAC. See the rpc_rac(3n) manual page + for details. - make install -For all installations, the Makefile macro DESTDIR is prepended to the -installation path. It is defined to be null in the Makefiles, so -installations are relative to root. (You will probably need root -privileges for installing the files under the default path.) To -install the files under some other tree (e.g., /usr/local), use the -command: +ROADMAP - make install DESTDIR=/usr/local +The directory hierarchy is as follows: -This will place the include files in /usr/local/usr/include, the RPC -library in /usr/local/usr/lib, rpcgen in /usr/local/usr/bin, and the -utilities in /usr/local/etc. You'll have to edit the Makefiles or -install the files by hand if you want to do anything other than this -kind of relocation of the installation tree. + cmd/ Utilities + cmd/rpcgen The RPC Language compiler (for .x files) + cmd/rpcbind The RPC bindery and portmapper + cmd/rpcinfo RPC bindery query utility + cmd/keyserv The Secure RPC keyserver + cmd/demo Some simple ONC demo services -The RPC library will be built and installed first. By default it is -installed in /usr/lib as "librpclib.a". The directory -/usr/include/rpc will also be created, and several header files will -be installed there. ALL RPC SERVICES INCLUDE THESE HEADER FILES. + doc/ Postscript versions of ONC documentation -The programs in etc/ link in routines from librpclib.a. If you change -where it is installed, be sure to edit etc/'s Makefile to reflect this. -These programs are installed in /etc. PORTMAP MUST BE RUNNING ON -YOUR SYSTEM BEFORE YOU START ANY OTHER RPC SERVICE. + head/ Header files + head/rpcsvc RPCL (.x) specifications for various ONC services, and + header files. -rpcgen is installed in /usr/bin. This program is required to build -the demonstration services in demo and the rstat client and server in -rpcsvc/. + lib/ Libraries + lib/librpc The RPC and XDR library + lib/librac The Remote Asynchronous Calls (RAC) library -The rpcsvc/ directory will install its files in the directory -/usr/include/rpcsvc. The Remote Status service (rstat_svc) will be -compiled and installed in /etc. If you wish to make this service -available, you should either start this service when needed or have -it started at boot time by invoking it in your /etc/rc.local script. -(Be sure that portmap is started first!) Sun has modified its -version of inetd to automatically start RPC services. (Use "make -LIB=" when building rstat on a Sun Workstation.) The Remote Status -client (rstat) will be installed in /usr/bin. This program queries -the rstat_svc on a remote host and prints a system status summary -similar to the one printed by "uptime". + man/ Manual pages for the RPC library and utilities. -The documentation is not built during the "make install" command. -Typing "make" in the doc directory will cause all of the manuals to -be formatted using nroff into a single file. We have had a report -that certain "troff" equivalents have trouble processing the full -manual. If you have trouble, try building the manuals individually -(see the Makefile). + uts/common/rpc RPC header files -The demonstration services in the demo directory are not built by the -top-level "make install" command. To build these, cd to the demo -directory and enter "make". The three services will be built. -RPCGEN MUST BE INSTALLED in a path that make can find. To run the -services, start the portmap program as root and invoke the service -(you probably will want to put it in the background). rpcinfo can be -used to check that the service succeeded in getting registered with -portmap, and to ping the service (see rpcinfo's man page). You can -then use the corresponding client program to exercise the service. -To build these services on a Sun workstation, you must prevent the -Makefile from trying to link the RPC library (as these routines are -already a part of Sun's libc). Use: "make LIB=". - -BUGFIX FOR 4.3BSD COMPILER -The use of a 'void *' declaration for one of the arguments in -the reply_proc() procedure in etc/rpcinfo.c will trigger a bug -in the 4.3BSD compiler. The bug is fixed by the following change to -the compiler file mip/manifest.h: -*** manifest.h.r1.1 Thu Apr 30 13:52:25 1987 ---- manifest.h.r1.2 Mon Nov 23 18:58:17 1987 -*************** -*** 21,27 **** - /* - * Bogus type values - */ -! #define TNULL PTR /* pointer to UNDEF */ - #define TVOID FTN /* function returning UNDEF (for void) */ - - /* ---- 21,27 ---- - /* - * Bogus type values - */ -! #define TNULL INCREF(MOETY) /* pointer to MOETY -- impossible type */ - #define TVOID FTN /* function returning UNDEF (for void) */ - - /* +BUILD INSTRUCTIONS -If you cannot fix your compiler, change the declaration in reply_proc() -from 'void *' to 'char *'. +Prior to building the release, you must define the SRC environment variable +to be the path to the top-level Makefile. For example, if /usr/src/tirpcsrc +is where to top-level Makefile is located, execute this command prior to +building the release: -BUGFIX FOR 4.2BSD COMPILER + setenv SRC /usr/src/tirpcsrc (csh) +or + SRC=/usr/src/tirpcsrc; export SRC (sh) -Unpatched 4.2BSD compilers complain about valid C. You can make old -compilers happy by changing some voids to ints. However, the fix to -the 4.2 VAX compiler is as follows (to mip/trees.c): +The sources in the lib directory depend on header files installed from head +and uts/common/rpc, and the programs in the cmd directory depend on libraries +from lib. Therefore, you should do a "make install" to build the release. -*** trees.c.r1.1 Mon May 11 13:47:58 1987 ---- trees.c.r1.2 Wed Jul 2 18:28:52 1986 -*************** -*** 1247,1253 **** - if(o==CAST && mt1==0)return(TYPL+TYMATCH); - if( mt12 & MDBI ) return( TYPL+LVAL+TYMATCH ); - else if( (mt1&MENU)||(mt2&MENU) ) return( LVAL+NCVT+TYPL+PTMATCH+PUN ); -! else if( mt12 == 0 ) break; - else if( mt1 & MPTR ) return( LVAL+PTMATCH+PUN ); - else if( mt12 & MPTI ) return( TYPL+LVAL+TYMATCH+PUN ); - break; ---- 1261,1269 ---- - if(o==CAST && mt1==0)return(TYPL+TYMATCH); - if( mt12 & MDBI ) return( TYPL+LVAL+TYMATCH ); - else if( (mt1&MENU)||(mt2&MENU) ) return( LVAL+NCVT+TYPL+PTMATCH+PUN ); -! /* if right is TVOID and looks like a CALL, is not ok */ -! else if (mt2 == 0 && (p->in.right->in.op == CALL || p->in.right->in.op == UNARY CALL)) -! break; - else if( mt1 & MPTR ) return( LVAL+PTMATCH+PUN ); - else if( mt12 & MPTI ) return( TYPL+LVAL+TYMATCH+PUN ); - break; +The top-level Makefile builds the release. The "ROOT" macro defines where the +headers and libraries are installed. The default for ROOT is "/proto". You +may change this by either modifiying Makefile.master, or issuing the build +command with a new definition for ROOT: -WHAT'S NEW IN THIS RELEASE: RPCSRC 4.0 + make install ROOT=/opt/onc -The previous release was RPCSRC 3.9. As with all previous releases, -this release is based directly on files from Sun Microsystem's -implementation. +You will of course need write privileges for the destination directory. +The headers, libraries and executables will be built and installed under the +ROOT. -Upgrade from RPCSRC 3.9 -1) RPCSRC 4.0 upgrades RPCSRC 3.9. Improvements from SunOS 4.0 have - been integrated into this release. +The demonstration services in the demo directory are not built by the +top-level "make install" command. To build these, cd to the cmd/demo +directory and enter "make". The four services will be built. +RPCGEN MUST BE INSTALLED in a path that make can find. To run the +services, rpcbind must be running, then invoke the service +(you probably will want to put it in the background). rpcinfo can be +used to check that the service succeeded in getting registered with +rpcbind, and to ping the service (see rpcinfo's man page). You can +then use the corresponding client program to exercise the service. -Secure RPC (in the secure_rpc/ directory) -2) DES Authentication routines and programs are provided. -3) A new manual, "Secure NFS" is provided, which describes Secure RPC - and Secure NFS. -4) Skeleton routines and manual pages are provided which describe the - DES encryption procedures required by Secure RPC. HOWEVER, NO DES - ROUTINE IS PROVIDED. +BUILDING ONC APPLICATIONS -New Functionality +See the Makefiles in the demonstration services for examples of building +ONC applications with this release. The $(ROOT)/usr/include directory +must be included in the compiler header file search path (-I), and the +$(ROOT)/usr/lib directory must be included in the linker library file search +path (-L). Also, to run executables built dynamically, the shared library +search path (LD_LIBRARY_PATH) must also include $(ROOT)/usr/lib. In addition +to linking in this release's librpc (via -lrpc), you must also link with +Solaris's libnsl (-lnsl) and the US domestic version of libcrypt (-lcrypt). -5) rpcinfo can now be used to de-register services from the portmapper - which may have terminated abnormally. -6) A new client, rstat, is provided which queries the rstat_svc and - prints a status line similar to the one displayed by "uptime". diff --git a/lib/libc/rpc/auth_des.c b/lib/libc/rpc/auth_des.c index 51cfb1f62bb3..e154cd2fe315 100644 --- a/lib/libc/rpc/auth_des.c +++ b/lib/libc/rpc/auth_des.c @@ -1,3 +1,4 @@ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -32,59 +33,58 @@ /* * auth_des.c, client-side implementation of DES authentication */ +#include "reentrant.h" +#include "namespace.h" +#include <err.h> +#include <errno.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <sys/cdefs.h> #include <rpc/des_crypt.h> +#include <syslog.h> #include <rpc/types.h> -#include <rpc/xdr.h> #include <rpc/auth.h> #include <rpc/auth_des.h> +#include <rpc/clnt.h> +#include <rpc/xdr.h> #include <netinet/in.h> /* XXX: just to get htonl() and ntohl() */ #include <sys/socket.h> #undef NIS #include <rpcsvc/nis.h> +#include "un-namespace.h" #if defined(LIBC_SCCS) && !defined(lint) /* from: static char sccsid[] = "@(#)auth_des.c 2.2 88/07/29 4.0 RPCSRC; from 1.9 88/02/08 SMI"; */ static const char rcsid[] = "$FreeBSD$"; #endif -extern bool_t __rpc_get_time_offset __P(( struct timeval *, nis_server *, - char *, char **, struct sockaddr_in * )); -extern int rtime __P(( struct sockaddr_in *, struct timeval *, struct timeval *)); -extern bool_t xdr_authdes_cred __P(( XDR *, struct authdes_cred * )); -extern bool_t xdr_authdes_verf __P(( XDR *, struct authdes_verf * )); - -#define MILLION 1000000L -#define RTIME_TIMEOUT 5 /* seconds to wait for sync */ +#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) -#define debug(msg) /*printf("%s\n", msg) */ +extern bool_t xdr_authdes_cred( XDR *, struct authdes_cred *); +extern bool_t xdr_authdes_verf( XDR *, struct authdes_verf *); +extern int key_encryptsession_pk(); + +extern bool_t __rpc_get_time_offset(struct timeval *, nis_server *, char *, + char **, char **); /* * DES authenticator operations vector */ -static void authdes_nextverf(); -static bool_t authdes_marshal(); -static bool_t authdes_validate(); -static bool_t authdes_refresh(); -static void authdes_destroy(); -static struct auth_ops authdes_ops = { - authdes_nextverf, - authdes_marshal, - authdes_validate, - authdes_refresh, - authdes_destroy -}; -#ifdef foo -static bool_t synchronize __P(( struct sockaddr *, struct timeval *)); -#endif +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 *" */ @@ -95,10 +95,10 @@ struct ad_private { u_int ad_servernamelen; /* length of name, rounded up */ u_int ad_window; /* client specified window */ bool_t ad_dosync; /* synchronize? */ - struct sockaddr ad_syncaddr; /* remote host to synch with */ + 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_long ad_nickname; /* server's nickname for client */ + 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 */ @@ -108,106 +108,50 @@ struct ad_private { 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 *); + /* - * Create the client des authentication object - */ + * 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_create(servername, window, syncaddr, ckey) - char *servername; /* network name of server */ - u_int window; /* time to live */ - struct sockaddr *syncaddr; /* optional addr of host to sync with */ - des_block *ckey; /* optional conversation key to use*/ +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; - AUTH *auth; - struct ad_private *ad; - char namebuf[MAXNETNAMELEN+1]; - u_char pkey_data[1024]; - - if (!getpublickey(servername, pkey_data)) - return(NULL); - - /* - * Allocate everything now - */ - auth = ALLOC(AUTH); - ad = ALLOC(struct ad_private); - (void) getnetname(namebuf); - - ad->ad_fullnamelen = RNDUP(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 (auth == NULL || ad == NULL || ad->ad_fullname == NULL || - ad->ad_servername == NULL) { - debug("authdes_create: out of memory"); - goto failed; - } - - /* - * Set up private data - */ - bcopy(namebuf, ad->ad_fullname, ad->ad_fullnamelen + 1); - bcopy(servername, ad->ad_servername, ad->ad_servernamelen + 1); - bcopy(pkey_data, ad->ad_pkey, strlen(pkey_data) + 1); - if (syncaddr != NULL) { - ad->ad_syncaddr = *syncaddr; - ad->ad_dosync = TRUE; - } else { - ad->ad_dosync = FALSE; - } - ad->ad_window = window; - if (ckey == NULL) { - if (key_gendes(&auth->ah_key) < 0) { - debug("authdes_create: unable to gen conversation key"); - return (NULL); - } - } else { - auth->ah_key = *ckey; + if (! getpublickey(servername, (char *) pkey_data)) { + syslog(LOG_ERR, + "authdes_seccreate: no public key found for %s", + servername); + return (NULL); } - /* - * 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)) { - goto failed; - } - return (auth); - -failed: - if (auth != NULL) - FREE(auth, sizeof(AUTH)); - if (ad != NULL) - FREE(ad, sizeof(struct ad_private)); - if (ad->ad_fullname != NULL) - FREE(ad->ad_fullname, ad->ad_fullnamelen + 1); - if (ad->ad_servername != NULL) - FREE(ad->ad_servername, ad->ad_servernamelen + 1); - 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 authdes_create which takes the public key + * 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_create(servername, pkey, window, timehost, ckey, srvr) - char *servername; /* network name of server */ - netobj *pkey; /* public key of server */ - u_int window; /* time to live */ - char *timehost; /* optional hostname to sync with */ - des_block *ckey; /* optional conversation key to use */ - nis_server *srvr; /* optional NIS+ server struct */ +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; @@ -218,12 +162,12 @@ authdes_pk_create(servername, pkey, window, timehost, ckey, srvr) */ auth = ALLOC(AUTH); if (auth == NULL) { - debug("authdes_pk_create: out of memory"); + syslog(LOG_ERR, "authdes_pk_seccreate: out of memory"); return (NULL); } ad = ALLOC(struct ad_private); if (ad == NULL) { - debug("authdes_pk_create: out of memory"); + syslog(LOG_ERR, "authdes_pk_seccreate: out of memory"); goto failed; } ad->ad_fullname = ad->ad_servername = NULL; /* Sanity reasons */ @@ -242,13 +186,13 @@ authdes_pk_create(servername, pkey, window, timehost, ckey, srvr) ad->ad_servername = (char *)mem_alloc(ad->ad_servernamelen + 1); if (ad->ad_fullname == NULL || ad->ad_servername == NULL) { - debug("authdes_pk_create: out of memory"); + 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) { - debug("authdes_pk_create: out of memory"); + syslog(LOG_ERR, "authdes_seccreate: out of memory"); goto failed; } memcpy(ad->ad_timehost, timehost, strlen(timehost) + 1); @@ -264,7 +208,8 @@ authdes_pk_create(servername, pkey, window, timehost, ckey, srvr) ad->ad_window = window; if (ckey == NULL) { if (key_gendes(&auth->ah_key) < 0) { - debug("authdes_pk_create: unable to gen conversation key"); + syslog(LOG_ERR, + "authdes_seccreate: keyserv(1m) is unable to generate session key"); goto failed; } } else { @@ -276,10 +221,10 @@ authdes_pk_create(servername, pkey, window, timehost, ckey, srvr) */ auth->ah_cred.oa_flavor = AUTH_DES; auth->ah_verf.oa_flavor = AUTH_DES; - auth->ah_ops = &authdes_ops; + auth->ah_ops = authdes_ops(); auth->ah_private = (caddr_t)ad; - if (!authdes_refresh(auth)) { + if (!authdes_refresh(auth, NULL)) { goto failed; } ad->ad_nis_srvr = NULL; /* not needed any longer */ @@ -296,13 +241,14 @@ failed: if (ad->ad_timehost) FREE(ad->ad_timehost, strlen(ad->ad_timehost) + 1); if (ad->ad_netid) - free(ad->ad_netid); + FREE(ad->ad_netid, strlen(ad->ad_netid) + 1); if (ad->ad_uaddr) - free(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 */ @@ -313,30 +259,27 @@ failed: */ /*ARGSUSED*/ static void -authdes_nextverf(auth) - AUTH *auth; +authdes_nextverf(AUTH *auth) { /* what the heck am I supposed to do??? */ } - /* * 2. Marshal */ static bool_t -authdes_marshal(auth, xdrs) - AUTH *auth; - XDR *xdrs; +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; - long len; - int32_t *ixdr; + int len; + register rpc_inline_t *ixdr; /* * Figure out the "time", accounting for any time difference @@ -345,30 +288,32 @@ authdes_marshal(auth, xdrs) (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; - if (ad->ad_timestamp.tv_usec >= MILLION) { - ad->ad_timestamp.tv_usec -= MILLION; - ad->ad_timestamp.tv_sec += 1; + 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 = (int32_t *)cryptbuf; - IXDR_PUT_LONG(ixdr, ad->ad_timestamp.tv_sec); - IXDR_PUT_LONG(ixdr, ad->ad_timestamp.tv_usec); + 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_LONG(ixdr, ad->ad_window); - IXDR_PUT_U_LONG(ixdr, ad->ad_window - 1); + 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, - 2*sizeof(des_block), DES_ENCRYPT | DES_HW, (char *)&ivec); + (u_int) 2 * sizeof (des_block), + DES_ENCRYPT | DES_HW, (char *)&ivec); } else { status = ecb_crypt((char *)&auth->ah_key, (char *)cryptbuf, - sizeof(des_block), DES_ENCRYPT | DES_HW); + (u_int) sizeof (des_block), + DES_ENCRYPT | DES_HW); } if (DES_FAILED(status)) { - debug("authdes_marshal: DES encryption failure"); + syslog(LOG_ERR, "authdes_marshal: DES encryption failure"); return (FALSE); } ad->ad_verf.adv_xtimestamp = cryptbuf[0]; @@ -391,21 +336,21 @@ authdes_marshal(auth, xdrs) } if ((ixdr = xdr_inline(xdrs, 2*BYTES_PER_XDR_UNIT))) { - IXDR_PUT_LONG(ixdr, AUTH_DES); - IXDR_PUT_LONG(ixdr, len); + IXDR_PUT_INT32(ixdr, AUTH_DES); + IXDR_PUT_INT32(ixdr, len); } else { - ATTEMPT(xdr_putlong(xdrs, (long *)&auth->ah_cred.oa_flavor)); - ATTEMPT(xdr_putlong(xdrs, &len)); + 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_LONG(ixdr, AUTH_DES); - IXDR_PUT_LONG(ixdr, len); + IXDR_PUT_INT32(ixdr, AUTH_DES); + IXDR_PUT_INT32(ixdr, len); } else { - ATTEMPT(xdr_putlong(xdrs, (long *)&auth->ah_verf.oa_flavor)); - ATTEMPT(xdr_putlong(xdrs, &len)); + ATTEMPT(xdr_putint32(xdrs, (int *)&auth->ah_verf.oa_flavor)); + ATTEMPT(xdr_putint32(xdrs, &len)); } ATTEMPT(xdr_authdes_verf(xdrs, verf)); return (TRUE); @@ -416,89 +361,92 @@ authdes_marshal(auth, xdrs) * 3. Validate */ static bool_t -authdes_validate(auth, rverf) - AUTH *auth; - struct opaque_auth *rverf; +authdes_validate(AUTH *auth, struct opaque_auth *rverf) { +/* LINTED pointer alignment */ struct ad_private *ad = AUTH_PRIVATE(auth); struct authdes_verf verf; int status; - register u_long *ixdr; + register uint32_t *ixdr; + des_block buf; if (rverf->oa_length != (2 + 1) * BYTES_PER_XDR_UNIT) { return (FALSE); } - ixdr = (u_long *)rverf->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++; /* nickname not XDR'd ! */ +/* 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 *)&verf.adv_xtimestamp, - sizeof(des_block), DES_DECRYPT | DES_HW); + status = ecb_crypt((char *)&auth->ah_key, (char *)&buf, + (u_int)sizeof (des_block), DES_DECRYPT | DES_HW); if (DES_FAILED(status)) { - debug("authdes_validate: DES decryption failure"); + syslog(LOG_ERR, "authdes_validate: DES decryption failure"); return (FALSE); } /* - * xdr the decrypted timestamp + * xdr the decrypted timestamp */ - ixdr = (u_long *)verf.adv_xtimestamp.c; - verf.adv_timestamp.tv_sec = IXDR_GET_LONG(ixdr) + 1; - verf.adv_timestamp.tv_usec = IXDR_GET_LONG(ixdr); +/* LINTED pointer alignment */ + ixdr = (uint32_t *)buf.c; + verf.adv_timestamp.tv_sec = IXDR_GET_INT32(ixdr) + 1; + verf.adv_timestamp.tv_usec = IXDR_GET_INT32(ixdr); /* * validate */ if (bcmp((char *)&ad->ad_timestamp, (char *)&verf.adv_timestamp, sizeof(struct timeval)) != 0) { - debug("authdes_validate: verifier mismatch\n"); + syslog(LOG_DEBUG, "authdes_validate: verifier mismatch"); return (FALSE); } /* * We have a nickname now, let's use it */ - ad->ad_nickname = verf.adv_nickname; - ad->ad_cred.adc_namekind = ADN_NICKNAME; - return (TRUE); + 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 *auth; +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 && -#ifdef old - !synchronize(&ad->ad_syncaddr, &ad->ad_timediff)) { -#else - !__rpc_get_time_offset(&ad->ad_timediff,ad->ad_nis_srvr, - ad->ad_timehost, &(ad->ad_uaddr), - (struct sockaddr_in *)&(ad->ad_syncaddr))) { -#endif - /* - * Hope the clocks are synced! - */ - ad->ad_timediff.tv_sec = ad->ad_timediff.tv_usec = 0; - ad->ad_dosync = 0; - debug("authdes_refresh: unable to synchronize with server"); + 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; + syslog(LOG_DEBUG, + "authdes_refresh: unable to synchronize clock"); + } } ad->ad_xkey = auth->ah_key; pkey.n_bytes = (char *)(ad->ad_pkey); - pkey.n_len = strlen((char *)ad->ad_pkey) + 1; + pkey.n_len = (u_int)strlen((char *)ad->ad_pkey) + 1; if (key_encryptsession_pk(ad->ad_servername, &pkey, &ad->ad_xkey) < 0) { - debug("authdes_create: unable to encrypt conversation key"); + syslog(LOG_INFO, + "authdes_refresh: keyserv(1m) is unable to encrypt session key"); return (FALSE); } cred->adc_fullname.key = ad->ad_xkey; @@ -512,43 +460,39 @@ authdes_refresh(auth) * 5. Destroy */ static void -authdes_destroy(auth) - AUTH *auth; +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); - FREE(ad, sizeof(struct ad_private)); + 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)); } - -#ifdef old -/* - * Synchronize with the server at the given address, that is, - * adjust timep to reflect the delta between our clocks - */ -static bool_t -synchronize(syncaddr, timep) - struct sockaddr *syncaddr; - struct timeval *timep; +static struct auth_ops * +authdes_ops(void) { - struct timeval mytime; - struct timeval timeout; + static struct auth_ops ops; + extern mutex_t authdes_ops_lock; - timeout.tv_sec = RTIME_TIMEOUT; - timeout.tv_usec = 0; - if (rtime((struct sockaddr_in *)syncaddr, timep, NULL /*&timeout*/) < 0) { - return (FALSE); - } - (void) gettimeofday(&mytime, (struct timezone *)NULL); - timep->tv_sec -= mytime.tv_sec; - if (mytime.tv_usec > timep->tv_usec) { - timep->tv_sec -= 1; - timep->tv_usec += MILLION; - } - timep->tv_usec -= mytime.tv_usec; - return (TRUE); + /* VARIABLES PROTECTED BY ops_lock: ops */ + + mutex_lock(&authdes_ops_lock); + if (ops.ah_nextverf == NULL) { + ops.ah_nextverf = authdes_nextverf; + ops.ah_marshal = authdes_marshal; + ops.ah_validate = authdes_validate; + ops.ah_refresh = authdes_refresh; + ops.ah_destroy = authdes_destroy; + } + mutex_unlock(&authdes_ops_lock); + return (&ops); } -#endif diff --git a/lib/libc/rpc/auth_none.c b/lib/libc/rpc/auth_none.c index 9649df3ab51b..403e00d571f4 100644 --- a/lib/libc/rpc/auth_none.c +++ b/lib/libc/rpc/auth_none.c @@ -1,3 +1,5 @@ +/* $NetBSD: auth_none.c,v 1.13 2000/01/22 22:19:17 mycroft Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -27,10 +29,11 @@ * Mountain View, California 94043 */ +#include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) -/*static char *sccsid = "from: @(#)auth_none.c 1.19 87/08/11 Copyr 1984 Sun Micro";*/ -/*static char *sccsid = "from: @(#)auth_none.c 2.1 88/07/29 4.0 RPCSRC";*/ static char *rcsid = "$FreeBSD$"; +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 /* @@ -41,96 +44,135 @@ static char *rcsid = "$FreeBSD$"; * Copyright (C) 1984, Sun Microsystems, Inc. */ +#include "reentrant.h" +#include "namespace.h" +#include <assert.h> #include <stdlib.h> #include <rpc/types.h> #include <rpc/xdr.h> #include <rpc/auth.h> -#define MAX_MARSHEL_SIZE 20 +#include "un-namespace.h" + +#define MAX_MARSHAL_SIZE 20 /* * Authenticator operations routines */ -static void authnone_verf(); -static void authnone_destroy(); -static bool_t authnone_marshal(); -static bool_t authnone_validate(); -static bool_t authnone_refresh(); -static struct auth_ops ops = { - authnone_verf, - authnone_marshal, - authnone_validate, - authnone_refresh, - authnone_destroy -}; +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_MARSHEL_SIZE]; + char marshalled_client[MAX_MARSHAL_SIZE]; u_int mcnt; } *authnone_private; AUTH * authnone_create() { - register struct authnone_private *ap = authnone_private; + struct authnone_private *ap = authnone_private; XDR xdr_stream; - register XDR *xdrs; + 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) + 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 = &ops; + ap->no_client.ah_ops = authnone_ops(); xdrs = &xdr_stream; - xdrmem_create(xdrs, ap->marshalled_client, (u_int)MAX_MARSHEL_SIZE, - XDR_ENCODE); + 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(client, xdrs) - AUTH *client; - XDR *xdrs; +authnone_marshal(AUTH *client, XDR *xdrs) { - register struct authnone_private *ap = authnone_private; + struct authnone_private *ap; + bool_t dummy; + extern mutex_t authnone_lock; - if (ap == 0) - return (0); - return ((*xdrs->x_ops->x_putbytes)(xdrs, - ap->marshalled_client, ap->mcnt)); + assert(xdrs != NULL); + + ap = authnone_private; + if (ap == NULL) { + mutex_unlock(&authnone_lock); + return (FALSE); + } + dummy = (*xdrs->x_ops->x_putbytes)(xdrs, + ap->marshalled_client, ap->mcnt); + mutex_unlock(&authnone_lock); + return (dummy); } +/* All these unused parameters are required to keep ANSI-C from grumbling */ +/*ARGSUSED*/ static void -authnone_verf() +authnone_verf(AUTH *client) { } +/*ARGSUSED*/ static bool_t -authnone_validate() +authnone_validate(AUTH *client, struct opaque_auth *opaque) { return (TRUE); } +/*ARGSUSED*/ static bool_t -authnone_refresh() +authnone_refresh(AUTH *client, void *dummy) { return (FALSE); } +/*ARGSUSED*/ static void -authnone_destroy() +authnone_destroy(AUTH *client) { } + +static struct auth_ops * +authnone_ops() +{ + static struct auth_ops ops; + extern mutex_t ops_lock; + +/* VARIABLES PROTECTED BY ops_lock: ops */ + + mutex_lock(&ops_lock); + if (ops.ah_nextverf == NULL) { + ops.ah_nextverf = authnone_verf; + ops.ah_marshal = authnone_marshal; + ops.ah_validate = authnone_validate; + ops.ah_refresh = authnone_refresh; + ops.ah_destroy = authnone_destroy; + } + mutex_unlock(&ops_lock); + return (&ops); +} diff --git a/lib/libc/rpc/auth_time.c b/lib/libc/rpc/auth_time.c index 114d59d4428c..f352c6d5eda9 100644 --- a/lib/libc/rpc/auth_time.c +++ b/lib/libc/rpc/auth_time.c @@ -45,20 +45,11 @@ #include <arpa/inet.h> #include <rpc/rpc.h> #include <rpc/rpc_com.h> +#include <rpc/rpcb_prot.h> #undef NIS #include <rpcsvc/nis.h> #include "un-namespace.h" -/* - * FreeBSD currently uses RPC 4.0, which uses portmap rather than - * rpcbind. Consequently, we need to fake up these values here. - * Luckily, the RPCB_GETTIME procedure uses only base XDR data types - * so we don't need anything besides these magic numbers. - */ -#define RPCBPROG (u_long)100000 -#define RPCBVERS (u_long)3 -#define RPCBPROC_GETTIME (u_long)6 - #ifdef TESTING #define msg(x) printf("ERROR: %s\n", x) /* #define msg(x) syslog(LOG_ERR, "%s", x) */ diff --git a/lib/libc/rpc/auth_unix.c b/lib/libc/rpc/auth_unix.c index dced8f2104b3..37d0ce9f0983 100644 --- a/lib/libc/rpc/auth_unix.c +++ b/lib/libc/rpc/auth_unix.c @@ -1,3 +1,5 @@ +/* $NetBSD: auth_unix.c,v 1.18 2000/07/06 03:03:30 christos Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -27,10 +29,11 @@ * Mountain View, California 94043 */ +#include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) -/*static char *sccsid = "from: @(#)auth_unix.c 1.19 87/08/11 Copyr 1984 Sun Micro";*/ -/*static char *sccsid = "from: @(#)auth_unix.c 2.2 88/08/01 4.0 RPCSRC";*/ static char *rcsid = "$FreeBSD$"; +static char *sccsid = "@(#)auth_unix.c 1.19 87/08/11 Copyr 1984 Sun Micro"; +static char *sccsid = "@(#)auth_unix.c 2.2 88/08/01 4.0 RPCSRC"; #endif /* @@ -45,33 +48,31 @@ static char *rcsid = "$FreeBSD$"; * */ +#include "reentrant.h" +#include "namespace.h" +#include <sys/param.h> + +#include <assert.h> +#include <err.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> -#include <sys/param.h> #include <rpc/types.h> #include <rpc/xdr.h> #include <rpc/auth.h> #include <rpc/auth_unix.h> +#include "un-namespace.h" -/* - * Unix authenticator operations vector - */ -static void authunix_nextverf(); -static bool_t authunix_marshal(); -static bool_t authunix_validate(); -static bool_t authunix_refresh(); -static void authunix_destroy(); - -static struct auth_ops auth_unix_ops = { - authunix_nextverf, - authunix_marshal, - authunix_validate, - authunix_refresh, - authunix_destroy -}; +/* 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. @@ -85,21 +86,6 @@ struct audata { }; #define AUTH_PRIVATE(auth) ((struct audata *)auth->ah_private) -static void marshal_new_auth(); - -/* - * This goop is here because some servers refuse to accept a - * credential with more than some number (usually 8) supplementary - * groups. Blargh! - */ -static int authunix_maxgrouplist = 0; - -void -set_rpc_maxgrouplist(int num) -{ - authunix_maxgrouplist = num; -} - /* * Create a unix style authenticator. * Returns an auth handle with the given stuff in it. @@ -109,60 +95,56 @@ authunix_create(machname, uid, gid, len, aup_gids) char *machname; int uid; int gid; - register int len; + int len; int *aup_gids; { struct authunix_parms aup; char mymem[MAX_AUTH_BYTES]; struct timeval now; XDR xdrs; - register AUTH *auth; - register struct audata *au; + AUTH *auth; + struct audata *au; /* * Allocate and set up auth handle */ - auth = (AUTH *)mem_alloc(sizeof(*auth)); + au = NULL; + auth = mem_alloc(sizeof(*auth)); #ifndef _KERNEL if (auth == NULL) { - (void)fprintf(stderr, "authunix_create: out of memory\n"); - return (NULL); + warnx("authunix_create: out of memory"); + goto cleanup_authunix_create; } #endif - au = (struct audata *)mem_alloc(sizeof(*au)); + au = mem_alloc(sizeof(*au)); #ifndef _KERNEL if (au == NULL) { - (void)fprintf(stderr, "authunix_create: out of memory\n"); - return (NULL); + warnx("authunix_create: out of memory"); + goto cleanup_authunix_create; } #endif - auth->ah_ops = &auth_unix_ops; + 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, (struct timezone *)0); + (void)gettimeofday(&now, NULL); aup.aup_time = now.tv_sec; aup.aup_machname = machname; aup.aup_uid = uid; aup.aup_gid = gid; - /* GW: continuation of max group list hack */ - if(authunix_maxgrouplist != 0) { - aup.aup_len = ((len < authunix_maxgrouplist) ? len - : authunix_maxgrouplist); - } else { - aup.aup_len = (u_int)len; - } + 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)) + if (! xdr_authunix_parms(&xdrs, &aup)) abort(); au->au_origcred.oa_length = len = XDR_GETPOS(&xdrs); au->au_origcred.oa_flavor = AUTH_UNIX; @@ -170,11 +152,11 @@ authunix_create(machname, uid, gid, len, aup_gids) au->au_origcred.oa_base = mem_alloc((u_int) len); #else if ((au->au_origcred.oa_base = mem_alloc((u_int) len)) == NULL) { - (void)fprintf(stderr, "authunix_create: out of memory\n"); - return (NULL); + warnx("authunix_create: out of memory"); + goto cleanup_authunix_create; } #endif - memcpy(au->au_origcred.oa_base, mymem, (u_int)len); + memmove(au->au_origcred.oa_base, mymem, (size_t)len); /* * set auth handle to reflect new cred. @@ -182,6 +164,17 @@ authunix_create(machname, uid, gid, len, aup_gids) 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 } /* @@ -191,32 +184,29 @@ authunix_create(machname, uid, gid, len, aup_gids) AUTH * authunix_create_default() { - register int len; - char machname[MAX_MACHINE_NAME + 1]; - register int uid; - register int gid; - int gids[NGRPS]; - int i; - gid_t real_gids[NGROUPS]; + int len; + char machname[MAXHOSTNAMELEN + 1]; + uid_t uid; + gid_t gid; + gid_t gids[NGRPS]; - if (gethostname(machname, MAX_MACHINE_NAME) == -1) + if (gethostname(machname, sizeof machname) == -1) abort(); - machname[MAX_MACHINE_NAME] = 0; - uid = (int)geteuid(); - gid = (int)getegid(); - if ((len = getgroups(NGROUPS, real_gids)) < 0) + machname[sizeof(machname) - 1] = 0; + uid = geteuid(); + gid = getegid(); + if ((len = getgroups(NGRPS, gids)) < 0) abort(); - if(len > NGRPS) len = NGRPS; /* GW: turn `gid_t's into `int's */ - for(i = 0; i < len; i++) { - gids[i] = (int)real_gids[i]; - } - return (authunix_create(machname, uid, gid, len, gids)); + /* XXX: interface problem; those should all have been unsigned */ + return (authunix_create(machname, (int)uid, (int)gid, len, + (int *)gids)); } /* * authunix operations */ +/* ARGSUSED */ static void authunix_nextverf(auth) AUTH *auth; @@ -229,22 +219,30 @@ authunix_marshal(auth, xdrs) AUTH *auth; XDR *xdrs; { - register struct audata *au = AUTH_PRIVATE(auth); + 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) - register AUTH *auth; - struct opaque_auth verf; + AUTH *auth; + struct opaque_auth *verf; { - register struct audata *au; + struct audata *au; XDR xdrs; - if (verf.oa_flavor == AUTH_SHORT) { + 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); + 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, @@ -265,14 +263,15 @@ authunix_validate(auth, verf) } static bool_t -authunix_refresh(auth) - register AUTH *auth; +authunix_refresh(AUTH *auth, void *dummy) { - register struct audata *au = AUTH_PRIVATE(auth); + struct audata *au = AUTH_PRIVATE(auth); struct authunix_parms aup; struct timeval now; XDR xdrs; - register int stat; + int stat; + + assert(auth != NULL); if (auth->ah_cred.oa_base == au->au_origcred.oa_base) { /* there is no hope. Punt */ @@ -282,7 +281,7 @@ authunix_refresh(auth) /* first deserialize the creds back into a struct authunix_parms */ aup.aup_machname = NULL; - aup.aup_gids = (int *)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); @@ -290,7 +289,7 @@ authunix_refresh(auth) goto done; /* update the time and serialize in place */ - (void)gettimeofday(&now, (struct timezone *)0); + (void)gettimeofday(&now, NULL); aup.aup_time = now.tv_sec; xdrs.x_op = XDR_ENCODE; XDR_SETPOS(&xdrs, 0); @@ -309,10 +308,13 @@ done: static void authunix_destroy(auth) - register AUTH *auth; + AUTH *auth; { - register struct audata *au = AUTH_PRIVATE(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) @@ -323,7 +325,7 @@ authunix_destroy(auth) if (auth->ah_verf.oa_base != NULL) mem_free(auth->ah_verf.oa_base, auth->ah_verf.oa_length); - mem_free((caddr_t)auth, sizeof(*auth)); + mem_free(auth, sizeof(*auth)); } /* @@ -332,18 +334,40 @@ authunix_destroy(auth) */ static void marshal_new_auth(auth) - register AUTH *auth; + AUTH *auth; { - XDR xdr_stream; - register XDR *xdrs = &xdr_stream; - register struct audata *au = AUTH_PRIVATE(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)))) { - perror("auth_none.c - Fatal marshalling problem"); - } else { + (! 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 struct auth_ops * +authunix_ops() +{ + static struct auth_ops ops; + extern mutex_t ops_lock; + + /* VARIABLES PROTECTED BY ops_lock: ops */ + + mutex_lock(&ops_lock); + if (ops.ah_nextverf == NULL) { + ops.ah_nextverf = authunix_nextverf; + ops.ah_marshal = authunix_marshal; + ops.ah_validate = authunix_validate; + ops.ah_refresh = authunix_refresh; + ops.ah_destroy = authunix_destroy; + } + mutex_unlock(&ops_lock); + return (&ops); +} diff --git a/lib/libc/rpc/authdes_prot.c b/lib/libc/rpc/authdes_prot.c index 14679c00a9cc..f60e79f9fa6b 100644 --- a/lib/libc/rpc/authdes_prot.c +++ b/lib/libc/rpc/authdes_prot.c @@ -1,6 +1,7 @@ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)authdes_prot.c 2.1 88/07/29 4.0 RPCSRC; from 1.6 88/02/08 SMI"; #endif +/* $FreeBSD$ */ /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -30,17 +31,19 @@ static char sccsid[] = "@(#)authdes_prot.c 2.1 88/07/29 4.0 RPCSRC; from 1.6 88 * Mountain View, California 94043 */ /* - * Copyright (c) 1988 by Sun Microsystems, Inc. + * Copyright (c) 1986-1991 by Sun Microsystems Inc. */ /* * authdes_prot.c, XDR routines for DES authentication */ +#include "namespace.h" #include <rpc/types.h> #include <rpc/xdr.h> #include <rpc/auth.h> #include <rpc/auth_des.h> +#include "un-namespace.h" #define ATTEMPT(xdr_op) if (!(xdr_op)) return (FALSE) @@ -55,12 +58,16 @@ xdr_authdes_cred(xdrs, cred) 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))); + 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))); + ATTEMPT(xdr_opaque(xdrs, (caddr_t)&cred->adc_nickname, + sizeof(cred->adc_nickname))); return (TRUE); default: return (FALSE); @@ -76,7 +83,9 @@ xdr_authdes_verf(xdrs, 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))); + 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/lib/libc/rpc/authunix_prot.c b/lib/libc/rpc/authunix_prot.c index 54f23fc9fefd..11bb74f8eb7f 100644 --- a/lib/libc/rpc/authunix_prot.c +++ b/lib/libc/rpc/authunix_prot.c @@ -1,3 +1,5 @@ +/* $NetBSD: authunix_prot.c,v 1.12 2000/01/22 22:19:17 mycroft Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -27,10 +29,11 @@ * Mountain View, California 94043 */ +#include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) -/*static char *sccsid = "from: @(#)authunix_prot.c 1.15 87/08/11 Copyr 1984 Sun Micro";*/ -/*static char *sccsid = "from: @(#)authunix_prot.c 2.1 88/07/29 4.0 RPCSRC";*/ static char *rcsid = "$FreeBSD$"; +static char *sccsid = "@(#)authunix_prot.c 1.15 87/08/11 Copyr 1984 Sun Micro"; +static char *sccsid = "@(#)authunix_prot.c 2.1 88/07/29 4.0 RPCSRC"; #endif /* @@ -40,29 +43,34 @@ static char *rcsid = "$FreeBSD$"; * Copyright (C) 1984, Sun Microsystems, Inc. */ +#include "namespace.h" +#include <assert.h> #include <rpc/types.h> #include <rpc/xdr.h> #include <rpc/auth.h> #include <rpc/auth_unix.h> +#include "un-namespace.h" /* * XDR for unix authentication parameters. */ bool_t xdr_authunix_parms(xdrs, p) - register XDR *xdrs; - register struct authunix_parms *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_int(xdrs, &(p->aup_uid)) && xdr_int(xdrs, &(p->aup_gid)) && xdr_array(xdrs, (caddr_t *)&(p->aup_gids), - &(p->aup_len), NGRPS, sizeof(int), xdr_int) ) { + &(p->aup_len), NGRPS, sizeof(int), (xdrproc_t)xdr_int) ) { return (TRUE); } return (FALSE); } - diff --git a/lib/libc/rpc/bindresvport.3 b/lib/libc/rpc/bindresvport.3 index b71339822dc4..bfb011e0316a 100644 --- a/lib/libc/rpc/bindresvport.3 +++ b/lib/libc/rpc/bindresvport.3 @@ -1,14 +1,18 @@ .\" @(#)bindresvport.3n 2.2 88/08/02 4.0 RPCSRC; from 1.7 88/03/14 SMI +.\" $NetBSD: bindresvport.3,v 1.8 2000/07/05 15:45:33 msaitoh Exp $ .\" $FreeBSD$ .\" -.Dd January 27, 2000 +.Dd November 22, 1987 .Dt BINDRESVPORT 3 .Os .Sh NAME .Nm bindresvport , .Nm bindresvport_sa .Nd bind a socket to a privileged IP port +.Sh LIBRARY +.Lb libc .Sh SYNOPSIS +.Fd #include <sys/types.h> .Fd #include <rpc/rpc.h> .Ft int .Fn bindresvport "int sd" "struct sockaddr_in *sin" @@ -23,25 +27,38 @@ are used to bind a socket descriptor to a privileged port, that is, a port number in the range 0-1023. .Pp -Only root can bind to a privileged port; this call will fail for any -other users. -.Pp -When -.Va sin -is not null, -.Va sin->sin_family +If +.Fa sin +is a pointer to a +.Ft "struct sockaddr_in" +then the appropriate fields in the structure should be defined. +Note that +.Fa sin->sin_family must be initialized to the address family of the socket, passed by -.Va sd . -If the value of sin->sin_port is non-zero -.Fn bindresvport -will attempt to use that specific port. If it fails, it chooses another -privileged port automatically. +.Fa sd . +If +.Fa sin->sin_port +is +.Sq 0 +then an anonymous port (in the range 600-1023) will be +chosen, and if +.Xr bind 2 +is successful, the +.Fa sin->sin_port +will be updated to contain the allocated port. .Pp -It is legal to pass null pointer to -.Va sin . -In this case, the caller cannot get the port number +If +.Fa sin +is the +.Dv NULL +pointer, +an anonymous port will be allocated (as above). +However, there is no way for .Fn bindresvport -has picked. +to return the allocated port in this case. +.Pp +Only root can bind to a privileged port; this call will fail for any +other users. .Pp Function prototype of .Fn bindresvport @@ -57,50 +74,24 @@ sockets as well as .Dv AF_INET sockets. .Sh RETURN VALUES -.Fn bindresvport -and -.Fn bindresvport_sa -return 0 if they are successful, otherwise \-1 is returned and -.Va errno -set to reflect the cause of the error. +.Rv -std bindresvport .Sh ERRORS -The -.Fn bindresvport -and -.Fn bindresvport_sa -functions fail if: .Bl -tag -width Er -.It Bq Er EBADF -.Fa sd -is not a valid descriptor. -.It Bq Er ENOTSOCK -.Fa sd -is not a socket. -.It Bq Er EADDRNOTAVAIL -The specified address is not available from the local machine. -.It Bq Er EADDRINUSE -The specified address is already in use. -.It Bq Er EINVAL -The socket is already bound to an address, -or the socket family and the family of specified address mismatch. -.It Bq Er EACCES -The requested address is protected, and the current user -has inadequate permission to access it. -.It Bq Er EFAULT -The -.Fa name -parameter is not in a valid part of the user -address space. -.It Bq Er ENOBUFS -Insufficient resources were available in the system -to perform the operation. .It Bq Er EPFNOSUPPORT -The protocol family has not been configured into the -system, no implementation for it exists, -or address family did not match between arguments. +If second argument was supplied, +and address family did not match between arguments. .El -.Sh "SEE ALSO" +.Pp +.Fn bindresvport +may also fail and set +.Va errno +for any of the errors specified for the calls +.Xr bind 2 , +.Xr getsockopt 2 , +or +.Xr setsockopt 2 . +.Sh SEE ALSO .Xr bind 2 , -.Xr socket 2 , -.Xr rresvport 3 , -.Xr rresvport_af 3 +.Xr getsockopt 2 , +.Xr setsockopt 2 , +.Xr ip 4 diff --git a/lib/libc/rpc/bindresvport.c b/lib/libc/rpc/bindresvport.c index 2aed9ddc48c8..43b2a4f3d8bc 100644 --- a/lib/libc/rpc/bindresvport.c +++ b/lib/libc/rpc/bindresvport.c @@ -1,3 +1,5 @@ +/* $NetBSD: bindresvport.c,v 1.19 2000/07/06 03:03:59 christos Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -27,6 +29,7 @@ * Mountain View, California 94043 */ +#include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)bindresvport.c 1.8 88/02/08 SMI";*/ /*static char *sccsid = "from: @(#)bindresvport.c 2.2 88/07/29 4.0 RPCSRC";*/ @@ -42,10 +45,16 @@ static char *rcsid = "$FreeBSD$"; #include "namespace.h" #include <sys/types.h> -#include <sys/errno.h> #include <sys/socket.h> + #include <netinet/in.h> + +#include <errno.h> +#include <string.h> #include <unistd.h> + +#include <rpc/rpc.h> + #include <string.h> #include "un-namespace.h" @@ -61,7 +70,7 @@ bindresvport(sd, sin) } /* - * Bind a socket to a privileged port for whatever protocol. + * Bind a socket to a privileged IP port */ int bindresvport_sa(sd, sa) @@ -71,10 +80,12 @@ bindresvport_sa(sd, 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 port; - int salen; + u_int16_t *portp; + socklen_t salen; if (sa == NULL) { salen = sizeof(myaddr); @@ -84,33 +95,38 @@ bindresvport_sa(sd, sa) return -1; /* errno is correctly set */ af = sa->sa_family; - memset(&myaddr, 0, salen); + memset(sa, 0, salen); } else af = sa->sa_family; - if (af == AF_INET) { + 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); - port = sin->sin_port; - } else if (af == AF_INET6) { + 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); - port = sin6->sin6_port; - } else { + portp = &sin6->sin6_port; + break; +#endif + default: errno = EPFNOSUPPORT; return (-1); } sa->sa_family = af; sa->sa_len = salen; - if (port == 0) { - int oldlen = sizeof(old); + if (*portp == 0) { + socklen_t oldlen = sizeof(old); error = _getsockopt(sd, proto, portrange, &old, &oldlen); if (error < 0) @@ -124,10 +140,10 @@ bindresvport_sa(sd, sa) error = _bind(sd, sa, salen); - if (port == 0) { + if (*portp == 0) { int saved_errno = errno; - if (error) { + if (error < 0) { if (_setsockopt(sd, proto, portrange, &old, sizeof(old)) < 0) errno = saved_errno; @@ -135,7 +151,7 @@ bindresvport_sa(sd, sa) } if (sa != (struct sockaddr *)&myaddr) { - /* Hmm, what did the kernel assign... */ + /* Hmm, what did the kernel assign? */ if (_getsockname(sd, sa, &salen) < 0) errno = saved_errno; return (error); diff --git a/lib/libc/rpc/clnt_bcast.c b/lib/libc/rpc/clnt_bcast.c new file mode 100644 index 000000000000..f6f8641142a7 --- /dev/null +++ b/lib/libc/rpc/clnt_bcast.c @@ -0,0 +1,667 @@ +/* $NetBSD: clnt_bcast.c,v 1.3 2000/07/06 03:05:20 christos Exp $ */ +/* $FreeBSD$ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ + +/* #ident "@(#)clnt_bcast.c 1.18 94/05/03 SMI" */ + +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)clnt_bcast.c 1.15 89/04/21 Copyr 1988 Sun Micro"; +#endif + + +/* + * 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 "namespace.h" +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/queue.h> +#include <net/if.h> +#include <netinet/in.h> +#include <ifaddrs.h> +#include <sys/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> +#ifdef RPC_DEBUG +#include <stdio.h> +#endif +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <netdb.h> +#include <err.h> +#include <string.h> +#include "un-namespace.h" + +#include "rpc_com.h" + +#define MAXBCAST 20 /* Max no of broadcasting transports */ +#define INITTIME 4000 /* Time to wait initially */ +#define WAITTIME 8000 /* Maximum time to wait */ + +/* + * 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. + */ + +struct broadif { + int index; + struct sockaddr_storage broadaddr; + TAILQ_ENTRY(broadif) link; +}; + +typedef TAILQ_HEAD(, broadif) broadlist_t; + +int __rpc_getbroadifs __P((int, int, int, broadlist_t *)); +void __rpc_freebroadifs __P((broadlist_t *)); +int __rpc_broadenable __P((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->sa_family != af || + !(ifap->ifa_flags & IFF_UP)) + continue; +#ifdef INET6 + if ((af == AF_INET6 && !(ifap->ifa_flags & IFF_MULTICAST)) || + !(ifap->ifa_flags & IFF_BROADCAST)) + continue; +#endif + bip = (struct broadif *)malloc(sizeof *bip); + if (bip == NULL) + break; + bip->index = if_nametoindex(ifap->ifa_name); +#ifdef INET6 + if (af != AF_INET6 && (ifap->ifa_flags & IFF_BROADCAST)) { +#else + if (ifap->ifa_flags & IFF_BROADCAST) { +#endif + memcpy(&bip->broadaddr, ifap->ifa_broadaddr, + (size_t)ifap->ifa_broadaddr->sa_len); + sin = (struct sockaddr_in *)(void *)&bip->broadaddr; + sin->sin_port = + ((struct sockaddr_in *) + (void *)res->ai_addr)->sin_port; +#ifdef INET6 + } else if (af == AF_INET6) { + sin6 = (struct sockaddr_in6 *)(void *)&bip->broadaddr; + inet_pton(af, RPCB_MULTICAST_ADDR, &sin6->sin6_addr); + sin6->sin6_family = af; + sin6->sin6_len = sizeof *sin6; + sin6->sin6_port = + ((struct sockaddr_in6 *) + (void *)res->ai_addr)->sin6_port; + sin6->sin6_scope_id = bip->index; +#endif + } + 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; +} + + +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, outlen_pmap; + struct netconfig *nconf; + int msec; + int pollretval; + int fds_found; + +#ifdef PORTMAP + u_long port; /* Remote port number */ + int pmap_flag = 0; /* UDP exists ? */ + char *outbuf_pmap = NULL; + struct rmtcallargs barg_pmap; /* Remote arguments */ + struct rmtcallres bres_pmap; /* Remote results */ + u_int udpbufsz = 0; +#endif /* PORTMAP */ + + if (sys_auth == NULL) { + return (RPC_SYSTEMERROR); + } + /* + * initialization: create a fd, a broadcast address, and send the + * request on the broadcast transport. + * Listen on all of them and on replies, call the user supplied + * function. + */ + + if (nettype == NULL) + nettype = "datagram_n"; + if ((handle = __rpc_setconf(nettype)) == NULL) { + return (RPC_UNKNOWNPROTO); + } + while ((nconf = __rpc_getconf(handle)) != NULL) { + int fd; + struct __rpc_sockinfo si; + + if (nconf->nc_semantics != NC_TPI_CLTS) + continue; + if (fdlistno >= MAXBCAST) + break; /* No more slots available */ + if (!__rpc_nconf2sockinfo(nconf, &si)) + continue; + + TAILQ_INIT(&fdlist[fdlistno].nal); + if (__rpc_getbroadifs(si.si_af, si.si_proto, si.si_socktype, + &fdlist[fdlistno].nal) == 0) + continue; + + fd = _socket(si.si_af, si.si_socktype, si.si_proto); + if (fd < 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) { +#ifdef RPC_DEBUG + perror("sendto"); +#endif + warnx("clnt_bcast: cannot send" + "broadcast packet"); + stat = RPC_CANTSEND; + continue; + }; +#ifdef RPC_DEBUG + if (!__rpc_lowvers) + fprintf(stderr, "Broadcast packet sent " + "for %s\n", + fdlist[i].nconf->nc_netid); +#endif +#ifdef PORTMAP + /* + * Send the version 2 packet also + * for UDP/IP + */ + if (fdlist[i].proto == IPPROTO_UDP) { + if (_sendto(fdlist[i].fd, outbuf_pmap, + outlen_pmap, 0, addr, + (size_t)fdlist[i].asize) != + outlen_pmap) { + warnx("clnt_bcast: " + "Cannot send broadcast packet"); + stat = RPC_CANTSEND; + continue; + } + } +#ifdef RPC_DEBUG + fprintf(stderr, "PMAP Broadcast packet " + "sent for %s\n", + fdlist[i].nconf->nc_netid); +#endif +#endif /* PORTMAP */ + } + /* End for sending all packets on this transport */ + } /* End for sending on all transports */ + + if (eachresult == NULL) { + stat = RPC_SUCCESS; + goto done_broad; + } + + /* + * Get all the replies from these broadcast requests + */ + recv_again: + + switch (pollretval = _poll(pfd, fdlistno, msec)) { + case 0: /* timed out */ + stat = RPC_TIMEDOUT; + continue; + case -1: /* some kind of error - we ignore it */ + goto recv_again; + } /* end of poll results switch */ + + for (i = fds_found = 0; + i < fdlistno && fds_found < pollretval; i++) { + bool_t done = FALSE; + + if (pfd[i].revents == 0) + continue; + else if (pfd[i].revents & POLLNVAL) { + /* + * Something bad has happened to this descri- + * ptor. We can cause _poll() to ignore + * it simply by using a negative fd. We do that + * rather than compacting the pfd[] and fdlist[] + * arrays. + */ + pfd[i].fd = -1; + fds_found++; + continue; + } else + fds_found++; +#ifdef RPC_DEBUG + fprintf(stderr, "response for %s\n", + fdlist[i].nconf->nc_netid); +#endif + try_again: + inlen = _recvfrom(fdlist[i].fd, inbuf, fdlist[i].dsize, + 0, (struct sockaddr *)(void *)&fdlist[i].raddr, + &fdlist[i].asize); + if (inlen < 0) { + if (errno == EINTR) + goto try_again; + warnx("clnt_bcast: Cannot receive reply to " + "broadcast"); + stat = RPC_CANTRECV; + continue; + } + if (inlen < sizeof (u_int32_t)) + continue; /* Drop that and go ahead */ + /* + * see if reply transaction id matches sent id. + * If so, decode the results. If return id is xid + 1 + * it was a PORTMAP reply + */ + if (*((u_int32_t *)(void *)(inbuf)) == + *((u_int32_t *)(void *)(outbuf))) { + pmap_reply_flag = 0; + msg.acpted_rply.ar_verf = _null_auth; + msg.acpted_rply.ar_results.where = + (caddr_t)(void *)&bres; + msg.acpted_rply.ar_results.proc = + (xdrproc_t)xdr_rpcb_rmtcallres; +#ifdef PORTMAP + } else if (pmap_flag && + *((u_int32_t *)(void *)(inbuf)) == + *((u_int32_t *)(void *)(outbuf_pmap))) { + pmap_reply_flag = 1; + msg.acpted_rply.ar_verf = _null_auth; + msg.acpted_rply.ar_results.where = + (caddr_t)(void *)&bres_pmap; + msg.acpted_rply.ar_results.proc = + (xdrproc_t)xdr_rmtcallres; +#endif /* PORTMAP */ + } else + continue; + xdrmem_create(xdrs, inbuf, (u_int)inlen, XDR_DECODE); + if (xdr_replymsg(xdrs, &msg)) { + if ((msg.rm_reply.rp_stat == MSG_ACCEPTED) && + (msg.acpted_rply.ar_stat == SUCCESS)) { + struct netbuf taddr, *np; + struct sockaddr_in *sin; + +#ifdef PORTMAP + if (pmap_flag && pmap_reply_flag) { + sin = (struct sockaddr_in *) + (void *)&fdlist[i].raddr; + sin->sin_port = + htons((u_short)port); + taddr.len = taddr.maxlen = + fdlist[i].raddr.ss_len; + taddr.buf = &fdlist[i].raddr; + done = (*eachresult)(resultsp, + &taddr, fdlist[i].nconf); + } else { +#endif /* PORTMAP */ +#ifdef RPC_DEBUG + fprintf(stderr, "uaddr %s\n", + uaddrp); +#endif + np = uaddr2taddr( + fdlist[i].nconf, uaddrp); + done = (*eachresult)(resultsp, + np, fdlist[i].nconf); + free(np); +#ifdef PORTMAP + } +#endif /* PORTMAP */ + } + /* otherwise, we just ignore the errors ... */ + } + /* else some kind of deserialization problem ... */ + + xdrs->x_op = XDR_FREE; + msg.acpted_rply.ar_results.proc = (xdrproc_t) xdr_void; + (void) xdr_replymsg(xdrs, &msg); + (void) (*xresults)(xdrs, resultsp); + XDR_DESTROY(xdrs); + if (done) { + stat = RPC_SUCCESS; + goto done_broad; + } else { + goto recv_again; + } + } /* The recv for loop */ + } /* The giant for loop */ + +done_broad: + if (inbuf) + (void) free(inbuf); + if (outbuf) + (void) free(outbuf); +#ifdef PORTMAP + if (outbuf_pmap) + (void) free(outbuf_pmap); +#endif /* PORTMAP */ + for (i = 0; i < fdlistno; i++) { + (void)_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/lib/libc/rpc/clnt_dg.c b/lib/libc/rpc/clnt_dg.c new file mode 100644 index 000000000000..f9f56127eb4a --- /dev/null +++ b/lib/libc/rpc/clnt_dg.c @@ -0,0 +1,821 @@ +/* $NetBSD: clnt_dg.c,v 1.4 2000/07/14 08:40:41 fvdl Exp $ */ +/* $FreeBSD$ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ + +/* #ident "@(#)clnt_dg.c 1.23 94/04/22 SMI" */ + +#if 0 +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)clnt_dg.c 1.19 89/03/16 Copyr 1988 Sun Micro"; +#endif +#endif + +/* + * Implements a connectionless client side RPC. + */ + +#include "reentrant.h" +#include "namespace.h" +#include <sys/poll.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <rpc/rpc.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <unistd.h> +#include <err.h> +#include "un-namespace.h" +#include "rpc_com.h" + + +#define RPC_MAX_BACKOFF 30 /* seconds */ + + +static struct clnt_ops *clnt_dg_ops __P((void)); +static bool_t time_not_ok __P((struct timeval *)); +static enum clnt_stat clnt_dg_call __P((CLIENT *, rpcproc_t, xdrproc_t, caddr_t, + xdrproc_t, caddr_t, struct timeval)); +static void clnt_dg_geterr __P((CLIENT *, struct rpc_err *)); +static bool_t clnt_dg_freeres __P((CLIENT *, xdrproc_t, caddr_t)); +static void clnt_dg_abort __P((CLIENT *)); +static bool_t clnt_dg_control __P((CLIENT *, u_int, char *)); +static void clnt_dg_destroy __P((CLIENT *)); +static int __rpc_timeval_to_msec __P((struct timeval *)); + + + + +/* + * This machinery implements per-fd locks for MT-safety. It is not + * sufficient to do per-CLIENT handle locks for MT-safety because a + * user may create more than one CLIENT handle with the same fd behind + * it. Therfore, we allocate an array of flags (dg_fd_locks), protected + * by the clnt_fd_lock mutex, and an array (dg_cv) of condition variables + * similarly protected. Dg_fd_lock[fd] == 1 => a call is activte on some + * CLIENT handle created for that fd. + * The current implementation holds locks across the entire RPC and reply, + * including retransmissions. Yes, this is silly, and as soon as this + * code is proven to work, this should be the first thing fixed. One step + * at a time. + */ +static int *dg_fd_locks; +extern mutex_t clnt_fd_lock; +static cond_t *dg_cv; +#define release_fd_lock(fd, mask) { \ + mutex_lock(&clnt_fd_lock); \ + if (__isthreaded) \ + dg_fd_locks[fd] = 0; \ + mutex_unlock(&clnt_fd_lock); \ + thr_sigsetmask(SIG_SETMASK, &(mask), (sigset_t *) NULL); \ + cond_signal(&dg_cv[fd]); \ +} + +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 */ + 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 */ + struct pollfd pfdp; + 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; + + sigfillset(&newmask); + thr_sigsetmask(SIG_SETMASK, &newmask, &mask); + mutex_lock(&clnt_fd_lock); + if (dg_fd_locks == (int *) NULL) { + int cv_allocsz; + size_t fd_allocsz; + int dtbsize = __rpc_dtbsize(); + + fd_allocsz = dtbsize * sizeof (int); + dg_fd_locks = (int *) mem_alloc(fd_allocsz); + if (dg_fd_locks == (int *) NULL) { + mutex_unlock(&clnt_fd_lock); + thr_sigsetmask(SIG_SETMASK, &(mask), NULL); + goto err1; + } else + memset(dg_fd_locks, '\0', fd_allocsz); + + cv_allocsz = dtbsize * sizeof (cond_t); + dg_cv = (cond_t *) mem_alloc(cv_allocsz); + if (dg_cv == (cond_t *) NULL) { + mem_free(dg_fd_locks, fd_allocsz); + dg_fd_locks = (int *) NULL; + mutex_unlock(&clnt_fd_lock); + thr_sigsetmask(SIG_SETMASK, &(mask), NULL); + goto err1; + } else { + int i; + + for (i = 0; i < dtbsize; i++) + cond_init(&dg_cv[i], 0, (void *) 0); + } + } + + mutex_unlock(&clnt_fd_lock); + thr_sigsetmask(SIG_SETMASK, &(mask), NULL); + + if (svcaddr == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNADDR; + return (NULL); + } + + if (!__rpc_fd2sockinfo(fd, &si)) { + rpc_createerr.cf_stat = RPC_TLIERROR; + rpc_createerr.cf_error.re_errno = 0; + return (NULL); + } + /* + * Find the receive and the send size + */ + sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); + recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); + if ((sendsz == 0) || (recvsz == 0)) { + rpc_createerr.cf_stat = RPC_TLIERROR; /* XXX */ + rpc_createerr.cf_error.re_errno = 0; + return (NULL); + } + + if ((cl = mem_alloc(sizeof (CLIENT))) == NULL) + goto err1; + /* + * Should be multiple of 4 for XDR. + */ + sendsz = ((sendsz + 3) / 4) * 4; + recvsz = ((recvsz + 3) / 4) * 4; + cu = mem_alloc(sizeof (*cu) + sendsz + recvsz); + if (cu == NULL) + goto err1; + (void) memcpy(&cu->cu_raddr, svcaddr->buf, (size_t)svcaddr->len); + cu->cu_rlen = svcaddr->len; + cu->cu_outbuf = &cu->cu_inbuf[recvsz]; + /* Other values can also be set through clnt_control() */ + cu->cu_wait.tv_sec = 15; /* heuristically chosen */ + cu->cu_wait.tv_usec = 0; + cu->cu_total.tv_sec = -1; + cu->cu_total.tv_usec = -1; + cu->cu_sendsz = sendsz; + cu->cu_recvsz = recvsz; + (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 + _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; + 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; + cu->pfdp.fd = cu->cu_fd; + cu->pfdp.events = POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND; + 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 */ + caddr_t argsp; /* pointer to args */ + xdrproc_t xresults; /* xdr routine for results */ + caddr_t 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; + struct rpc_msg reply_msg; + XDR reply_xdrs; + struct timeval time_waited; + bool_t ok; + int nrefreshes = 2; /* number of times to refresh cred */ + struct timeval timeout; + struct timeval retransmit_time; + struct timeval startime, curtime; + int firsttimeout = 1; + int dtbsize = __rpc_dtbsize(); + sigset_t mask; + sigset_t newmask; + socklen_t fromlen, inlen; + ssize_t recvlen = 0; + int rpc_lock_value; + + sigfillset(&newmask); + thr_sigsetmask(SIG_SETMASK, &newmask, &mask); + mutex_lock(&clnt_fd_lock); + while (dg_fd_locks[cu->cu_fd]) + cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock); + if (__isthreaded) + rpc_lock_value = 1; + else + rpc_lock_value = 0; + dg_fd_locks[cu->cu_fd] = rpc_lock_value; + mutex_unlock(&clnt_fd_lock); + if (cu->cu_total.tv_usec == -1) { + timeout = utimeout; /* use supplied timeout */ + } else { + timeout = cu->cu_total; /* use default timeout */ + } + + time_waited.tv_sec = 0; + time_waited.tv_usec = 0; + retransmit_time = cu->cu_wait; + +call_again: + xdrs = &(cu->cu_outxdrs); + xdrs->x_op = XDR_ENCODE; + XDR_SETPOS(xdrs, cu->cu_xdrpos); + /* + * the transaction is the first thing in the out buffer + */ + (*(u_int32_t *)(void *)(cu->cu_outbuf))++; + if ((! XDR_PUTINT32(xdrs, &proc)) || + (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || + (! (*xargs)(xdrs, argsp))) { + release_fd_lock(cu->cu_fd, mask); + return (cu->cu_error.re_status = RPC_CANTENCODEARGS); + } + outlen = (size_t)XDR_GETPOS(xdrs); + +send_again: + if (_sendto(cu->cu_fd, cu->cu_outbuf, outlen, 0, + (struct sockaddr *)(void *)&cu->cu_raddr, (socklen_t)cu->cu_rlen) + != outlen) { + cu->cu_error.re_errno = errno; + release_fd_lock(cu->cu_fd, mask); + return (cu->cu_error.re_status = RPC_CANTSEND); + } + + /* + * Hack to provide rpc-based message passing + */ + if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { + release_fd_lock(cu->cu_fd, mask); + return (cu->cu_error.re_status = RPC_TIMEDOUT); + } + /* + * sub-optimal code appears here because we have + * some clock time to spare while the packets are in flight. + * (We assume that this is actually only executed once.) + */ + reply_msg.acpted_rply.ar_verf = _null_auth; + reply_msg.acpted_rply.ar_results.where = resultsp; + reply_msg.acpted_rply.ar_results.proc = xresults; + + + for (;;) { + switch (_poll(&cu->pfdp, 1, + __rpc_timeval_to_msec(&retransmit_time))) { + case 0: + time_waited.tv_sec += retransmit_time.tv_sec; + time_waited.tv_usec += retransmit_time.tv_usec; + while (time_waited.tv_usec >= 1000000) { + time_waited.tv_sec++; + time_waited.tv_usec -= 1000000; + } + /* update retransmit_time */ + if (retransmit_time.tv_sec < RPC_MAX_BACKOFF) { + retransmit_time.tv_usec *= 2; + retransmit_time.tv_sec *= 2; + while (retransmit_time.tv_usec >= 1000000) { + retransmit_time.tv_sec++; + retransmit_time.tv_usec -= 1000000; + } + } + + if ((time_waited.tv_sec < timeout.tv_sec) || + ((time_waited.tv_sec == timeout.tv_sec) && + (time_waited.tv_usec < timeout.tv_usec))) + goto send_again; + release_fd_lock(cu->cu_fd, mask); + return (cu->cu_error.re_status = RPC_TIMEDOUT); + + case -1: + if (errno == EBADF) { + cu->cu_error.re_errno = errno; + release_fd_lock(cu->cu_fd, mask); + return (cu->cu_error.re_status = RPC_CANTRECV); + } + if (errno != EINTR) { + errno = 0; /* reset it */ + continue; + } + /* interrupted by another signal, update time_waited */ + if (firsttimeout) { + /* + * Could have done gettimeofday before clnt_call + * but that means 1 more system call per each + * clnt_call, so do it after first time out + */ + if (gettimeofday(&startime, + (struct timezone *) NULL) == -1) { + errno = 0; + continue; + } + firsttimeout = 0; + errno = 0; + continue; + }; + if (gettimeofday(&curtime, + (struct timezone *) NULL) == -1) { + errno = 0; + continue; + }; + time_waited.tv_sec += curtime.tv_sec - startime.tv_sec; + time_waited.tv_usec += curtime.tv_usec - + startime.tv_usec; + while (time_waited.tv_usec < 0) { + time_waited.tv_sec--; + time_waited.tv_usec += 1000000; + }; + while (time_waited.tv_usec >= 1000000) { + time_waited.tv_sec++; + time_waited.tv_usec -= 1000000; + } + startime.tv_sec = curtime.tv_sec; + startime.tv_usec = curtime.tv_usec; + if ((time_waited.tv_sec > timeout.tv_sec) || + ((time_waited.tv_sec == timeout.tv_sec) && + (time_waited.tv_usec > timeout.tv_usec))) { + release_fd_lock(cu->cu_fd, mask); + return (cu->cu_error.re_status = RPC_TIMEDOUT); + } + errno = 0; /* reset it */ + continue; + }; + + if (cu->pfdp.revents & POLLNVAL || (cu->pfdp.revents == 0)) { + cu->cu_error.re_status = RPC_CANTRECV; + /* + * Note: we're faking errno here because we + * previously would have expected _poll() to + * return -1 with errno EBADF. Poll(BA_OS) + * returns 0 and sets the POLLNVAL revents flag + * instead. + */ + cu->cu_error.re_errno = errno = EBADF; + release_fd_lock(cu->cu_fd, mask); + return (-1); + } + + /* We have some data now */ + do { + if (errno == EINTR) { + /* + * Must make sure errno was not already + * EINTR in case _recvfrom() returns -1. + */ + errno = 0; + } + fromlen = sizeof (struct sockaddr_storage); + recvlen = _recvfrom(cu->cu_fd, cu->cu_inbuf, + cu->cu_recvsz, 0, (struct sockaddr *)(void *)&cu->cu_raddr, + &fromlen); + } while (recvlen < 0 && errno == EINTR); + if (recvlen < 0) { + if (errno == EWOULDBLOCK) + continue; + cu->cu_error.re_errno = errno; + release_fd_lock(cu->cu_fd, mask); + return (cu->cu_error.re_status = RPC_CANTRECV); + } + if (recvlen < sizeof (u_int32_t)) + continue; + /* see if reply transaction id matches sent id */ + if (*((u_int32_t *)(void *)(cu->cu_inbuf)) != + *((u_int32_t *)(void *)(cu->cu_outbuf))) + continue; + /* we now assume we have the proper reply */ + break; + } + inlen = (socklen_t)recvlen; + + /* + * now decode and validate the response + */ + + xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)inlen, XDR_DECODE); + ok = xdr_replymsg(&reply_xdrs, &reply_msg); + /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */ + if (ok) { + if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) && + (reply_msg.acpted_rply.ar_stat == SUCCESS)) + cu->cu_error.re_status = RPC_SUCCESS; + else + _seterr_reply(&reply_msg, &(cu->cu_error)); + + if (cu->cu_error.re_status == RPC_SUCCESS) { + if (! AUTH_VALIDATE(cl->cl_auth, + &reply_msg.acpted_rply.ar_verf)) { + cu->cu_error.re_status = RPC_AUTHERROR; + cu->cu_error.re_why = AUTH_INVALIDRESP; + } + if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { + xdrs->x_op = XDR_FREE; + (void) xdr_opaque_auth(xdrs, + &(reply_msg.acpted_rply.ar_verf)); + } + } /* end successful completion */ + /* + * If unsuccesful AND error is an authentication error + * then refresh credentials and try again, else break + */ + else if (cu->cu_error.re_status == RPC_AUTHERROR) + /* maybe our credentials need to be refreshed ... */ + if (nrefreshes > 0 && + AUTH_REFRESH(cl->cl_auth, &reply_msg)) { + nrefreshes--; + goto call_again; + } + /* end of unsuccessful completion */ + } /* end of valid reply message */ + else { + cu->cu_error.re_status = RPC_CANTDECODERES; + + } + release_fd_lock(cu->cu_fd, mask); + return (cu->cu_error.re_status); +} + +static void +clnt_dg_geterr(cl, errp) + CLIENT *cl; + struct rpc_err *errp; +{ + struct cu_data *cu = (struct cu_data *)cl->cl_private; + + *errp = cu->cu_error; +} + +static bool_t +clnt_dg_freeres(cl, xdr_res, res_ptr) + CLIENT *cl; + xdrproc_t xdr_res; + caddr_t 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); + while (dg_fd_locks[cu->cu_fd]) + cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock); + xdrs->x_op = XDR_FREE; + dummy = (*xdr_res)(xdrs, res_ptr); + mutex_unlock(&clnt_fd_lock); + thr_sigsetmask(SIG_SETMASK, &mask, NULL); + cond_signal(&dg_cv[cu->cu_fd]); + return (dummy); +} + +/*ARGSUSED*/ +static void +clnt_dg_abort(h) + CLIENT *h; +{ +} + +static bool_t +clnt_dg_control(cl, request, info) + CLIENT *cl; + u_int request; + char *info; +{ + struct cu_data *cu = (struct cu_data *)cl->cl_private; + struct netbuf *addr; + sigset_t mask; + sigset_t newmask; + int rpc_lock_value; + + sigfillset(&newmask); + thr_sigsetmask(SIG_SETMASK, &newmask, &mask); + mutex_lock(&clnt_fd_lock); + while (dg_fd_locks[cu->cu_fd]) + cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock); + if (__isthreaded) + rpc_lock_value = 1; + else + rpc_lock_value = 0; + dg_fd_locks[cu->cu_fd] = rpc_lock_value; + mutex_unlock(&clnt_fd_lock); + switch (request) { + case CLSET_FD_CLOSE: + cu->cu_closeit = TRUE; + release_fd_lock(cu->cu_fd, mask); + return (TRUE); + case CLSET_FD_NCLOSE: + cu->cu_closeit = FALSE; + release_fd_lock(cu->cu_fd, mask); + return (TRUE); + } + + /* for other requests which use info */ + if (info == NULL) { + release_fd_lock(cu->cu_fd, mask); + return (FALSE); + } + switch (request) { + case CLSET_TIMEOUT: + if (time_not_ok((struct timeval *)(void *)info)) { + release_fd_lock(cu->cu_fd, mask); + return (FALSE); + } + cu->cu_total = *(struct timeval *)(void *)info; + break; + case CLGET_TIMEOUT: + *(struct timeval *)(void *)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 *)(void *)info)) { + release_fd_lock(cu->cu_fd, mask); + return (FALSE); + } + cu->cu_wait = *(struct timeval *)(void *)info; + break; + case CLGET_RETRY_TIMEOUT: + *(struct timeval *)(void *)info = cu->cu_wait; + break; + case CLGET_FD: + *(int *)(void *)info = cu->cu_fd; + break; + case CLGET_SVC_ADDR: + addr = (struct netbuf *)(void *)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 *)(void *)info; + if (addr->len < sizeof cu->cu_raddr) + 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 *)(void *)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 *)(void *)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 *)(void *)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 *)(void *)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 *)(void *)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 *)(void *)info); + break; + + default: + release_fd_lock(cu->cu_fd, mask); + return (FALSE); + } + release_fd_lock(cu->cu_fd, mask); + return (TRUE); +} + +static void +clnt_dg_destroy(cl) + CLIENT *cl; +{ + struct cu_data *cu = (struct cu_data *)cl->cl_private; + int cu_fd = cu->cu_fd; + sigset_t mask; + sigset_t newmask; + + sigfillset(&newmask); + thr_sigsetmask(SIG_SETMASK, &newmask, &mask); + mutex_lock(&clnt_fd_lock); + while (dg_fd_locks[cu_fd]) + cond_wait(&dg_cv[cu_fd], &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)); + mutex_unlock(&clnt_fd_lock); + thr_sigsetmask(SIG_SETMASK, &mask, NULL); + cond_signal(&dg_cv[cu_fd]); +} + +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); +} + + +/* + * Convert from timevals (used by select) to milliseconds (used by poll). + */ +static int +__rpc_timeval_to_msec(t) + struct timeval *t; +{ + int t1, tmp; + + /* + * We're really returning t->tv_sec * 1000 + (t->tv_usec / 1000) + * but try to do so efficiently. Note: 1000 = 1024 - 16 - 8. + */ + tmp = (int)t->tv_sec << 3; + t1 = -tmp; + t1 += t1 << 1; + t1 += tmp << 7; + if (t->tv_usec) + t1 += (int)(t->tv_usec / 1000); + + return (t1); +} diff --git a/lib/libc/rpc/clnt_generic.c b/lib/libc/rpc/clnt_generic.c index d885f1820d17..696ea541a2ed 100644 --- a/lib/libc/rpc/clnt_generic.c +++ b/lib/libc/rpc/clnt_generic.c @@ -1,3 +1,5 @@ +/* $NetBSD: clnt_generic.c,v 1.18 2000/07/06 03:10:34 christos Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -27,6 +29,8 @@ * Mountain View, California 94043 */ +/* #ident "@(#)clnt_generic.c 1.20 94/05/03 SMI" */ + #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)clnt_generic.c 1.4 87/08/11 (C) 1987 SMI";*/ /*static char *sccsid = "from: @(#)clnt_generic.c 2.2 88/08/01 4.0 RPCSRC";*/ @@ -34,104 +38,312 @@ static char *rcsid = "$FreeBSD$"; #endif /* - * Copyright (C) 1987, Sun Microsystems, Inc. + * Copyright (c) 1986-1991 by Sun Microsystems Inc. */ -#include <rpc/rpc.h> +#include "reentrant.h" +#include "namespace.h" +#include <sys/types.h> #include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <stdio.h> #include <errno.h> #include <netdb.h> +#include <rpc/rpc.h> +#include <rpc/nettype.h> #include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include "un-namespace.h" +#include "rpc_com.h" + +/* + * 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. + */ +CLIENT * +clnt_create_vers(hostname, prog, vers_out, vers_low, vers_high, nettype) + const char *hostname; + rpcprog_t prog; + rpcvers_t *vers_out; + rpcvers_t vers_low; + rpcvers_t vers_high; + const char *nettype; +{ + CLIENT *clnt; + struct timeval to; + enum clnt_stat rpc_stat; + struct rpc_err rpcerr; + + clnt = clnt_create(hostname, prog, vers_high, nettype); + 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); + } + if (rpc_stat == RPC_PROGVERSMISMATCH) { + unsigned long minvers, maxvers; + + clnt_geterr(clnt, &rpcerr); + minvers = rpcerr.re_vers.low; + maxvers = rpcerr.re_vers.high; + if (maxvers < vers_high) + vers_high = (rpcvers_t)maxvers; + if (minvers > vers_low) + vers_low = (rpcvers_t)minvers; + if (vers_low > vers_high) { + goto error; + } + CLNT_CONTROL(clnt, CLSET_VERS, (char *)(void *)&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); +} /* - * Generic client creation: takes (hostname, program-number, protocol) and + * 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_tp_create(); */ CLIENT * -clnt_create(hostname, prog, vers, proto) - char *hostname; - u_long prog; - u_long vers; - char *proto; +clnt_create(hostname, prog, vers, nettype) + const char *hostname; /* server name */ + rpcprog_t prog; /* program number */ + rpcvers_t vers; /* version number */ + const char *nettype; /* net type */ { - struct hostent *h; - struct protoent *p; - struct sockaddr_in sin; - struct sockaddr_un sun; - int sock; - static struct timeval tv; - CLIENT *client; + struct netconfig *nconf; + CLIENT *clnt = NULL; + void *handle; + enum clnt_stat save_cf_stat = RPC_SUCCESS; + struct rpc_err save_cf_error; - if (!strcmp(proto, "unix")) { - bzero((char *)&sun, sizeof(sun)); - sun.sun_family = AF_UNIX; - strcpy(sun.sun_path, hostname); - sun.sun_len = sizeof(sun.sun_len) + sizeof(sun.sun_family) + - strlen(sun.sun_path) + 1; - sock = RPC_ANYSOCK; - client = clntunix_create(&sun, prog, vers, &sock, 0, 0); - if (client == NULL) - return(NULL); - tv.tv_sec = 25; - tv.tv_usec = 0; - clnt_control(client, CLSET_TIMEOUT, &tv); - return(client); - } - h = gethostbyname(hostname); - if (h == NULL) { - rpc_createerr.cf_stat = RPC_UNKNOWNHOST; + if ((handle = __rpc_setconf(nettype)) == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; return (NULL); } - if (h->h_addrtype != AF_INET) { - /* - * Only support INET for now - */ - rpc_createerr.cf_stat = RPC_SYSTEMERROR; - rpc_createerr.cf_error.re_errno = EAFNOSUPPORT; - 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(hostname, prog, vers, nconf); + 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). + */ + if (rpc_createerr.cf_stat != RPC_N2AXLATEFAILURE) { + save_cf_stat = rpc_createerr.cf_stat; + save_cf_error = rpc_createerr.cf_error; + } } - memset(&sin, 0, sizeof(sin)); - sin.sin_len = sizeof(struct sockaddr_in); - sin.sin_family = h->h_addrtype; - sin.sin_port = 0; - memcpy((char*)&sin.sin_addr, h->h_addr, h->h_length); - p = getprotobyname(proto); - if (p == NULL) { + + /* + * Attempt to return an error more specific than ``Name to address + * translation failed'' + */ + if ((rpc_createerr.cf_stat == RPC_N2AXLATEFAILURE) && + (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() + */ +CLIENT * +clnt_tp_create(hostname, prog, vers, nconf) + const char *hostname; /* server name */ + rpcprog_t prog; /* program number */ + rpcvers_t vers; /* version number */ + const struct netconfig *nconf; /* net config struct */ +{ + struct netbuf *svcaddr; /* servers address */ + CLIENT *cl = NULL; /* client handle */ + + if (nconf == NULL) { rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; - rpc_createerr.cf_error.re_errno = EPFNOSUPPORT; return (NULL); } - sock = RPC_ANYSOCK; - switch (p->p_proto) { - case IPPROTO_UDP: - tv.tv_sec = 5; - tv.tv_usec = 0; - client = clntudp_create(&sin, prog, vers, tv, &sock); - if (client == NULL) { - return (NULL); + + /* + * Get the address of the server + */ + if ((svcaddr = __rpcb_findaddr(prog, vers, nconf, hostname, + &cl)) == 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); } -#if 0 /* XXX do we need this? */ - tv.tv_sec = 25; - tv.tv_usec = 0; - clnt_control(client, CLSET_TIMEOUT, &tv); -#endif - break; - case IPPROTO_TCP: - client = clnttcp_create(&sin, prog, vers, &sock, 0, 0); - if (client == NULL) { + } + free(svcaddr->buf); + free(svcaddr); + return (cl); +} + +/* + * Generic client creation: returns client handle. + * Default options are set, which the user can + * change using the rpc equivalent of _ioctl()'s : clnt_control(). + * If fd is RPC_ANYFD, it will be opened using nconf. + * It will be bound if not so. + * If sizes are 0; appropriate defaults will be chosen. + */ +CLIENT * +clnt_tli_create(fd, nconf, svcaddr, prog, vers, sendsz, recvsz) + int fd; /* fd */ + const struct netconfig *nconf; /* netconfig structure */ + const struct netbuf *svcaddr; /* servers address */ + rpcprog_t prog; /* program number */ + rpcvers_t vers; /* version number */ + u_int sendsz; /* send size */ + u_int recvsz; /* recv size */ +{ + CLIENT *cl; /* client handle */ + bool_t madefd = FALSE; /* whether fd opened here */ + long servtype; + int one = 1; + struct __rpc_sockinfo si; + + if (fd == RPC_ANYFD) { + if (nconf == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; return (NULL); } -#if 0 /* XXX do we need this? */ - tv.tv_sec = 25; - tv.tv_usec = 0; - clnt_control(client, CLSET_TIMEOUT, &tv); -#endif + + fd = __rpc_nconf2fd(nconf); + + if (fd == -1) + goto err; + + 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_ORD: + cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz); + if (!nconf || !cl) + break; + /* XXX fvdl - is this useful? */ + if (strncmp(nconf->nc_protofmly, "inet", 4) == 0) + _setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, + sizeof (one)); + break; + case NC_TPI_CLTS: + cl = clnt_dg_create(fd, svcaddr, prog, vers, sendsz, recvsz); break; default: - rpc_createerr.cf_stat = RPC_SYSTEMERROR; - rpc_createerr.cf_error.re_errno = EPFNOSUPPORT; - return (NULL); + goto err; } - return (client); + + 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, (char *) 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); } diff --git a/lib/libc/rpc/clnt_perror.c b/lib/libc/rpc/clnt_perror.c index 331f52b04496..6ddf39d98347 100644 --- a/lib/libc/rpc/clnt_perror.c +++ b/lib/libc/rpc/clnt_perror.c @@ -1,3 +1,6 @@ +/* $NetBSD: clnt_perror.c,v 1.24 2000/06/02 23:11:07 fvdl Exp $ */ + + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -27,9 +30,10 @@ * Mountain View, California 94043 */ +#include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) -/*static char *sccsid = "from: @(#)clnt_perror.c 1.15 87/10/07 Copyr 1984 Sun Micro";*/ -/*static char *sccsid = "from: @(#)clnt_perror.c 2.1 88/07/29 4.0 RPCSRC";*/ +static char *sccsid = "@(#)clnt_perror.c 1.15 87/10/07 Copyr 1984 Sun Micro"; +static char *sccsid = "@(#)clnt_perror.c 2.1 88/07/29 4.0 RPCSRC"; static char *rcsid = "$FreeBSD$"; #endif @@ -39,19 +43,24 @@ static char *rcsid = "$FreeBSD$"; * Copyright (C) 1984, Sun Microsystems, Inc. * */ +#include "namespace.h" +#include <assert.h> #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 *auth_errmsg(); -#define CLNT_PERROR_BUFLEN 256 +#include "un-namespace.h" static char *buf; +static char *_buf __P((void)); +static char *auth_errmsg __P((enum auth_stat)); +#define CLNT_PERROR_BUFLEN 256 + static char * _buf() { @@ -67,19 +76,32 @@ _buf() char * clnt_sperror(rpch, s) CLIENT *rpch; - char *s; + const char *s; { struct rpc_err e; char *err; - char *str = _buf(); - char *strstart = str; + char *str; + char *strstart; + size_t len, i; + + assert(rpch != NULL); + assert(s != NULL); + str = _buf(); /* side effect: sets CLNT_PERROR_BUFLEN */ if (str == 0) return (0); + len = CLNT_PERROR_BUFLEN; + strstart = str; CLNT_GETERR(rpch, &e); - (void) snprintf(str, CLNT_PERROR_BUFLEN, "%s: %s", s, clnt_sperrno(e.re_status)); - str += strlen(str); + i = snprintf(str, len, "%s: ", s); + 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: @@ -99,42 +121,48 @@ clnt_sperror(rpch, s) case RPC_CANTSEND: case RPC_CANTRECV: - (void) snprintf(str, CLNT_PERROR_BUFLEN - (str - strstart), - "; errno = %s\n", strerror(e.re_errno)); + i = snprintf(str, len, "; errno = %s", strerror(e.re_errno)); + str += i; + len -= i; break; case RPC_VERSMISMATCH: - (void) sprintf(str, - "; low version = %lu, high version = %lu\n", - (u_long)e.re_vers.low, (u_long)e.re_vers.high); + i = snprintf(str, len, "; low version = %u, high version = %u", + e.re_vers.low, e.re_vers.high); + str += i; + len -= i; break; case RPC_AUTHERROR: err = auth_errmsg(e.re_why); - (void) sprintf(str,"; why = "); - str += strlen(str); + i = snprintf(str, len, "; why = "); + str += i; + len -= i; if (err != NULL) { - (void) sprintf(str, "%s\n",err); + i = snprintf(str, len, "%s",err); } else { - (void) sprintf(str, - "(unknown authentication error - %d)\n", + i = snprintf(str, len, + "(unknown authentication error - %d)", (int) e.re_why); } + str += i; + len -= i; break; case RPC_PROGVERSMISMATCH: - (void) sprintf(str, - "; low version = %lu, high version = %lu\n", - (u_long)e.re_vers.low, (u_long)e.re_vers.high); + i = snprintf(str, len, "; low version = %u, high version = %u", + e.re_vers.low, e.re_vers.high); + str += i; + len -= i; break; default: /* unknown */ - (void) sprintf(str, - "; s1 = %lu, s2 = %lu\n", - (long)e.re_lb.s1, (long)e.re_lb.s2); + i = snprintf(str, len, "; s1 = %u, s2 = %u", + e.re_lb.s1, e.re_lb.s2); + str += i; + len -= i; break; } - strstart[CLNT_PERROR_BUFLEN-2] = '\n'; strstart[CLNT_PERROR_BUFLEN-1] = '\0'; return(strstart) ; } @@ -142,11 +170,14 @@ clnt_sperror(rpch, s) void clnt_perror(rpch, s) CLIENT *rpch; - char *s; + const char *s; { - (void) fprintf(stderr,"%s\n",clnt_sperror(rpch,s)); -} + assert(rpch != NULL); + assert(s != NULL); + + (void) fprintf(stderr, "%s\n", clnt_sperror(rpch,s)); +} static const char *const rpc_errlist[] = { "RPC: Success", /* 0 - RPC_SUCCESS */ @@ -180,6 +211,7 @@ clnt_sperrno(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)"); @@ -189,53 +221,78 @@ void clnt_perrno(num) enum clnt_stat num; { - (void) fprintf(stderr,"%s\n",clnt_sperrno(num)); + (void) fprintf(stderr, "%s\n", clnt_sperrno(num)); } char * clnt_spcreateerror(s) - char *s; + const char *s; { - char *str = _buf(); + char *str; + size_t len, i; + assert(s != NULL); + + str = _buf(); /* side effect: sets CLNT_PERROR_BUFLEN */ if (str == 0) return(0); + len = CLNT_PERROR_BUFLEN; + i = snprintf(str, len, "%s: ", s); + len -= i; + (void)strncat(str, clnt_sperrno(rpc_createerr.cf_stat), len - 1); switch (rpc_createerr.cf_stat) { case RPC_PMAPFAILURE: - (void) snprintf(str, CLNT_PERROR_BUFLEN, "%s: %s - %s\n", s, - clnt_sperrno(rpc_createerr.cf_stat), - clnt_sperrno(rpc_createerr.cf_error.re_status)); + (void) strncat(str, " - ", len - 1); + (void) strncat(str, + clnt_sperrno(rpc_createerr.cf_error.re_status), len - 4); break; case RPC_SYSTEMERROR: - (void) snprintf(str, CLNT_PERROR_BUFLEN, "%s: %s - %s\n", s, - clnt_sperrno(rpc_createerr.cf_stat), - strerror(rpc_createerr.cf_error.re_errno)); + (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: - (void) snprintf(str, CLNT_PERROR_BUFLEN, "%s: %s\n", s, - clnt_sperrno(rpc_createerr.cf_stat)); break; } - str[CLNT_PERROR_BUFLEN-2] = '\n'; str[CLNT_PERROR_BUFLEN-1] = '\0'; return (str); } void clnt_pcreateerror(s) - char *s; + const char *s; { - (void) fprintf(stderr,"%s\n",clnt_spcreateerror(s)); + + assert(s != NULL); + + (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 */ + "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 */ @@ -248,6 +305,7 @@ auth_errmsg(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/lib/libc/rpc/clnt_raw.c b/lib/libc/rpc/clnt_raw.c index 6f228fe99d69..01dfc7997d0a 100644 --- a/lib/libc/rpc/clnt_raw.c +++ b/lib/libc/rpc/clnt_raw.c @@ -1,3 +1,5 @@ +/* $NetBSD: clnt_raw.c,v 1.20 2000/12/10 04:12:03 christos Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -27,9 +29,10 @@ * Mountain View, California 94043 */ +#include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) -/*static char *sccsid = "from: @(#)clnt_raw.c 1.22 87/08/11 Copyr 1984 Sun Micro";*/ -/*static char *sccsid = "from: @(#)clnt_raw.c 2.2 88/08/01 4.0 RPCSRC";*/ +static char *sccsid = "@(#)clnt_raw.c 1.22 87/08/11 Copyr 1984 Sun Micro"; +static char *sccsid = "@(#)clnt_raw.c 2.2 88/08/01 4.0 RPCSRC"; static char *rcsid = "$FreeBSD$"; #endif @@ -44,9 +47,18 @@ static char *rcsid = "$FreeBSD$"; * any interference from the kernal. */ -#include <rpc/rpc.h> -#include <stdlib.h> +#include "reentrant.h" +#include "namespace.h" +#include <assert.h> +#include <err.h> #include <stdio.h> +#include <stdlib.h> + +#include <rpc/rpc.h> +#include <rpc/raw.h> +#include "un-namespace.h" + +extern mutex_t clntraw_lock; #define MCALL_MSG_SIZE 24 @@ -56,46 +68,47 @@ static char *rcsid = "$FreeBSD$"; static struct clntraw_private { CLIENT client_object; XDR xdr_stream; - char _raw_buf[UDPMSGSIZE]; - char mashl_callmsg[MCALL_MSG_SIZE]; + 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 clntraw_call(); -static void clntraw_abort(); -static void clntraw_geterr(); -static bool_t clntraw_freeres(); -static bool_t clntraw_control(); -static void clntraw_destroy(); - -static struct clnt_ops client_ops = { - clntraw_call, - clntraw_abort, - clntraw_geterr, - clntraw_freeres, - clntraw_destroy, - clntraw_control -}; - -void svc_getreq(); +static enum clnt_stat clnt_raw_call __P((CLIENT *, rpcproc_t, xdrproc_t, + caddr_t, xdrproc_t, caddr_t, struct timeval)); +static void clnt_raw_geterr __P((CLIENT *, struct rpc_err *)); +static bool_t clnt_raw_freeres __P((CLIENT *, xdrproc_t, caddr_t)); +static void clnt_raw_abort __P((CLIENT *)); +static bool_t clnt_raw_control __P((CLIENT *, u_int, char *)); +static void clnt_raw_destroy __P((CLIENT *)); +static struct clnt_ops *clnt_raw_ops __P((void)); /* * Create a client handle for memory based rpc. */ CLIENT * -clntraw_create(prog, vers) - u_long prog; - u_long vers; +clnt_raw_create(prog, vers) + rpcprog_t prog; + rpcvers_t vers; { - register struct clntraw_private *clp = clntraw_private; + struct clntraw_private *clp = clntraw_private; struct rpc_msg call_msg; XDR *xdrs = &clp->xdr_stream; CLIENT *client = &clp->client_object; - if (clp == 0) { + mutex_lock(&clntraw_lock); + if (clp == NULL) { clp = (struct clntraw_private *)calloc(1, sizeof (*clp)); - if (clp == 0) - return (0); + 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; } /* @@ -103,12 +116,12 @@ clntraw_create(prog, vers) */ call_msg.rm_direction = CALL; call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; - call_msg.rm_call.cb_prog = prog; - call_msg.rm_call.cb_vers = vers; - xdrmem_create(xdrs, clp->mashl_callmsg, MCALL_MSG_SIZE, XDR_ENCODE); - if (! xdr_callhdr(xdrs, &call_msg)) { - perror("clnt_raw.c - Fatal header serialization error."); - } + /* 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); @@ -120,38 +133,47 @@ clntraw_create(prog, vers) /* * create client handle */ - client->cl_ops = &client_ops; + client->cl_ops = clnt_raw_ops(); client->cl_auth = authnone_create(); + mutex_unlock(&clntraw_lock); return (client); } -static enum clnt_stat -clntraw_call(h, proc, xargs, argsp, xresults, resultsp, timeout) +/* ARGSUSED */ +static enum clnt_stat +clnt_raw_call(h, proc, xargs, argsp, xresults, resultsp, timeout) CLIENT *h; - u_long proc; + rpcproc_t proc; xdrproc_t xargs; caddr_t argsp; xdrproc_t xresults; caddr_t resultsp; struct timeval timeout; { - register struct clntraw_private *clp = clntraw_private; - register XDR *xdrs = &clp->xdr_stream; + struct clntraw_private *clp = clntraw_private; + XDR *xdrs = &clp->xdr_stream; struct rpc_msg msg; enum clnt_stat status; struct rpc_err error; - if (clp == 0) + assert(h != NULL); + + mutex_lock(&clntraw_lock); + if (clp == NULL) { + mutex_unlock(&clntraw_lock); return (RPC_FAILED); + } + mutex_unlock(&clntraw_lock); + call_again: /* * send request */ xdrs->x_op = XDR_ENCODE; XDR_SETPOS(xdrs, 0); - ((struct rpc_msg *)clp->mashl_callmsg)->rm_xid ++ ; - if ((! XDR_PUTBYTES(xdrs, clp->mashl_callmsg, clp->mcnt)) || - (! XDR_PUTLONG(xdrs, (long *)&proc)) || + clp->u.mashl_rpcmsg.rm_xid ++ ; + if ((! XDR_PUTBYTES(xdrs, clp->u.mashl_callmsg, clp->mcnt)) || + (! XDR_PUTINT32(xdrs, &proc)) || (! AUTH_MARSHALL(h->cl_auth, xdrs)) || (! (*xargs)(xdrs, argsp))) { return (RPC_CANTENCODEARGS); @@ -162,7 +184,7 @@ call_again: * We have to call server input routine here because this is * all going on in one process. Yuk. */ - svc_getreq(1); + svc_getreq_common(FD_SETSIZE); /* * get results @@ -172,8 +194,23 @@ call_again: 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)) + 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; @@ -183,7 +220,7 @@ call_again: } } /* end successful completion */ else { - if (AUTH_REFRESH(h->cl_auth)) + if (AUTH_REFRESH(h->cl_auth, &msg)) goto call_again; } /* end of unsuccessful completion */ @@ -200,43 +237,78 @@ call_again: return (status); } +/*ARGSUSED*/ static void -clntraw_geterr() +clnt_raw_geterr(cl, err) + CLIENT *cl; + struct rpc_err *err; { } +/* ARGSUSED */ static bool_t -clntraw_freeres(cl, xdr_res, res_ptr) +clnt_raw_freeres(cl, xdr_res, res_ptr) CLIENT *cl; xdrproc_t xdr_res; caddr_t res_ptr; { - register struct clntraw_private *clp = clntraw_private; - register XDR *xdrs = &clp->xdr_stream; + struct clntraw_private *clp = clntraw_private; + XDR *xdrs = &clp->xdr_stream; bool_t rval; - if (clp == 0) - { + mutex_lock(&clntraw_lock); + if (clp == NULL) { rval = (bool_t) RPC_FAILED; + mutex_unlock(&clntraw_lock); return (rval); } + mutex_unlock(&clntraw_lock); xdrs->x_op = XDR_FREE; return ((*xdr_res)(xdrs, res_ptr)); } +/*ARGSUSED*/ static void -clntraw_abort() +clnt_raw_abort(cl) + CLIENT *cl; { } +/*ARGSUSED*/ static bool_t -clntraw_control() +clnt_raw_control(cl, ui, str) + CLIENT *cl; + u_int ui; + char *str; { return (FALSE); } +/*ARGSUSED*/ static void -clntraw_destroy() +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/lib/libc/rpc/clnt_simple.c b/lib/libc/rpc/clnt_simple.c index 46d959b22011..09b65fc0b0d0 100644 --- a/lib/libc/rpc/clnt_simple.c +++ b/lib/libc/rpc/clnt_simple.c @@ -1,3 +1,5 @@ +/* $NetBSD: clnt_simple.c,v 1.21 2000/07/06 03:10:34 christos Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -26,6 +28,9 @@ * 2550 Garcia Avenue * Mountain View, California 94043 */ +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)clnt_simple.c 1.35 87/08/11 Copyr 1984 Sun Micro";*/ @@ -35,90 +40,156 @@ static char *rcsid = "$FreeBSD$"; /* * clnt_simple.c - * Simplified front end to rpc. + * Simplified front end to client rpc. * - * Copyright (C) 1984, Sun Microsystems, Inc. */ +#include "reentrant.h" #include "namespace.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 <string.h> -#include <rpc/rpc.h> -#include <sys/socket.h> -#include <netdb.h> #include "un-namespace.h" -static struct callrpc_private { - CLIENT *client; - int socket; - int oldprognum, oldversnum, valid; - char *oldhost; -} *callrpc_private; +#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 struct rpc_call_private *rpc_call_private_main; -int -callrpc(host, prognum, versnum, procnum, inproc, in, outproc, out) - char *host; - int prognum, versnum, procnum; - xdrproc_t inproc, outproc; - char *in, *out; +static void rpc_call_destroy __P((void *)); + +static void +rpc_call_destroy(void *vp) { - register struct callrpc_private *crp = callrpc_private; - struct sockaddr_in server_addr; + 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 hostent *hp; struct timeval timeout, tottimeout; + static thread_key_t rpc_call_key; + extern mutex_t tsd_lock; + int main_thread = 1; - if (crp == 0) { - crp = (struct callrpc_private *)calloc(1, sizeof (*crp)); - if (crp == 0) - return (0); - callrpc_private = crp; + if ((main_thread = thr_main())) { + rcp = rpc_call_private_main; + } else { + if (rpc_call_key == 0) { + mutex_lock(&tsd_lock); + if (rpc_call_key == 0) + thr_keycreate(&rpc_call_key, rpc_call_destroy); + mutex_unlock(&tsd_lock); + } + rcp = (struct rpc_call_private *)thr_getspecific(rpc_call_key); } - if (crp->oldhost == NULL) { - crp->oldhost = malloc(MAXHOSTNAMELEN); - crp->oldhost[0] = 0; - crp->socket = RPC_ANYSOCK; + 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); + } + if (main_thread) + rpc_call_private_main = rcp; + else + thr_setspecific(rpc_call_key, (void *) rcp); + rcp->valid = 0; + rcp->client = NULL; } - if (crp->valid && crp->oldprognum == prognum && crp->oldversnum == versnum - && strcmp(crp->oldhost, host) == 0) { - /* reuse old client */ - } else { - crp->valid = 0; - if (crp->socket != -1) - (void)_close(crp->socket); - crp->socket = RPC_ANYSOCK; - if (crp->client) { - clnt_destroy(crp->client); - crp->client = NULL; + if ((nettype == NULL) || (nettype[0] == NULL)) + 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); } - if ((hp = gethostbyname(host)) == NULL) - return ((int) RPC_UNKNOWNHOST); + /* + * 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; - memset(&server_addr, 0, sizeof(server_addr)); - memcpy((char *)&server_addr.sin_addr, hp->h_addr, hp->h_length); - server_addr.sin_len = sizeof(struct sockaddr_in); - server_addr.sin_family = AF_INET; - server_addr.sin_port = 0; - if ((crp->client = clntudp_create(&server_addr, (u_long)prognum, - (u_long)versnum, timeout, &crp->socket)) == NULL) - return ((int) rpc_createerr.cf_stat); - crp->valid = 1; - crp->oldprognum = prognum; - crp->oldversnum = versnum; - (void) strcpy(crp->oldhost, host); - } + (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; - clnt_stat = clnt_call(crp->client, procnum, inproc, in, + /*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) - crp->valid = 0; - return ((int) clnt_stat); + rcp->valid = 0; + return (clnt_stat); } diff --git a/lib/libc/rpc/clnt_tcp.c b/lib/libc/rpc/clnt_tcp.c deleted file mode 100644 index 9e8e3948d26b..000000000000 --- a/lib/libc/rpc/clnt_tcp.c +++ /dev/null @@ -1,582 +0,0 @@ -/* - * Sun RPC is a product of Sun Microsystems, Inc. and is provided for - * unrestricted use provided that this legend is included on all tape - * media and as a part of the software program in whole or part. Users - * may copy or modify Sun RPC without charge, but are not authorized - * to license or distribute it to anyone else except as part of a product or - * program developed by the user. - * - * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE - * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR - * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. - * - * Sun RPC is provided with no support and without any obligation on the - * part of Sun Microsystems, Inc. to assist in its use, correction, - * modification or enhancement. - * - * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE - * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC - * OR ANY PART THEREOF. - * - * In no event will Sun Microsystems, Inc. be liable for any lost revenue - * or profits or other special, indirect and consequential damages, even if - * Sun has been advised of the possibility of such damages. - * - * Sun Microsystems, Inc. - * 2550 Garcia Avenue - * Mountain View, California 94043 - */ - -#if defined(LIBC_SCCS) && !defined(lint) -/*static char *sccsid = "from: @(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro";*/ -/*static char *sccsid = "from: @(#)clnt_tcp.c 2.2 88/08/01 4.0 RPCSRC";*/ -static char *rcsid = "$FreeBSD$"; -#endif - -/* - * 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 "namespace.h" -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <rpc/rpc.h> -#include <sys/socket.h> -#include <netdb.h> -#include <errno.h> -#include <rpc/pmap_clnt.h> -#include "un-namespace.h" - -#define MCALL_MSG_SIZE 24 - -static int readtcp(); -static int writetcp(); - -static enum clnt_stat clnttcp_call(); -static void clnttcp_abort(); -static void clnttcp_geterr(); -static bool_t clnttcp_freeres(); -static bool_t clnttcp_control(); -static void clnttcp_destroy(); - -static struct clnt_ops tcp_ops = { - clnttcp_call, - clnttcp_abort, - clnttcp_geterr, - clnttcp_freeres, - clnttcp_destroy, - clnttcp_control -}; - -struct ct_data { - int ct_sock; - bool_t ct_closeit; - struct timeval ct_wait; - bool_t ct_waitset; /* wait set by clnt_control? */ - struct sockaddr_in ct_addr; - struct rpc_err ct_error; - char ct_mcall[MCALL_MSG_SIZE]; /* marshalled callmsg */ - u_int ct_mpos; /* pos after marshal */ - XDR ct_xdrs; -}; - -/* - * Create a client handle for a tcp/ip connection. - * If *sockp<0, *sockp is set to a newly created TCP socket and it is - * connected to raddr. If *sockp non-negative then - * raddr is ignored. The rpc/tcp package does buffering - * similar to stdio, so the client must pick send and receive buffer sizes,]; - * 0 => use the default. - * If raddr->sin_port is 0, then a binder on the remote machine is - * consulted for the right port number. - * NB: *sockp is copied into a private area. - * NB: It is the clients responsibility to close *sockp. - * NB: The rpch->cl_auth is set null authentication. Caller may wish to set this - * something more useful. - */ -CLIENT * -clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz) - struct sockaddr_in *raddr; - u_long prog; - u_long vers; - register int *sockp; - u_int sendsz; - u_int recvsz; -{ - CLIENT *h; - register struct ct_data *ct = NULL; - struct timeval now; - struct rpc_msg call_msg; - static u_int32_t disrupt; - - if (disrupt == 0) - disrupt = (u_int32_t)(long)raddr; - - h = (CLIENT *)mem_alloc(sizeof(*h)); - if (h == NULL) { - (void)fprintf(stderr, "clnttcp_create: out of memory\n"); - rpc_createerr.cf_stat = RPC_SYSTEMERROR; - rpc_createerr.cf_error.re_errno = errno; - goto fooy; - } - ct = (struct ct_data *)mem_alloc(sizeof(*ct)); - if (ct == NULL) { - (void)fprintf(stderr, "clnttcp_create: out of memory\n"); - rpc_createerr.cf_stat = RPC_SYSTEMERROR; - rpc_createerr.cf_error.re_errno = errno; - goto fooy; - } - - /* - * If no port number given ask the pmap for one - */ - if (raddr->sin_port == 0) { - u_short port; - if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP)) == 0) { - mem_free((caddr_t)ct, sizeof(struct ct_data)); - mem_free((caddr_t)h, sizeof(CLIENT)); - return ((CLIENT *)NULL); - } - raddr->sin_port = htons(port); - } - - /* - * If no socket given, open one - */ - if (*sockp < 0) { - *sockp = _socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - (void)bindresvport(*sockp, (struct sockaddr_in *)0); - if ((*sockp < 0) - || (_connect(*sockp, (struct sockaddr *)raddr, - sizeof(*raddr)) < 0)) { - rpc_createerr.cf_stat = RPC_SYSTEMERROR; - rpc_createerr.cf_error.re_errno = errno; - if (*sockp != -1) - (void)_close(*sockp); - goto fooy; - } - ct->ct_closeit = TRUE; - } else { - ct->ct_closeit = FALSE; - } - - /* - * Set up private data struct - */ - ct->ct_sock = *sockp; - ct->ct_wait.tv_usec = 0; - ct->ct_waitset = FALSE; - ct->ct_addr = *raddr; - - /* - * Initialize call message - */ - (void)gettimeofday(&now, (struct timezone *)0); - call_msg.rm_xid = (++disrupt) ^ getpid() ^ now.tv_sec ^ now.tv_usec; - call_msg.rm_direction = CALL; - call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; - call_msg.rm_call.cb_prog = prog; - call_msg.rm_call.cb_vers = vers; - - /* - * pre-serialize the static part of the call msg and stash it away - */ - xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, - XDR_ENCODE); - if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { - if (ct->ct_closeit) { - (void)_close(*sockp); - } - goto fooy; - } - 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. - */ - xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, - (caddr_t)ct, readtcp, writetcp); - h->cl_ops = &tcp_ops; - h->cl_private = (caddr_t) ct; - h->cl_auth = authnone_create(); - return (h); - -fooy: - /* - * Something goofed, free stuff and barf - */ - if (ct) - mem_free((caddr_t)ct, sizeof(struct ct_data)); - if (h) - mem_free((caddr_t)h, sizeof(CLIENT)); - return ((CLIENT *)NULL); -} - -static enum clnt_stat -clnttcp_call(h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout) - register CLIENT *h; - u_long proc; - xdrproc_t xdr_args; - caddr_t args_ptr; - xdrproc_t xdr_results; - caddr_t results_ptr; - struct timeval timeout; -{ - register struct ct_data *ct = (struct ct_data *) h->cl_private; - register XDR *xdrs = &(ct->ct_xdrs); - struct rpc_msg reply_msg; - u_long x_id; - u_int32_t *msg_x_id = (u_int32_t *)(ct->ct_mcall); /* yuk */ - register bool_t shipnow; - int refreshes = 2; - - if (!ct->ct_waitset) { - ct->ct_wait = timeout; - } - - shipnow = - (xdr_results == (xdrproc_t)0 && timeout.tv_sec == 0 - && timeout.tv_usec == 0) ? FALSE : TRUE; - -call_again: - xdrs->x_op = XDR_ENCODE; - ct->ct_error.re_status = RPC_SUCCESS; - x_id = ntohl(--(*msg_x_id)); - if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) || - (! XDR_PUTLONG(xdrs, (long *)&proc)) || - (! AUTH_MARSHALL(h->cl_auth, xdrs)) || - (! (*xdr_args)(xdrs, args_ptr))) { - if (ct->ct_error.re_status == RPC_SUCCESS) - ct->ct_error.re_status = RPC_CANTENCODEARGS; - (void)xdrrec_endofrecord(xdrs, TRUE); - return (ct->ct_error.re_status); - } - if (! xdrrec_endofrecord(xdrs, shipnow)) - return (ct->ct_error.re_status = RPC_CANTSEND); - if (! shipnow) - return (RPC_SUCCESS); - /* - * Hack to provide rpc-based message passing - */ - if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { - 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 = xdr_void; - if (! xdrrec_skiprecord(xdrs)) - 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; - 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(h->cl_auth, &reply_msg.acpted_rply.ar_verf)) { - ct->ct_error.re_status = RPC_AUTHERROR; - ct->ct_error.re_why = AUTH_INVALIDRESP; - } else if (! (*xdr_results)(xdrs, results_ptr)) { - if (ct->ct_error.re_status == RPC_SUCCESS) - ct->ct_error.re_status = RPC_CANTDECODERES; - } - /* free verifier ... */ - if (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(h->cl_auth)) - goto call_again; - } /* end of unsuccessful completion */ - return (ct->ct_error.re_status); -} - -static void -clnttcp_geterr(h, errp) - CLIENT *h; - struct rpc_err *errp; -{ - register struct ct_data *ct = - (struct ct_data *) h->cl_private; - - *errp = ct->ct_error; -} - -static bool_t -clnttcp_freeres(cl, xdr_res, res_ptr) - CLIENT *cl; - xdrproc_t xdr_res; - caddr_t res_ptr; -{ - register struct ct_data *ct = (struct ct_data *)cl->cl_private; - register XDR *xdrs = &(ct->ct_xdrs); - - xdrs->x_op = XDR_FREE; - return ((*xdr_res)(xdrs, res_ptr)); -} - -static void -clnttcp_abort() -{ -} - - -static bool_t -clnttcp_control(cl, request, info) - CLIENT *cl; - int request; - char *info; -{ - register struct ct_data *ct = (struct ct_data *)cl->cl_private; - register struct timeval *tv; - int len; - - switch (request) { - case CLSET_FD_CLOSE: - ct->ct_closeit = TRUE; - break; - case CLSET_FD_NCLOSE: - ct->ct_closeit = FALSE; - break; - case CLSET_TIMEOUT: - if (info == NULL) - return(FALSE); - tv = (struct timeval *)info; - ct->ct_wait.tv_sec = tv->tv_sec; - ct->ct_wait.tv_usec = tv->tv_usec; - ct->ct_waitset = TRUE; - break; - case CLGET_TIMEOUT: - if (info == NULL) - return(FALSE); - *(struct timeval *)info = ct->ct_wait; - break; - case CLGET_SERVER_ADDR: - if (info == NULL) - return(FALSE); - *(struct sockaddr_in *)info = ct->ct_addr; - break; - case CLGET_FD: - if (info == NULL) - return(FALSE); - *(int *)info = ct->ct_sock; - 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 - */ - if (info == NULL) - return(FALSE); - *(u_long *)info = ntohl(*(u_long *)ct->ct_mcall); - break; - case CLSET_XID: - /* This will set the xid of the NEXT call */ - if (info == NULL) - return(FALSE); - *(u_long *)ct->ct_mcall = htonl(*(u_long *)info - 1); - /* decrement by 1 as clnttcp_call() increments once */ - 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 - */ - if (info == NULL) - return(FALSE); - *(u_long *)info = ntohl(*(u_long *)(ct->ct_mcall + - 4 * BYTES_PER_XDR_UNIT)); - break; - case CLSET_VERS: - if (info == NULL) - return(FALSE); - *(u_long *)(ct->ct_mcall + 4 * BYTES_PER_XDR_UNIT) - = htonl(*(u_long *)info); - break; - case CLGET_PROG: - /* - * This RELIES on the information that, in the call body, - * the program number field is the field from the - * begining of the RPC header. MUST be changed if the - * call_struct is changed - */ - if (info == NULL) - return(FALSE); - *(u_long *)info = ntohl(*(u_long *)(ct->ct_mcall + - 3 * BYTES_PER_XDR_UNIT)); - break; - case CLSET_PROG: - if (info == NULL) - return(FALSE); - *(u_long *)(ct->ct_mcall + 3 * BYTES_PER_XDR_UNIT) - = htonl(*(u_long *)info); - break; - case CLGET_LOCAL_ADDR: - len = sizeof(struct sockaddr); - if (_getsockname(ct->ct_sock, (struct sockaddr *)info, &len) <0) - return(FALSE); - break; - case CLGET_RETRY_TIMEOUT: - case CLSET_RETRY_TIMEOUT: - case CLGET_SVC_ADDR: - case CLSET_SVC_ADDR: - case CLSET_PUSH_TIMOD: - case CLSET_POP_TIMOD: - default: - return (FALSE); - } - return (TRUE); -} - - -static void -clnttcp_destroy(h) - CLIENT *h; -{ - register struct ct_data *ct = - (struct ct_data *) h->cl_private; - - if (ct->ct_closeit) { - (void)_close(ct->ct_sock); - } - XDR_DESTROY(&(ct->ct_xdrs)); - mem_free((caddr_t)ct, sizeof(struct ct_data)); - mem_free((caddr_t)h, sizeof(CLIENT)); -} - -/* - * 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 -readtcp(ct, buf, len) - register struct ct_data *ct; - caddr_t buf; - register int len; -{ - fd_set *fds, readfds; - struct timeval start, after, duration, delta, tmp, tv; - int r, save_errno; - - if (len == 0) - return (0); - - if (ct->ct_sock + 1 > FD_SETSIZE) { - int bytes = howmany(ct->ct_sock + 1, NFDBITS) * sizeof(fd_mask); - fds = (fd_set *)malloc(bytes); - if (fds == NULL) - return (-1); - memset(fds, 0, bytes); - } else { - fds = &readfds; - FD_ZERO(fds); - } - - gettimeofday(&start, NULL); - delta = ct->ct_wait; - while (TRUE) { - /* XXX we know the other bits are still clear */ - FD_SET(ct->ct_sock, fds); - tv = delta; /* in case select writes back */ - r = _select(ct->ct_sock+1, fds, NULL, NULL, &tv); - save_errno = errno; - - gettimeofday(&after, NULL); - timersub(&start, &after, &duration); - timersub(&ct->ct_wait, &duration, &tmp); - delta = tmp; - if (delta.tv_sec < 0 || !timerisset(&delta)) - r = 0; - - switch (r) { - case 0: - if (fds != &readfds) - free(fds); - ct->ct_error.re_status = RPC_TIMEDOUT; - return (-1); - - case -1: - if (errno == EINTR) - continue; - if (fds != &readfds) - free(fds); - ct->ct_error.re_status = RPC_CANTRECV; - ct->ct_error.re_errno = save_errno; - return (-1); - } - break; - } - switch (len = _read(ct->ct_sock, buf, 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 -writetcp(ct, buf, len) - struct ct_data *ct; - caddr_t buf; - int len; -{ - register int i, cnt; - - for (cnt = len; cnt > 0; cnt -= i, buf += i) { - if ((i = _write(ct->ct_sock, buf, cnt)) == -1) { - ct->ct_error.re_errno = errno; - ct->ct_error.re_status = RPC_CANTSEND; - return (-1); - } - } - return (len); -} diff --git a/lib/libc/rpc/clnt_udp.c b/lib/libc/rpc/clnt_udp.c deleted file mode 100644 index bc103ed09503..000000000000 --- a/lib/libc/rpc/clnt_udp.c +++ /dev/null @@ -1,569 +0,0 @@ -/* - * Sun RPC is a product of Sun Microsystems, Inc. and is provided for - * unrestricted use provided that this legend is included on all tape - * media and as a part of the software program in whole or part. Users - * may copy or modify Sun RPC without charge, but are not authorized - * to license or distribute it to anyone else except as part of a product or - * program developed by the user. - * - * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE - * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR - * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. - * - * Sun RPC is provided with no support and without any obligation on the - * part of Sun Microsystems, Inc. to assist in its use, correction, - * modification or enhancement. - * - * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE - * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC - * OR ANY PART THEREOF. - * - * In no event will Sun Microsystems, Inc. be liable for any lost revenue - * or profits or other special, indirect and consequential damages, even if - * Sun has been advised of the possibility of such damages. - * - * Sun Microsystems, Inc. - * 2550 Garcia Avenue - * Mountain View, California 94043 - */ - -#if defined(LIBC_SCCS) && !defined(lint) -/*static char *sccsid = "from: @(#)clnt_udp.c 1.39 87/08/11 Copyr 1984 Sun Micro";*/ -/*static char *sccsid = "from: @(#)clnt_udp.c 2.2 88/08/01 4.0 RPCSRC";*/ -static char *rcsid = "$FreeBSD$"; -#endif - -/* - * clnt_udp.c, Implements a UDP/IP based, client side RPC. - * - * Copyright (C) 1984, Sun Microsystems, Inc. - */ - -#include "namespace.h" -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <rpc/rpc.h> -#include <sys/socket.h> -#include <sys/ioctl.h> -#include <netdb.h> -#include <errno.h> -#include <rpc/pmap_clnt.h> -#include "un-namespace.h" - -/* - * UDP bases client side rpc operations - */ -static enum clnt_stat clntudp_call(); -static void clntudp_abort(); -static void clntudp_geterr(); -static bool_t clntudp_freeres(); -static bool_t clntudp_control(); -static void clntudp_destroy(); - -static struct clnt_ops udp_ops = { - clntudp_call, - clntudp_abort, - clntudp_geterr, - clntudp_freeres, - clntudp_destroy, - clntudp_control -}; - -/* - * Private data kept per client handle - */ -struct cu_data { - int cu_sock; - bool_t cu_closeit; - struct sockaddr_in cu_raddr; - int cu_rlen; - struct timeval cu_wait; - struct timeval cu_total; - struct rpc_err cu_error; - XDR cu_outxdrs; - u_int cu_xdrpos; - u_int cu_sendsz; - char *cu_outbuf; - u_int cu_recvsz; - char cu_inbuf[1]; -}; - -/* - * Create a UDP based client handle. - * If *sockp<0, *sockp is set to a newly created UPD socket. - * If raddr->sin_port is 0 a binder on the remote machine - * is consulted for the correct port number. - * NB: It is the clients responsibility to close *sockp. - * NB: The rpch->cl_auth is initialized to null authentication. - * Caller may wish to set this something more useful. - * - * wait is the amount of time used between retransmitting a call if - * no response has been heard; retransmition occurs until the actual - * rpc call times out. - * - * sendsz and recvsz are the maximum allowable packet sizes that can be - * sent and received. - */ -CLIENT * -clntudp_bufcreate(raddr, program, version, wait, sockp, sendsz, recvsz) - struct sockaddr_in *raddr; - u_long program; - u_long version; - struct timeval wait; - register int *sockp; - u_int sendsz; - u_int recvsz; -{ - CLIENT *cl; - register struct cu_data *cu = NULL; - struct timeval now; - struct rpc_msg call_msg; - static u_int32_t disrupt; - - if (disrupt == 0) - disrupt = (u_int32_t)(long)raddr; - - cl = (CLIENT *)mem_alloc(sizeof(CLIENT)); - if (cl == NULL) { - (void) fprintf(stderr, "clntudp_create: out of memory\n"); - rpc_createerr.cf_stat = RPC_SYSTEMERROR; - rpc_createerr.cf_error.re_errno = errno; - goto fooy; - } - sendsz = ((sendsz + 3) / 4) * 4; - recvsz = ((recvsz + 3) / 4) * 4; - cu = (struct cu_data *)mem_alloc(sizeof(*cu) + sendsz + recvsz); - if (cu == NULL) { - (void) fprintf(stderr, "clntudp_create: out of memory\n"); - rpc_createerr.cf_stat = RPC_SYSTEMERROR; - rpc_createerr.cf_error.re_errno = errno; - goto fooy; - } - cu->cu_outbuf = &cu->cu_inbuf[recvsz]; - - (void)gettimeofday(&now, (struct timezone *)0); - if (raddr->sin_port == 0) { - u_short port; - if ((port = - pmap_getport(raddr, program, version, IPPROTO_UDP)) == 0) { - goto fooy; - } - raddr->sin_port = htons(port); - } - cl->cl_ops = &udp_ops; - cl->cl_private = (caddr_t)cu; - cu->cu_raddr = *raddr; - cu->cu_rlen = sizeof (cu->cu_raddr); - cu->cu_wait = wait; - cu->cu_total.tv_sec = -1; - cu->cu_total.tv_usec = -1; - cu->cu_sendsz = sendsz; - cu->cu_recvsz = recvsz; - call_msg.rm_xid = (++disrupt) ^ getpid() ^ now.tv_sec ^ now.tv_usec; - call_msg.rm_direction = CALL; - call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; - 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)) { - goto fooy; - } - cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs)); - if (*sockp < 0) { - int dontblock = 1; - - *sockp = _socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (*sockp < 0) { - rpc_createerr.cf_stat = RPC_SYSTEMERROR; - rpc_createerr.cf_error.re_errno = errno; - goto fooy; - } - /* attempt to bind to priv port */ - (void)bindresvport(*sockp, (struct sockaddr_in *)0); - /* the sockets rpc controls are non-blocking */ - (void)_ioctl(*sockp, FIONBIO, (char *) &dontblock); - cu->cu_closeit = TRUE; - } else { - cu->cu_closeit = FALSE; - } - cu->cu_sock = *sockp; - cl->cl_auth = authnone_create(); - return (cl); -fooy: - if (cu) - mem_free((caddr_t)cu, sizeof(*cu) + sendsz + recvsz); - if (cl) - mem_free((caddr_t)cl, sizeof(CLIENT)); - return ((CLIENT *)NULL); -} - -CLIENT * -clntudp_create(raddr, program, version, wait, sockp) - struct sockaddr_in *raddr; - u_long program; - u_long version; - struct timeval wait; - register int *sockp; -{ - - return(clntudp_bufcreate(raddr, program, version, wait, sockp, - UDPMSGSIZE, UDPMSGSIZE)); -} - -static enum clnt_stat -clntudp_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout) - register CLIENT *cl; /* client handle */ - u_long 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 */ - struct timeval utimeout; /* seconds to wait before giving up */ -{ - register struct cu_data *cu = (struct cu_data *)cl->cl_private; - register XDR *xdrs; - register int outlen; - register int inlen; - int fromlen; - fd_set *fds, readfds; - struct sockaddr_in from; - struct rpc_msg reply_msg; - XDR reply_xdrs; - struct timeval time_waited, start, after, tmp1, tmp2, tv; - bool_t ok; - int nrefreshes = 2; /* number of times to refresh cred */ - struct timeval timeout; - - if (cu->cu_total.tv_usec == -1) - timeout = utimeout; /* use supplied timeout */ - else - timeout = cu->cu_total; /* use default timeout */ - - if (cu->cu_sock + 1 > FD_SETSIZE) { - int bytes = howmany(cu->cu_sock + 1, NFDBITS) * sizeof(fd_mask); - fds = (fd_set *)malloc(bytes); - if (fds == NULL) - return (cu->cu_error.re_status = RPC_CANTSEND); - memset(fds, 0, bytes); - } else { - fds = &readfds; - FD_ZERO(fds); - } - - timerclear(&time_waited); - -call_again: - xdrs = &(cu->cu_outxdrs); - xdrs->x_op = XDR_ENCODE; - XDR_SETPOS(xdrs, cu->cu_xdrpos); - /* - * the transaction is the first thing in the out buffer - */ - (*(u_short *)(cu->cu_outbuf))++; - if ((! XDR_PUTLONG(xdrs, (long *)&proc)) || - (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || - (! (*xargs)(xdrs, argsp))) { - if (fds != &readfds) - free(fds); - return (cu->cu_error.re_status = RPC_CANTENCODEARGS); - } - outlen = (int)XDR_GETPOS(xdrs); - -send_again: - if (_sendto(cu->cu_sock, cu->cu_outbuf, outlen, 0, - (struct sockaddr *)&(cu->cu_raddr), cu->cu_rlen) != outlen) { - cu->cu_error.re_errno = errno; - if (fds != &readfds) - free(fds); - return (cu->cu_error.re_status = RPC_CANTSEND); - } - - /* - * Hack to provide rpc-based message passing - */ - if (!timerisset(&timeout)) { - if (fds != &readfds) - free(fds); - return (cu->cu_error.re_status = RPC_TIMEDOUT); - } - /* - * sub-optimal code appears here because we have - * some clock time to spare while the packets are in flight. - * (We assume that this is actually only executed once.) - */ - reply_msg.acpted_rply.ar_verf = _null_auth; - reply_msg.acpted_rply.ar_results.where = resultsp; - reply_msg.acpted_rply.ar_results.proc = xresults; - - gettimeofday(&start, NULL); - for (;;) { - /* XXX we know the other bits are still clear */ - FD_SET(cu->cu_sock, fds); - tv = cu->cu_wait; - switch (_select(cu->cu_sock+1, fds, NULL, NULL, &tv)) { - - case 0: - timeradd(&time_waited, &cu->cu_wait, &tmp1); - time_waited = tmp1; - if (timercmp(&time_waited, &timeout, <)) - goto send_again; - if (fds != &readfds) - free(fds); - return (cu->cu_error.re_status = RPC_TIMEDOUT); - - case -1: - if (errno == EINTR) { - gettimeofday(&after, NULL); - timersub(&after, &start, &tmp1); - timeradd(&time_waited, &tmp1, &tmp2); - time_waited = tmp2; - if (timercmp(&time_waited, &timeout, <)) - continue; - if (fds != &readfds) - free(fds); - return (cu->cu_error.re_status = RPC_TIMEDOUT); - } - cu->cu_error.re_errno = errno; - if (fds != &readfds) - free(fds); - return (cu->cu_error.re_status = RPC_CANTRECV); - } - - do { - fromlen = sizeof(struct sockaddr); - inlen = _recvfrom(cu->cu_sock, cu->cu_inbuf, - (int) cu->cu_recvsz, 0, - (struct sockaddr *)&from, &fromlen); - } while (inlen < 0 && errno == EINTR); - if (inlen < 0) { - if (errno == EWOULDBLOCK) - continue; - cu->cu_error.re_errno = errno; - if (fds != &readfds) - free(fds); - return (cu->cu_error.re_status = RPC_CANTRECV); - } - if (inlen < sizeof(u_int32_t)) - continue; - /* see if reply transaction id matches sent id */ - if (*((u_int32_t *)(cu->cu_inbuf)) != *((u_int32_t *)(cu->cu_outbuf))) - continue; - /* we now assume we have the proper reply */ - break; - } - - /* - * now decode and validate the response - */ - xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)inlen, XDR_DECODE); - ok = xdr_replymsg(&reply_xdrs, &reply_msg); - /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */ - if (ok) { - _seterr_reply(&reply_msg, &(cu->cu_error)); - if (cu->cu_error.re_status == RPC_SUCCESS) { - if (! AUTH_VALIDATE(cl->cl_auth, - &reply_msg.acpted_rply.ar_verf)) { - cu->cu_error.re_status = RPC_AUTHERROR; - cu->cu_error.re_why = AUTH_INVALIDRESP; - } - if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { - xdrs->x_op = XDR_FREE; - (void)xdr_opaque_auth(xdrs, - &(reply_msg.acpted_rply.ar_verf)); - } - } /* end successful completion */ - else { - /* maybe our credentials need to be refreshed ... */ - if (nrefreshes > 0 && AUTH_REFRESH(cl->cl_auth)) { - nrefreshes--; - goto call_again; - } - } /* end of unsuccessful completion */ - } /* end of valid reply message */ - else { - /* - * 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 = reply_xdrs.x_op; - reply_xdrs.x_op = XDR_FREE; - xdr_replymsg(&reply_xdrs, &reply_msg); - reply_xdrs.x_op = op; - cu->cu_error.re_status = RPC_CANTDECODERES; - } - if (fds != &readfds) - free(fds); - return (cu->cu_error.re_status); -} - -static void -clntudp_geterr(cl, errp) - CLIENT *cl; - struct rpc_err *errp; -{ - register struct cu_data *cu = (struct cu_data *)cl->cl_private; - - *errp = cu->cu_error; -} - - -static bool_t -clntudp_freeres(cl, xdr_res, res_ptr) - CLIENT *cl; - xdrproc_t xdr_res; - caddr_t res_ptr; -{ - register struct cu_data *cu = (struct cu_data *)cl->cl_private; - register XDR *xdrs = &(cu->cu_outxdrs); - - xdrs->x_op = XDR_FREE; - return ((*xdr_res)(xdrs, res_ptr)); -} - -static void -clntudp_abort(/*h*/) - /*CLIENT *h;*/ -{ -} - - -static bool_t -clntudp_control(cl, request, info) - CLIENT *cl; - int request; - char *info; -{ - register struct cu_data *cu = (struct cu_data *)cl->cl_private; - register struct timeval *tv; - int len; - - switch (request) { - case CLSET_FD_CLOSE: - cu->cu_closeit = TRUE; - break; - case CLSET_FD_NCLOSE: - cu->cu_closeit = FALSE; - break; - case CLSET_TIMEOUT: - if (info == NULL) - return(FALSE); - tv = (struct timeval *)info; - cu->cu_total.tv_sec = tv->tv_sec; - cu->cu_total.tv_usec = tv->tv_usec; - break; - case CLGET_TIMEOUT: - if (info == NULL) - return(FALSE); - *(struct timeval *)info = cu->cu_total; - break; - case CLSET_RETRY_TIMEOUT: - if (info == NULL) - return(FALSE); - tv = (struct timeval *)info; - cu->cu_wait.tv_sec = tv->tv_sec; - cu->cu_wait.tv_usec = tv->tv_usec; - break; - case CLGET_RETRY_TIMEOUT: - if (info == NULL) - return(FALSE); - *(struct timeval *)info = cu->cu_wait; - break; - case CLGET_SERVER_ADDR: - if (info == NULL) - return(FALSE); - *(struct sockaddr_in *)info = cu->cu_raddr; - break; - case CLGET_FD: - if (info == NULL) - return(FALSE); - *(int *)info = cu->cu_sock; - 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 - */ - if (info == NULL) - return(FALSE); - *(u_long *)info = ntohl(*(u_long *)cu->cu_outbuf); - break; - case CLSET_XID: - /* This will set the xid of the NEXT call */ - if (info == NULL) - return(FALSE); - *(u_long *)cu->cu_outbuf = htonl(*(u_long *)info - 1); - /* decrement by 1 as clntudp_call() increments once */ - 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 - */ - if (info == NULL) - return(FALSE); - *(u_long *)info = ntohl(*(u_long *)(cu->cu_outbuf + - 4 * BYTES_PER_XDR_UNIT)); - break; - case CLSET_VERS: - if (info == NULL) - return(FALSE); - *(u_long *)(cu->cu_outbuf + 4 * BYTES_PER_XDR_UNIT) - = htonl(*(u_long *)info); - break; - case CLGET_PROG: - /* - * This RELIES on the information that, in the call body, - * the program number field is the field from the - * begining of the RPC header. MUST be changed if the - * call_struct is changed - */ - if (info == NULL) - return(FALSE); - *(u_long *)info = ntohl(*(u_long *)(cu->cu_outbuf + - 3 * BYTES_PER_XDR_UNIT)); - break; - case CLSET_PROG: - if (info == NULL) - return(FALSE); - *(u_long *)(cu->cu_outbuf + 3 * BYTES_PER_XDR_UNIT) - = htonl(*(u_long *)info); - break; - case CLGET_LOCAL_ADDR: - len = sizeof(struct sockaddr); - if (_getsockname(cu->cu_sock, (struct sockaddr *)info, &len) <0) - return(FALSE); - break; - case CLGET_SVC_ADDR: - case CLSET_SVC_ADDR: - case CLSET_PUSH_TIMOD: - case CLSET_POP_TIMOD: - default: - return (FALSE); - } - return (TRUE); -} - -static void -clntudp_destroy(cl) - CLIENT *cl; -{ - register struct cu_data *cu = (struct cu_data *)cl->cl_private; - - if (cu->cu_closeit) { - (void)_close(cu->cu_sock); - } - XDR_DESTROY(&(cu->cu_outxdrs)); - mem_free((caddr_t)cu, (sizeof(*cu) + cu->cu_sendsz + cu->cu_recvsz)); - mem_free((caddr_t)cl, sizeof(CLIENT)); -} diff --git a/lib/libc/rpc/clnt_unix.c b/lib/libc/rpc/clnt_unix.c deleted file mode 100644 index d55859ca1fdb..000000000000 --- a/lib/libc/rpc/clnt_unix.c +++ /dev/null @@ -1,637 +0,0 @@ -/* - * Sun RPC is a product of Sun Microsystems, Inc. and is provided for - * unrestricted use provided that this legend is included on all tape - * media and as a part of the software program in whole or part. Users - * may copy or modify Sun RPC without charge, but are not authorized - * to license or distribute it to anyone else except as part of a product or - * program developed by the user. - * - * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE - * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR - * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. - * - * Sun RPC is provided with no support and without any obligation on the - * part of Sun Microsystems, Inc. to assist in its use, correction, - * modification or enhancement. - * - * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE - * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC - * OR ANY PART THEREOF. - * - * In no event will Sun Microsystems, Inc. be liable for any lost revenue - * or profits or other special, indirect and consequential damages, even if - * Sun has been advised of the possibility of such damages. - * - * Sun Microsystems, Inc. - * 2550 Garcia Avenue - * Mountain View, California 94043 - */ - -#if defined(LIBC_SCCS) && !defined(lint) -/*static char *sccsid = "from: @(#)clnt_unix.c 1.37 87/10/05 Copyr 1984 Sun Micro";*/ -/*static char *sccsid = "from: @(#)clnt_unix.c 2.2 88/08/01 4.0 RPCSRC";*/ -static char *rcsid = "$FreeBSD$"; -#endif - -/* - * clnt_unix.c, Implements a AF_UNIX based, client side RPC. - * - * Copyright (C) 1984, Sun Microsystems, Inc. - * - * AF_UNIX 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 "namespace.h" -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <rpc/rpc.h> -#include <sys/uio.h> -#include <sys/socket.h> -#include <sys/un.h> -#include <netdb.h> -#include <errno.h> -#include <rpc/pmap_clnt.h> -#include "un-namespace.h" - -#define MCALL_MSG_SIZE 24 - -static int readunix(); -static int writeunix(); - -static enum clnt_stat clntunix_call(); -static void clntunix_abort(); -static void clntunix_geterr(); -static bool_t clntunix_freeres(); -static bool_t clntunix_control(); -static void clntunix_destroy(); - -static struct clnt_ops unix_ops = { - clntunix_call, - clntunix_abort, - clntunix_geterr, - clntunix_freeres, - clntunix_destroy, - clntunix_control -}; - -struct ct_data { - int ct_sock; - bool_t ct_closeit; - struct timeval ct_wait; - bool_t ct_waitset; /* wait set by clnt_control? */ - struct sockaddr_un ct_addr; - struct rpc_err ct_error; - char ct_mcall[MCALL_MSG_SIZE]; /* marshalled callmsg */ - u_int ct_mpos; /* pos after marshal */ - XDR ct_xdrs; -}; - -/* - * Create a client handle for a unix/ip connection. - * If *sockp<0, *sockp is set to a newly created TCP socket and it is - * connected to raddr. If *sockp non-negative then - * raddr is ignored. The rpc/unix package does buffering - * similar to stdio, so the client must pick send and receive buffer sizes,]; - * 0 => use the default. - * If raddr->sin_port is 0, then a binder on the remote machine is - * consulted for the right port number. - * NB: *sockp is copied into a private area. - * NB: It is the clients responsibility to close *sockp. - * NB: The rpch->cl_auth is set null authentication. Caller may wish to set this - * something more useful. - */ -CLIENT * -clntunix_create(raddr, prog, vers, sockp, sendsz, recvsz) - struct sockaddr_un *raddr; - u_long prog; - u_long vers; - register int *sockp; - u_int sendsz; - u_int recvsz; -{ - CLIENT *h; - register struct ct_data *ct = NULL; - struct timeval now; - struct rpc_msg call_msg; - static u_int32_t disrupt; - int len; - - if (disrupt == 0) - disrupt = (u_int32_t)(long)raddr; - - h = (CLIENT *)mem_alloc(sizeof(*h)); - if (h == NULL) { - (void)fprintf(stderr, "clntunix_create: out of memory\n"); - rpc_createerr.cf_stat = RPC_SYSTEMERROR; - rpc_createerr.cf_error.re_errno = errno; - goto fooy; - } - ct = (struct ct_data *)mem_alloc(sizeof(*ct)); - if (ct == NULL) { - (void)fprintf(stderr, "clntunix_create: out of memory\n"); - rpc_createerr.cf_stat = RPC_SYSTEMERROR; - rpc_createerr.cf_error.re_errno = errno; - goto fooy; - } - - /* - * If no socket given, open one - */ - if (*sockp < 0) { - *sockp = _socket(AF_UNIX, SOCK_STREAM, 0); - len = strlen(raddr->sun_path) + sizeof(raddr->sun_family) + - sizeof(raddr->sun_len) + 1; - raddr->sun_len = len; - 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 fooy; - } - ct->ct_closeit = TRUE; - } else { - ct->ct_closeit = FALSE; - } - - /* - * Set up private data struct - */ - ct->ct_sock = *sockp; - ct->ct_wait.tv_usec = 0; - ct->ct_waitset = FALSE; - ct->ct_addr = *raddr; - - /* - * Initialize call message - */ - (void)gettimeofday(&now, (struct timezone *)0); - call_msg.rm_xid = (++disrupt) ^ getpid() ^ now.tv_sec ^ now.tv_usec; - call_msg.rm_direction = CALL; - call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; - call_msg.rm_call.cb_prog = prog; - call_msg.rm_call.cb_vers = vers; - - /* - * pre-serialize the static part of the call msg and stash it away - */ - xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, - XDR_ENCODE); - if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { - if (ct->ct_closeit) { - (void)_close(*sockp); - } - goto fooy; - } - 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. - */ - xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, - (caddr_t)ct, readunix, writeunix); - h->cl_ops = &unix_ops; - h->cl_private = (caddr_t) ct; - h->cl_auth = authnone_create(); - return (h); - -fooy: - /* - * Something goofed, free stuff and barf - */ - if (ct) - mem_free((caddr_t)ct, sizeof(struct ct_data)); - if (h) - mem_free((caddr_t)h, sizeof(CLIENT)); - return ((CLIENT *)NULL); -} - -static enum clnt_stat -clntunix_call(h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout) - register CLIENT *h; - u_long proc; - xdrproc_t xdr_args; - caddr_t args_ptr; - xdrproc_t xdr_results; - caddr_t results_ptr; - struct timeval timeout; -{ - register struct ct_data *ct = (struct ct_data *) h->cl_private; - register XDR *xdrs = &(ct->ct_xdrs); - struct rpc_msg reply_msg; - u_long x_id; - u_int32_t *msg_x_id = (u_int32_t *)(ct->ct_mcall); /* yuk */ - register bool_t shipnow; - int refreshes = 2; - - if (!ct->ct_waitset) { - ct->ct_wait = timeout; - } - - shipnow = - (xdr_results == (xdrproc_t)0 && timeout.tv_sec == 0 - && timeout.tv_usec == 0) ? FALSE : TRUE; - -call_again: - xdrs->x_op = XDR_ENCODE; - ct->ct_error.re_status = RPC_SUCCESS; - x_id = ntohl(--(*msg_x_id)); - if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) || - (! XDR_PUTLONG(xdrs, (long *)&proc)) || - (! AUTH_MARSHALL(h->cl_auth, xdrs)) || - (! (*xdr_args)(xdrs, args_ptr))) { - if (ct->ct_error.re_status == RPC_SUCCESS) - ct->ct_error.re_status = RPC_CANTENCODEARGS; - (void)xdrrec_endofrecord(xdrs, TRUE); - return (ct->ct_error.re_status); - } - if (! xdrrec_endofrecord(xdrs, shipnow)) - return (ct->ct_error.re_status = RPC_CANTSEND); - if (! shipnow) - return (RPC_SUCCESS); - /* - * Hack to provide rpc-based message passing - */ - if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { - 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 = xdr_void; - if (! xdrrec_skiprecord(xdrs)) - 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; - 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(h->cl_auth, &reply_msg.acpted_rply.ar_verf)) { - ct->ct_error.re_status = RPC_AUTHERROR; - ct->ct_error.re_why = AUTH_INVALIDRESP; - } else if (! (*xdr_results)(xdrs, results_ptr)) { - if (ct->ct_error.re_status == RPC_SUCCESS) - ct->ct_error.re_status = RPC_CANTDECODERES; - } - /* free verifier ... */ - if (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(h->cl_auth)) - goto call_again; - } /* end of unsuccessful completion */ - return (ct->ct_error.re_status); -} - -static void -clntunix_geterr(h, errp) - CLIENT *h; - struct rpc_err *errp; -{ - register struct ct_data *ct = - (struct ct_data *) h->cl_private; - - *errp = ct->ct_error; -} - -static bool_t -clntunix_freeres(cl, xdr_res, res_ptr) - CLIENT *cl; - xdrproc_t xdr_res; - caddr_t res_ptr; -{ - register struct ct_data *ct = (struct ct_data *)cl->cl_private; - register XDR *xdrs = &(ct->ct_xdrs); - - xdrs->x_op = XDR_FREE; - return ((*xdr_res)(xdrs, res_ptr)); -} - -static void -clntunix_abort() -{ -} - - -static bool_t -clntunix_control(cl, request, info) - CLIENT *cl; - int request; - char *info; -{ - register struct ct_data *ct = (struct ct_data *)cl->cl_private; - register struct timeval *tv; - int len; - - switch (request) { - case CLSET_FD_CLOSE: - ct->ct_closeit = TRUE; - break; - case CLSET_FD_NCLOSE: - ct->ct_closeit = FALSE; - break; - case CLSET_TIMEOUT: - if (info == NULL) - return(FALSE); - tv = (struct timeval *)info; - ct->ct_wait.tv_sec = tv->tv_sec; - ct->ct_wait.tv_usec = tv->tv_usec; - ct->ct_waitset = TRUE; - break; - case CLGET_TIMEOUT: - if (info == NULL) - return(FALSE); - *(struct timeval *)info = ct->ct_wait; - break; - case CLGET_SERVER_ADDR: - if (info == NULL) - return(FALSE); - *(struct sockaddr_un *)info = ct->ct_addr; - break; - case CLGET_FD: - if (info == NULL) - return(FALSE); - *(int *)info = ct->ct_sock; - 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 - */ - if (info == NULL) - return(FALSE); - *(u_long *)info = ntohl(*(u_long *)ct->ct_mcall); - break; - case CLSET_XID: - /* This will set the xid of the NEXT call */ - if (info == NULL) - return(FALSE); - *(u_long *)ct->ct_mcall = htonl(*(u_long *)info - 1); - /* decrement by 1 as clntunix_call() increments once */ - 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 - */ - if (info == NULL) - return(FALSE); - *(u_long *)info = ntohl(*(u_long *)(ct->ct_mcall + - 4 * BYTES_PER_XDR_UNIT)); - break; - case CLSET_VERS: - if (info == NULL) - return(FALSE); - *(u_long *)(ct->ct_mcall + 4 * BYTES_PER_XDR_UNIT) - = htonl(*(u_long *)info); - break; - case CLGET_PROG: - /* - * This RELIES on the information that, in the call body, - * the program number field is the field from the - * begining of the RPC header. MUST be changed if the - * call_struct is changed - */ - if (info == NULL) - return(FALSE); - *(u_long *)info = ntohl(*(u_long *)(ct->ct_mcall + - 3 * BYTES_PER_XDR_UNIT)); - break; - case CLSET_PROG: - if (info == NULL) - return(FALSE); - *(u_long *)(ct->ct_mcall + 3 * BYTES_PER_XDR_UNIT) - = htonl(*(u_long *)info); - break; - case CLGET_LOCAL_ADDR: - len = sizeof(struct sockaddr); - if (_getsockname(ct->ct_sock, (struct sockaddr *)info, &len) <0) - return(FALSE); - break; - case CLGET_RETRY_TIMEOUT: - case CLSET_RETRY_TIMEOUT: - case CLGET_SVC_ADDR: - case CLSET_SVC_ADDR: - case CLSET_PUSH_TIMOD: - case CLSET_POP_TIMOD: - default: - return (FALSE); - } - return (TRUE); -} - - -static void -clntunix_destroy(h) - CLIENT *h; -{ - register struct ct_data *ct = - (struct ct_data *) h->cl_private; - - if (ct->ct_closeit) { - (void)_close(ct->ct_sock); - } - XDR_DESTROY(&(ct->ct_xdrs)); - mem_free((caddr_t)ct, sizeof(struct ct_data)); - mem_free((caddr_t)h, sizeof(CLIENT)); -} - -/* - * _read() and _write() are replaced with _recvmsg()/_sendmsg() so that - * we can pass ancillary control data. In this case, the data constists - * of credential information which the kernel will fill in for us. - * XXX: This code is specific to FreeBSD and will not work on other - * platforms without the requisite kernel modifications. - */ -struct cmessage { - struct cmsghdr cmsg; - struct cmsgcred cmcred; -}; - -static int __msgread(sock, buf, cnt) - int sock; - void *buf; - size_t cnt; -{ - struct iovec iov[1]; - struct msghdr msg; - struct cmessage cm; - - bzero((char *)&cm, sizeof(cm)); - iov[0].iov_base = buf; - iov[0].iov_len = cnt; - - msg.msg_iov = iov; - msg.msg_iovlen = 1; - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_control = (caddr_t)&cm; - msg.msg_controllen = sizeof(struct cmessage); - msg.msg_flags = 0; - - return(_recvmsg(sock, &msg, 0)); -} - -static int __msgwrite(sock, buf, cnt) - int sock; - void *buf; - size_t cnt; -{ - struct iovec iov[1]; - struct msghdr msg; - struct cmessage cm; - - bzero((char *)&cm, sizeof(cm)); - iov[0].iov_base = buf; - iov[0].iov_len = cnt; - - cm.cmsg.cmsg_type = SCM_CREDS; - cm.cmsg.cmsg_level = SOL_SOCKET; - cm.cmsg.cmsg_len = sizeof(struct cmessage); - - msg.msg_iov = iov; - msg.msg_iovlen = 1; - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_control = (caddr_t)&cm; - msg.msg_controllen = sizeof(struct cmessage); - msg.msg_flags = 0; - - return(_sendmsg(sock, &msg, 0)); -} - -/* - * Interface between xdr serializer and unix connection. - * Behaves like the system calls, read & write, but keeps some error state - * around for the rpc level. - */ -static int -readunix(ct, buf, len) - register struct ct_data *ct; - caddr_t buf; - register int len; -{ - fd_set *fds, readfds; - struct timeval start, after, duration, delta, tmp, tv; - int r, save_errno; - - if (len == 0) - return (0); - - if (ct->ct_sock + 1 > FD_SETSIZE) { - int bytes = howmany(ct->ct_sock + 1, NFDBITS) * sizeof(fd_mask); - fds = (fd_set *)malloc(bytes); - if (fds == NULL) - return (-1); - memset(fds, 0, bytes); - } else { - fds = &readfds; - FD_ZERO(fds); - } - - gettimeofday(&start, NULL); - delta = ct->ct_wait; - while (TRUE) { - /* XXX we know the other bits are still clear */ - FD_SET(ct->ct_sock, fds); - tv = delta; /* in case select writes back */ - r = _select(ct->ct_sock+1, fds, NULL, NULL, &tv); - save_errno = errno; - - gettimeofday(&after, NULL); - timersub(&start, &after, &duration); - timersub(&delta, &duration, &tmp); - delta = tmp; - if (delta.tv_sec < 0 || !timerisset(&delta)) - r = 0; - - switch (r) { - case 0: - if (fds != &readfds) - free(fds); - ct->ct_error.re_status = RPC_TIMEDOUT; - return (-1); - - case -1: - if (errno == EINTR) - continue; - if (fds != &readfds) - free(fds); - ct->ct_error.re_status = RPC_CANTRECV; - ct->ct_error.re_errno = save_errno; - return (-1); - } - break; - } - switch (len = __msgread(ct->ct_sock, buf, 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 -writeunix(ct, buf, len) - struct ct_data *ct; - caddr_t buf; - int len; -{ - register int i, cnt; - - for (cnt = len; cnt > 0; cnt -= i, buf += i) { - if ((i = __msgwrite(ct->ct_sock, buf, cnt)) == -1) { - ct->ct_error.re_errno = errno; - ct->ct_error.re_status = RPC_CANTSEND; - return (-1); - } - } - return (len); -} diff --git a/lib/libc/rpc/clnt_vc.c b/lib/libc/rpc/clnt_vc.c new file mode 100644 index 000000000000..bce8fbe31ae1 --- /dev/null +++ b/lib/libc/rpc/clnt_vc.c @@ -0,0 +1,839 @@ +/* $NetBSD: clnt_vc.c,v 1.4 2000/07/14 08:40:42 fvdl Exp $ */ +/* $FreeBSD$ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +static char *sccsid = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro"; +static char *sccsid = "@(#)clnt_tcp.c 2.2 88/08/01 4.0 RPCSRC"; +static char sccsid[] = "@(#)clnt_vc.c 1.19 89/03/16 Copyr 1988 Sun Micro"; +#endif + +/* + * 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 "reentrant.h" +#include "namespace.h" +#include <sys/types.h> +#include <sys/poll.h> +#include <sys/syslog.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/uio.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 <rpc/rpc.h> +#include "un-namespace.h" +#include "rpc_com.h" + +#define MCALL_MSG_SIZE 24 + +static enum clnt_stat clnt_vc_call __P((CLIENT *, rpcproc_t, xdrproc_t, caddr_t, + xdrproc_t, caddr_t, struct timeval)); +static void clnt_vc_geterr __P((CLIENT *, struct rpc_err *)); +static bool_t clnt_vc_freeres __P((CLIENT *, xdrproc_t, caddr_t)); +static void clnt_vc_abort __P((CLIENT *)); +static bool_t clnt_vc_control __P((CLIENT *, u_int, char *)); +static void clnt_vc_destroy __P((CLIENT *)); +static struct clnt_ops *clnt_vc_ops __P((void)); +static bool_t time_not_ok __P((struct timeval *)); +static int read_vc __P((caddr_t, caddr_t, int)); +static int write_vc __P((caddr_t, caddr_t, int)); +static int __msgwrite(int, void *, size_t); +static int __msgread(int, void *, size_t); + +struct ct_data { + int ct_fd; /* connection's fd */ + bool_t ct_closeit; /* close it on destroy */ + struct timeval ct_wait; /* wait interval in milliseconds */ + bool_t ct_waitset; /* wait set by clnt_control? */ + struct netbuf ct_addr; /* remote addr */ + struct rpc_err ct_error; + union { + char ct_mcallc[MCALL_MSG_SIZE]; /* marshalled callmsg */ + u_int32_t ct_mcalli; + } ct_u; + u_int ct_mpos; /* pos after marshal */ + XDR ct_xdrs; /* XDR stream */ +}; + +struct cmessage { + struct cmsghdr cmsg; + struct cmsgcred cmcred; +}; + + +/* + * This machinery implements per-fd locks for MT-safety. It is not + * sufficient to do per-CLIENT handle locks for MT-safety because a + * user may create more than one CLIENT handle with the same fd behind + * it. Therfore, we allocate an array of flags (vc_fd_locks), protected + * by the clnt_fd_lock mutex, and an array (vc_cv) of condition variables + * similarly protected. Vc_fd_lock[fd] == 1 => a call is activte on some + * CLIENT handle created for that fd. + * The current implementation holds locks across the entire RPC and reply. + * Yes, this is silly, and as soon as this code is proven to work, this + * should be the first thing fixed. One step at a time. + */ +static int *vc_fd_locks; +extern mutex_t clnt_fd_lock; +static cond_t *vc_cv; +#define release_fd_lock(fd, mask) { \ + mutex_lock(&clnt_fd_lock); \ + if (__isthreaded) \ + vc_fd_locks[fd] = 0; \ + mutex_unlock(&clnt_fd_lock); \ + thr_sigsetmask(SIG_SETMASK, &(mask), (sigset_t *) NULL); \ + cond_signal(&vc_cv[fd]); \ +} + +static const char clnt_vc_errstr[] = "%s : %s"; +static const char clnt_vc_str[] = "clnt_vc_create"; +static const char clnt_read_vc_str[] = "read_vc"; +static const char __no_mem_str[] = "out of memory"; + +/* + * 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 */ + rpcprog_t prog; /* program number */ + 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; + + if (disrupt == 0) + disrupt = (u_int32_t)(long)raddr; + + cl = (CLIENT *)mem_alloc(sizeof (*cl)); + ct = (struct ct_data *)mem_alloc(sizeof (*ct)); + if ((cl == (CLIENT *)NULL) || (ct == (struct ct_data *)NULL)) { + (void) syslog(LOG_ERR, clnt_vc_errstr, + clnt_vc_str, __no_mem_str); + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + goto err; + } + ct->ct_addr.buf = NULL; + sigfillset(&newmask); + thr_sigsetmask(SIG_SETMASK, &newmask, &mask); + mutex_lock(&clnt_fd_lock); + if (vc_fd_locks == (int *) NULL) { + int cv_allocsz, fd_allocsz; + int dtbsize = __rpc_dtbsize(); + + fd_allocsz = dtbsize * sizeof (int); + vc_fd_locks = (int *) mem_alloc(fd_allocsz); + if (vc_fd_locks == (int *) NULL) { + mutex_unlock(&clnt_fd_lock); + thr_sigsetmask(SIG_SETMASK, &(mask), NULL); + goto err; + } else + memset(vc_fd_locks, '\0', fd_allocsz); + + assert(vc_cv == (cond_t *) NULL); + cv_allocsz = dtbsize * sizeof (cond_t); + vc_cv = (cond_t *) mem_alloc(cv_allocsz); + if (vc_cv == (cond_t *) NULL) { + mem_free(vc_fd_locks, fd_allocsz); + vc_fd_locks = (int *) NULL; + mutex_unlock(&clnt_fd_lock); + thr_sigsetmask(SIG_SETMASK, &(mask), NULL); + goto err; + } else { + int i; + + for (i = 0; i < dtbsize; i++) + cond_init(&vc_cv[i], 0, (void *) 0); + } + } else + assert(vc_cv != (cond_t *) NULL); + + /* + * XXX - fvdl connecting while holding a mutex? + */ + slen = sizeof ss; + if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { + if (errno != ENOTCONN) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + mutex_unlock(&clnt_fd_lock); + goto err; + } + if (_connect(fd, (struct sockaddr *)raddr->buf, raddr->len) < 0){ + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + mutex_unlock(&clnt_fd_lock); + goto err; + } + } + mutex_unlock(&clnt_fd_lock); + if (!__rpc_fd2sockinfo(fd, &si)) + goto err; + thr_sigsetmask(SIG_SETMASK, &(mask), NULL); + + ct->ct_closeit = FALSE; + + /* + * Set up private data struct + */ + ct->ct_fd = fd; + ct->ct_wait.tv_usec = 0; + ct->ct_waitset = FALSE; + ct->ct_addr.buf = malloc(raddr->maxlen); + if (ct->ct_addr.buf == NULL) + goto err; + memcpy(ct->ct_addr.buf, &raddr->buf, raddr->len); + ct->ct_addr.len = raddr->maxlen; + ct->ct_addr.maxlen = raddr->maxlen; + + /* + * Initialize call message + */ + (void)gettimeofday(&now, NULL); + call_msg.rm_xid = ((u_int32_t)++disrupt) ^ __RPC_GETXID(&now); + call_msg.rm_direction = CALL; + call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; + call_msg.rm_call.cb_prog = (u_int32_t)prog; + call_msg.rm_call.cb_vers = (u_int32_t)vers; + + /* + * pre-serialize the static part of the call msg and stash it away + */ + xdrmem_create(&(ct->ct_xdrs), ct->ct_u.ct_mcallc, MCALL_MSG_SIZE, + XDR_ENCODE); + if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { + if (ct->ct_closeit) { + (void)_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((caddr_t)ct, sizeof (struct ct_data)); + } + if (cl) + mem_free((caddr_t)cl, sizeof (CLIENT)); + } + return ((CLIENT *)NULL); +} + +static enum clnt_stat +clnt_vc_call(cl, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout) + CLIENT *cl; + rpcproc_t proc; + xdrproc_t xdr_args; + caddr_t args_ptr; + xdrproc_t xdr_results; + caddr_t 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; + int rpc_lock_value; + + assert(cl != NULL); + + sigfillset(&newmask); + thr_sigsetmask(SIG_SETMASK, &newmask, &mask); + mutex_lock(&clnt_fd_lock); + while (vc_fd_locks[ct->ct_fd]) + cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock); + if (__isthreaded) + rpc_lock_value = 1; + else + rpc_lock_value = 0; + vc_fd_locks[ct->ct_fd] = rpc_lock_value; + 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; + +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, &proc)) || + (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || + (! (*xdr_args)(xdrs, args_ptr))) { + if (ct->ct_error.re_status == RPC_SUCCESS) + ct->ct_error.re_status = RPC_CANTENCODEARGS; + (void)xdrrec_endofrecord(xdrs, TRUE); + release_fd_lock(ct->ct_fd, mask); + return (ct->ct_error.re_status); + } + if (! xdrrec_endofrecord(xdrs, shipnow)) { + release_fd_lock(ct->ct_fd, mask); + return (ct->ct_error.re_status = RPC_CANTSEND); + } + if (! shipnow) { + release_fd_lock(ct->ct_fd, mask); + return (RPC_SUCCESS); + } + /* + * Hack to provide rpc-based message passing + */ + if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { + release_fd_lock(ct->ct_fd, mask); + 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, 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, 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 (! (*xdr_results)(xdrs, 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, 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; + caddr_t 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); + while (vc_fd_locks[ct->ct_fd]) + cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock); + xdrs->x_op = XDR_FREE; + dummy = (*xdr_res)(xdrs, res_ptr); + mutex_unlock(&clnt_fd_lock); + thr_sigsetmask(SIG_SETMASK, &(mask), NULL); + cond_signal(&vc_cv[ct->ct_fd]); + + return dummy; +} + +/*ARGSUSED*/ +static void +clnt_vc_abort(cl) + CLIENT *cl; +{ +} + +static bool_t +clnt_vc_control(cl, request, info) + CLIENT *cl; + u_int request; + char *info; +{ + struct ct_data *ct; + void *infop = info; + sigset_t mask; + sigset_t newmask; + int rpc_lock_value; + + assert(cl != NULL); + + ct = (struct ct_data *)cl->cl_private; + + sigfillset(&newmask); + thr_sigsetmask(SIG_SETMASK, &newmask, &mask); + mutex_lock(&clnt_fd_lock); + while (vc_fd_locks[ct->ct_fd]) + cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock); + if (__isthreaded) + rpc_lock_value = 1; + else + rpc_lock_value = 0; + vc_fd_locks[ct->ct_fd] = rpc_lock_value; + mutex_unlock(&clnt_fd_lock); + + switch (request) { + case CLSET_FD_CLOSE: + ct->ct_closeit = TRUE; + release_fd_lock(ct->ct_fd, mask); + return (TRUE); + case CLSET_FD_NCLOSE: + ct->ct_closeit = FALSE; + release_fd_lock(ct->ct_fd, mask); + return (TRUE); + default: + break; + } + + /* for other requests which use info */ + if (info == NULL) { + release_fd_lock(ct->ct_fd, mask); + return (FALSE); + } + switch (request) { + case CLSET_TIMEOUT: + if (time_not_ok((struct timeval *)(void *)info)) { + release_fd_lock(ct->ct_fd, mask); + return (FALSE); + } + ct->ct_wait = *(struct timeval *)infop; + ct->ct_waitset = TRUE; + break; + case CLGET_TIMEOUT: + *(struct timeval *)infop = ct->ct_wait; + break; + case CLGET_SERVER_ADDR: + (void) memcpy(info, ct->ct_addr.buf, (size_t)ct->ct_addr.len); + break; + case CLGET_FD: + *(int *)(void *)info = ct->ct_fd; + break; + case CLGET_SVC_ADDR: + /* The caller should not free this memory area */ + *(struct netbuf *)(void *)info = ct->ct_addr; + break; + case CLSET_SVC_ADDR: /* set to new address */ + release_fd_lock(ct->ct_fd, mask); + return (FALSE); + case CLGET_XID: + /* + * use the knowledge that xid is the + * first element in the call structure + * This will get the xid of the PREVIOUS call + */ + *(u_int32_t *)(void *)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 *)(void *)info) + 1); + /* increment by 1 as clnt_vc_call() decrements once */ + break; + case CLGET_VERS: + /* + * This RELIES on the information that, in the call body, + * the version number field is the fifth field from the + * begining of the RPC header. MUST be changed if the + * call_struct is changed + */ + *(u_int32_t *)(void *)info = + ntohl(*(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + + 4 * BYTES_PER_XDR_UNIT)); + break; + + case CLSET_VERS: + *(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + + 4 * BYTES_PER_XDR_UNIT) = + htonl(*(u_int32_t *)(void *)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 *)(void *)info = + ntohl(*(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + + 3 * BYTES_PER_XDR_UNIT)); + break; + + case CLSET_PROG: + *(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + + 3 * BYTES_PER_XDR_UNIT) = + htonl(*(u_int32_t *)(void *)info); + break; + + default: + release_fd_lock(ct->ct_fd, mask); + return (FALSE); + } + release_fd_lock(ct->ct_fd, mask); + return (TRUE); +} + + +static void +clnt_vc_destroy(cl) + CLIENT *cl; +{ + struct ct_data *ct = (struct ct_data *) cl->cl_private; + int ct_fd = ct->ct_fd; + sigset_t mask; + sigset_t newmask; + + assert(cl != NULL); + + ct = (struct ct_data *) cl->cl_private; + + sigfillset(&newmask); + thr_sigsetmask(SIG_SETMASK, &newmask, &mask); + mutex_lock(&clnt_fd_lock); + while (vc_fd_locks[ct_fd]) + cond_wait(&vc_cv[ct_fd], &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)); + mem_free(cl, sizeof(CLIENT)); + mutex_unlock(&clnt_fd_lock); + thr_sigsetmask(SIG_SETMASK, &(mask), NULL); + cond_signal(&vc_cv[ct_fd]); +} + +/* + * Interface between xdr serializer and tcp connection. + * Behaves like the system calls, read & write, but keeps some error state + * around for the rpc level. + */ +static int +read_vc(ctp, buf, len) + caddr_t ctp; + caddr_t buf; + int len; +{ + struct sockaddr sa; + socklen_t sal; + struct ct_data *ct = (struct ct_data *)(void *)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; + } + + sal = sizeof(sa); + if ((_getpeername(ct->ct_fd, &sa, &sal) == 0) && + (sa.sa_family == AF_LOCAL)) { + len = __msgread(ct->ct_fd, buf, (size_t)len); + } else { + 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) + caddr_t ctp; + caddr_t buf; + int len; +{ + struct sockaddr sa; + socklen_t sal; + struct ct_data *ct = (struct ct_data *)(void *)ctp; + int i, cnt; + + sal = sizeof(sa); + if ((_getpeername(ct->ct_fd, &sa, &sal) == 0) && + (sa.sa_family == AF_LOCAL)) { + for (cnt = len; cnt > 0; cnt -= i, buf += i) { + if ((i = __msgwrite(ct->ct_fd, buf, + (size_t)cnt)) == -1) { + ct->ct_error.re_errno = errno; + ct->ct_error.re_status = RPC_CANTSEND; + return (-1); + } + } + } else { + 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); +} + +__msgread(sock, buf, cnt) + int sock; + void *buf; + size_t cnt; +{ + struct iovec iov[1]; + struct msghdr msg; + struct cmessage cm; + + bzero((char *)&cm, sizeof(cm)); + iov[0].iov_base = buf; + iov[0].iov_len = cnt; + + msg.msg_iov = iov; + msg.msg_iovlen = 1; + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_control = (caddr_t)&cm; + msg.msg_controllen = sizeof(struct cmessage); + msg.msg_flags = 0; + + return(_recvmsg(sock, &msg, 0)); +} + +static int +__msgwrite(sock, buf, cnt) + int sock; + void *buf; + size_t cnt; +{ + struct iovec iov[1]; + struct msghdr msg; + struct cmessage cm; + + bzero((char *)&cm, sizeof(cm)); + iov[0].iov_base = buf; + iov[0].iov_len = cnt; + + cm.cmsg.cmsg_type = SCM_CREDS; + cm.cmsg.cmsg_level = SOL_SOCKET; + cm.cmsg.cmsg_len = sizeof(struct cmessage); + + msg.msg_iov = iov; + msg.msg_iovlen = 1; + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_control = (caddr_t)&cm; + msg.msg_controllen = sizeof(struct cmessage); + msg.msg_flags = 0; + + return(_sendmsg(sock, &msg, 0)); +} diff --git a/lib/libc/rpc/crypt_client.c b/lib/libc/rpc/crypt_client.c index ab01971657e7..a62cad2227f2 100644 --- a/lib/libc/rpc/crypt_client.c +++ b/lib/libc/rpc/crypt_client.c @@ -28,15 +28,15 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ +#include "namespace.h" #include <sys/types.h> #include <rpc/des_crypt.h> #include <rpc/des.h> #include <string.h> #include <rpcsvc/crypt.h> +#include "un-namespace.h" #ifndef lint static const char rcsid[] = "$FreeBSD$"; diff --git a/lib/libc/rpc/get_myaddress.c b/lib/libc/rpc/get_myaddress.c deleted file mode 100644 index 70c3ac00fb99..000000000000 --- a/lib/libc/rpc/get_myaddress.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Sun RPC is a product of Sun Microsystems, Inc. and is provided for - * unrestricted use provided that this legend is included on all tape - * media and as a part of the software program in whole or part. Users - * may copy or modify Sun RPC without charge, but are not authorized - * to license or distribute it to anyone else except as part of a product or - * program developed by the user. - * - * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE - * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR - * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. - * - * Sun RPC is provided with no support and without any obligation on the - * part of Sun Microsystems, Inc. to assist in its use, correction, - * modification or enhancement. - * - * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE - * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC - * OR ANY PART THEREOF. - * - * In no event will Sun Microsystems, Inc. be liable for any lost revenue - * or profits or other special, indirect and consequential damages, even if - * Sun has been advised of the possibility of such damages. - * - * Sun Microsystems, Inc. - * 2550 Garcia Avenue - * Mountain View, California 94043 - */ - -#if defined(LIBC_SCCS) && !defined(lint) -/*static char *sccsid = "from: @(#)get_myaddress.c 1.4 87/08/11 Copyr 1984 Sun Micro";*/ -/*static char *sccsid = "from: @(#)get_myaddress.c 2.1 88/07/29 4.0 RPCSRC";*/ -static char *rcsid = "$FreeBSD$"; -#endif - -/* - * get_myaddress.c - * - * Get client's IP address via ioctl. This avoids using the yellowpages. - * Copyright (C) 1984, Sun Microsystems, Inc. - */ - -#include "namespace.h" -#include <rpc/types.h> -#include <rpc/xdr.h> -#include <rpc/pmap_prot.h> -#include <sys/socket.h> -#include <stdio.h> -#include <unistd.h> -#include <net/if.h> -#include <sys/ioctl.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include "un-namespace.h" - -/* - * don't use gethostbyname, which would invoke yellow pages - * - * Avoid loopback interfaces. We return information from a loopback - * interface only if there are no other possible interfaces. - */ -int -get_myaddress(addr) - struct sockaddr_in *addr; -{ - int s; - char buf[BUFSIZ]; - struct ifconf ifc; - struct ifreq ifreq, *ifr, *end; - int loopback = 0, gotit = 0; - - if ((s = _socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - return(-1); - } - ifc.ifc_len = sizeof (buf); - ifc.ifc_buf = buf; - if (_ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) { - _close(s); - return(-1); - } -again: - ifr = ifc.ifc_req; - end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); - - while (ifr < end) { - memcpy(&ifreq, ifr, sizeof(ifreq)); - if (_ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) { - _close(s); - return(-1); - } - if (((ifreq.ifr_flags & IFF_UP) && - ifr->ifr_addr.sa_family == AF_INET && - !(ifreq.ifr_flags & IFF_LOOPBACK)) || - (loopback == 1 && (ifreq.ifr_flags & IFF_LOOPBACK) - && (ifr->ifr_addr.sa_family == AF_INET) - && (ifreq.ifr_flags & IFF_UP))) { - *addr = *((struct sockaddr_in *)&ifr->ifr_addr); - addr->sin_port = htons(PMAPPORT); - gotit = 1; - break; - } - if (ifr->ifr_addr.sa_len) - ifr = (struct ifreq *) ((caddr_t) ifr + - ifr->ifr_addr.sa_len - - sizeof(struct sockaddr)); - ifr++; - } - if (gotit == 0 && loopback == 0) { - loopback = 1; - goto again; - } - (void)_close(s); - return (gotit ? 0 : -1); -} diff --git a/lib/libc/rpc/getnetconfig.3 b/lib/libc/rpc/getnetconfig.3 new file mode 100644 index 000000000000..fb1151eebd4c --- /dev/null +++ b/lib/libc/rpc/getnetconfig.3 @@ -0,0 +1,182 @@ +.\" @(#)getnetconfig.3n 1.28 93/06/02 SMI; from SVr4 +.\" $NetBSD: getnetconfig.3,v 1.1 2000/06/02 23:11:11 fvdl Exp $ +.\" $FreeBSD$ +.\" Copyright 1989 AT&T +.Dd April 22, 2000 +.Dt GETNETCONFIG 3 +.Os +.Sh NAME +.Nm getnetconfig , +.Nm setnetconfig , +.Nm endnetconfig , +.Nm getnetconfigent , +.Nm freenetconfigent , +.Nm nc_perror , +.Nm nc_sperror +.Nd get network configuration database entry +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.Fd #include <netconfig.h> +.Ft "struct netconfig *" +.Fn getnetconfig "void *handlep" +.Ft "void *" +.Fn setnetconfig "void" +.Ft int +.Fn endnetconfig "void *handlep" +.Ft "struct netconfig *" +.Fn getnetconfigent "const char *netid" +.Ft void +.Fn freenetconfigent "struct netconfig *netconfigp" +.Ft void +.Fn nc_perror "const char *msg" +.Ft "char *" +.Fn nc_sperror "void" +.Sh DESCRIPTION +The library routines described on this page +provide the application access to +the system network configuration database, +.Pa /etc/netconfig . +.Fn getnetconfig +returns a pointer to the +current entry in the +netconfig +database, formatted as a +.Ft "struct netconfig" . +Successive calls will return successive netconfig +entries in the netconfig database. +.Fn getnetconfig +can be used to search the entire netconfig +file. +.Fn getnetconfig +returns +.Dv NULL +at the end of the file. +.Fa handlep +is the handle obtained through +.Fn setnetconfig . +.Pp +A call to +.Fn setnetconfig +has the effect of +.Dq binding +to or +.Dq rewinding +the netconfig database. +.Fn setnetconfig +must be called before the first call to +.Fn getnetconfig +and may be called at any other time. +.Fn setnetconfig +need not be called before a call to +.Fn getnetconfigent . +.Fn setnetconfig +returns a unique handle to be used by +.Fn getnetconfig . +.Pp +.Fn endnetconfig +should be called when processing is complete to release resources for reuse. +.Fa handlep +is the handle obtained through +.Fn setnetconfig . +Programmers should be aware, however, that the last call to +.Fn endnetconfig +frees all memory allocated by +.Fn getnetconfig +for the +.Ft "struct netconfig" +data structure. +.Fn endnetconfig +may not be called before +.Fn setnetconfig . +.Pp +.Fn getnetconfigent +returns a pointer +to the netconfig structure corresponding +to +.Fa netid . +It returns +.Dv NULL +if +.Fa netid +is invalid +(that is, does not name an entry in the netconfig database). +.Pp +.Fn freenetconfigent +frees the netconfig structure pointed to by +.Fa netconfigp +(previously returned by +.Fn getnetconfigent ) . +.Pp +.Fn nc_perror +prints a message to the standard error indicating why any of the +above routines failed. +The message is prepended with the string +.Fa msg +and a colon. +A newline character is appended at the end of the message. +.Pp +.Fn nc_sperror +is similar to +.Fn nc_perror +but instead of sending the message +to the standard error, will return a pointer to a string that +contains the error message. +.Pp +.Fn nc_perror +and +.Fn nc_sperror +can also be used with the +.Ev NETPATH +access routines defined in +.Xr getnetpath 3 . +.Sh RETURN VALUES +.Fn setnetconfig +returns a unique handle to be used by +.Fn getnetconfig . +In the case of an error, +.Fn setnetconfig +returns +.Dv NULL +and +.Fn nc_perror +or +.Fn nc_sperror +can be used to print the reason for failure. +.Pp +.Fn getnetconfig +returns a pointer to the current entry in the netconfig +database, formatted as a +.Ft "struct netconfig" . +.Fn getnetconfig +returns +.Dv NULL +at the end of the file, or upon failure. +.Pp +.Fn endnetconfig +returns 0 on success and \-1 on failure +(for example, if +.Fn setnetconfig +was not called previously). +.Pp +On success, +.Fn getnetconfigent +returns a pointer to the +.Ft "struct netconfig" +structure corresponding to +.Fa netid ; +otherwise it returns +.Dv NULL . +.Pp +.Fn nc_sperror +returns a pointer to a buffer which contains the error message string. +This buffer is overwritten on each call. +In multithreaded applications, this buffer is +implemented as thread-specific data. +.Sh FILES +.Bl -tag -width /etc/netconfig -compact +.It Pa /etc/netconfig +.El +.Sh SEE ALSO +.Xr getnetpath 3 , +.Xr netconfig 5 diff --git a/lib/libc/rpc/getnetconfig.c b/lib/libc/rpc/getnetconfig.c new file mode 100644 index 000000000000..c7278b1cf91b --- /dev/null +++ b/lib/libc/rpc/getnetconfig.c @@ -0,0 +1,674 @@ +/* $NetBSD: getnetconfig.c,v 1.3 2000/07/06 03:10:34 christos Exp $ */ +/* $FreeBSD$ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user or with the express written consent of + * Sun Microsystems, Inc. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* +#ifndef lint +static char sccsid[] = "@(#)getnetconfig.c 1.12 91/12/19 SMI"; +#endif +*/ + +/* + * Copyright (c) 1989 by Sun Microsystems, Inc. + */ + +#include "reentrant.h" +#include "namespace.h" +#include <sys/cdefs.h> +#include <stdio.h> +#include <errno.h> +#include <netconfig.h> +#include <stdlib.h> +#include <string.h> +#include <rpc/rpc.h> +#include "un-namespace.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 */ + +/* + * 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" +}; + +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 __P((void)); +static int parse_ncp __P((char *, struct netconfig *)); +static struct netconfig *dup_ncp __P((struct netconfig *)); + + +static FILE *nc_file; /* for netconfig db */ +static struct netconfig_info ni = { 0, 0, NULL, NULL}; + +#define MAXNETCONFIGLINE 1000 + +static int * +__nc_error() +{ + extern pthread_mutex_t nc_lock; + static thread_key_t nc_key = 0; + static thread_key_t rce_key = 0; + int *nc_addr = NULL; + static int nc_error = 0; + + if ((nc_addr = (int *)thr_getspecific(nc_key)) != 0) { + mutex_lock(&nc_lock); + if (thr_keycreate(&rce_key, free) != 0) { + mutex_unlock(&nc_lock); + return nc_addr; + } + mutex_unlock(&nc_lock); + } + if (nc_addr == NULL) { + nc_addr = (int *)malloc(sizeof (int)); + if (thr_setspecific(nc_key, (void *) nc_addr) != 0) { + if (nc_addr) + free(nc_addr); + return &nc_error; + } + *nc_addr = 0; + return nc_addr; + } + return nc_addr; +} + +#define nc_error (*(__nc_error())) +/* + * A call to setnetconfig() establishes a /etc/netconfig "session". A session + * "handle" is returned on a successful call. At the start of a session (after + * a call to setnetconfig()) searches through the /etc/netconfig database will + * proceed from the start of the file. The session handle must be passed to + * getnetconfig() to parse the file. Each call to getnetconfig() using the + * current handle will process one subsequent entry in /etc/netconfig. + * setnetconfig() must be called before the first call to getnetconfig(). + * (Handles are used to allow for nested calls to setnetpath()). + * + * A new session is established with each call to setnetconfig(), with a new + * handle being returned on each call. Previously established sessions remain + * active until endnetconfig() is called with that session's handle as an + * argument. + * + * setnetconfig() need *not* be called before a call to getnetconfigent(). + * setnetconfig() returns a NULL pointer on failure (for example, if + * the netconfig database is not present). + */ +void * +setnetconfig() +{ + struct netconfig_vars *nc_vars; + + if ((nc_vars = (struct netconfig_vars *)malloc(sizeof + (struct netconfig_vars))) == NULL) { + return(NULL); + } + + /* + * For multiple calls, i.e. nc_file is not NULL, we just return the + * handle without reopening the netconfig db. + */ + ni.ref++; + if ((nc_file != NULL) || (nc_file = fopen(NETCONFIG, "r")) != NULL) { + nc_vars->valid = NC_VALID; + nc_vars->flag = 0; + nc_vars->nc_configs = ni.head; + return ((void *)nc_vars); + } + ni.ref--; + nc_error = NC_NONETCONFIG; + free(nc_vars); + return (NULL); +} + + +/* + * When first called, getnetconfig() returns a pointer to the first entry in + * the netconfig database, formatted as a struct netconfig. On each subsequent + * call, getnetconfig() returns a pointer to the next entry in the database. + * getnetconfig() can thus be used to search the entire netconfig file. + * getnetconfig() returns NULL at end of file. + */ + +struct netconfig * +getnetconfig(handlep) +void *handlep; +{ + struct netconfig_vars *ncp = (struct netconfig_vars *)handlep; + char *stringp; /* tmp string pointer */ + struct netconfig_list *list; + struct netconfig *np; + + /* + * Verify that handle is valid + */ + if (ncp == NULL || nc_file == NULL) { + nc_error = NC_NOTINIT; + return (NULL); + } + + switch (ncp->valid) { + case NC_VALID: + /* + * If entry has already been read into the list, + * we return the entry in the linked list. + * If this is the first time call, check if there are any entries in + * linked list. If no entries, we need to read the netconfig db. + * If we have been here and the next entry is there, we just return + * it. + */ + if (ncp->flag == 0) { /* first time */ + ncp->flag = 1; + ncp->nc_configs = ni.head; + if (ncp->nc_configs != NULL) /* entry already exist */ + return(ncp->nc_configs->ncp); + } + else if (ncp->nc_configs != NULL && ncp->nc_configs->next != NULL) { + ncp->nc_configs = ncp->nc_configs->next; + return(ncp->nc_configs->ncp); + } + + /* + * If we cannot find the entry in the list and is end of file, + * we give up. + */ + if (ni.eof == 1) return(NULL); + break; + default: + nc_error = NC_NOTINIT; + return (NULL); + } + + stringp = (char *) malloc(MAXNETCONFIGLINE); + if (stringp == NULL) + return (NULL); + +#ifdef MEM_CHK + if (malloc_verify() == 0) { + fprintf(stderr, "memory heap corrupted in getnetconfig\n"); + exit(1); + } +#endif + + /* + * Read a line from netconfig file. + */ + do { + if (fgets(stringp, MAXNETCONFIGLINE, nc_file) == NULL) { + free(stringp); + ni.eof = 1; + return (NULL); + } + } while (*stringp == '#'); + + list = (struct netconfig_list *) malloc(sizeof (struct netconfig_list)); + if (list == NULL) { + free(stringp); + return(NULL); + } + np = (struct netconfig *) malloc(sizeof (struct netconfig)); + if (np == NULL) { + free(stringp); + free(list); + return(NULL); + } + list->ncp = np; + list->next = NULL; + list->ncp->nc_lookups = NULL; + list->linep = stringp; + if (parse_ncp(stringp, list->ncp) == -1) { + free(stringp); + free(np); + free(list); + 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; + return(ni.tail->ncp); + } +} + +/* + * endnetconfig() may be called to "unbind" or "close" the netconfig database + * when processing is complete, releasing resources for reuse. endnetconfig() + * may not be called before setnetconfig(). endnetconfig() returns 0 on + * success and -1 on failure (for example, if setnetconfig() was not called + * previously). + */ +int +endnetconfig(handlep) +void *handlep; +{ + struct netconfig_vars *nc_handlep = (struct netconfig_vars *)handlep; + + struct netconfig_list *q, *p; + + /* + * Verify that handle is valid + */ + if (nc_handlep == NULL || (nc_handlep->valid != NC_VALID && + nc_handlep->valid != NC_STORAGE)) { + nc_error = NC_NOTINIT; + return (-1); + } + + /* + * Return 0 if anyone still needs it. + */ + nc_handlep->valid = NC_INVALID; + nc_handlep->flag = 0; + nc_handlep->nc_configs = NULL; + if (--ni.ref > 0) { + free(nc_handlep); + return(0); + } + + /* + * Noone needs these entries anymore, then frees them. + * Make sure all info in netconfig_info structure has been reinitialized. + */ + q = p = ni.head; + ni.eof = ni.ref = 0; + ni.head = NULL; + ni.tail = NULL; + while (q) { + p = q->next; + if (q->ncp->nc_lookups != NULL) free(q->ncp->nc_lookups); + free(q->ncp); + free(q->linep); + free(q); + q = p; + } + free(nc_handlep); + + fclose(nc_file); + nc_file = NULL; + return (0); +} + +/* + * getnetconfigent(netid) returns a pointer to the struct netconfig structure + * corresponding to netid. It returns NULL if netid is invalid (that is, does + * not name an entry in the netconfig database). It returns NULL and sets + * errno in case of failure (for example, if the netconfig database cannot be + * opened). + */ + +struct netconfig * +getnetconfigent(netid) + 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 */ + + if (netid == NULL || strlen(netid) == 0) { + return (NULL); + } + + /* + * Look up table if the entries have already been read and parsed in + * getnetconfig(), then copy this entry into a buffer and return it. + * If we cannot find the entry in the current list and there are more + * entries in the netconfig db that has not been read, we then read the + * db and try find the match netid. + * If all the netconfig db has been read and placed into the list and + * there is no match for the netid, return NULL. + */ + if (ni.head != NULL) { + for (list = ni.head; list; list = list->next) { + if (strcmp(list->ncp->nc_netid, netid) == 0) { + return(dup_ncp(list->ncp)); + } + } + if (ni.eof == 1) /* that's all the entries */ + return(NULL); + } + + + if ((file = fopen(NETCONFIG, "r")) == NULL) { + return (NULL); + } + + if ((linep = malloc(MAXNETCONFIGLINE)) == NULL) { + fclose(file); + return (NULL); + } + do { + int 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) == (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; + 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", s, nc_sperror()); +} + +/* + * Duplicates the matched netconfig buffer. + */ +static struct netconfig * +dup_ncp(ncp) +struct netconfig *ncp; +{ + struct netconfig *p; + char *tmp; + 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 + * neccessary information in the pre-allocated buffer and let each + * of the netconfig char pointer member point to the right address + * in the buffer. + */ + *p = *ncp; + p->nc_netid = (char *)strcpy(tmp,ncp->nc_netid); + tmp = strchr(tmp, NULL) + 1; + p->nc_protofmly = (char *)strcpy(tmp,ncp->nc_protofmly); + tmp = strchr(tmp, NULL) + 1; + p->nc_proto = (char *)strcpy(tmp,ncp->nc_proto); + tmp = strchr(tmp, NULL) + 1; + p->nc_device = (char *)strcpy(tmp,ncp->nc_device); + p->nc_lookups = (char **)malloc((size_t)(p->nc_nlookups+1) * sizeof(char *)); + if (p->nc_lookups == NULL) { + free(p->nc_netid); + return(NULL); + } + for (i=0; i < p->nc_nlookups; i++) { + tmp = strchr(tmp, NULL) + 1; + p->nc_lookups[i] = (char *)strcpy(tmp,ncp->nc_lookups[i]); + } + return(p); +} diff --git a/lib/libc/rpc/getnetpath.3 b/lib/libc/rpc/getnetpath.3 new file mode 100644 index 000000000000..913a4cb1e8b2 --- /dev/null +++ b/lib/libc/rpc/getnetpath.3 @@ -0,0 +1,154 @@ +.\" @(#)getnetpath.3n 1.26 93/05/07 SMI; from SVr4 +.\" $NetBSD: getnetpath.3,v 1.1 2000/06/02 23:11:11 fvdl Exp $ +.\" $FreeBSD$ +.\" Copyright 1989 AT&T +.Dd April 22, 2000 +.Dt GETNETPATH 3 +.Os +.Sh NAME +.Nm getnetpath , +.Nm setnetpath , +.Nm endnetpath +.Nd get +.Pa /etc/netconfig +entry corresponding to +.Ev NETPATH +component +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.Fd #include <netconfig.h> +.Ft "struct netconfig *" +.Fn getnetpath "void *handlep" +.Ft "void *" +.Fn setnetpath "void" +.Ft int +.Fn endnetpath "void *handlep" +.Sh DESCRIPTION +The routines described in this page provide the application access to the system +network configuration database, +.Pa /etc/netconfig , +as it is +.Dq filtered +by the +.Ev NETPATH +environment variable (see +.Xr environ 5 ) . +See +.Xr getnetconfig 3 +for other routines that also access the +network configuration database directly. +The +.Ev NETPATH +variable is a list of colon-separated network identifiers. +.Pp +.Fn getnetpath +returns a pointer to the +netconfig database entry corresponding to the first valid +.Ev NETPATH +component. +The netconfig entry is formatted as a +.Ft "struct netconfig" . +On each subsequent call, +.Fn getnetpath +returns a pointer to the netconfig entry that corresponds to the next +valid +.Ev NETPATH +component. +.Fn getnetpath +can thus be used to search the netconfig database for all networks +included in the +.Ev NETPATH +variable. +When +.Ev NETPATH +has been exhausted, +.Fn getnetpath +returns +.Dv NULL . +.Pp +A call to +.Fn setnetpath +.Dq binds +to or +.Dq rewinds +.Ev NETPATH . +.Fn setnetpath +must be called before the first call to +.Fn getnetpath +and may be called at any other time. +It returns a handle that is used by +.Fn getnetpath . +.Pp +.Fn getnetpath +silently ignores invalid +.Ev NETPATH +components. +A +.Ev NETPATH +component is invalid if there is no corresponding +entry in the netconfig database. +.Pp +If the +.Ev NETPATH +variable is unset, +.Fn getnetpath +behaves as if +.Ev NETPATH +were set to the sequence of +.Dq default +or +.Dq visible +networks in the netconfig database, in the +order in which they are listed. +.\"This proviso holds also for this +.\"whole manpage. +.Pp +.Fn endnetpath +may be called to +.Dq unbind +from +.Ev NETPATH +when processing is complete, releasing resources for reuse. +Programmers should be aware, however, that +.Fn endnetpath +frees all memory allocated by +.Fn getnetpath +for the struct netconfig data structure. +.Sh RETURN VALUES +.Fn setnetpath +returns a handle that is used by +.Fn getnetpath . +In case of an error, +.Fn setnetpath +returns +.Dv NULL . +.Pp +.Fn endnetpath +returns 0 on success and \-1 on failure +(for example, if +.Fn setnetpath +was not called previously). +.Fn nc_perror +or +.Fn nc_sperror +can be used to print out the reason for failure. +See +.Xr getnetconfig 3 . +.Pp +When first called, +.Fn getnetpath +returns a pointer to the netconfig database entry corresponding to the first +valid +.Ev NETPATH +component. +When +.Ev NETPATH +has been exhausted, +.Fn getnetpath +returns +.Dv NULL . +.Sh SEE ALSO +.Xr getnetconfig 3 , +.Xr environ 5 , +.Xr netconfig 5 diff --git a/lib/libc/rpc/getnetpath.c b/lib/libc/rpc/getnetpath.c new file mode 100644 index 000000000000..132a5102a83b --- /dev/null +++ b/lib/libc/rpc/getnetpath.c @@ -0,0 +1,273 @@ +/* $NetBSD: getnetpath.c,v 1.3 2000/07/06 03:10:34 christos Exp $ */ +/* $FreeBSD$ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user or with the express written consent of + * Sun Microsystems, Inc. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* +#ifndef lint +static char sccsid[] = "@(#)getnetpath.c 1.11 91/12/19 SMI"; +#endif +*/ + +/* + * Copyright (c) 1989 by Sun Microsystems, Inc. + */ + +#include "namespace.h" +#include <sys/cdefs.h> +#include <stdio.h> +#include <errno.h> +#include <netconfig.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include "un-namespace.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 __P((char *, int)); + + +/* + * A call to setnetpath() establishes a NETPATH "session". setnetpath() + * must be called before the first call to getnetpath(). A "handle" is + * returned to distinguish the session; this handle should be passed + * subsequently to getnetpath(). (Handles are used to allow for nested calls + * to setnetpath()). + * If setnetpath() is unable to establish a session (due to lack of memory + * resources, or the absence of the /etc/netconfig file), a NULL pointer is + * returned. + */ + +void * +setnetpath() +{ + + struct netpath_vars *np_sessionp; /* this session's variables */ + char *npp; /* NETPATH env variable */ + +#ifdef MEM_CHK + malloc_debug(1); +#endif + + if ((np_sessionp = + (struct netpath_vars *)malloc(sizeof (struct netpath_vars))) == NULL) { + return (NULL); + } + if ((np_sessionp->nc_handlep = setnetconfig()) == NULL) { + syslog (LOG_ERR, "rpc: failed to open " NETCONFIG); + return (NULL); + } + np_sessionp->valid = NP_VALID; + np_sessionp->ncp_list = NULL; + if ((npp = getenv(NETPATH)) == NULL) { + np_sessionp->netpath = NULL; + } else { + (void) endnetconfig(np_sessionp->nc_handlep);/* won't need nc session*/ + np_sessionp->nc_handlep = NULL; + if ((np_sessionp->netpath = malloc(strlen(npp)+1)) == NULL) { + free(np_sessionp); + return (NULL); + } else { + (void) strcpy(np_sessionp->netpath, npp); + } + } + np_sessionp->netpath_start = np_sessionp->netpath; + return ((void *)np_sessionp); +} + +/* + * When first called, getnetpath() returns a pointer to the netconfig + * database entry corresponding to the first valid NETPATH component. The + * netconfig entry is formatted as a struct netconfig. + * On each subsequent call, getnetpath returns a pointer to the netconfig + * entry that corresponds to the next valid NETPATH component. getnetpath + * can thus be used to search the netconfig database for all networks + * included in the NETPATH variable. + * When NETPATH has been exhausted, getnetpath() returns NULL. It returns + * NULL and sets errno in case of an error (e.g., setnetpath was not called + * previously). + * getnetpath() silently ignores invalid NETPATH components. A NETPATH + * compnent is invalid if there is no corresponding entry in the netconfig + * database. + * If the NETPATH variable is unset, getnetpath() behaves as if NETPATH + * were set to the sequence of default or visible networks in the netconfig + * database, in the order in which they are listed. + */ + +struct netconfig * +getnetpath(handlep) + void *handlep; +{ + struct netpath_vars *np_sessionp = (struct netpath_vars *)handlep; + struct netconfig *ncp = NULL; /* temp. holds a netconfig session */ + struct netpath_chain *chainp; /* holds chain of ncp's we alloc */ + char *npp; /* holds current NETPATH */ + + if (np_sessionp == NULL || np_sessionp->valid != NP_VALID) { + errno = EINVAL; + return (NULL); + } + if (np_sessionp->netpath_start == NULL) { /* NETPATH was not set */ + do { /* select next visible network */ + if (np_sessionp->nc_handlep == NULL) { + np_sessionp->nc_handlep = setnetconfig(); + if (np_sessionp->nc_handlep == NULL) + syslog (LOG_ERR, "rpc: failed to open " NETCONFIG); + } + if ((ncp = getnetconfig(np_sessionp->nc_handlep)) == NULL) { + return(NULL); + } + } while ((ncp->nc_flag & NC_VISIBLE) == 0); + return (ncp); + } + /* + * Find first valid network ID in netpath. + */ + while ((npp = np_sessionp->netpath) != NULL && strlen(npp) != 0) { + np_sessionp->netpath = _get_next_token(npp, ':'); + /* + * npp is a network identifier. + */ + if ((ncp = getnetconfigent(npp)) != NULL) { + chainp = (struct netpath_chain *) /* cobble alloc chain entry */ + malloc(sizeof (struct netpath_chain)); + chainp->ncp = ncp; + chainp->nchain_next = NULL; + if (np_sessionp->ncp_list == NULL) { + np_sessionp->ncp_list = chainp; + } else { + np_sessionp->ncp_list->nchain_next = chainp; + } + return (ncp); + } + /* couldn't find this token in the database; go to next one. */ + } + return (NULL); +} + +/* + * endnetpath() may be called to unbind NETPATH when processing is complete, + * releasing resources for reuse. It returns 0 on success and -1 on failure + * (e.g. if setnetpath() was not called previously. + */ +int +endnetpath(handlep) + void *handlep; +{ + struct netpath_vars *np_sessionp = (struct netpath_vars *)handlep; + struct netpath_chain *chainp, *lastp; + + if (np_sessionp == NULL || np_sessionp->valid != NP_VALID) { + errno = EINVAL; + return (-1); + } + if (np_sessionp->nc_handlep != NULL) + endnetconfig(np_sessionp->nc_handlep); + if (np_sessionp->netpath_start != NULL) + free(np_sessionp->netpath_start); + for (chainp = np_sessionp->ncp_list; chainp != NULL; + lastp=chainp, chainp=chainp->nchain_next, free(lastp)) { + freenetconfigent(chainp->ncp); + } + free(np_sessionp); +#ifdef MEM_CHK + if (malloc_verify() == 0) { + fprintf(stderr, "memory heap corrupted in endnetpath\n"); + exit(1); + } +#endif + return (0); +} + + + +/* + * Returns pointer to the rest-of-the-string after the current token. + * The token itself starts at arg, and we null terminate it. We return NULL + * if either the arg is empty, or if this is the last token. + */ + +char * +_get_next_token(npp, token) +char *npp; /* string */ +int token; /* char to parse string for */ +{ + char *cp; /* char pointer */ + char *np; /* netpath pointer */ + char *ep; /* escape pointer */ + + if ((cp = strchr(npp, token)) == NULL) { + return (NULL); + } + /* + * did find a token, but it might be escaped. + */ + if (cp[-1] == '\\') { + /* if slash was also escaped, carry on, otherwise find next token */ + if (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/lib/libc/rpc/getpublickey.c b/lib/libc/rpc/getpublickey.c index 49227b41b5f4..6c8fe5e21534 100644 --- a/lib/libc/rpc/getpublickey.c +++ b/lib/libc/rpc/getpublickey.c @@ -41,6 +41,7 @@ static char sccsid[] = "@(#)publickey.c 1.10 91/03/11 Copyr 1986 Sun Micro"; /* * Public key lookup routines */ +#include "namespace.h" #include <stdio.h> #include <pwd.h> #include <rpc/rpc.h> @@ -49,6 +50,7 @@ static char sccsid[] = "@(#)publickey.c 1.10 91/03/11 Copyr 1986 Sun Micro"; #include <rpcsvc/ypclnt.h> #include <string.h> #include <stdlib.h> +#include "un-namespace.h" #define PKFILE "/etc/publickey" diff --git a/lib/libc/rpc/getrpcent.3 b/lib/libc/rpc/getrpcent.3 index 208e5d0ea104..6a02ca152c7f 100644 --- a/lib/libc/rpc/getrpcent.3 +++ b/lib/libc/rpc/getrpcent.3 @@ -1,4 +1,5 @@ .\" @(#)getrpcent.3n 2.2 88/08/02 4.0 RPCSRC; from 1.11 88/03/14 SMI +.\" $NetBSD: getrpcent.3,v 1.6 1998/02/05 18:49:06 perry Exp $ .\" $FreeBSD$ .\" .Dd December 14, 1987 @@ -11,6 +12,8 @@ .Nm endrpcent , .Nm setrpcent .Nd get RPC entry +.Sh LIBRARY +.Lb libc .Sh SYNOPSIS .Fd #include <rpc/rpc.h> .Ft struct rpcent * @@ -24,19 +27,17 @@ .Ft void .Fn endrpcent void .Sh DESCRIPTION -The .Fn getrpcent , .Fn getrpcbyname , and .Fn getrpcbynumber -functions each return a pointer to an object with the +each return a pointer to an object with the following structure containing the broken-out fields of a line in the rpc program number data base, -.Pa /etc/rpc . +.Pa /etc/rpc : .Bd -literal - -struct rpcent { +struct rpcent { char *r_name; /* name of server for this rpc program */ char **r_aliases; /* alias list */ long r_number; /* rpc program number */ @@ -44,29 +45,28 @@ struct rpcent { .Ed .Pp The members of this structure are: -.Bl -tag -width r_aliasesxxx -.It Fa r_name +.Bl -tag -width r_aliases -offset indent +.It Va r_name The name of the server for this rpc program. -.It Fa r_aliases +.It Va r_aliases A zero terminated list of alternate names for the rpc program. -.It Fa r_number +.It Va r_number The rpc program number for this service. .El .Pp -The .Fn getrpcent -function reads the next line of the file, opening the file if necessary. -The +reads the next line of the file, opening the file if necessary. +.Pp .Fn setrpcent -function opens and rewinds the file. If the +opens and rewinds the file. If the .Fa stayopen flag is non-zero, the net data base will not be closed after each call to .Fn getrpcent (either directly, or indirectly through one of the other -.Fn getrpcent -function family. +.Dq getrpc +calls). .Pp .Fn endrpcent closes the file. @@ -81,7 +81,7 @@ program number is found, or until end-of-file is encountered. .Bl -tag -width /etc/rpc -compact .It Pa /etc/rpc .El -.Sh "SEE ALSO" +.Sh SEE ALSO .Xr rpc 5 , .Xr rpcinfo 8 , .Xr ypserv 8 diff --git a/lib/libc/rpc/getrpcent.c b/lib/libc/rpc/getrpcent.c index 4290235e686d..d200103c2281 100644 --- a/lib/libc/rpc/getrpcent.c +++ b/lib/libc/rpc/getrpcent.c @@ -1,3 +1,5 @@ +/* $NetBSD: getrpcent.c,v 1.17 2000/01/22 22:19:17 mycroft Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -28,8 +30,9 @@ * Mountain View, California 94043 */ +#include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) -/*static char *sccsid = "from: @(#)getrpcent.c 1.14 91/03/11 Copyr 1984 Sun Micro";*/ +static char *sccsid = "@(#)getrpcent.c 1.14 91/03/11 Copyr 1984 Sun Micro"; static char *rcsid = "$FreeBSD$"; #endif @@ -37,20 +40,29 @@ static char *rcsid = "$FreeBSD$"; * Copyright (c) 1984 by Sun Microsystems, Inc. */ +#include "namespace.h" +#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 <sys/types.h> #include <string.h> + #include <rpc/rpc.h> #ifdef YP #include <rpcsvc/yp_prot.h> #include <rpcsvc/ypclnt.h> #endif +#include "un-namespace.h" /* * Internet version. */ -struct rpcdata { +static struct rpcdata { FILE *rpcf; int stayopen; #define MAXALIASES 35 @@ -64,21 +76,21 @@ struct rpcdata { #endif } *rpcdata; +static struct rpcent *interpret __P((char *val, size_t len)); + #ifdef YP static int __yp_nomap = 0; extern int _yp_check(char **); #endif /* YP */ -static struct rpcent *interpret(); -struct hostent *gethostent(); -char *inet_ntoa(); +#define RPCDB "/etc/rpc" -static char RPCDB[] = "/etc/rpc"; +static struct rpcdata *_rpcdata __P((void)); static struct rpcdata * _rpcdata() { - register struct rpcdata *d = rpcdata; + struct rpcdata *d = rpcdata; if (d == 0) { d = (struct rpcdata *)calloc(1, sizeof (struct rpcdata)); @@ -89,14 +101,14 @@ _rpcdata() struct rpcent * getrpcbynumber(number) - register int number; + int number; { - register struct rpcdata *d = _rpcdata(); - register struct rpcent *p; #ifdef YP int reason; char adrstr[16]; #endif + struct rpcent *p; + struct rpcdata *d = _rpcdata(); if (d == 0) return (0); @@ -123,8 +135,9 @@ getrpcbynumber(number) } no_yp: #endif /* YP */ + setrpcent(0); - while ((p = getrpcent())) { + while ((p = getrpcent()) != NULL) { if (p->r_number == number) break; } @@ -139,8 +152,10 @@ getrpcbyname(name) struct rpcent *rpc = NULL; char **rp; + assert(name != NULL); + setrpcent(0); - while ((rpc = getrpcent())) { + while ((rpc = getrpcent()) != NULL) { if (strcmp(rpc->r_name, name) == 0) goto done; for (rp = rpc->r_aliases; *rp != NULL; rp++) { @@ -157,7 +172,7 @@ void setrpcent(f) int f; { - register struct rpcdata *d = _rpcdata(); + struct rpcdata *d = _rpcdata(); if (d == 0) return; @@ -181,7 +196,7 @@ setrpcent(f) void endrpcent() { - register struct rpcdata *d = _rpcdata(); + struct rpcdata *d = _rpcdata(); if (d == 0) return; @@ -204,7 +219,7 @@ endrpcent() struct rpcent * getrpcent() { - register struct rpcdata *d = _rpcdata(); + struct rpcdata *d = _rpcdata(); #ifdef YP struct rpcent *hp; int reason; @@ -255,11 +270,13 @@ no_yp: static struct rpcent * interpret(val, len) char *val; - int len; + size_t len; { - register struct rpcdata *d = _rpcdata(); + struct rpcdata *d = _rpcdata(); char *p; - register char *cp, **q; + char *cp, **q; + + assert(val != NULL); if (d == 0) return (0); diff --git a/lib/libc/rpc/getrpcport.3 b/lib/libc/rpc/getrpcport.3 index b4fa8124d43e..3b6768532b6f 100644 --- a/lib/libc/rpc/getrpcport.3 +++ b/lib/libc/rpc/getrpcport.3 @@ -7,6 +7,8 @@ .Sh NAME .Nm getrpcport .Nd get RPC port number +.Sh LIBRARY +.Lb libc .Sh SYNOPSIS .Ft int .Fn getrpcport "char *host" "int prognum" "int versnum" "int proto" diff --git a/lib/libc/rpc/getrpcport.c b/lib/libc/rpc/getrpcport.c index 24c6257fd886..193ef26e1afc 100644 --- a/lib/libc/rpc/getrpcport.c +++ b/lib/libc/rpc/getrpcport.c @@ -1,3 +1,5 @@ +/* $NetBSD: getrpcport.c,v 1.16 2000/01/22 22:19:18 mycroft Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -27,9 +29,10 @@ * Mountain View, California 94043 */ +#include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) -/*static char *sccsid = "from: @(#)getrpcport.c 1.3 87/08/11 SMI";*/ -/*static char *sccsid = "from: @(#)getrpcport.c 2.1 88/07/29 4.0 RPCSRC";*/ +static char *sccsid = "@(#)getrpcport.c 1.3 87/08/11 SMI"; +static char *sccsid = "@(#)getrpcport.c 2.1 88/07/29 4.0 RPCSRC"; static char *rcsid = "$FreeBSD$"; #endif @@ -37,12 +40,18 @@ static char *rcsid = "$FreeBSD$"; * Copyright (c) 1985 by Sun Microsystems, Inc. */ +#include "namespace.h" +#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> -#include <netdb.h> -#include <sys/socket.h> +#include "un-namespace.h" int getrpcport(host, prognum, versnum, proto) @@ -52,12 +61,18 @@ getrpcport(host, 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_len = sizeof(struct sockaddr_in); addr.sin_family = AF_INET; addr.sin_port = 0; - memcpy((char *)&addr.sin_addr, hp->h_addr, hp->h_length); - return (pmap_getport(&addr, prognum, versnum, proto)); + if (hp->h_length > addr.sin_len) + hp->h_length = addr.sin_len; + 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/lib/libc/rpc/key_call.c b/lib/libc/rpc/key_call.c index c6c3e78f1558..8adb29de1861 100644 --- a/lib/libc/rpc/key_call.c +++ b/lib/libc/rpc/key_call.c @@ -43,6 +43,7 @@ * gendeskey(deskey) - generate a secure des key */ +#include "reentrant.h" #include "namespace.h" #include <stdio.h> #include <stdlib.h> @@ -53,6 +54,7 @@ #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> @@ -232,7 +234,7 @@ key_gendes(key) int key_setnet(arg) -struct netstarg *arg; +struct key_netstarg *arg; { keystatus status; @@ -276,7 +278,6 @@ struct key_call_private { }; static struct key_call_private *key_call_private_main = NULL; -#ifdef foo static void key_call_destroy(void *vp) { @@ -288,7 +289,6 @@ key_call_destroy(void *vp) free(kcp); } } -#endif /* * Keep the handle cached. This call may be made quite often. @@ -297,21 +297,40 @@ 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 main_thread; int fd; - struct sockaddr_un name; - int namelen = sizeof(struct sockaddr_un); + static 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 ((main_thread = thr_main())) { + kcp = key_call_private_main; + } else { + if (key_call_key == 0) { + mutex_lock(&tsd_lock); + if (key_call_key == 0) + 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); } - key_call_private_main = kcp; + if (main_thread) + key_call_private_main = kcp; + else + thr_setspecific(key_call_key, (void *) kcp); kcp->client = NULL; } @@ -322,16 +341,6 @@ int vers; } if (kcp->client != NULL) { - /* if other side closed socket, build handle again */ - clnt_control(kcp->client, CLGET_FD, (char *)&fd); - if (_getpeername(fd,(struct sockaddr *)&name,&namelen) == -1) { - auth_destroy(kcp->client->cl_auth); - 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(); @@ -348,15 +357,51 @@ int vers; clnt_control(kcp->client, CLSET_VERS, (void *)&vers); return (kcp->client); } + if (!(localhandle = setnetconfig())) { + return ((CLIENT *) NULL); + } + tpconf = NULL; +#if defined(i386) +#if defined(__FreeBSD__) + if (uname(&u) == -1) +#else + if (_nuname(&u) == -1) +#endif +#elif defined(sparc) + if (_uname(&u) == -1) +#else +#error Unknown architecture! +#endif + { + endnetconfig(localhandle); + return ((CLIENT *) NULL); + } - if ((kcp->client == (CLIENT *) NULL)) - /* Use the AF_UNIX transport */ - kcp->client = clnt_create("/var/run/keyservsock", KEY_PROG, - vers, "unix"); + while (nconf = getnetconfig(localhandle)) { + 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); diff --git a/lib/libc/rpc/key_prot_xdr.c b/lib/libc/rpc/key_prot_xdr.c index 8cd6b6b0678e..298a451d2f77 100644 --- a/lib/libc/rpc/key_prot_xdr.c +++ b/lib/libc/rpc/key_prot_xdr.c @@ -3,7 +3,9 @@ * It was generated using rpcgen. */ +#include "namespace.h" #include <rpc/key_prot.h> +#include "un-namespace.h" /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -32,8 +34,8 @@ * 2550 Garcia Avenue * Mountain View, California 94043 */ -#pragma ident "@(#)key_prot.x 1.7 94/04/29 SMI" - +/* From: #pragma ident "@(#)key_prot.x 1.7 94/04/29 SMI" */ +/* $FreeBSD$ */ /* Copyright (c) 1990, 1991 Sun Microsystems, Inc. */ /* diff --git a/lib/libc/rpc/mt_misc.c b/lib/libc/rpc/mt_misc.c new file mode 100644 index 000000000000..5abf831fd750 --- /dev/null +++ b/lib/libc/rpc/mt_misc.c @@ -0,0 +1,125 @@ +/* $NetBSD: mt_misc.c,v 1.1 2000/06/02 23:11:11 fvdl Exp $ */ +/* $FreeBSD$ */ + +/* #pragma ident "@(#)mt_misc.c 1.24 93/04/29 SMI" */ + +#include "reentrant.h" +#include "namespace.h" +#include <rpc/rpc.h> +#include <sys/time.h> +#include <stdlib.h> +#include "un-namespace.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_rwlock_t rpcbaddr_cache_lock = PTHREAD_RWLOCK_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; + +#ifdef KERBEROS +/* auth_kerb.c serialization */ +pthread_mutex_t authkerb_lock = PTHREAD_MUTEX_INITIALIZER; +/* protects kerb stats list */ +pthread_mutex_t svcauthkerbstats_lock = PTHREAD_MUTEX_INITIALIZER; +#endif /* KERBEROS */ + +/* 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 netconfig list */ +pthread_mutex_t nc_lock = PTHREAD_MUTEX_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; + +#undef rpc_createerr + +struct rpc_createerr rpc_createerr; + +struct rpc_createerr * +__rpc_createerr() +{ + static thread_key_t rce_key = 0; + struct rpc_createerr *rce_addr = 0; + + if (thr_main()) + return (&rpc_createerr); + if ((rce_addr = + (struct rpc_createerr *)thr_getspecific(rce_key)) != 0) { + mutex_lock(&tsd_lock); + if (thr_keycreate(&rce_key, free) != 0) { + mutex_unlock(&tsd_lock); + return (&rpc_createerr); + } + mutex_unlock(&tsd_lock); + } + if (!rce_addr) { + rce_addr = (struct rpc_createerr *) + malloc(sizeof (struct rpc_createerr)); + if (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); + } + return (rce_addr); +} diff --git a/lib/libc/rpc/netconfig.5 b/lib/libc/rpc/netconfig.5 new file mode 100644 index 000000000000..25738bcc2efe --- /dev/null +++ b/lib/libc/rpc/netconfig.5 @@ -0,0 +1,126 @@ +.\" $NetBSD: netconfig.5,v 1.2 2000/11/08 13:18:28 lukem Exp $ +.\" $NetBSD: netconfig.5,v 1.2 2000/11/08 13:18:28 lukem Exp $ +.\" $FreeBSD$ +.Dd November 17, 2000 +.Dt NETCONFIG 5 +.Os +.Sh NAME +.Nm netconfig +.Nd network configuration data base +.Sh SYNOPSIS +.Pa /etc/netconfig +.Sh DESCRIPTION +The +.Nm +file defines a list of +.Dq transport names , +describing their semantics and protocol. +In +.Fx , +this file is only used by the RPC library code. +.Pp +Entries have the following format: +.Pp +.Ar network_id semantics flags family protoname device libraries +.Pp +Entries consist of the following fields: +.Bl -tag -width network_id +.It Ar network_id +The name of the transport described. +.It Ar semantics +Describes the semantics of the transport. +This can be one of: +.Bl -tag -width tpi_cots_ord -offset indent +.It Sy tpi_clts +Connectionless transport. +.It Sy tpi_cots +Connection-oriented transport +.It Sy tpi_cots_ord +Connection-oriented, ordered transport. +.It Sy tpi_raw +A raw connection. +.El +.It Ar flags +This field is either blank (specified by +.Dq Li - ) , +or contains a +.Dq Li v , +meaning visible to the +.Xr getnetconfig 3 +function. +.It Ar family +The protocol family of the transport. +This is currently one of: +.Bl -tag -width loopback -offset indent +.It Sy inet6 +The IPv6 +.Pq Dv PF_INET6 +family of protocols. +.It Sy inet +The IPv4 +.Pq Dv PF_INET +family of protocols. +.It Sy loopback +The +.Dv PF_LOCAL +protocol family. +.El +.It Ar protoname +The name of the protocol used for this transport. +Can currently be either +.Sy udp , +.Sy tcp +or empty. +.It Ar device +This field is always empty in +.Fx . +.It Ar libraries +This field is always empty in +.Fx . +.El +.Pp +The order of entries in this file will determine which transport will +be preferred by the RPC library code, given a match on a specified +network type. +For example, if a sample network config file would look like this: +.Bd -literal -offset indent +udp6 tpi_clts v inet6 udp - - +tcp6 tpi_cots_ord v inet6 tcp - - +udp tpi_clts v inet udp - - +tcp tpi_cots_ord v inet tcp - - +rawip tpi_raw - inet - - - +local tpi_cots_ord - loopback - - - +.Ed +.Pp +then using the network type +.Sy udp +in calls to the RPC library function (see +.Xr rpc 3 ) +will make the code first try +.Sy udp6 , +and then +.Sy udp . +.Pp +.Xr getnetconfig 3 +and associated functions will parse this file and return structures of +the following format: +.Bd -literal +struct netconfig { + char *nc_netid; /* Network ID */ + unsigned long nc_semantics; /* Semantics (see below) */ + unsigned long nc_flag; /* Flags (see below) */ + char *nc_protofmly; /* Protocol family */ + char *nc_proto; /* Protocol name */ + char *nc_device; /* Network device pathname (unused) */ + unsigned long nc_nlookups; /* Number of lookup libs (unused) */ + char **nc_lookups; /* Names of the libraries (unused) */ + unsigned long nc_unused[9]; /* reserved */ +}; +.Ed +.Sh FILES +.Bl -tag -width /etc/netconfig -compact +.It Pa /etc/netconfig +.El +.Sh SEE ALSO +.Xr getnetconfig 3 , +.Xr getnetpath 3 diff --git a/lib/libc/rpc/netname.c b/lib/libc/rpc/netname.c index cec14df72ab5..f598f78d3ee0 100644 --- a/lib/libc/rpc/netname.c +++ b/lib/libc/rpc/netname.c @@ -41,6 +41,7 @@ static char sccsid[] = "@(#)netname.c 1.8 91/03/11 Copyr 1986 Sun Micro"; * the sun NIS domain architecture. */ +#include "namespace.h" #include <sys/param.h> #include <rpc/rpc.h> #include <rpc/rpc_com.h> @@ -54,6 +55,7 @@ static char sccsid[] = "@(#)netname.c 1.8 91/03/11 Copyr 1986 Sun Micro"; #include <stdlib.h> #include <string.h> #include <unistd.h> +#include "un-namespace.h" #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 256 @@ -101,8 +103,8 @@ getnetname(name) int user2netname(netname, uid, domain) char netname[MAXNETNAMELEN + 1]; - uid_t uid; - char *domain; + const uid_t uid; + const char *domain; { char *dfltdom; @@ -126,8 +128,8 @@ user2netname(netname, uid, domain) int host2netname(netname, host, domain) char netname[MAXNETNAMELEN + 1]; - char *host; - char *domain; + const char *host; + const char *domain; { char *dfltdom; char hostname[MAXHOSTNAMELEN+1]; diff --git a/lib/libc/rpc/netnamer.c b/lib/libc/rpc/netnamer.c index 2fa0a3c1bd57..36fa3dcd629c 100644 --- a/lib/libc/rpc/netnamer.c +++ b/lib/libc/rpc/netnamer.c @@ -38,6 +38,7 @@ static char sccsid[] = "@(#)netnamer.c 1.13 91/03/11 Copyr 1986 Sun Micro"; * will work with any unix system that has adopted the sun NIS domain * architecture. */ +#include "namespace.h" #include <sys/param.h> #include <rpc/rpc.h> #include <rpc/rpc_com.h> @@ -52,6 +53,7 @@ static char sccsid[] = "@(#)netnamer.c 1.13 91/03/11 Copyr 1986 Sun Micro"; #include <string.h> #include <stdlib.h> #include <unistd.h> +#include "un-namespace.h" static char *OPSYS = "unix"; static char *NETID = "netid.byname"; diff --git a/lib/libc/rpc/pmap_clnt.c b/lib/libc/rpc/pmap_clnt.c index 41bb78d582db..676444e1e5d4 100644 --- a/lib/libc/rpc/pmap_clnt.c +++ b/lib/libc/rpc/pmap_clnt.c @@ -1,3 +1,5 @@ +/* $NetBSD: pmap_clnt.c,v 1.16 2000/07/06 03:10:34 christos Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -27,6 +29,7 @@ * Mountain View, California 94043 */ +#include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)pmap_clnt.c 1.37 87/08/11 Copyr 1984 Sun Micro";*/ /*static char *sccsid = "from: @(#)pmap_clnt.c 2.2 88/08/01 4.0 RPCSRC";*/ @@ -44,108 +47,74 @@ static char *rcsid = "$FreeBSD$"; #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 "un-namespace.h" -static struct timeval timeout = { 5, 0 }; -static struct timeval tottimeout = { 60, 0 }; +#include <stdio.h> +#include <stdlib.h> -void clnt_perror(); +#include "rpc_com.h" -#ifndef PORTMAPSOCK -#define PORTMAPSOCK "/var/run/portmapsock" -#endif - -/* - * Set a mapping between program,version and port. - * Calls the pmap service remotely to do the mapping. - */ bool_t -pmap_set(program, version, protocol, port) - u_long program; - u_long version; - int protocol; - u_short port; +pmap_set(u_long program, u_long version, int protocol, int port) { - struct sockaddr_in myaddress; - int socket = -1; - register CLIENT *client; - struct pmap parms; bool_t rslt; - struct stat st; + struct netbuf *na; + struct netconfig *nconf; + char buf[32]; - /* - * Temporary hack for backwards compatibility. Eventually - * this test will go away and we'll use only the "unix" transport. - */ - if (stat(PORTMAPSOCK, &st) == 0 && st.st_mode & S_IFSOCK) - client = clnt_create(PORTMAPSOCK, PMAPPROG, PMAPVERS, "unix"); - else { - if (get_myaddress(&myaddress) != 0) - return (FALSE); - myaddress.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - client = clntudp_bufcreate(&myaddress, PMAPPROG, PMAPVERS, - timeout, &socket, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE); + if ((protocol != IPPROTO_UDP) && (protocol != IPPROTO_TCP)) { + return (FALSE); } - - if (client == (CLIENT *)NULL) + nconf = __rpc_getconfip(protocol == IPPROTO_UDP ? "udp" : "tcp"); + if (nconf == NULL) { return (FALSE); - parms.pm_prog = program; - parms.pm_vers = version; - parms.pm_prot = protocol; - parms.pm_port = port; - if (CLNT_CALL(client, PMAPPROC_SET, xdr_pmap, &parms, xdr_bool, &rslt, - tottimeout) != RPC_SUCCESS) { - clnt_perror(client, "Cannot register service"); + } + 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); } - CLNT_DESTROY(client); - if (socket != -1) - (void)_close(socket); + 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. + * Remove the mapping between program, version and port. * Calls the pmap service remotely to do the un-mapping. */ bool_t -pmap_unset(program, version) - u_long program; - u_long version; +pmap_unset(u_long program, u_long version) { - struct sockaddr_in myaddress; - int socket = -1; - register CLIENT *client; - struct pmap parms; - bool_t rslt; - struct stat st; + 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); + } /* - * Temporary hack for backwards compatibility. Eventually - * this test will go away and we'll use only the "unix" transport. + * 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. */ - if (stat(PORTMAPSOCK, &st) == 0 && st.st_mode & S_IFSOCK) - client = clnt_create(PORTMAPSOCK, PMAPPROG, PMAPVERS, "unix"); - else { - if (get_myaddress(&myaddress) != 0) - return (FALSE); - myaddress.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - client = clntudp_bufcreate(&myaddress, PMAPPROG, PMAPVERS, - timeout, &socket, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE); - } - if (client == (CLIENT *)NULL) - return (FALSE); - parms.pm_prog = program; - parms.pm_vers = version; - parms.pm_port = parms.pm_prot = 0; - CLNT_CALL(client, PMAPPROC_UNSET, xdr_pmap, &parms, xdr_bool, &rslt, - tottimeout); - CLNT_DESTROY(client); - if (socket != -1) - (void)_close(socket); - return (rslt); + return (tcp_rslt || udp_rslt); } diff --git a/lib/libc/rpc/pmap_getmaps.c b/lib/libc/rpc/pmap_getmaps.c index b51ac696b0f3..4c8397f412d4 100644 --- a/lib/libc/rpc/pmap_getmaps.c +++ b/lib/libc/rpc/pmap_getmaps.c @@ -1,3 +1,5 @@ +/* $NetBSD: pmap_getmaps.c,v 1.16 2000/07/06 03:10:34 christos Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -27,6 +29,7 @@ * Mountain View, California 94043 */ +#include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)pmap_getmaps.c 1.10 87/08/11 Copyr 1984 Sun Micro";*/ /*static char *sccsid = "from: @(#)pmap_getmaps.c 2.2 88/08/01 4.0 RPCSRC";*/ @@ -42,16 +45,21 @@ static char *rcsid = "$FreeBSD$"; */ #include "namespace.h" -#include <rpc/rpc.h> -#include <rpc/pmap_prot.h> -#include <rpc/pmap_clnt.h> +#include <sys/types.h> #include <sys/socket.h> +#include <sys/ioctl.h> + +#include <net/if.h> + +#include <assert.h> +#include <errno.h> #include <netdb.h> #include <stdio.h> #include <unistd.h> -#include <errno.h> -#include <net/if.h> -#include <sys/ioctl.h> + +#include <rpc/rpc.h> +#include <rpc/pmap_prot.h> +#include <rpc/pmap_clnt.h> #include "un-namespace.h" #define NAMELEN 255 @@ -65,25 +73,27 @@ struct pmaplist * pmap_getmaps(address) struct sockaddr_in *address; { - struct pmaplist *head = (struct pmaplist *)NULL; - int socket = -1; + struct pmaplist *head = NULL; + int sock = -1; struct timeval minutetimeout; - register CLIENT *client; + CLIENT *client; + + assert(address != NULL); minutetimeout.tv_sec = 60; minutetimeout.tv_usec = 0; address->sin_port = htons(PMAPPORT); client = clnttcp_create(address, PMAPPROG, - PMAPVERS, &socket, 50, 500); - if (client != (CLIENT *)NULL) { - if (CLNT_CALL(client, PMAPPROC_DUMP, xdr_void, NULL, xdr_pmaplist, - &head, minutetimeout) != RPC_SUCCESS) { + 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); } - if (socket != -1) - (void)_close(socket); address->sin_port = 0; return (head); } diff --git a/lib/libc/rpc/pmap_getport.c b/lib/libc/rpc/pmap_getport.c index bef94fdf45eb..ff75c9ff1d62 100644 --- a/lib/libc/rpc/pmap_getport.c +++ b/lib/libc/rpc/pmap_getport.c @@ -1,3 +1,5 @@ +/* $NetBSD: pmap_getport.c,v 1.16 2000/07/06 03:10:34 christos Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -27,6 +29,7 @@ * Mountain View, California 94043 */ +#include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)pmap_getport.c 1.9 87/08/11 Copyr 1984 Sun Micro";*/ /*static char *sccsid = "from: @(#)pmap_getport.c 2.2 88/08/01 4.0 RPCSRC";*/ @@ -41,16 +44,21 @@ static char *rcsid = "$FreeBSD$"; */ #include "namespace.h" -#include <rpc/rpc.h> -#include <rpc/pmap_prot.h> -#include <rpc/pmap_clnt.h> +#include <sys/types.h> #include <sys/socket.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> #include "un-namespace.h" -static struct timeval timeout = { 5, 0 }; -static struct timeval tottimeout = { 60, 0 }; +static const struct timeval timeout = { 5, 0 }; +static const struct timeval tottimeout = { 60, 0 }; /* * Find the mapped port for program,version. @@ -65,20 +73,24 @@ pmap_getport(address, program, version, protocol) u_int protocol; { u_short port = 0; - int socket = -1; - register CLIENT *client; + int sock = -1; + CLIENT *client; struct pmap parms; + assert(address != NULL); + address->sin_port = htons(PMAPPORT); client = clntudp_bufcreate(address, PMAPPROG, - PMAPVERS, timeout, &socket, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE); - if (client != (CLIENT *)NULL) { + 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, PMAPPROC_GETPORT, xdr_pmap, &parms, - xdr_u_short, &port, tottimeout) != RPC_SUCCESS){ + 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) { @@ -86,8 +98,6 @@ pmap_getport(address, program, version, protocol) } CLNT_DESTROY(client); } - if (socket != -1) - (void)_close(socket); address->sin_port = 0; return (port); } diff --git a/lib/libc/rpc/pmap_prot.c b/lib/libc/rpc/pmap_prot.c index f42484299477..62b572562d57 100644 --- a/lib/libc/rpc/pmap_prot.c +++ b/lib/libc/rpc/pmap_prot.c @@ -1,3 +1,5 @@ +/* $NetBSD: pmap_prot.c,v 1.10 2000/01/22 22:19:18 mycroft Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -27,9 +29,10 @@ * Mountain View, California 94043 */ +#include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) -/*static char *sccsid = "from: @(#)pmap_prot.c 1.17 87/08/11 Copyr 1984 Sun Micro";*/ -/*static char *sccsid = "from: @(#)pmap_prot.c 2.1 88/07/29 4.0 RPCSRC";*/ +static char *sccsid = "@(#)pmap_prot.c 1.17 87/08/11 Copyr 1984 Sun Micro"; +static char *sccsid = "@(#)pmap_prot.c 2.1 88/07/29 4.0 RPCSRC"; static char *rcsid = "$FreeBSD$"; #endif @@ -40,9 +43,13 @@ static char *rcsid = "$FreeBSD$"; * Copyright (C) 1984, Sun Microsystems, Inc. */ +#include "namespace.h" +#include <assert.h> + #include <rpc/types.h> #include <rpc/xdr.h> #include <rpc/pmap_prot.h> +#include "un-namespace.h" bool_t @@ -51,6 +58,9 @@ xdr_pmap(xdrs, regs) 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)) diff --git a/lib/libc/rpc/pmap_prot2.c b/lib/libc/rpc/pmap_prot2.c index 9c5230ddaeba..e30f977cb309 100644 --- a/lib/libc/rpc/pmap_prot2.c +++ b/lib/libc/rpc/pmap_prot2.c @@ -1,3 +1,5 @@ +/* $NetBSD: pmap_prot2.c,v 1.14 2000/07/06 03:10:34 christos Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -27,9 +29,10 @@ * Mountain View, California 94043 */ +#include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) -/*static char *sccsid = "from: @(#)pmap_prot2.c 1.3 87/08/11 Copyr 1984 Sun Micro";*/ -/*static char *sccsid = "from: @(#)pmap_prot2.c 2.1 88/07/29 4.0 RPCSRC";*/ +static char *sccsid = "@(#)pmap_prot2.c 1.3 87/08/11 Copyr 1984 Sun Micro"; +static char *sccsid = "@(#)pmap_prot2.c 2.1 88/07/29 4.0 RPCSRC"; static char *rcsid = "$FreeBSD$"; #endif @@ -40,9 +43,13 @@ static char *rcsid = "$FreeBSD$"; * Copyright (C) 1984, Sun Microsystems, Inc. */ +#include "namespace.h" +#include <assert.h> + #include <rpc/types.h> #include <rpc/xdr.h> #include <rpc/pmap_prot.h> +#include "un-namespace.h" /* @@ -85,8 +92,8 @@ static char *rcsid = "$FreeBSD$"; */ bool_t xdr_pmaplist(xdrs, rp) - register XDR *xdrs; - register struct pmaplist **rp; + XDR *xdrs; + struct pmaplist **rp; { /* * more_elements is pre-computed in case the direction is @@ -94,10 +101,15 @@ xdr_pmaplist(xdrs, rp) * xdr_bool when the direction is XDR_DECODE. */ bool_t more_elements; - register int freeing = (xdrs->x_op == XDR_FREE); - register struct pmaplist **next = NULL; + int freeing; + struct pmaplist **next = NULL; /* pacify gcc */ + + assert(xdrs != NULL); + assert(rp != NULL); - while (TRUE) { + freeing = (xdrs->x_op == XDR_FREE); + + for (;;) { more_elements = (bool_t)(*rp != NULL); if (! xdr_bool(xdrs, &more_elements)) return (FALSE); @@ -109,10 +121,23 @@ xdr_pmaplist(xdrs, rp) * before we free the current object ... */ if (freeing) - next = &((*rp)->pml_next); + next = &((*rp)->pml_next); if (! xdr_reference(xdrs, (caddr_t *)rp, - (u_int)sizeof(struct pmaplist), xdr_pmap)) + (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/lib/libc/rpc/pmap_rmt.c b/lib/libc/rpc/pmap_rmt.c index 298c95613e4e..51e6d3a0c3e0 100644 --- a/lib/libc/rpc/pmap_rmt.c +++ b/lib/libc/rpc/pmap_rmt.c @@ -1,3 +1,5 @@ +/* $NetBSD: pmap_rmt.c,v 1.29 2000/07/06 03:10:34 christos Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -27,6 +29,7 @@ * Mountain View, California 94043 */ +#include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)pmap_rmt.c 1.21 87/08/27 Copyr 1984 Sun Micro";*/ /*static char *sccsid = "from: @(#)pmap_rmt.c 2.2 88/08/01 4.0 RPCSRC";*/ @@ -42,24 +45,29 @@ static char *rcsid = "$FreeBSD$"; */ #include "namespace.h" +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/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> -#include <sys/socket.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <errno.h> -#include <string.h> -#include <net/if.h> -#include <sys/ioctl.h> -#include <arpa/inet.h> #include "un-namespace.h" -#define MAX_BROADCAST_SIZE 1400 - -static struct timeval timeout = { 3, 0 }; +static const struct timeval timeout = { 3, 0 }; /* * pmapper remote-call-service interface. @@ -69,7 +77,8 @@ static struct timeval timeout = { 3, 0 }; * 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) +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; @@ -77,15 +86,18 @@ pmap_rmtcall(addr, prog, vers, proc, xdrargs, argsp, xdrres, resp, tout, port_pt struct timeval tout; u_long *port_ptr; { - int socket = -1; - register CLIENT *client; + 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, &socket); - if (client != (CLIENT *)NULL) { + client = clntudp_create(addr, PMAPPROG, PMAPVERS, timeout, &sock); + if (client != NULL) { a.prog = prog; a.vers = vers; a.proc = proc; @@ -94,14 +106,13 @@ pmap_rmtcall(addr, prog, vers, proc, xdrargs, argsp, xdrres, resp, tout, port_pt r.port_ptr = port_ptr; r.results_ptr = resp; r.xdr_results = xdrres; - stat = CLNT_CALL(client, PMAPPROC_CALLIT, xdr_rmtcall_args, &a, - xdr_rmtcallres, &r, tout); + 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; } - if (socket != -1) - (void)_close(socket); addr->sin_port = 0; return (stat); } @@ -113,11 +124,14 @@ pmap_rmtcall(addr, prog, vers, proc, xdrargs, argsp, xdrres, resp, tout, port_pt */ bool_t xdr_rmtcall_args(xdrs, cap) - register XDR *xdrs; - register struct rmtcallargs *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))) { @@ -144,275 +158,19 @@ xdr_rmtcall_args(xdrs, cap) */ bool_t xdr_rmtcallres(xdrs, crp) - register XDR *xdrs; - register struct rmtcallres *crp; + XDR *xdrs; + struct rmtcallres *crp; { caddr_t port_ptr; - port_ptr = (caddr_t)crp->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), - xdr_u_long) && xdr_u_long(xdrs, &crp->resultslen)) { - crp->port_ptr = (u_long *)port_ptr; + (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); } - - -/* - * The following is kludged-up support for simple rpc broadcasts. - * Someday a large, complicated system will replace these trivial - * routines which only support udp/ip . - */ - -static int -getbroadcastnets(addrs, sock, buf) - struct in_addr *addrs; - int sock; /* any valid socket will do */ - char *buf; /* why allocxate more when we can use existing... */ -{ - struct ifconf ifc; - struct ifreq ifreq, *ifr; - struct sockaddr_in *sin; - struct in_addr addr; - char *cp, *cplim; - int n, i = 0; - - ifc.ifc_len = UDPMSGSIZE; - ifc.ifc_buf = buf; - if (_ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) { - perror("broadcast: ioctl (get interface configuration)"); - return (0); - } -#define max(a, b) (a > b ? a : b) -#define size(p) max((p).sa_len, sizeof(p)) - cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */ - for (cp = buf; cp < cplim; - cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) { - ifr = (struct ifreq *)cp; - if (ifr->ifr_addr.sa_family != AF_INET) - continue; - memcpy(&ifreq, ifr, sizeof(ifreq)); - if (_ioctl(sock, SIOCGIFFLAGS, (char *)&ifreq) < 0) { - perror("broadcast: ioctl (get interface flags)"); - continue; - } - if ((ifreq.ifr_flags & IFF_BROADCAST) && - (ifreq.ifr_flags & IFF_UP)) { - sin = (struct sockaddr_in *)&ifr->ifr_addr; -#ifdef SIOCGIFBRDADDR /* 4.3BSD */ - if (_ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { - addr = - inet_makeaddr(inet_netof(sin->sin_addr), - INADDR_ANY); - } else { - addr = ((struct sockaddr_in*) - &ifreq.ifr_addr)->sin_addr; - } -#else /* 4.2 BSD */ - addr = inet_makeaddr(inet_netof(sin->sin_addr), - INADDR_ANY); -#endif - for (n=i-1; n>=0; n--) { - if (addr.s_addr == addrs[n].s_addr) - break; - } - if (n<0) { - addrs[i++] = addr; - } - } - } - return (i); -} - -typedef bool_t (*resultproc_t)(); - -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 */ - 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 */ -{ - enum clnt_stat stat; - AUTH *unix_auth = authunix_create_default(); - XDR xdr_stream; - register XDR *xdrs = &xdr_stream; - int outlen, inlen, fromlen, nets; - register int sock; - int on = 1; - fd_set *fds, readfds; - register int i; - bool_t done = FALSE; - register u_long xid; - u_long port; - struct in_addr addrs[20]; - struct sockaddr_in baddr, raddr; /* broadcast and response addresses */ - struct rmtcallargs a; - struct rmtcallres r; - struct rpc_msg msg; - struct timeval t, tv; - char outbuf[MAX_BROADCAST_SIZE], inbuf[UDPMSGSIZE]; - static u_int32_t disrupt; - - if (disrupt == 0) - disrupt = (u_int32_t)(long)resultsp; - - /* - * initialization: create a socket, a broadcast address, and - * preserialize the arguments into a send buffer. - */ - if ((sock = _socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { - perror("Cannot create socket for broadcast rpc"); - stat = RPC_CANTSEND; - goto done_broad; - } -#ifdef SO_BROADCAST - if (_setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) { - perror("Cannot set socket option SO_BROADCAST"); - stat = RPC_CANTSEND; - goto done_broad; - } -#endif /* def SO_BROADCAST */ - if (sock + 1 > FD_SETSIZE) { - int bytes = howmany(sock + 1, NFDBITS) * sizeof(fd_mask); - fds = (fd_set *)malloc(bytes); - if (fds == NULL) { - stat = RPC_CANTSEND; - goto done_broad; - } - memset(fds, 0, bytes); - } else { - fds = &readfds; - FD_ZERO(fds); - } - - nets = getbroadcastnets(addrs, sock, inbuf); - memset(&baddr, 0, sizeof (baddr)); - baddr.sin_len = sizeof(struct sockaddr_in); - baddr.sin_family = AF_INET; - baddr.sin_port = htons(PMAPPORT); - baddr.sin_addr.s_addr = htonl(INADDR_ANY); - (void)gettimeofday(&t, (struct timezone *)0); - msg.rm_xid = xid = (++disrupt) ^ getpid() ^ t.tv_sec ^ t.tv_usec; - t.tv_usec = 0; - msg.rm_direction = CALL; - msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; - msg.rm_call.cb_prog = PMAPPROG; - msg.rm_call.cb_vers = PMAPVERS; - msg.rm_call.cb_proc = PMAPPROC_CALLIT; - msg.rm_call.cb_cred = unix_auth->ah_cred; - msg.rm_call.cb_verf = unix_auth->ah_verf; - a.prog = prog; - a.vers = vers; - a.proc = proc; - a.xdr_args = xargs; - a.args_ptr = argsp; - r.port_ptr = &port; - r.xdr_results = xresults; - r.results_ptr = resultsp; - xdrmem_create(xdrs, outbuf, MAX_BROADCAST_SIZE, XDR_ENCODE); - if ((! xdr_callmsg(xdrs, &msg)) || (! xdr_rmtcall_args(xdrs, &a))) { - stat = RPC_CANTENCODEARGS; - goto done_broad; - } - outlen = (int)xdr_getpos(xdrs); - xdr_destroy(xdrs); - /* - * Basic loop: broadcast a packet and wait a while for response(s). - * The response timeout grows larger per iteration. - * - * XXX This will loop about 5 times the stop. If there are - * lots of signals being received by the process it will quit - * send them all in one quick burst, not paying attention to - * the intended function of sending them slowly over half a - * minute or so - */ - for (t.tv_sec = 4; t.tv_sec <= 14; t.tv_sec += 2) { - for (i = 0; i < nets; i++) { - baddr.sin_addr = addrs[i]; - if (_sendto(sock, outbuf, outlen, 0, - (struct sockaddr *)&baddr, - sizeof (struct sockaddr)) != outlen) { - perror("Cannot send broadcast packet"); - stat = RPC_CANTSEND; - goto done_broad; - } - } - if (eachresult == NULL) { - stat = RPC_SUCCESS; - goto done_broad; - } - recv_again: - msg.acpted_rply.ar_verf = _null_auth; - msg.acpted_rply.ar_results.where = (caddr_t)&r; - msg.acpted_rply.ar_results.proc = xdr_rmtcallres; - /* XXX we know the other bits are still clear */ - FD_SET(sock, fds); - tv = t; /* for _select() that copies back */ - switch (_select(sock + 1, fds, NULL, NULL, &tv)) { - - case 0: /* timed out */ - stat = RPC_TIMEDOUT; - continue; - - case -1: /* some kind of error */ - if (errno == EINTR) - goto recv_again; - perror("Broadcast select problem"); - stat = RPC_CANTRECV; - goto done_broad; - - } /* end of select results switch */ - try_again: - fromlen = sizeof(struct sockaddr); - inlen = _recvfrom(sock, inbuf, UDPMSGSIZE, 0, - (struct sockaddr *)&raddr, &fromlen); - if (inlen < 0) { - if (errno == EINTR) - goto try_again; - perror("Cannot receive reply to broadcast"); - stat = RPC_CANTRECV; - goto done_broad; - } - if (inlen < sizeof(u_int32_t)) - goto recv_again; - /* - * see if reply transaction id matches sent id. - * If so, decode the results. - */ - xdrmem_create(xdrs, inbuf, (u_int)inlen, XDR_DECODE); - if (xdr_replymsg(xdrs, &msg)) { - if ((msg.rm_xid == xid) && - (msg.rm_reply.rp_stat == MSG_ACCEPTED) && - (msg.acpted_rply.ar_stat == SUCCESS)) { - raddr.sin_port = htons((u_short)port); - done = (*eachresult)(resultsp, &raddr); - } - /* otherwise, we just ignore the errors ... */ - } - xdrs->x_op = XDR_FREE; - msg.acpted_rply.ar_results.proc = 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; - } - } -done_broad: - if (fds != &readfds) - free(fds); - if (sock >= 0) - (void)_close(sock); - AUTH_DESTROY(unix_auth); - return (stat); -} - diff --git a/lib/libc/rpc/rpc.3 b/lib/libc/rpc/rpc.3 index e2c73cf88de5..fdd28512fd4e 100644 --- a/lib/libc/rpc/rpc.3 +++ b/lib/libc/rpc/rpc.3 @@ -1,1519 +1,507 @@ -.\" @(#)rpc.3n 2.4 88/08/08 4.0 RPCSRC; from 1.19 88/06/24 SMI +.\" @(#)rpc.3n 1.31 93/08/31 SMI; from SVr4 +.\" Copyright 1989 AT&T +.\" $NetBSD: rpc.3,v 1.10 2000/06/02 23:11:12 fvdl Exp $ .\" $FreeBSD$ -.\" -.Dd February 16, 1988 +.Dd May 7, 1993 .Dt RPC 3 .Os .Sh NAME .Nm rpc -.Nd "library routines for remote procedure calls" +.Nd library routines for remote procedure calls .Sh LIBRARY .Lb libc .Sh SYNOPSIS -.Fd "#include <rpc/rpc.h>" -.Pp -See -.Sx DESCRIPTION -for function declarations. +.Fd #include <rpc/rpc.h> +.Fd #include <netconfig.h> .Sh DESCRIPTION -These routines allow C programs to make procedure -calls on other machines across the network. -First, the client calls a procedure to send a -data packet to the server. -Upon receipt of the packet, the server calls a dispatch routine -to perform the requested service, and then sends back a -reply. -Finally, the procedure call returns to the client. -.Pp -Routines that are used for Secure -.Tn RPC ( DES -authentication) are described in -.Xr rpc_secure 3 . -Secure -.Tn RPC -can be used only if -.Tn DES -encryption is available. -.Bl -tag -width indent -compact -.Pp -.It Xo -.Ft void -.Xc -.It Xo -.Fn auth_destroy "AUTH *auth" -.Xc -.Pp -A macro that destroys the authentication information associated with -.Fa auth . -Destruction usually involves deallocation of private data -structures. -The use of -.Fa auth -is undefined after calling -.Fn auth_destroy . -.Pp -.It Xo -.Ft "AUTH *" -.Xc -.It Xo -.Fn authnone_create -.Xc -.Pp -Create and return an -.Tn RPC -authentication handle that passes nonusable authentication -information with each remote procedure call. -This is the -default authentication used by -.Tn RPC . -.Pp -.It Xo -.Ft "AUTH *" -.Xc -.It Xo -.Fn authunix_create "char *host" "int uid" "int gid" "int len" "int *aup_gids" -.Xc -.Pp -Create and return an -.Tn RPC -authentication handle that contains -.Ux -authentication information. -The parameter -.Fa host -is the name of the machine on which the information was -created; -.Fa uid -is the user's user ID; -.Fa gid -is the user's current group ID; -.Fa len -and -.Fa aup_gids -refer to a counted array of groups to which the user belongs. -It is easy to impersonate a user. -.Pp -.It Xo -.Ft "AUTH *" -.Xc -.It Xo -.Fn authunix_create_default -.Xc -.Pp -Calls -.Fn authunix_create -with the appropriate parameters. -.Pp -.It Xo -.Fo callrpc -.Fa "char *host" -.Fa "u_long prognum" -.Fa "u_long versnum" -.Fa "u_long procnum" -.Fa "xdrproc_t inproc" -.Fa "char *in" -.Fa "xdrproc_t outproc" -.Fa "char *out" -.Fc -.Xc -.Pp -Call the remote procedure associated with -.Fa prognum , -.Fa versnum , -and -.Fa procnum -on the machine -.Fa host . -The parameter -.Fa in -is the address of the procedure's argument(s), and -.Fa out -is the address of where to place the result(s); -.Fa inproc -is used to encode the procedure's parameters, and -.Fa outproc -is used to decode the procedure's results. -This routine returns zero if it succeeds, or the value of -.Vt "enum clnt_stat" -cast to an integer if it fails. -The routine -.Fn clnt_perrno -is handy for translating failure statuses into messages. -.Pp -Warning: calling remote procedures with this routine -uses -.Tn UDP/IP -as a transport; see -.Fn clntudp_create -for restrictions. -You do not have control of timeouts or authentication using -this routine. -.Pp -.It Xo -.Ft "enum clnt_stat" -.Xc -.It Xo -.Fo clnt_broadcast -.Fa "u_long prognum" -.Fa "u_long versnum" -.Fa "u_long procnum" -.Fa "xdrproc_t inproc" -.Fa "char *in" -.Fa "xdrproc_t outproc" -.Fa "char *out" -.Fa "bool_t (*eachresult)(caddr_t, struct sockaddr_in *) -.Fc -.Xc -.Pp -Like -.Fn callrpc , -except the call message is broadcast to all locally -connected broadcast nets. -Each time it receives a -response, this routine calls -.Fn eachresult , -whose form is: -.Bd -ragged -offset indent -.Ft bool_t -.Fn eachresult "caddr_t out" "struct sockaddr_in *addr" -.Ed -.Pp -where -.Fa out -is the same as -.Fa out -passed to -.Fn clnt_broadcast , -except that the remote procedure's output is decoded there; -.Fa addr -points to the address of the machine that sent the results. -If -.Fn eachresult -returns zero, -.Fn clnt_broadcast -waits for more replies; otherwise it returns with appropriate -status. -.Pp -Warning: broadcast sockets are limited in size to the -maximum transfer unit of the data link. -For ethernet, -this value is 1500 bytes. -.Pp -.It Xo -.Ft "enum clnt_stat" -.Xc -.It Xo -.Fo clnt_call -.Fa "CLIENT *clnt" -.Fa "u_long procnum" -.Fa "xdrproc_t inproc" -.Fa "char *in" -.Fa "xdrproc_t outproc" -.Fa "char *out" -.Fa "struct timeval tout" -.Fc -.Xc +These +routines allow C language programs to make procedure +calls on other machines across a network. +First, the client sends a request to the server. +On receipt of the request, the server calls a dispatch routine +to perform the requested service, and then sends back a reply. .Pp -A macro that calls the remote procedure -.Fa procnum -associated with the client handle, -.Fa clnt , -which is obtained with an -.Tn RPC -client creation routine such as -.Fn clnt_create . -The parameter -.Fa in -is the address of the procedure's argument(s), and -.Fa out -is the address of where to place the result(s); -.Fa inproc -is used to encode the procedure's parameters, and -.Fa outproc -is used to decode the procedure's results; -.Fa tout -is the time allowed for results to come back. -.Pp -.It Xo -.Ft void -.Fn clnt_destroy "CLIENT *clnt" -.Xc -.Pp -A macro that destroys the client's -.Tn RPC -handle. -Destruction usually involves deallocation -of private data structures, including -.Fa clnt -itself. -Use of -.Fa clnt -is undefined after calling -.Fn clnt_destroy . -If the -.Tn RPC -library opened the associated socket, it will close it also. -Otherwise, the socket remains open. -.Pp -.It Xo -.Ft CLIENT * -.Xc -.It Xo -.Fn clnt_create "char *host" "u_long prog" "u_long vers" "char *proto" -.Xc -.Pp -Generic client creation routine. -.Fa host -identifies the name of the remote host where the server -is located. -.Fa proto -indicates which kind of transport protocol to use. -The -currently supported values for this field are -.Qq Li udp -and -.Qq Li tcp . -Default timeouts are set, but can be modified using -.Fn clnt_control . -.Pp -Warning: Using -.Tn UDP -has its shortcomings. -Since -.Tn UDP Ns \-based -.Tn RPC -messages can only hold up to 8 Kbytes of encoded data, -this transport cannot be used for procedures that take -large arguments or return huge results. -.Pp -.It Xo -.Ft bool_t -.Xc -.It Xo -.Fn clnt_control "CLIENT *cl" "u_int req" "char *info" -.Xc -.Pp -A macro used to change or retrieve various information -about a client object. -.Fa req -indicates the type of operation, and -.Fa info -is a pointer to the information. -For both -.Tn UDP -and -.Tn TCP , -the supported values of -.Fa req -and their argument types and what they do are: -.Bl -column "CLSET_RETRY_TIMEOUT" "struct sockaddr_in" -.It Dv CLSET_TIMEOUT Ta Xo -.Vt "struct timeval" Ta "set total timeout" -.Xc -.It Dv CLGET_TIMEOUT Ta Xo -.Vt "struct timeval" Ta "get total timeout" -.Xc -.El -.Pp -Note: if you set the timeout using -.Fn clnt_control , -the timeout parameter passed to -.Fn clnt_call -will be ignored in all future calls. -.Bl -column "CLSET_RETRY_TIMEOUT" "struct sockaddr_in" -.It Dv CLGET_SERVER_ADDR Ta Xo -.Vt "struct sockaddr_in" Ta "get server's address" -.Xc -.El -.Pp -The following operations are valid for -.Tn UDP -only: -.Bl -column "CLSET_RETRY_TIMEOUT" "struct sockaddr_in" -.It Dv CLSET_RETRY_TIMEOUT Ta Xo -.Vt "struct timeval" Ta "set the retry timeout" -.Xc -.It Dv CLGET_RETRY_TIMEOUT Ta Xo -.Vt "struct timeval" Ta "get the retry timeout" -.Xc -.El -.Pp -The retry timeout is the time that -.Tn "UDP RPC" -waits for the server to reply before -retransmitting the request. -.Pp -.It Xo -.Ft bool_t -.Fn clnt_freeres "CLIENT *clnt" "xdrproc_t outproc" "char *out" -.Xc -.Pp -A macro that frees any data allocated by the -.Tn RPC/XDR -system when it decoded the results of an -.Tn RPC -call. -The parameter -.Fa out -is the address of the results, and -.Fa outproc -is the -.Tn XDR -routine describing the results. -This routine returns one if the results were successfully -freed, -and zero otherwise. -.Pp -.It Xo -.Ft void -.Xc -.It Xo -.Fn clnt_geterr "CLIENT *clnt" "struct rpc_err *errp" -.Xc -.Pp -A macro that copies the error structure out of the client -handle -to the structure at address -.Fa errp . -.Pp -.It Xo -.Ft void -.Xc -.It Xo -.Fn clnt_pcreateerror "char *s" -.Xc -.Pp -prints a message to standard error indicating -why a client -.Tn RPC -handle could not be created. -The message is prepended with string -.Fa s -and a colon. -Used when a +All +RPC routines require the header +.Aq Pa rpc/rpc.h . +Routines that take a +.Vt "struct netconfig" +also require that +.Aq Pa netconfig.h +be included. +.Sh Nettype +Some of the high-level +RPC interface routines take a +.Fa nettype +string as one of the parameters +(for example, .Fn clnt_create , -.Fn clntraw_create , -.Fn clnttcp_create , -or -.Fn clntudp_create -call fails. +.Fn svc_create , +.Fn rpc_reg , +.Fn rpc_call ) . +This string defines a class of transports which can be used +for a particular application. .Pp -.It Xo -.Ft void -.Xc -.It Xo -.Fn clnt_perrno "enum clnt_stat stat" -.Xc -.Pp -Print a message to standard error corresponding -to the condition indicated by -.Fa stat . -Used after -.Fn callrpc . -.Pp -.It Xo -.Ft void -.Fn clnt_perror "CLIENT *clnt" "char *s" -.Xc -.Pp -Print a message to standard error indicating why an -.Tn RPC -call failed; -.Fa clnt -is the handle used to do the call. -The message is prepended with string -.Fa s -and a colon. -Used after -.Fn clnt_call . -.Pp -.It Xo -.Ft "char *" -.Xc -.It Xo -.Fn clnt_spcreateerror "char *s" -.Xc -.Pp -Like -.Fn clnt_pcreateerror , -except that it returns a string -instead of printing to the standard error. -.Pp -Bugs: returns pointer to static data that is overwritten -on each call. -.Pp -.It Xo -.Ft "char *" -.Xc -.It Xo -.Fn clnt_sperrno "enum clnt_stat stat" -.Xc -.Pp -Take the same arguments as -.Fn clnt_perrno , -but instead of sending a message to the standard error -indicating why an -.Tn RPC -call failed, return a pointer to a string which contains -the message. -The string ends with a newline -.Pq Ql "\en" . -.Pp -.Fn clnt_sperrno -is used instead of -.Fn clnt_perrno -if the program does not have a standard error (as a program -running as a server quite likely does not), or if the -programmer -does not want the message to be output with -.Fn printf , -or if a message format different from that supported by -.Fn clnt_perrno -is to be used. -.Pp -Note: unlike -.Fn clnt_sperror -and -.Fn clnt_spcreaterror , -.Fn clnt_sperrno -returns pointer to static data, but the -result will not get overwritten on each call. -.Pp -.It Xo -.Ft "char *" -.Xc -.It Xo -.Fn clnt_sperror "CLIENT *rpch" "char *s" -.Xc -.Pp -Like -.Fn clnt_perror , -except that (like -.Fn clnt_sperrno ) -it returns a string instead of printing to standard error. -.Pp -Bugs: returns pointer to static data that is overwritten -on each call. -.Pp -.It Xo -.Ft "CLIENT *" -.Xc -.It Xo -.Fn clntraw_create "u_long prognum" "u_long versnum" -.Xc -.Pp -This routine creates a toy -.Tn RPC -client for the remote program -.Fa prognum , -version -.Fa versnum . -The transport used to pass messages to the service is -actually a buffer within the process's address space, so the -corresponding -.Tn RPC -server should live in the same address space; see -.Fn svcraw_create . -This allows simulation of -.Tn RPC -and acquisition of -.Tn RPC -overheads, such as round trip times, without any -kernel interference. -This routine returns -.Dv NULL -if it fails. -.Pp -.It Xo -.Ft "CLIENT *" -.Xc -.It Xo -.Fo clnttcp_create -.Fa "struct sockaddr_in *addr" -.Fa "u_long prognum" -.Fa "u_long versnum" -.Fa "int *sockp" -.Fa "u_int sendsz" -.Fa "u_int recvsz" -.Fc -.Xc -.Pp -This routine creates an -.Tn RPC -client for the remote program -.Fa prognum , -version -.Fa versnum ; -the client uses -.Tn TCP/IP -as a transport. -The remote program is located at Internet -address -.Fa addr . -If -.Fa addr\->sin_port -is zero, then it is set to the actual port that the remote -program is listening on (the remote -.Xr portmap 8 -service is consulted for this information). -The parameter -.Fa sockp -is a socket; if it is -.Dv RPC_ANYSOCK , -then this routine opens a new one and sets -.Fa sockp . -Since -.Tn TCP Ns \-based -.Tn RPC -uses buffered -.Tn I/O , -the user may specify the size of the send and receive buffers -with the parameters -.Fa sendsz -and -.Fa recvsz ; -values of zero choose suitable defaults. -This routine returns -.Dv NULL -if it fails. -.Pp -.It Xo -.Ft "CLIENT *" -.Xc -.It Xo -.Fo clntudp_create -.Fa "struct sockaddr_in *addr" -.Fa "u_long prognum" -.Fa "u_long versnum" -.Fa "struct timeval wait" -.Fa "int *sockp" -.Fc -.Xc -.Pp -This routine creates an -.Tn RPC -client for the remote program -.Fa prognum , -version -.Fa versnum ; -the client uses -.Tn UDP/IP -as a transport. -The remote program is located at Internet -address -.Fa addr . -If -.Fa addr\->sin_port -is zero, then it is set to actual port that the remote -program is listening on (the remote -.Xr portmap 8 -service is consulted for this information). -The parameter -.Fa sockp -is a socket; if it is -.Dv RPC_ANYSOCK , -then this routine opens a new one and sets -.Fa sockp . -The -.Tn UDP -transport resends the call message in intervals of -.Fa wait -time until a response is received or until the call times -out. -The total time for the call to time out is specified by -.Fn clnt_call . -.Pp -Warning: since -.Tn UDP Ns \-based -.Tn RPC -messages can only hold up to 8 Kbytes -of encoded data, this transport cannot be used for procedures -that take large arguments or return huge results. -.Pp -.It Xo -.Ft "CLIENT *" -.Xc -.It Xo -.Fo clntudp_bufcreate -.Fa "struct sockaddr_in *addr" -.Fa "u_long prognum" -.Fa "u_long versnum" -.Fa "struct timeval wait" -.Fa "int *sockp" -.Fa "unsigned int sendsize" -.Fa "unsigned int recosize" -.Fc -.Xc -.Pp -This routine creates an -.Tn RPC -client for the remote program -.Fa prognum , -on -.Fa versnum ; -the client uses -.Tn UDP/IP -as a transport. -The remote program is located at Internet -address -.Fa addr . -If -.Fa addr\->sin_port -is zero, then it is set to actual port that the remote -program is listening on (the remote -.Xr portmap 8 -service is consulted for this information). -The parameter -.Fa sockp -is a socket; if it is -.Dv RPC_ANYSOCK , -then this routine opens a new one and sets -.Fa sockp . -The -.Tn UDP -transport resends the call message in intervals of -.Fa wait -time until a response is received or until the call times -out. -The total time for the call to time out is specified by -.Fn clnt_call . -.Pp -This allows the user to specify the maximum packet size -for sending and receiving -.Tn UDP Ns \-based -.Tn RPC -messages. -.Pp -.It Xo -.Ft int -.Xc -.It Xo -.Fn get_myaddress "struct sockaddr_in *addr" -.Xc -.Pp -Stuff the machine's -.Tn IP -address into -.Fa addr , -without consulting the library routines that deal with -.Pa /etc/hosts . -The port number is always set to -.Fn htons PMAPPORT . -Returns zero on success, non-zero on failure. -.Pp -.It Xo -.Ft "struct pmaplist *" -.Xc -.It Xo -.Fn pmap_getmaps "struct sockaddr_in *addr" -.Xc -.Pp -A user interface to the -.Xr portmap 8 -service, which returns a list of the current -.Tn RPC -program\-to\-port mappings -on the host located at -.Tn IP -address -.Fa addr . -This routine can return -.Dv NULL . -The command -.Dq Nm rpcinfo Fl p -uses this routine. -.Pp -.It Xo -.Ft u_short -.Xc -.It Xo -.Fo pmap_getport -.Fa "struct sockaddr_in *addr" -.Fa "u_long prognum" -.Fa "u_long versnum" -.Fa "u_long protocol" -.Fc -.Xc -.Pp -A user interface to the -.Xr portmap 8 -service, which returns the port number -on which waits a service that supports program number -.Fa prognum , -version -.Fa versnum , -and speaks the transport protocol associated with -.Fa protocol . -The value of -.Fa protocol -is most likely -.Dv IPPROTO_UDP +.Fa nettype +can be one of the following: +.Bl -tag -width datagram_v +.It netpath +Choose from the transports which have been +indicated by their token names in the +.Ev NETPATH +environment variable. +.Ev NETPATH +is unset or +.Dv NULL , +it defaults to +.Qq visible . +.Qq netpath +is the default +.Fa nettype . +.It visible +Choose the transports which have the visible flag (v) +set in the +.Pa /etc/netconfig +file. +.It circuit_v +This is same as +.Qq visible +except that it chooses only the connection oriented transports +(semantics +.Qq tpi_cots or -.Dv IPPROTO_TCP . -A return value of zero means that the mapping does not exist -or that -the -.Tn RPC -system failed to contact the remote -.Xr portmap 8 -service. -In the latter case, the global variable -.Va rpc_createerr -contains the -.Tn RPC -status. -.Pp -.It Xo -.Ft "enum clnt_stat" -.Xc -.It Xo -.Fo pmap_rmtcall -.Fa "struct sockaddr_in *addr" -.Fa "u_long prognum" -.Fa "u_long versnum" -.Fa "u_long procnum" -.Fa "xdrproc_t inproc" -.Fa "char *in" -.Fa "xdrproc_t outproc" -.Fa "char *out" -.Fa "struct timeval tout" -.Fa "u_long *portp" -.Fc -.Xc -.Pp -A user interface to the -.Xr portmap 8 -service, which instructs -.Xr portmap 8 -on the host at -.Tn IP -address -.Fa addr -to make an -.Tn RPC -call on your behalf to a procedure on that host. -The parameter -.Fa portp -will be modified to the program's port number if the -procedure -succeeds. -The definitions of other parameters are discussed -in -.Fn callrpc -and -.Fn clnt_call . -This procedure should be used for a -.Dq ping -and nothing -else. -See also -.Fn clnt_broadcast . -.Pp -.It Xo -.Ft bool_t -.Fn pmap_set "u_long prognum" "u_long versnum" "u_long protocol" "u_short port" -.Xc -.Pp -A user interface to the -.Xr portmap 8 -service, which establishes a mapping between the triple -.Pq Fa prognum , versnum , protocol -and -.Fa port -on the machine's -.Xr portmap 8 -service. -The value of -.Fa protocol -is most likely -.Dv IPPROTO_UDP +.Qq tpi_cots_ord ) +from the entries in the +.Pa /etc/netconfig +file. +.It datagram_v +This is same as +.Qq visible +except that it chooses only the connectionless datagram transports +(semantics +.Qq tpi_clts ) +from the entries in the +.Pa /etc/netconfig +file. +.It circuit_n +This is same as +.Qq netpath +except that it chooses only the connection oriented datagram transports +(semantics +.Qq tpi_cots or -.Dv IPPROTO_TCP . -This routine returns one if it succeeds, zero otherwise. -Automatically done by -.Fn svc_register . -.Pp -.It Xo -.Ft bool_t -.Fn pmap_unset "u_long prognum" "u_long versnum" -.Xc -.Pp -A user interface to the -.Xr portmap 8 -service, which destroys all mapping between the triple -.Pq Fa prognum , versnum , * -and -.Fa ports -on the machine's -.Xr portmap 8 -service. -This routine returns one if it succeeds, zero -otherwise. -.Pp -.It Xo -.Ft bool_t -.Fo registerrpc -.Fa "u_long prognum" -.Fa "u_long versnum" -.Fa "u_long procnum" -.Fa "char *(*procname)(void)" -.Fa "xdrproc_t inproc" -.Fa "xdrproc_t outproc" -.Fc -.Xc -.Pp -Register procedure -.Fa procname -with the -.Tn RPC -service package. -If a request arrives for program -.Fa prognum , -version -.Fa versnum , -and procedure -.Fa procnum , -.Fa procname -is called with a pointer to its parameter(s); -.Fa progname -should return a pointer to its static result(s); -.Fa inproc -is used to decode the parameters while -.Fa outproc -is used to encode the results. -This routine returns zero if the registration succeeded, \-1 -otherwise. -.Pp -Warning: remote procedures registered in this form -are accessed using the -.Tn UDP/IP -transport; see -.Fn svcudp_create -for restrictions. -.Pp -.It Xo -.Vt "struct rpc_createerr" rpc_createerr ; -.Xc -.Pp -A global variable whose value is set by any -.Tn RPC -client creation routine -that does not succeed. -Use the routine -.Fn clnt_pcreateerror -to print the reason why. -.Pp -.It Xo -.Ft bool_t -.Fn svc_destroy "SVCXPRT * xprt" -.Xc -.Pp -A macro that destroys the -.Tn RPC -service transport handle, -.Fa xprt . -Destruction usually involves deallocation -of private data structures, including -.Fa xprt -itself. -Use of -.Fa xprt -is undefined after calling this routine. -.Pp -.It Xo -.Vt fd_set svc_fdset ; -.Xc -.Pp -A global variable reflecting the -.Tn RPC -service side's -read file descriptor bit mask; it is suitable as a template parameter -to the -.Xr select 2 -system call. -This is only of interest -if a service implementor does not call -.Fn svc_run , -but rather does his own asynchronous event processing. -This variable is read\-only (do not pass its address to -.Xr select 2 ! ) , -yet it may change after calls to -.Fn svc_getreqset -or any creation routines. -As well, note that if the process has descriptor limits -which are extended beyond -.Dv FD_SETSIZE , -this variable will only be usable for the first -.Dv FD_SETSIZE -descriptors. -.Pp -.It Xo -.Vt int svc_fds ; -.Xc -.Pp -Similar to -.Va svc_fdset , -but limited to 32 descriptors. -This -interface is obsoleted by -.Va svc_fdset . -.Pp -.It Xo -.Ft bool_t -.Fn svc_freeargs "SVCXPRT *xprt" "xdrproc_t inproc" "char *in" -.Xc -.Pp -A macro that frees any data allocated by the -.Tn RPC/XDR -system when it decoded the arguments to a service procedure -using -.Fn svc_getargs . -This routine returns 1 if the results were successfully -freed, -and zero otherwise. -.Pp -.It Xo -.Ft bool_t -.Fn svc_getargs "SVCXPRT *xprt" "xdrproc_t inproc" "char *in" -.Xc -.Pp -A macro that decodes the arguments of an -.Tn RPC -request -associated with the -.Tn RPC -service transport handle, -.Fa xprt . -The parameter -.Fa in -is the address where the arguments will be placed; -.Fa inproc -is the -.Tn XDR -routine used to decode the arguments. -This routine returns one if decoding succeeds, and zero -otherwise. -.Pp -.It Xo -.Ft "struct sockaddr_in *" -.Xc -.It Xo -.Fn svc_getcaller "SVCXPRT *xprt" -.Xc -.Pp -The approved way of getting the network address of the caller -of a procedure associated with the -.Tn RPC -service transport handle, -.Fa xprt . -.Pp -.It Xo -.Ft void -.Fn svc_getreqset "fd_set *rdfds" -.Xc -.Pp -This routine is only of interest if a service implementor -does not call -.Fn svc_run , -but instead implements custom asynchronous event processing. -It is called when the -.Xr select 2 -system call has determined that an -.Tn RPC -request has arrived on some -.Tn RPC -socket(s); -.Fa rdfds -is the resultant read file descriptor bit mask. -The routine returns when all sockets associated with the -value of -.Fa rdfds -have been serviced. -.Pp -.It Xo -.Ft void -.Fn svc_getreq "int rdfds" -.Xc -.Pp -Similar to -.Fn svc_getreqset , -but limited to 32 descriptors. -This interface is obsoleted by -.Fn svc_getreqset . -.Pp -.It Xo -.Ft bool_t -.Fo svc_register -.Fa "SVCXPRT *xprt" -.Fa "u_long prognum" -.Fa "u_long versnum" -.Fa "void (*dispatch)(struct svc_req *, SVCXPRT *)" -.Fa "int protocol" -.Fc -.Xc +.Qq tpi_cots_ord ) . +.It datagram_n +This is same as +.Qq netpath +except that it chooses only the connectionless datagram transports +(semantics +.Qq tpi_clts ) . +.It udp +This refers to Internet UDP, both version 4 and 6. +.It tcp +This refers to Internet TCP, both version 4 and 6. +.El .Pp -Associates -.Fa prognum -and -.Fa versnum -with the service dispatch procedure, -.Fn dispatch . -If -.Fa protocol -is zero, the service is not registered with the -.Xr portmap 8 -service. If -.Fa protocol -is non-zero, then a mapping of the triple -.Pq Fa prognum , versnum , protocol -to -.Fa xprt\->xp_port -is established with the local -.Xr portmap 8 -service (generally -.Fa protocol -is zero, -.Dv IPPROTO_UDP -or -.Dv IPPROTO_TCP ) . -The procedure -.Fn dispatch -has the following form: -.Bd -ragged -offset indent -.Ft bool_t -.Fn dispatch "struct svc_req *request" "SVCXPRT *xprt" +.Fa nettype +is +.Dv NULL , +it defaults to +.Qq netpath . +The transports are tried in left to right order in the +.Ev NETPATH +variable or in top to down order in the +.Pa /etc/netconfig +file. +.Sh Derived Types +The derived types used in the RPC interfaces are defined as follows: +.Bd -literal + typedef u_int32_t rpcprog_t; + typedef u_int32_t rpcvers_t; + typedef u_int32_t rpcproc_t; + typedef u_int32_t rpcprot_t; + typedef u_int32_t rpcport_t; + typedef int32_t rpc_inline_t; .Ed +.Sh "Data Structures" +Some of the data structures used by the +RPC package are shown below. +.Sh "The AUTH Structure" +.Bd -literal +/* + * Authentication info. Opaque to client. + */ +struct opaque_auth { + enum_t oa_flavor; /* flavor of auth */ + caddr_t oa_base; /* address of more auth stuff */ + u_int oa_length; /* not to exceed MAX_AUTH_BYTES */ +}; + +/* + * Auth handle, interface to client side authenticators. + */ +typedef struct { + struct opaque_auth ah_cred; + struct opaque_auth ah_verf; + struct auth_ops { + void (*ah_nextverf)(\|); + int (*ah_marshal)(\|); /* nextverf & serialize */ + int (*ah_validate)(\|); /* validate verifier */ + int (*ah_refresh)(\|); /* refresh credentials */ + void (*ah_destroy)(\|); /* destroy this structure */ + } *ah_ops; + caddr_t ah_private; +} AUTH; +.Ed +.Sh "The CLIENT Structure" +.Bd -literal +/* + * Client rpc handle. + * Created by individual implementations. + * Client is responsible for initializing auth. + */ + +typedef struct { + AUTH *cl_auth; /* authenticator */ + struct clnt_ops { + enum clnt_stat (*cl_call)(); /* call remote procedure */ + void (*cl_abort)(); /* abort a call */ + void (*cl_geterr)(); /* get specific error code */ + bool_t (*cl_freeres)(); /* frees results */ + void (*cl_destroy)(); /* destroy this structure */ + bool_t (*cl_control)(); /* the ioctl() of rpc */ + } *cl_ops; + caddr_t cl_private; /* private stuff */ + char *cl_netid; /* network identifier */ + char *cl_tp; /* device name */ +} CLIENT; +.Ed +.Sh "The SVCXPRT structure" +.Bd -literal +enum xprt_stat { + XPRT_DIED, + XPRT_MOREREQS, + XPRT_IDLE +}; + +/* + * Server side transport handle + */ +typedef struct { + int xp_fd; /* file descriptor for the server handle */ + u_short xp_port; /* obsolete */ + const struct xp_ops { + bool_t (*xp_recv)(); /* receive incoming requests */ + enum xprt_stat (*xp_stat)(); /* get transport status */ + bool_t (*xp_getargs)(); /* get arguments */ + bool_t (*xp_reply)(); /* send reply */ + bool_t (*xp_freeargs)(); /* free mem allocated for args */ + void (*xp_destroy)(); /* destroy this struct */ + } *xp_ops; + int xp_addrlen; /* length of remote addr. Obsolete */ + struct sockaddr_in xp_raddr; /* Obsolete */ + const struct xp_ops2 { + bool_t (*xp_control)(); /* catch-all function */ + } *xp_ops2; + char *xp_tp; /* transport provider device name */ + char *xp_netid; /* network identifier */ + struct netbuf xp_ltaddr; /* local transport address */ + struct netbuf xp_rtaddr; /* remote transport address */ + struct opaque_auth xp_verf; /* raw response verifier */ + caddr_t xp_p1; /* private: for use by svc ops */ + caddr_t xp_p2; /* private: for use by svc ops */ + caddr_t xp_p3; /* private: for use by svc lib */ + int xp_type /* transport type */ +} SVCXPRT; +.Ed +.Sh "The svc_reg structure" +.Bd -literal +struct svc_req { + rpcprog_t rq_prog; /* service program number */ + rpcvers_t rq_vers; /* service protocol version */ + rpcproc_t rq_proc; /* the desired procedure */ + struct opaque_auth rq_cred; /* raw creds from the wire */ + caddr_t rq_clntcred; /* read only cooked cred */ + SVCXPRT *rq_xprt; /* associated transport */ +}; +.Ed +.Sh "The XDR structure" +.Bd -literal +/* + * XDR operations. + * XDR_ENCODE causes the type to be encoded into the stream. + * XDR_DECODE causes the type to be extracted from the stream. + * XDR_FREE can be used to release the space allocated by an XDR_DECODE + * request. + */ +enum xdr_op { + XDR_ENCODE=0, + XDR_DECODE=1, + XDR_FREE=2 +}; +/* + * This is the number of bytes per unit of external data. + */ +#define BYTES_PER_XDR_UNIT (4) +#define RNDUP(x) ((((x) + BYTES_PER_XDR_UNIT - 1) / + BYTES_PER_XDR_UNIT) \e * BYTES_PER_XDR_UNIT) + +/* + * A xdrproc_t exists for each data type which is to be encoded or + * decoded. The second argument to the xdrproc_t is a pointer to + * an opaque pointer. The opaque pointer generally points to a + * structure of the data type to be decoded. If this points to 0, + * then the type routines should allocate dynamic storage of the + * appropriate size and return it. + * bool_t (*xdrproc_t)(XDR *, caddr_t *); + */ +typedef bool_t (*xdrproc_t)(); + +/* + * The XDR handle. + * Contains operation which is being applied to the stream, + * an operations vector for the particular implementation + */ +typedef struct { + enum xdr_op x_op; /* operation; fast additional param */ + struct xdr_ops { + bool_t (*x_getlong)(); /* get a long from underlying stream */ + bool_t (*x_putlong)(); /* put a long to underlying stream */ + bool_t (*x_getbytes)(); /* get bytes from underlying stream */ + bool_t (*x_putbytes)(); /* put bytes to underlying stream */ + u_int (*x_getpostn)(); /* returns bytes off from beginning */ + bool_t (*x_setpostn)(); /* lets you reposition the stream */ + long * (*x_inline)(); /* buf quick ptr to buffered data */ + void (*x_destroy)(); /* free privates of this xdr_stream */ + } *x_ops; + caddr_t x_public; /* users' data */ + caddr_t x_private; /* pointer to private data */ + caddr_t x_base; /* private used for position info */ + int x_handy; /* extra private word */ +} XDR; + +/* + * The netbuf structure. This structure is defined in <xti.h> on SysV + * systems, but NetBSD / FreeBSD do not use XTI. + * + * Usually, buf will point to a struct sockaddr, and len and maxlen + * will contain the length and maximum length of that socket address, + * respectively. + */ +struct netbuf { + unsigned int maxlen; + unsigned int len; + void *buf; +}; + +/* + * The format of the addres and options arguments of the XTI t_bind call. + * Only provided for compatibility, it should not be used other than + * as an argument to svc_tli_create(). + */ + +struct t_bind { + struct netbuf addr; + unsigned int qlen; +}; +.Ed +.Sh "Index to Routines" +The following table lists RPC routines and the manual reference +pages on which they are described: .Pp -The -.Fn svc_register -routine returns one if it succeeds, and zero otherwise. -.Pp -.It Xo -.Fn svc_run -.Xc -.Pp -This routine never returns. -It waits for -.Tn RPC -requests to arrive, and calls the appropriate service -procedure using -.Fn svc_getreq -when one arrives. -This procedure is usually waiting for a -.Xr select 2 -system call to return. -.Pp -.It Xo -.Ft bool_t -.Fn svc_sendreply "SVCXPRT *xprt" "xdrproc_t outproc" "char *out" -.Xc -.Pp -Called by an -.Tn RPC -service's dispatch routine to send the results of a -remote procedure call. -The parameter -.Fa xprt -is the request's associated transport handle; -.Fa outproc -is the -.Tn XDR -routine which is used to encode the results; and -.Fa out -is the address of the results. -This routine returns one if it succeeds, zero otherwise. -.Pp -.It Xo -.Ft void -.Xc -.It Xo -.Fn svc_unregister "u_long prognum" "u_long versnum" -.Xc -.Pp -Remove all mapping of the double -.Pq Fa prognum , versnum -to dispatch routines, and of the triple -.Pq Fa prognum , versnum , * -to port number. -.Pp -.It Xo -.Ft void -.Xc -.It Xo -.Fn svcerr_auth "SVCXPRT *xprt" "enum auth_stat why" -.Xc -.Pp -Called by a service dispatch routine that refuses to perform -a remote procedure call due to an authentication error. -.Pp -.It Xo -.Ft void -.Xc -.It Xo -.Fn svcerr_decode "SVCXPRT *xprt" -.Xc -.Pp -Called by a service dispatch routine that cannot successfully -decode its parameters. -See also -.Fn svc_getargs . -.Pp -.It Xo -.Ft void -.Xc -.It Xo -.Fn svcerr_noproc "SVCXPRT *xprt" -.Xc -.Pp -Called by a service dispatch routine that does not implement -the procedure number that the caller requests. -.Pp -.It Xo -.Ft void -.Xc -.It Xo -.Fn svcerr_noprog "SVCXPRT *xprt" -.Xc -.Pp -Called when the desired program is not registered with the -.Tn RPC -package. -Service implementors usually do not need this routine. -.Pp -.It Xo -.Ft void -.Xc -.It Xo -.Fn svcerr_progvers "SVCXPRT *xprt" "u_long low_vers" "u_long high_vers" -.Xc -.Pp -Called when the desired version of a program is not registered -with the -.Tn RPC -package. -Service implementors usually do not need this routine. -.Pp -.It Xo -.Ft void -.Xc -.It Xo -.Fn svcerr_systemerr "SVCXPRT *xprt" -.Xc -.Pp -Called by a service dispatch routine when it detects a system -error -not covered by any particular protocol. -For example, if a service can no longer allocate storage, -it may call this routine. -.Pp -.It Xo -.Ft void -.Xc -.It Xo -.Fn svcerr_weakauth "SVCXPRT *xprt" -.Xc -.Pp -Called by a service dispatch routine that refuses to perform -a remote procedure call due to insufficient -authentication parameters. -The routine calls -.Fn svcerr_auth xprt AUTH_TOOWEAK . -.Pp -.It Xo -.Ft "SVCXPRT *" -.Xc -.It Xo -.Fn svcraw_create void -.Xc -.Pp -This routine creates a toy -.Tn RPC -service transport, to which it returns a pointer. -The transport -is really a buffer within the process's address space, -so the corresponding -.Tn RPC -client should live in the same -address space; -see -.Fn clntraw_create . -This routine allows simulation of -.Tn RPC -and acquisition of -.Tn RPC -overheads (such as round trip times), without any kernel -interference. -This routine returns -.Dv NULL -if it fails. -.Pp -.It Xo -.Ft "SVCXPRT *" -.Xc -.It Xo -.Fn svctcp_create "int sock" "u_int send_buf_size" "u_int recv_buf_size" -.Xc -.Pp -This routine creates a -.Tn TCP/IP Ns \-based -.Tn RPC -service transport, to which it returns a pointer. -The transport is associated with the socket -.Fa sock , -which may be -.Dv RPC_ANYSOCK , -in which case a new socket is created. -If the socket is not bound to a local -.Tn TCP -port, then this routine binds it to an arbitrary port. -Upon completion, -.Fa xprt\->xp_sock -is the transport's socket descriptor, and -.Fa xprt\->xp_port -is the transport's port number. -This routine returns -.Dv NULL -if it fails. -Since -.Tn TCP Ns \-based -.Tn RPC -uses buffered -.Tn I/O , -users may specify the size of buffers; values of zero -choose suitable defaults. -.Pp -.It Xo -.Ft "SVCXPRT *" -.Xc -.It Xo -.Fn svcfd_create "int fd" "u_int sendsize" "u_int recvsize" -.Xc -.Pp -Create a service on top of any open descriptor. -Typically, -this -descriptor is a connected socket for a stream protocol such -as -.Tn TCP . -.Fa sendsize -and -.Fa recvsize -indicate sizes for the send and receive buffers. -If they are -zero, a reasonable default is chosen. -.Pp -.It Xo -.Ft "SVCXPRT *" -.Xc -.It Xo -.Fn svcudp_bufcreate "int sock" "u_int sendsize" "u_int recvsize" -.Xc -.Pp -This routine creates a -.Tn UDP/IP Ns \-based -.Tn RPC -service transport, to which it returns a pointer. -The transport is associated with the socket -.Fa sock , -which may be -.Dv RPC_ANYSOCK , -in which case a new socket is created. -If the socket is not bound to a local -.Tn UDP -port, then this routine binds it to an arbitrary port. -Upon -completion, -.Fa xprt\->xp_sock -is the transport's socket descriptor, and -.Fa xprt\->xp_port -is the transport's port number. -This routine returns -.Dv NULL -if it fails. -.Pp -This allows the user to specify the maximum packet size for sending and -receiving -.Tn UDP Ns \-based -.Tn RPC -messages. -.Pp -.It Xo -.Ft bool_t -.Fn xdr_accepted_reply "XDR *xdrs" "struct accepted_reply *ar" -.Xc -.Pp -Used for encoding -.Tn RPC -reply messages. -This routine is useful for users who -wish to generate -.Tn RPC Ns \-style -messages without using the -.Tn RPC -package. -.Pp -.It Xo -.Ft bool_t -.Fn xdr_authunix_parms "XDR *xdrs" "struct authunix_parms *aupp" -.Xc -.Pp -Used for describing -.Ux -credentials. -This routine is useful for users -who wish to generate these credentials without using the -.Tn RPC -authentication package. -.Pp -.It Xo -.Ft void -.Xc -.It Xo -.Ft bool_t -.Fn xdr_callhdr "XDR *xdrs" "struct rpc_msg *chdr" -.Xc -.Pp -Used for describing -.Tn RPC -call header messages. -This routine is useful for users who wish to generate -.Tn RPC Ns \-style -messages without using the -.Tn RPC -package. -.Pp -.It Xo -.Ft bool_t -.Fn xdr_callmsg "XDR *xdrs" "struct rpc_msg *cmsg" -.Xc -.Pp -Used for describing -.Tn RPC -call messages. -This routine is useful for users who wish to generate -.Tn RPC Ns \-style -messages without using the -.Tn RPC -package. -.Pp -.It Xo -.Ft bool_t -.Fn xdr_opaque_auth "XDR *xdrs" "struct opaque_auth *ap" -.Xc -.Pp -Used for describing -.Tn RPC -authentication information messages. -This routine is useful for users who wish to generate -.Tn RPC Ns \-style -messages without using the -.Tn RPC -package. -.Pp -.It Xo -.Vt struct pmap ; -.Xc -.It Xo -.Ft bool_t -.Fn xdr_pmap "XDR *xdrs" "struct pmap *regs" -.Xc -.Pp -Used for describing parameters to various -.Xr portmap 8 -procedures, externally. -This routine is useful for users who wish to generate -these parameters without using the -.Fn pmap_* -interface. -.Pp -.It Xo -.Ft bool_t -.Fn xdr_pmaplist "XDR *xdrs" "struct pmaplist **rp" -.Xc -.Pp -Used for describing a list of port mappings, externally. -This routine is useful for users who wish to generate -these parameters without using the -.Fn pmap_* -interface. -.Pp -.It Xo -.Ft bool_t -.Fn xdr_rejected_reply "XDR *xdrs" "struct rejected_reply *rr" -.Xc -.Pp -Used for describing -.Tn RPC -reply messages. -This routine is useful for users who wish to generate -.Tn RPC Ns \-style -messages without using the -.Tn RPC -package. -.Pp -.It Xo -.Ft bool_t -.Fn xdr_replymsg "XDR *xdrs" "struct rpc_msg *rmsg" -.Xc -.Pp -Used for describing -.Tn RPC -reply messages. -This routine is useful for users who wish to generate -.Tn RPC -style messages without using the -.Tn RPC -package. -.Pp -.It Xo -.Ft void -.Xc -.It Xo -.Fn xprt_register "SVCXPRT *xprt" -.Xc -.Pp -After -.Tn RPC -service transport handles are created, -they should register themselves with the -.Tn RPC -service package. -This routine modifies the global variable -.Va svc_fds . -Service implementors usually do not need this routine. -.Pp -.It Xo -.Ft void -.Xc -.It Xo -.Fn xprt_unregister "SVCXPRT *xprt" -.Xc +.Bl -tag -width "authunix_create_default()" -compact +.It Em "RPC Routine" +.Em "Manual Reference Page" .Pp -Before an -.Tn RPC -service transport handle is destroyed, -it should unregister itself with the -.Tn RPC -service package. -This routine modifies the global variable -.Va svc_fds . -Service implementors usually do not need this routine. +.It Fn auth_destroy +.Xr rpc_clnt_auth 3 +.It Fn authdes_create +.Xr rpc_soc 3 +.It Fn authnone_create +.Xr rpc_clnt_auth 3 +.It Fn authsys_create +.Xr rpc_clnt_auth 3 +.It Fn authsys_create_default +.Xr rpc_clnt_auth 3 +.It Fn authunix_create +.Xr rpc_soc 3 +.It Fn authunix_create_default +.Xr rpc_soc 3 +.It Fn callrpc +.Xr rpc_soc 3 +.It Fn clnt_broadcast +.Xr rpc_soc 3 +.It Fn clnt_call +.Xr rpc_clnt_calls 3 +.It Fn clnt_control +.Xr rpc_clnt_create 3 +.It Fn clnt_create +.Xr rpc_clnt_create 3 +.It Fn clnt_destroy +.Xr rpc_clnt_create 3 +.It Fn clnt_dg_create +.Xr rpc_clnt_create 3 +.It Fn clnt_freeres +.Xr rpc_clnt_calls 3 +.It Fn clnt_geterr +.Xr rpc_clnt_calls 3 +.It Fn clnt_pcreateerror +.Xr rpc_clnt_create 3 +.It Fn clnt_perrno +.Xr rpc_clnt_calls 3 +.It Fn clnt_perror +.Xr rpc_clnt_calls 3 +.It Fn clnt_raw_create +.Xr rpc_clnt_create 3 +.It Fn clnt_spcreateerror +.Xr rpc_clnt_create 3 +.It Fn clnt_sperrno +.Xr rpc_clnt_calls 3 +.It Fn clnt_sperror +.Xr rpc_clnt_calls 3 +.It Fn clnt_tli_create +.Xr rpc_clnt_create 3 +.It Fn clnt_tp_create +.Xr rpc_clnt_create 3 +.It Fn clnt_udpcreate +.Xr rpc_soc 3 +.It Fn clnt_vc_create +.Xr rpc_clnt_create 3 +.It Fn clntraw_create +.Xr rpc_soc 3 +.It Fn clnttcp_create +.Xr rpc_soc 3 +.It Fn clntudp_bufcreate +.Xr rpc_soc 3 +.It Fn get_myaddress +.Xr rpc_soc 3 +.It Fn pmap_getmaps +.Xr rpc_soc 3 +.It Fn pmap_getport +.Xr rpc_soc 3 +.It Fn pmap_rmtcall +.Xr rpc_soc 3 +.It Fn pmap_set +.Xr rpc_soc 3 +.It Fn pmap_unset +.Xr rpc_soc 3 +.It Fn registerrpc +.Xr rpc_soc 3 +.It Fn rpc_broadcast +.Xr rpc_clnt_calls 3 +.It Fn rpc_broadcast_exp +.Xr rpc_clnt_calls 3 +.It Fn rpc_call +.Xr rpc_clnt_calls 3 +.It Fn rpc_reg +.Xr rpc_svc_calls 3 +.It Fn svc_create +.Xr rpc_svc_create 3 +.It Fn svc_destroy +.Xr rpc_svc_create 3 +.It Fn svc_dg_create +.Xr rpc_svc_create 3 +.It Fn svc_dg_enablecache +.Xr rpc_svc_calls 3 +.It Fn svc_fd_create +.Xr rpc_svc_create 3 +.It Fn svc_fds +.Xr rpc_soc 3 +.It Fn svc_freeargs +.Xr rpc_svc_reg 3 +.It Fn svc_getargs +.Xr rpc_svc_reg 3 +.It Fn svc_getcaller +.Xr rpc_soc 3 +.It Fn svc_getreq +.Xr rpc_soc 3 +.It Fn svc_getreqset +.Xr rpc_svc_calls 3 +.It Fn svc_getrpccaller +.Xr rpc_svc_calls 3 +.It Fn svc_kerb_reg +.Xr kerberos_rpc 3 +.It Fn svc_raw_create +.Xr rpc_svc_create 3 +.It Fn svc_reg +.Xr rpc_svc_calls 3 +.It Fn svc_register +.Xr rpc_soc 3 +.It Fn svc_run +.Xr rpc_svc_reg 3 +.It Fn svc_sendreply +.Xr rpc_svc_reg 3 +.It Fn svc_tli_create +.Xr rpc_svc_create 3 +.It Fn svc_tp_create +.Xr rpc_svc_create 3 +.It Fn svc_unreg +.Xr rpc_svc_calls 3 +.It Fn svc_unregister +.Xr rpc_soc 3 +.It Fn svc_vc_create +.Xr rpc_svc_create 3 +.It Fn svcerr_auth +.Xr rpc_svc_err 3 +.It Fn svcerr_decode +.Xr rpc_svc_err 3 +.It Fn svcerr_noproc +.Xr rpc_svc_err 3 +.It Fn svcerr_noprog +.Xr rpc_svc_err 3 +.It Fn svcerr_progvers +.Xr rpc_svc_err 3 +.It Fn svcerr_systemerr +.Xr rpc_svc_err 3 +.It Fn svcerr_weakauth +.Xr rpc_svc_err 3 +.It Fn svcfd_create +.Xr rpc_soc 3 +.It Fn svcraw_create +.Xr rpc_soc 3 +.It Fn svctcp_create +.Xr rpc_soc 3 +.It Fn svcudp_bufcreate +.Xr rpc_soc 3 +.It Fn svcudp_create +.Xr rpc_soc 3 +.It Fn xdr_accepted_reply +.Xr rpc_xdr 3 +.It Fn xdr_authsys_parms +.Xr rpc_xdr 3 +.It Fn xdr_authunix_parms +.Xr rpc_soc 3 +.It Fn xdr_callhdr +.Xr rpc_xdr 3 +.It Fn xdr_callmsg +.Xr rpc_xdr 3 +.It Fn xdr_opaque_auth +.Xr rpc_xdr 3 +.It Fn xdr_rejected_reply +.Xr rpc_xdr 3 +.It Fn xdr_replymsg +.Xr rpc_xdr 3 +.It Fn xprt_register +.Xr rpc_svc_calls 3 +.It Fn xprt_unregister +.Xr rpc_svc_calls 3 +.El +.Sh FILES +.Bl -tag -width /etc/netconfig +.It Pa /etc/netconfig .El .Sh SEE ALSO -.Xr rpc_secure 3 , -.Xr xdr 3 -.Rs -.%T "Remote Procedure Calls: Protocol Specification" -.Re -.Rs -.%T "Remote Procedure Call Programming Guide" -.Re -.Rs -.%T "rpcgen Programming Guide" -.Re -.Rs -.%T "RPC: Remote Procedure Call Protocol Specification" -.%O RFC1050 -.%Q "Sun Microsystems, Inc., USC-ISI" -.Re +.Xr getnetconfig 3 , +.Xr getnetpath 3 , +.Xr rpc_clnt_auth 3 , +.Xr rpc_clnt_calls 3 , +.Xr rpc_clnt_create 3 , +.Xr rpc_svc_calls 3 , +.Xr rpc_svc_create 3 , +.Xr rpc_svc_err 3 , +.Xr rpc_svc_reg 3 , +.Xr rpc_xdr 3 , +.Xr rpcbind 3 , +.Xr xdr 3 , +.Xr netconfig 5 diff --git a/lib/libc/rpc/rpc.5 b/lib/libc/rpc/rpc.5 index 8a45a9979a9d..6cf79f06bd2c 100644 --- a/lib/libc/rpc/rpc.5 +++ b/lib/libc/rpc/rpc.5 @@ -1,36 +1,60 @@ +.\" $NetBSD: rpc.5,v 1.3 2000/06/15 20:05:54 fvdl Exp $ .\" $FreeBSD$ -.\" @(#)rpc.5 2.2 88/08/03 4.0 RPCSRC; from 1.4 87/11/27 SMI; -.Dd September 26, 1985 +.\" $FreeBSD$ +.\" @(#)rpc.4 1.17 93/08/30 SMI; from SVr4 +.\" Copyright 1989 AT&T +.Dd December 10, 1991 .Dt RPC 5 .Os .Sh NAME .Nm rpc .Nd rpc program number data base .Sh SYNOPSIS -/etc/rpc +.Pa /etc/rpc .Sh DESCRIPTION The -.Pa /etc/rpc +.Nm file contains user readable names that -can be used in place of rpc program numbers. -Each line has the following information: +can be used in place of RPC program numbers. +For each RPC program a single line should be present +with the following information: .Pp -.Bl -bullet -compact +.Bl -enum -compact .It -name of server for the rpc program +name of the RPC program .It -rpc program number +RPC program number .It aliases .El .Pp Items are separated by any number of blanks and/or tab characters. -A ``#'' indicates the beginning of a comment; characters up to the end of +A hash +.Pq Dq Li # +indicates the beginning of a comment; characters up to the end of the line are not interpreted by routines which search the file. +.Sh EXAMPLES +Below is an example of an RPC database: +.Bd -literal +# +# rpc +# +rpcbind 100000 portmap sunrpc portmapper +rusersd 100002 rusers +nfs 100003 nfsprog +mountd 100005 mount showmount +walld 100008 rwall shutdown +sprayd 100012 spray +llockmgr 100020 +nlockmgr 100021 +status 100024 +bootparam 100026 +keyserv 100029 keyserver +.Ed .Sh FILES -.Bl -tag -compact -width /etc/rpc -.It Pa /etc/rpc +.Bl -tag -width /etc/nsswitch.conf -compact +.It Pa /etc/nsswitch.conf .El -.Sh "SEE ALSO" +.Sh SEE ALSO .Xr getrpcent 3 diff --git a/lib/libc/rpc/rpc_callmsg.c b/lib/libc/rpc/rpc_callmsg.c index dca3a1880d93..827fd3eb7caf 100644 --- a/lib/libc/rpc/rpc_callmsg.c +++ b/lib/libc/rpc/rpc_callmsg.c @@ -1,3 +1,5 @@ +/* $NetBSD: rpc_callmsg.c,v 1.16 2000/07/14 08:40:42 fvdl Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -27,9 +29,10 @@ * Mountain View, California 94043 */ +#include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) -/*static char *sccsid = "from: @(#)rpc_callmsg.c 1.4 87/08/11 Copyr 1984 Sun Micro";*/ -/*static char *sccsid = "from: @(#)rpc_callmsg.c 2.1 88/07/29 4.0 RPCSRC";*/ +static char *sccsid = "@(#)rpc_callmsg.c 1.4 87/08/11 Copyr 1984 Sun Micro"; +static char *sccsid = "@(#)rpc_callmsg.c 2.1 88/07/29 4.0 RPCSRC"; static char *rcsid = "$FreeBSD$"; #endif @@ -40,21 +43,27 @@ static char *rcsid = "$FreeBSD$"; * */ -#include <sys/param.h> +#include "namespace.h" +#include <assert.h> #include <stdlib.h> #include <string.h> + #include <rpc/rpc.h> +#include "un-namespace.h" /* * XDR a call message */ bool_t xdr_callmsg(xdrs, cmsg) - register XDR *xdrs; - register struct rpc_msg *cmsg; + XDR *xdrs; + struct rpc_msg *cmsg; { - register int32_t *buf; - register struct opaque_auth *oa; + 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) { @@ -68,30 +77,30 @@ xdr_callmsg(xdrs, cmsg) + 2 * BYTES_PER_XDR_UNIT + RNDUP(cmsg->rm_call.cb_verf.oa_length)); if (buf != NULL) { - IXDR_PUT_LONG(buf, cmsg->rm_xid); + IXDR_PUT_INT32(buf, cmsg->rm_xid); IXDR_PUT_ENUM(buf, cmsg->rm_direction); if (cmsg->rm_direction != CALL) { return (FALSE); } - IXDR_PUT_LONG(buf, cmsg->rm_call.cb_rpcvers); + IXDR_PUT_INT32(buf, cmsg->rm_call.cb_rpcvers); if (cmsg->rm_call.cb_rpcvers != RPC_MSG_VERSION) { return (FALSE); } - IXDR_PUT_LONG(buf, cmsg->rm_call.cb_prog); - IXDR_PUT_LONG(buf, cmsg->rm_call.cb_vers); - IXDR_PUT_LONG(buf, cmsg->rm_call.cb_proc); + 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_LONG(buf, oa->oa_length); + IXDR_PUT_INT32(buf, oa->oa_length); if (oa->oa_length) { - memcpy((caddr_t)buf, oa->oa_base, 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_LONG(buf, oa->oa_length); + IXDR_PUT_INT32(buf, oa->oa_length); if (oa->oa_length) { - memcpy((caddr_t)buf, oa->oa_base, oa->oa_length); + memmove(buf, oa->oa_base, oa->oa_length); /* no real need.... buf += RNDUP(oa->oa_length) / sizeof (int32_t); */ @@ -102,28 +111,30 @@ xdr_callmsg(xdrs, cmsg) if (xdrs->x_op == XDR_DECODE) { buf = XDR_INLINE(xdrs, 8 * BYTES_PER_XDR_UNIT); if (buf != NULL) { - cmsg->rm_xid = IXDR_GET_LONG(buf); + 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_LONG(buf); + 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_LONG(buf); - cmsg->rm_call.cb_vers = IXDR_GET_LONG(buf); - cmsg->rm_call.cb_proc = IXDR_GET_LONG(buf); + 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 = IXDR_GET_LONG(buf); + 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); + mem_alloc(oa->oa_length); + if (oa->oa_base == NULL) + return (FALSE); } buf = XDR_INLINE(xdrs, RNDUP(oa->oa_length)); if (buf == NULL) { @@ -132,7 +143,7 @@ xdr_callmsg(xdrs, cmsg) return (FALSE); } } else { - memcpy(oa->oa_base, (caddr_t)buf, + memmove(oa->oa_base, buf, oa->oa_length); /* no real need.... buf += RNDUP(oa->oa_length) / @@ -149,7 +160,7 @@ xdr_callmsg(xdrs, cmsg) } } else { oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t); - oa->oa_length = IXDR_GET_LONG(buf); + oa->oa_length = (u_int)IXDR_GET_U_INT32(buf); } if (oa->oa_length) { if (oa->oa_length > MAX_AUTH_BYTES) { @@ -157,7 +168,9 @@ xdr_callmsg(xdrs, cmsg) } if (oa->oa_base == NULL) { oa->oa_base = (caddr_t) - mem_alloc(oa->oa_length); + mem_alloc(oa->oa_length); + if (oa->oa_base == NULL) + return (FALSE); } buf = XDR_INLINE(xdrs, RNDUP(oa->oa_length)); if (buf == NULL) { @@ -166,7 +179,7 @@ xdr_callmsg(xdrs, cmsg) return (FALSE); } } else { - memcpy(oa->oa_base, (caddr_t)buf, + memmove(oa->oa_base, buf, oa->oa_length); /* no real need... buf += RNDUP(oa->oa_length) / @@ -187,7 +200,6 @@ xdr_callmsg(xdrs, cmsg) 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 (xdr_opaque_auth(xdrs, &(cmsg->rm_call.cb_verf))); return (FALSE); } - diff --git a/lib/libc/rpc/rpc_clnt_auth.3 b/lib/libc/rpc/rpc_clnt_auth.3 new file mode 100644 index 000000000000..b3d720b0fae2 --- /dev/null +++ b/lib/libc/rpc/rpc_clnt_auth.3 @@ -0,0 +1,95 @@ +.\" @(#)rpc_clnt_auth.3n 1.21 93/05/07 SMI; from SVr4 +.\" Copyright 1989 AT&T +.\" @(#)rpc_clnt_auth 1.4 89/07/20 SMI; +.\" Copyright (c) 1988 Sun Microsystems, Inc. - All Rights Reserved. +.\" $NetBSD: rpc_clnt_auth.3,v 1.1 2000/06/03 09:29:50 fvdl Exp $ +.\" $FreeBSD$ +.Dd May 7, 1993 +.Dt RPC_CLNT_AUTH 3 +.Os +.Sh NAME +.Nm auth_destroy , +.Nm authnone_create , +.Nm authsys_create , +.Nm authsys_create_default +.Nd library routines for client side remote procedure call authentication +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.Fd #include <rpc/rpc.h> +.Ft "void" +.Fn auth_destroy "AUTH *auth" +.Ft "AUTH *" +.Fn authnone_create "void" +.Ft "AUTH *" +.Fn authsys_create "const char *host" "const uid_t uid" "const gid_t gid" "const int len" "const gid_t *aup_gids" +.Ft "AUTH *" +.Fn authsys_create_default "void" +.Sh DESCRIPTION +These routines are part of the +RPC library that allows C language programs to make procedure +calls on other machines across the network, +with desired authentication. +.Pp +These routines are normally called after creating the +.Vt CLIENT +handle. +The +.Va cl_auth +field of the +.Vt CLIENT +structure should be initialized by the +.Vt AUTH +structure returned by some of the following routines. +The client's authentication information +is passed to the server when the +RPC +call is made. +.Pp +Only the +.Dv NULL +and the +.Dv SYS +style of authentication is discussed here. +.Sh Routines +.Bl -tag -width authsys_create_default() +.It Fn auth_destroy +A function macro that destroys the authentication +information associated with +.Fa auth . +Destruction usually involves deallocation +of private data structures. +The use of +.Fn auth +is undefined after calling +.Fn auth_destroy . +.It Fn authnone_create +Create and return an RPC +authentication handle that passes nonusable +authentication information with each remote procedure call. +This is the default authentication used by RPC. +.It Fn authsys_create +Create and return an RPC authentication handle that contains +.Dv AUTH_SYS +authentication information. +The parameter +.Fa host +is the name of the machine on which the information was +created; +.Fa uid +is the user's user ID; +.Fa gid +is the user's current group ID; +.Fa len +and +.Fa aup_gids +refer to a counted array of groups to which the user belongs. +.It Fn authsys_create_default +Call +.Fn authsys_create +with the appropriate parameters. +.El +.Sh SEE ALSO +.Xr rpc 3 , +.Xr rpc_clnt_calls 3 , +.Xr rpc_clnt_create 3 diff --git a/lib/libc/rpc/rpc_clnt_calls.3 b/lib/libc/rpc/rpc_clnt_calls.3 new file mode 100644 index 000000000000..cd368dd351a3 --- /dev/null +++ b/lib/libc/rpc/rpc_clnt_calls.3 @@ -0,0 +1,302 @@ +.\" @(#)rpc_clnt_calls.3n 1.30 93/08/31 SMI; from SVr4 +.\" Copyright 1989 AT&T +.\" @(#)rpc_clnt_calls 1.4 89/07/20 SMI; +.\" Copyright (c) 1988 Sun Microsystems, Inc. - All Rights Reserved. +.\" $FreeBSD$ +.Dd May 7, 1993 +.Dt RPC_CLNT_CALLS 3 +.Os +.Sh NAME +.Nm rpc_clnt_calls , +.Nm clnt_call , +.Nm clnt_freeres , +.Nm clnt_geterr , +.Nm clnt_perrno , +.Nm clnt_perror , +.Nm clnt_sperrno , +.Nm clnt_sperror , +.Nm rpc_broadcast , +.Nm rpc_broadcast_exp , +.Nm rpc_call +.Nd library routines for client side calls +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.Fd #include <rpc/rpc.h> +.Ft "enum clnt_stat" +.Fn clnt_call "CLIENT *clnt" "const rpcproc_t procnum" "const xdrproc_t inproc" "const caddr_t in" "const xdrproc_t outproc" "caddr_t out" "const struct timeval tout" +.Ft bool_t +.Fn clnt_freeres "CLIENT *clnt" "const xdrproc_t outproc" "caddr_t out" +.Ft void +.Fn clnt_geterr "const CLIENT * clnt" "struct rpc_err * errp" +.Ft void +.Fn clnt_perrno "const enum clnt_stat stat" +.Ft void +.Fn clnt_perror "const CLIENT * clnt" "const char *s" +.Ft "char *" +.Fn clnt_sperrno "const enum clnt_stat stat" +.Ft "char *" +.Fn clnt_sperror "const CLIENT *clnt" "const char * s" +.Ft "enum clnt_stat" +.Fo rpc_broadcast +.Fa "const rpcprog_t prognum" "const rpcvers_t versnum" +.Fa "const rpcproc_t procnum" "const xdrproc_t inproc" +.Fa "const caddr_t in" "const xdrproc_t outproc" "caddr_t out" +.Fa "const resultproc_t eachresult" "const char *nettype" +.Fc +.Ft "enum clnt_stat" +.Fo rpc_broadcast_exp +.Fa "rpcprog_t prognum" "const rpcvers_t versnum" +.Fa "const rpcproc_t procnum" "const xdrproc_t xargs" +.Fa "caddr_t argsp" "const xdrproc_t xresults" +.Fa "caddr_t resultsp" "const int inittime" "const int waittime" +.Fa "const resultproc_t eachresult" "const char * nettype" +.Fc +.Ft "enum clnt_stat" +.Fo rpc_call +.Fa "const char *host" "const rpcprog_t prognum" +.Fa "const rpcvers_t versnum" "const rpcproc_t procnum" +.Fa "const xdrproc_t inproc" "const char *in" +.Fa "const xdrproc_t outproc" "char *out" "const char *nettype" +.Fc +.Sh DESCRIPTION +RPC library routines allow C language programs to make procedure +calls on other machines across the network. +First, the client calls a procedure to send a request to the server. +Upon receipt of the request, the server calls a dispatch routine +to perform the requested service, and then sends back a reply. +.Pp +The +.Fn clnt_call , +.Fn rpc_call , +and +.Fn rpc_broadcast +routines handle the client side of the procedure call. +The remaining routines deal with error handling in the case of errors. +.Pp +Some of the routines take a +.Vt CLIENT +handle as one of the parameters. +A +.Vt CLIENT +handle can be created by an RPC creation routine such as +.Fn clnt_create +(see +.Xr rpc_clnt_create 3 ) . +.Pp +These routines are safe for use in multithreaded applications. +.Vt CLIENT +handles can be shared between threads, however in this implementation +requests by different threads are serialized (that is, the first request will +receive its results before the second request is sent). +.Sh Routines +See +.Xr rpc 3 +for the definition of the +.Vt CLIENT +data structure. +.Bl -tag -width XXXXX +.It Fn clnt_call +A function macro that calls the remote procedure +.Fa procnum +associated with the client handle, +.Fa clnt , +which is obtained with an RPC +client creation routine such as +.Fn clnt_create +(see +.Xr rpc_clnt_create 3 ) . +The parameter +.Fa inproc +is the XDR function used to encode the procedure's parameters, and +.Fa outproc +is the XDR function used to decode the procedure's results; +.Fa in +is the address of the procedure's argument(s), and +.Fa out +is the address of where to place the result(s). +.Fa tout +is the time allowed for results to be returned, which is overridden by +a time-out set explicitly through +.Fn clnt_control , +see +.Xr rpc_clnt_create 3 . +If the remote call succeeds, the status returned is +.Dv RPC_SUCCESS , +otherwise an appropriate status is returned. +.It Fn clnt_freeres +A function macro that frees any data allocated by the +RPC/XDR system when it decoded the results of an RPC call. +The parameter +.Fa out +is the address of the results, and +.Fa outproc +is the XDR routine describing the results. +This routine returns 1 if the results were successfully freed, +and 0 otherwise. +.It Fn clnt_geterr +A function macro that copies the error structure out of the client +handle to the structure at address +.Fa errp . +.It Fn clnt_perrno +Print a message to standard error corresponding +to the condition indicated by +.Fa stat . +A newline is appended. +Normally used after a procedure call fails for a routine +for which a client handle is not needed, for instance +.Fn rpc_call . +.It Fn clnt_perror +Print a message to the standard error indicating why an +RPC call failed; +.Fa clnt +is the handle used to do the call. +The message is prepended with string +.Fa s +and a colon. +A newline is appended. +Normally used after a remote procedure call fails +for a routine which requires a client handle, +for instance +.Fn clnt_call . +.It Fn clnt_sperrno +Take the same arguments as +.Fn clnt_perrno , +but instead of sending a message to the standard error +indicating why an RPC +call failed, return a pointer to a string which contains the message. +.Fn clnt_sperrno +is normally used instead of +.Fn clnt_perrno +when the program does not have a standard error (as a program +running as a server quite likely does not), or if the programmer +does not want the message to be output with +.Fn printf +(see +.Xr printf 3 ) , +or if a message format different than that supported by +.Fn clnt_perrno +is to be used. +Note: +unlike +.Fn clnt_sperror +and +.Fn clnt_spcreaterror +(see +.Xr rpc_clnt_create 3 ) , +.Fn clnt_sperrno +does not return pointer to static data so the +result will not get overwritten on each call. +.It Fn clnt_sperror +Like +.Fn clnt_perror , +except that (like +.Fn clnt_sperrno ) +it returns a string instead of printing to standard error. +However, +.Fn clnt_sperror +does not append a newline at the end of the message. +Warning: +returns pointer to a buffer that is overwritten +on each call. +.It Fn rpc_broadcast +Like +.Fn rpc_call , +except the call message is broadcast to +all the connectionless transports specified by +.Fa nettype . +If +.Fa nettype +is +.Dv NULL , +it defaults to +.Qq netpath . +Each time it receives a response, +this routine calls +.Fn eachresult , +whose form is: +.Ft bool_t +.Fn eachresult "caddr_t out" "const struct netbuf * addr" "const struct netconfig * netconf" +where +.Fa out +is the same as +.Fa out +passed to +.Fn rpc_broadcast , +except that the remote procedure's output is decoded there; +.Fa addr +points to the address of the machine that sent the results, and +.Fa netconf +is the netconfig structure of the transport on which the remote +server responded. +If +.Fn eachresult +returns 0, +.Fn rpc_broadcast +waits for more replies; +otherwise it returns with appropriate status. +Warning: +broadcast file descriptors are limited in size to the +maximum transfer size of that transport. +For Ethernet, this value is 1500 bytes. +.Fn rpc_broadcast +uses +.Dv AUTH_SYS +credentials by default (see +.Xr rpc_clnt_auth 3 ) . +.It Fn rpc_broadcast_exp +Like +.Fn rpc_broadcast , +except that the initial timeout, +.Fa inittime +and the maximum timeout, +.Fa waittime +are specified in milliseconds. +.Fa inittime +is the initial time that +.Fn rpc_broadcast_exp +waits before resending the request. +After the first resend, the re-transmission interval +increases exponentially until it exceeds +.Fa waittime . +.It Fn rpc_call +Call the remote procedure associated with +.Fa prognum , +.Fa versnum , +and +.Fa procnum +on the machine, +.Fa host . +The parameter +.Fa inproc +is used to encode the procedure's parameters, and +.Fa outproc +is used to decode the procedure's results; +.Fa in +is the address of the procedure's argument(s), and +.Fa out +is the address of where to place the result(s). +.Fa nettype +can be any of the values listed on +.Xr rpc 3 . +This routine returns +.Dv RPC_SUCCESS +if it succeeds, +or an appropriate status is returned. +Use the +.Fn clnt_perrno +routine to translate failure status into error messages. +Warning: +.Fn rpc_call +uses the first available transport belonging +to the class +.Fa nettype , +on which it can create a connection. +You do not have control of timeouts or authentication +using this routine. +.El +.Sh SEE ALSO +.Xr printf 3 , +.Xr rpc 3 , +.Xr rpc_clnt_auth 3 , +.Xr rpc_clnt_create 3 diff --git a/lib/libc/rpc/rpc_clnt_create.3 b/lib/libc/rpc/rpc_clnt_create.3 new file mode 100644 index 000000000000..e13ac5b86427 --- /dev/null +++ b/lib/libc/rpc/rpc_clnt_create.3 @@ -0,0 +1,437 @@ +.\" @(#)rpc_clnt_create.3n 1.36 93/08/31 SMI; from SVr4 +.\" Copyright 1989 AT&T +.\" @(#)rpc_clnt_create 1.5 89/07/24 SMI; +.\" Copyright (c) 1988 Sun Microsystems, Inc. - All Rights Reserved. +.\" $NetBSD: rpc_clnt_create.3,v 1.2 2000/06/20 00:53:08 fvdl Exp $ +.\" $FreeBSD$ +.Dd May 7, 1993 +.Dt RPC_CLNT_CREATE 3 +.Os +.Sh NAME +.Nm rpc_clnt_create , +.Nm clnt_control , +.Nm clnt_create , +.Nm clnt_create_vers , +.Nm clnt_destroy , +.Nm clnt_dg_create , +.Nm clnt_pcreateerror , +.Nm clnt_raw_create , +.Nm clnt_spcreateerror , +.Nm clnt_tli_create , +.Nm clnt_tp_create , +.Nm clnt_vc_create , +.Nm rpc_createerr +.Nd "library routines for dealing with creation and manipulation of" +.Vt CLIENT +handles +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.Fd #include <rpc/rpc.h> +.Ft bool_t +.Fn clnt_control "CLIENT *clnt" "const u_int req" "char *info" +.Ft "CLIENT *" +.Fn clnt_create "const char * host" "const rpcprog_t prognum" "const rpcvers_t versnum" "const char *nettype" +.Ft "CLIENT *" +.Fn clnt_create_vers "const char * host" "const rpcprog_t prognum" "rpcvers_t *vers_outp" "const rpcvers_t vers_low" "const rpcvers_t vers_high" "char *nettype" +.Ft void +.Fn clnt_destroy "CLIENT *" "clnt" +.Ft "CLIENT *" +.Fn clnt_dg_create "const int fildes" "const struct netbuf *svcaddr" "const rpcprog_t prognum" "const rpcvers_t versnum" "const u_int sendsz" "const u_int recvsz" +.Ft void +.Fn clnt_pcreateerror "const char *s" +.Ft "char *" +.Fn clnt_spcreateerror "const char *s" +.Ft "CLIENT *" +.Fn clnt_raw_create "const rpcprog_t prognum" "const rpcvers_t versnum" +.Ft "CLIENT *" +.Fn clnt_tli_create "const int fildes" "const struct netconfig *netconf" "const struct netbuf *svcaddr" "const rpcprog_t prognum" "const rpcvers_t versnum" "const u_int sendsz" "const u_int recvsz" +.Ft "CLIENT *" +.Fn clnt_tp_create "const char * host" "const rpcprog_t prognum" "const rpcvers_t versnum" "const struct netconfig *netconf" +.Ft "CLIENT *" +.Fn clnt_vc_create "const int fildes" "const struct netbuf *svcaddr" "const rpcprog_t prognum" "const rpcvers_t versnum" "const u_int sendsz" "const u_int recvsz" +.Sh DESCRIPTION +RPC library routines allow C language programs to make procedure +calls on other machines across the network. +First a +.Vt CLIENT +handle is created and then the client calls a procedure to send a +request to the server. +On receipt of the request, the server calls a dispatch routine +to perform the requested service, and then sends a reply. +.Sh Routines +.Bl -tag -width YYYYYYY +.It Fn clnt_control +A function macro to change or retrieve various information +about a client object. +.Fa req +indicates the type of operation, and +.Fa info +is a pointer to the information. +For both connectionless and connection-oriented transports, +the supported values of +.Fa req +and their argument types and what they do are: +.Bl -column "CLSET_FD_NCLOSE" "struct timeval *" "set total timeout" +.It Dv CLSET_TIMEOUT Ta "struct timeval *" Ta "set total timeout" +.It Dv CLGET_TIMEOUT Ta "struct timeval *" Ta "get total timeout" +.El +.Pp +Note: +if you set the timeout using +.Fn clnt_control , +the timeout argument passed by +.Fn clnt_call +is ignored in all subsequent calls. +.Pp +Note: +If you set the timeout value to 0, +.Fn clnt_control +immediately returns an error +.Pq Dv RPC_TIMEDOUT . +Set the timeout parameter to 0 for batching calls. +.Bl -column CLSET_FD_NCLOSE "struct timeval *" "do not close fd on destroy" +.It Dv CLGET_SVC_ADDR Ta "struct netbuf *" Ta "get servers address" +.It Dv CLGET_FD Ta "int *" Ta "get fd from handle" +.It Dv CLSET_FD_CLOSE Ta "void" Ta "close fd on destroy" +.It Dv CLSET_FD_NCLOSE Ta void Ta "don't close fd on destroy" +.It Dv CLGET_VERS Ta "unsigned long *" Ta "get RPC program version" +.It Dv CLSET_VERS Ta "unsigned long *" Ta "set RPC program version" +.It Dv CLGET_XID Ta "unsigned long *" Ta "get XID of previous call" +.It Dv CLSET_XID Ta "unsigned long *" Ta "set XID of next call" +.El +.Pp +The following operations are valid for connectionless transports only: +.Bl -column CLSET_RETRY_TIMEOUT "struct timeval *" "set total timeout" +.It Dv CLSET_RETRY_TIMEOUT Ta "struct timeval *" Ta "set the retry timeout" +.It Dv CLGET_RETRY_TIMEOUT Ta "struct timeval *" Ta "get the retry timeout" +.El +.Pp +The retry timeout is the time that RPC +waits for the server to reply before retransmitting the request. +.Fn clnt_control +returns +.Dv TRUE +on success and +.Dv FALSE +on failure. +.It Fn clnt_create +Generic client creation routine for program +.Fa prognum +and version +.Fa versnum . +.Fa host +identifies the name of the remote host where the server +is located. +.Fa nettype +indicates the class of transport protocol to use. +The transports are tried in left to right order in +.Ev NETPATH +environment variable or in top to bottom order in +the netconfig database. +.Fn clnt_create +tries all the transports of the +.Fa nettype +class available from the +.Ev NETPATH +environment variable and the netconfig database, +and chooses the first successful one. +A default timeout is set and can be modified using +.Fn clnt_control . +This routine returns +.Dv NULL +if it fails. +The +.Fn clnt_pcreateerror +routine can be used to print the reason for failure. +.Pp +Note: +.Fn clnt_create +returns a valid client handle even +if the particular version number supplied to +.Fn clnt_create +is not registered with the +.Xr rpcbind 8 +service. +This mismatch will be discovered by a +.Fn clnt_call +later (see +.Xr rpc_clnt_calls 3 ) . +.It Fn clnt_create_vers +Generic client creation routine which is similar to +.Fn clnt_create +but which also checks for the +version availability. +.Fa host +identifies the name of the remote host where the server +is located. +.Fa nettype +indicates the class transport protocols to be used. +If the routine is successful it returns a client handle created for +the highest version between +.Fa vers_low +and +.Fa vers_high +that is supported by the server. +.Fa vers_outp +is set to this value. +That is, after a successful return +.Fa vers_low +<= +.Fa *vers_outp +<= +.Fa vers_high . +If no version between +.Fa vers_low +and +.Fa vers_high +is supported by the server then the routine fails and returns +.Dv NULL . +A default timeout is set and can be modified using +.Fn clnt_control . +This routine returns +.Dv NULL +if it fails. +The +.Fn clnt_pcreateerror +routine can be used to print the reason for failure. +Note: +.Fn clnt_create +returns a valid client handle even +if the particular version number supplied to +.Fn clnt_create +is not registered with the +.Xr rpcbind 8 +service. +This mismatch will be discovered by a +.Fn clnt_call +later (see +.Xr rpc_clnt_calls 3 ) . +However, +.Fn clnt_create_vers +does this for you and returns a valid handle +only if a version within +the range supplied is supported by the server. +.It Fn clnt_destroy +A function macro that destroys the client's RPC handle. +Destruction usually involves deallocation +of private data structures, including +.Fa clnt +itself. +Use of +.Fa clnt +is undefined after calling +.Fn clnt_destroy . +If the RPC library opened the associated file descriptor, or +.Dv CLSET_FD_CLOSE +was set using +.Fn clnt_control , +the file descriptor will be closed. +The caller should call +.Fn auth_destroy "clnt->cl_auth" +(before calling +.Fn clnt_destroy ) +to destroy the associated +.Vt AUTH +structure (see +.Xr rpc_clnt_auth 3 ) . +.It Fn clnt_dg_create +This routine creates an RPC client for the remote program +.Fa prognum +and version +.Fa versnum ; +the client uses a connectionless transport. +The remote program is located at address +.Fa svcaddr . +The parameter +.Fa fildes +is an open and bound file descriptor. +This routine will resend the call message in intervals of +15 seconds until a response is received or until the +call times out. +The total time for the call to time out is specified by +.Fn clnt_call +(see +.Fn clnt_call +in +.Xr rpc_clnt_calls 3 ) . +The retry time out and the total time out periods can +be changed using +.Fn clnt_control . +The user may set the size of the send and receive +buffers with the parameters +.Fa sendsz +and +.Fa recvsz ; +values of 0 choose suitable defaults. +This routine returns +.Dv NULL +if it fails. +.It Fn clnt_pcreateerror +Print a message to standard error indicating +why a client RPC handle could not be created. +The message is prepended with the string +.Fa s +and a colon, and appended with a newline. +.It Fn clnt_spcreateerror +Like +.Fn clnt_pcreateerror , +except that it returns a string +instead of printing to the standard error. +A newline is not appended to the message in this case. +Warning: +returns a pointer to a buffer that is overwritten +on each call. +.It Fn clnt_raw_create +This routine creates an RPC +client handle for the remote program +.Fa prognum +and version +.Fa versnum . +The transport used to pass messages to the service is +a buffer within the process's address space, +so the corresponding RPC +server should live in the same address space; +(see +.Fn svc_raw_create +in +.Xr rpc_svc_create 3 ) . +This allows simulation of RPC and measurement of +RPC overheads, such as round trip times, +without any kernel or networking interference. +This routine returns +.Dv NULL +if it fails. +.Fn clnt_raw_create +should be called after +.Fn svc_raw_create . +.It Fn clnt_tli_create +This routine creates an RPC +client handle for the remote program +.Fa prognum +and version +.Fa versnum . +The remote program is located at address +.Fa svcaddr . +If +.Fa svcaddr +is +.Dv NULL +and it is connection-oriented, it is assumed that the file descriptor +is connected. +For connectionless transports, if +.Fa svcaddr +is +.Dv NULL , +.Dv RPC_UNKNOWNADDR +error is set. +.Fa fildes +is a file descriptor which may be open, bound and connected. +If it is +.Dv RPC_ANYFD , +it opens a file descriptor on the transport specified by +.Fa netconf . +If +.Fa fildes +is +.Dv RPC_ANYFD +and +.Fa netconf +is +.Dv NULL , +a +.Dv RPC_UNKNOWNPROTO +error is set. +If +.Fa fildes +is unbound, then it will attempt to bind the descriptor. +The user may specify the size of the buffers with the parameters +.Fa sendsz +and +.Fa recvsz ; +values of 0 choose suitable defaults. +Depending upon the type of the transport (connection-oriented +or connectionless), +.Fn clnt_tli_create +calls appropriate client creation routines. +This routine returns +.Dv NULL +if it fails. +The +.Fn clnt_pcreateerror +routine can be used to print the reason for failure. +The remote rpcbind +service (see +.Xr rpcbind 8 ) +is not consulted for the address of the remote +service. +.It Fn clnt_tp_create +Like +.Fn clnt_create +except +.Fn clnt_tp_create +tries only one transport specified through +.Fa netconf . +.Fn clnt_tp_create +creates a client handle for the program +.Fa prognum , +the version +.Fa versnum , +and for the transport specified by +.Fa netconf . +Default options are set, +which can be changed using +.Fn clnt_control +calls. +The remote rpcbind service on the host +.Fa host +is consulted for the address of the remote service. +This routine returns +.Dv NULL +if it fails. +The +.Fn clnt_pcreateerror +routine can be used to print the reason for failure. +.It Fn clnt_vc_create +This routine creates an RPC +client for the remote program +.Fa prognum +and version +.Fa versnum ; +the client uses a connection-oriented transport. +The remote program is located at address +.Fa svcaddr . +The parameter +.Fa fildes +is an open and bound file descriptor. +The user may specify the size of the send and receive buffers +with the parameters +.Fa sendsz +and +.Fa recvsz ; +values of 0 choose suitable defaults. +This routine returns +.Dv NULL +if it fails. +The address +.Fa svcaddr +should not be +.Dv NULL +and should point to the actual address of the remote program. +.Fn clnt_vc_create +does not consult the remote rpcbind service for this information. +.It Xo +.Vt "struct rpc_createerr" Va rpc_createerr ; +.Xc +A global variable whose value is set by any RPC +client handle creation routine +that fails. +It is used by the routine +.Fn clnt_pcreateerror +to print the reason for the failure. +.El +.Sh SEE ALSO +.Xr rpc 3 , +.Xr rpc_clnt_auth 3 , +.Xr rpc_clnt_calls 3 , +.Xr rpcbind 8 diff --git a/lib/libc/rpc/rpc_com.h b/lib/libc/rpc/rpc_com.h new file mode 100644 index 000000000000..8a1269393aff --- /dev/null +++ b/lib/libc/rpc/rpc_com.h @@ -0,0 +1,85 @@ +/* $NetBSD: rpc_com.h,v 1.3 2000/12/10 04:10:08 christos Exp $ */ +/* $FreeBSD$ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* + * 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 _RPC_RPCCOM_H +#define _RPC_RPCCOM_H + +#include <sys/cdefs.h> + +/* #pragma ident "@(#)rpc_com.h 1.11 93/07/05 SMI" */ + +/* + * The max size of the transport, if the size cannot be determined + * by other means. + */ +#define RPC_MAXDATASIZE 9000 +#define RPC_MAXADDRSIZE 1024 + +#define __RPC_GETXID(now) ((u_int32_t)getpid() ^ (u_int32_t)(now)->tv_sec ^ \ + (u_int32_t)(now)->tv_usec) + +__BEGIN_DECLS +extern u_int __rpc_get_a_size __P((int)); +extern int __rpc_dtbsize __P((void)); +extern struct netconfig * __rpcgettp __P((int)); +extern int __rpc_get_default_domain __P((char **)); + +char *__rpc_taddr2uaddr_af __P((int, const struct netbuf *)); +struct netbuf *__rpc_uaddr2taddr_af __P((int, const char *)); +int __rpc_fixup_addr __P((struct netbuf *, const struct netbuf *)); +int __rpc_sockinfo2netid __P((struct __rpc_sockinfo *, const char **)); +int __rpc_seman2socktype __P((int)); +int __rpc_socktype2seman __P((int)); +void *rpc_nullproc __P((CLIENT *)); +int __rpc_sockisbound __P((int)); + +struct netbuf *__rpcb_findaddr __P((rpcprog_t, rpcvers_t, + const struct netconfig *, + const char *, CLIENT **)); +bool_t __rpc_control __P((int,void *)); + +char *_get_next_token __P((char *, int)); + +__END_DECLS + +#endif /* _RPC_RPCCOM_H */ diff --git a/lib/libc/rpc/rpc_commondata.c b/lib/libc/rpc/rpc_commondata.c index 043c08285056..ba5839e6df3f 100644 --- a/lib/libc/rpc/rpc_commondata.c +++ b/lib/libc/rpc/rpc_commondata.c @@ -1,3 +1,5 @@ +/* $NetBSD: rpc_commondata.c,v 1.7 2000/06/02 23:11:13 fvdl Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -5,39 +7,42 @@ * may copy or modify Sun RPC without charge, but are not authorized * to license or distribute it to anyone else except as part of a product or * program developed by the user. - * + * * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. - * + * * Sun RPC is provided with no support and without any obligation on the * part of Sun Microsystems, Inc. to assist in its use, correction, * modification or enhancement. - * + * * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC * OR ANY PART THEREOF. - * + * * In no event will Sun Microsystems, Inc. be liable for any lost revenue * or profits or other special, indirect and consequential damages, even if * Sun has been advised of the possibility of such damages. - * + * * Sun Microsystems, Inc. * 2550 Garcia Avenue * Mountain View, California 94043 */ +#include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) -/*static char *sccsid = "from: @(#)rpc_commondata.c 2.1 88/07/29 4.0 RPCSRC";*/ +static char *sccsid = "@(#)rpc_commondata.c 2.1 88/07/29 4.0 RPCSRC"; static char *rcsid = "$FreeBSD$"; #endif +#include "namespace.h" #include <rpc/rpc.h> +#include "un-namespace.h" + /* * This file should only contain common data (global data) that is exported - * by public interfaces + * by public interfaces */ struct opaque_auth _null_auth; fd_set svc_fdset; int svc_maxfd = -1; -struct rpc_createerr rpc_createerr; diff --git a/lib/libc/rpc/rpc_dtablesize.c b/lib/libc/rpc/rpc_dtablesize.c index 44b327966039..16e0a2b00305 100644 --- a/lib/libc/rpc/rpc_dtablesize.c +++ b/lib/libc/rpc/rpc_dtablesize.c @@ -1,3 +1,5 @@ +/* $NetBSD: rpc_dtablesize.c,v 1.14 1998/11/15 17:32:43 christos Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -27,14 +29,18 @@ * Mountain View, California 94043 */ +#include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)rpc_dtablesize.c 1.2 87/08/11 Copyr 1987 Sun Micro";*/ /*static char *sccsid = "from: @(#)rpc_dtablesize.c 2.1 88/07/29 4.0 RPCSRC";*/ static char *rcsid = "$FreeBSD$"; #endif -#include <sys/types.h> +#include "namespace.h" #include <unistd.h> +#include "un-namespace.h" + +int _rpc_dtablesize __P((void)); /* XXX */ /* * Cache the result of getdtablesize(), so we don't have to do an diff --git a/lib/libc/rpc/rpc_generic.c b/lib/libc/rpc/rpc_generic.c new file mode 100644 index 000000000000..790bbc59683f --- /dev/null +++ b/lib/libc/rpc/rpc_generic.c @@ -0,0 +1,816 @@ +/* $NetBSD: rpc_generic.c,v 1.4 2000/09/28 09:07:04 kleink Exp $ */ +/* $FreeBSD$ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ + +/* #pragma ident "@(#)rpc_generic.c 1.17 94/04/24 SMI" */ + +/* + * rpc_generic.c, Miscl routines for RPC. + * + */ + +#include "reentrant.h" +#include "namespace.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 <stdio.h> +#include <netdb.h> +#include <netconfig.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <rpc/nettype.h> +#include "un-namespace.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 + { "unix", AF_LOCAL, 0 } +}; + +#if 0 +static char *strlocase __P((char *)); +#endif +static int getnettype __P((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_max); + } + /* + * 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; + + switch (proto) { + case IPPROTO_TCP: + maxsize = 65536; /* XXX */ + break; + case IPPROTO_UDP: + maxsize = 8192; /* XXX */ + break; + default: + maxsize = RPC_MAXDATASIZE; + break; + } + if (size == 0) + return maxsize; + + /* 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] == NULL)) { + return (_RPC_NETPATH); /* Default */ + } + +#if 0 + nettype = strlocase(nettype); +#endif + for (i = 0; _rpctypelist[i].name; i++) + if (strcasecmp(nettype, _rpctypelist[i].name) == 0) { + return (_rpctypelist[i].type); + } + return (_rpctypelist[i].type); +} + +/* + * For the given nettype (tcp or udp only), return the first structure found. + * This should be freed by calling freenetconfigent() + */ +struct netconfig * +__rpc_getconfip(nettype) + const char *nettype; +{ + char *netid; + char *netid_tcp = (char *) NULL; + char *netid_udp = (char *) NULL; + static char *netid_tcp_main; + static char *netid_udp_main; + struct netconfig *dummy; + int main_thread; + static thread_key_t tcp_key, udp_key; + extern mutex_t tsd_lock; + + if ((main_thread = thr_main())) { + netid_udp = netid_udp_main; + netid_tcp = netid_tcp_main; + } else { + if (tcp_key == 0) { + mutex_lock(&tsd_lock); + if (tcp_key == 0) + thr_keycreate(&tcp_key, free); + mutex_unlock(&tsd_lock); + } + netid_tcp = (char *)thr_getspecific(tcp_key); + if (udp_key == 0) { + mutex_lock(&tsd_lock); + if (udp_key == 0) + 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 = strdup(nconf->nc_netid); + if (main_thread) + netid_tcp_main = netid_tcp; + else + thr_setspecific(tcp_key, + (void *) netid_tcp); + } else + if (strcmp(nconf->nc_proto, NC_UDP) == 0) { + netid_udp = strdup(nconf->nc_netid); + if (main_thread) + netid_udp_main = netid_udp; + else + 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] == NULL)) { + return (NULL); + } + dummy = getnetconfigent(netid); + return (dummy); +} + +/* + * Returns the type of the nettype, which should then be used with + * __rpc_getconf(). + */ +void * +__rpc_setconf(nettype) + const char *nettype; +{ + struct handle *handle; + + handle = (struct handle *) malloc(sizeof (struct handle)); + if (handle == NULL) { + return (NULL); + } + switch (handle->nettype = getnettype(nettype)) { + case _RPC_NETPATH: + case _RPC_CIRCUIT_N: + case _RPC_DATAGRAM_N: + if (!(handle->nhandle = setnetpath())) { + free(handle); + return (NULL); + } + handle->nflag = TRUE; + break; + case _RPC_VISIBLE: + case _RPC_CIRCUIT_V: + case _RPC_DATAGRAM_V: + case _RPC_TCP: + case _RPC_UDP: + if (!(handle->nhandle = setnetconfig())) { + syslog (LOG_ERR, "rpc: failed to open " NETCONFIG); + free(handle); + return (NULL); + } + handle->nflag = FALSE; + break; + default: + return (NULL); + } + + return (handle); +} + +/* + * Returns the next netconfig struct for the given "net" type. + * __rpc_setconf() should have been called previously. + */ +struct netconfig * +__rpc_getconf(vhandle) + void *vhandle; +{ + struct handle *handle; + struct netconfig *nconf; + + handle = (struct handle *)vhandle; + if (handle == NULL) { + return (NULL); + } + for (;;) { + if (handle->nflag) + nconf = getnetpath(handle->nhandle); + else + nconf = getnetconfig(handle->nhandle); + if (nconf == NULL) + break; + if ((nconf->nc_semantics != NC_TPI_CLTS) && + (nconf->nc_semantics != NC_TPI_COTS) && + (nconf->nc_semantics != NC_TPI_COTS_ORD)) + continue; + switch (handle->nettype) { + case _RPC_VISIBLE: + if (!(nconf->nc_flag & NC_VISIBLE)) + continue; + /* FALLTHROUGH */ + case _RPC_NETPATH: /* Be happy */ + break; + case _RPC_CIRCUIT_V: + if (!(nconf->nc_flag & NC_VISIBLE)) + continue; + /* FALLTHROUGH */ + case _RPC_CIRCUIT_N: + if ((nconf->nc_semantics != NC_TPI_COTS) && + (nconf->nc_semantics != NC_TPI_COTS_ORD)) + continue; + break; + case _RPC_DATAGRAM_V: + if (!(nconf->nc_flag & NC_VISIBLE)) + continue; + /* FALLTHROUGH */ + case _RPC_DATAGRAM_N: + if (nconf->nc_semantics != NC_TPI_CLTS) + continue; + break; + case _RPC_TCP: + if (((nconf->nc_semantics != NC_TPI_COTS) && + (nconf->nc_semantics != NC_TPI_COTS_ORD)) || + (strcmp(nconf->nc_protofmly, NC_INET) +#ifdef INET6 + && strcmp(nconf->nc_protofmly, NC_INET6)) +#else + ) +#endif + || + strcmp(nconf->nc_proto, NC_TCP)) + continue; + break; + case _RPC_UDP: + if ((nconf->nc_semantics != NC_TPI_CLTS) || + (strcmp(nconf->nc_protofmly, NC_INET) +#ifdef INET6 + && strcmp(nconf->nc_protofmly, NC_INET6)) +#else + ) +#endif + || + strcmp(nconf->nc_proto, NC_UDP)) + continue; + break; + } + break; + } + return (nconf); +} + +void +__rpc_endconf(vhandle) + void * vhandle; +{ + struct handle *handle; + + handle = (struct handle *) vhandle; + if (handle == NULL) { + return; + } + if (handle->nflag) { + endnetpath(handle->nhandle); + } else { + endnetconfig(handle->nhandle); + } + free(handle); +} + +/* + * Used to ping the NULL procedure for clnt handle. + * Returns NULL if fails, else a non-NULL pointer. + */ +void * +rpc_nullproc(clnt) + CLIENT *clnt; +{ + struct timeval TIMEOUT = {25, 0}; + + if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL, + (xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return ((void *) clnt); +} + +/* + * Try all possible transports until + * one succeeds in finding the netconf for the given fd. + */ +struct netconfig * +__rpcgettp(fd) + 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 *)(void *)&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)) { + 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(const struct netconfig *nconf) +{ + struct __rpc_sockinfo si; + + if (!__rpc_nconf2sockinfo(nconf, &si)) + return 0; + + return _socket(si.si_af, si.si_socktype, si.si_proto); +} + +int +__rpc_sockinfo2netid(struct __rpc_sockinfo *sip, const char **netid) +{ + int i; + + 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 (netid) + *netid = na_cvt[i].netid; + return 1; + } + + 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 + u_int16_t port; + + switch (af) { + case AF_INET: + sin = nbuf->buf; + if (inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf) + == NULL) + return NULL; + port = ntohs(sin->sin_port); + if (asprintf(&ret, "%s.%u.%u", namebuf, ((u_int32_t)port) >> 8, + port & 0xff) < 0) + return NULL; + break; +#ifdef INET6 + case AF_INET6: + sin6 = nbuf->buf; + if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6) + == NULL) + return NULL; + port = ntohs(sin6->sin6_port); + if (asprintf(&ret, "%s.%u.%u", namebuf6, ((u_int32_t)port) >> 8, + port & 0xff) < 0) + return NULL; + break; +#endif + case AF_LOCAL: + sun = nbuf->buf; + sun->sun_path[sizeof(sun->sun_path) - 1] = '\0'; /* safety */ + ret = strdup(sun->sun_path); + 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; + + 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); + + 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; + } + sin->sin_len = 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(sin); + free(ret); + ret = NULL; + goto out; + } + sin6->sin6_len = 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); + 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; + 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: + return (((struct sockaddr_in *) + (void *)&ss)->sin_port != 0); +#ifdef INET6 + case AF_INET6: + return (((struct sockaddr_in6 *) + (void *)&ss)->sin6_port != 0); +#endif + case AF_LOCAL: + /* XXX check this */ + return (((struct sockaddr_un *) + (void *)&ss)->sun_path[0] != '\0'); + default: + break; + } + + return 0; +} diff --git a/lib/libc/rpc/rpc_prot.c b/lib/libc/rpc/rpc_prot.c index 940a29d13704..4dbfe19839e3 100644 --- a/lib/libc/rpc/rpc_prot.c +++ b/lib/libc/rpc/rpc_prot.c @@ -1,3 +1,5 @@ +/* $NetBSD: rpc_prot.c,v 1.16 2000/06/02 23:11:13 fvdl Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -27,9 +29,10 @@ * Mountain View, California 94043 */ +#include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) -/*static char *sccsid = "from: @(#)rpc_prot.c 1.36 87/08/11 Copyr 1984 Sun Micro";*/ -/*static char *sccsid = "from: @(#)rpc_prot.c 2.3 88/08/07 4.0 RPCSRC";*/ +static char *sccsid = "@(#)rpc_prot.c 1.36 87/08/11 Copyr 1984 Sun Micro"; +static char *sccsid = "@(#)rpc_prot.c 2.3 88/08/07 4.0 RPCSRC"; static char *rcsid = "$FreeBSD$"; #endif @@ -46,13 +49,20 @@ static char *rcsid = "$FreeBSD$"; * routines are also in this program. */ +#include "namespace.h" #include <sys/param.h> +#include <assert.h> + #include <rpc/rpc.h> +#include "un-namespace.h" + +static void accepted __P((enum accept_stat, struct rpc_err *)); +static void rejected __P((enum reject_stat, struct rpc_err *)); /* * * * * * * * * * * * * * XDR Authentication * * * * * * * * * * * */ -struct opaque_auth _null_auth; +extern struct opaque_auth _null_auth; /* * XDR an opaque authentication struct @@ -60,10 +70,13 @@ struct opaque_auth _null_auth; */ bool_t xdr_opaque_auth(xdrs, ap) - register XDR *xdrs; - register struct opaque_auth *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)); @@ -75,10 +88,14 @@ xdr_opaque_auth(xdrs, ap) */ bool_t xdr_des_block(xdrs, blkp) - register XDR *xdrs; - register des_block *blkp; + XDR *xdrs; + des_block *blkp; { - return (xdr_opaque(xdrs, (caddr_t)blkp, sizeof(des_block))); + + assert(xdrs != NULL); + assert(blkp != NULL); + + return (xdr_opaque(xdrs, (caddr_t)(void *)blkp, sizeof(des_block))); } /* * * * * * * * * * * * * * XDR RPC MESSAGE * * * * * * * * * * * * * * * */ @@ -88,10 +105,13 @@ xdr_des_block(xdrs, blkp) */ bool_t xdr_accepted_reply(xdrs, ar) - register XDR *xdrs; - register struct accepted_reply *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); @@ -106,7 +126,11 @@ xdr_accepted_reply(xdrs, ar) if (! xdr_u_int32_t(xdrs, &(ar->ar_vers.low))) return (FALSE); return (xdr_u_int32_t(xdrs, &(ar->ar_vers.high))); - default: + + case GARBAGE_ARGS: + case SYSTEM_ERR: + case PROC_UNAVAIL: + case PROG_UNAVAIL: break; } return (TRUE); /* TRUE => open ended set of problems */ @@ -115,12 +139,15 @@ xdr_accepted_reply(xdrs, ar) /* * XDR the MSG_DENIED part of a reply message union */ -bool_t +bool_t xdr_rejected_reply(xdrs, rr) - register XDR *xdrs; - register struct rejected_reply *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); @@ -134,12 +161,14 @@ xdr_rejected_reply(xdrs, rr) case AUTH_ERROR: return (xdr_enum(xdrs, (enum_t *)&(rr->rj_why))); } + /* NOTREACHED */ + assert(0); return (FALSE); } -static struct xdr_discrim reply_dscrm[3] = { - { (int)MSG_ACCEPTED, xdr_accepted_reply }, - { (int)MSG_DENIED, xdr_rejected_reply }, +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 } }; /* @@ -147,15 +176,19 @@ static struct xdr_discrim reply_dscrm[3] = { */ bool_t xdr_replymsg(xdrs, rmsg) - register XDR *xdrs; - register struct rpc_msg *rmsg; + XDR *xdrs; + struct rpc_msg *rmsg; { + assert(xdrs != NULL); + assert(rmsg != NULL); + if ( - xdr_u_int32_t(xdrs, &(rmsg->rm_xid)) && + 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)&(rmsg->rm_reply.ru), reply_dscrm, NULL_xdrproc_t)); + (caddr_t)(void *)&(rmsg->rm_reply.ru), reply_dscrm, + NULL_xdrproc_t)); return (FALSE); } @@ -167,10 +200,13 @@ xdr_replymsg(xdrs, rmsg) */ bool_t xdr_callhdr(xdrs, cmsg) - register XDR *xdrs; - register struct rpc_msg *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 ( @@ -179,7 +215,7 @@ xdr_callhdr(xdrs, cmsg) 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 (xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_vers))); return (FALSE); } @@ -187,10 +223,12 @@ xdr_callhdr(xdrs, cmsg) static void accepted(acpt_stat, error) - register enum accept_stat acpt_stat; - register struct rpc_err *error; + enum accept_stat acpt_stat; + struct rpc_err *error; { + assert(error != NULL); + switch (acpt_stat) { case PROG_UNAVAIL: @@ -217,34 +255,35 @@ accepted(acpt_stat, error) 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 = (long)MSG_ACCEPTED; - error->re_lb.s2 = (long)acpt_stat; + error->re_lb.s1 = (int32_t)MSG_ACCEPTED; + error->re_lb.s2 = (int32_t)acpt_stat; } -static void +static void rejected(rjct_stat, error) - register enum reject_stat rjct_stat; - register struct rpc_err *error; + enum reject_stat rjct_stat; + struct rpc_err *error; { - switch (rjct_stat) { + assert(error != NULL); - case RPC_VERSMISMATCH: + switch (rjct_stat) { + case RPC_MISMATCH: error->re_status = RPC_VERSMISMATCH; return; case AUTH_ERROR: error->re_status = RPC_AUTHERROR; return; - default: - break; } /* something's wrong, but we don't know what ... */ + /* NOTREACHED */ error->re_status = RPC_FAILED; - error->re_lb.s1 = (long)MSG_DENIED; - error->re_lb.s2 = (long)rjct_stat; + error->re_lb.s1 = (int32_t)MSG_DENIED; + error->re_lb.s2 = (int32_t)rjct_stat; } /* @@ -252,10 +291,13 @@ rejected(rjct_stat, error) */ void _seterr_reply(msg, error) - register struct rpc_msg *msg; - register struct rpc_err *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) { @@ -263,7 +305,7 @@ _seterr_reply(msg, error) if (msg->acpted_rply.ar_stat == SUCCESS) { error->re_status = RPC_SUCCESS; return; - }; + } accepted(msg->acpted_rply.ar_stat, error); break; @@ -273,7 +315,7 @@ _seterr_reply(msg, error) default: error->re_status = RPC_FAILED; - error->re_lb.s1 = (long)(msg->rm_reply.rp_stat); + error->re_lb.s1 = (int32_t)(msg->rm_reply.rp_stat); break; } switch (error->re_status) { @@ -291,6 +333,22 @@ _seterr_reply(msg, error) 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/lib/libc/rpc/rpc_soc.3 b/lib/libc/rpc/rpc_soc.3 new file mode 100644 index 000000000000..a915e5743b86 --- /dev/null +++ b/lib/libc/rpc/rpc_soc.3 @@ -0,0 +1,1810 @@ +.\" @(#)rpc.3n 2.4 88/08/08 4.0 RPCSRC; from 1.19 88/06/24 SMI +.\" $NetBSD: rpc_soc.3,v 1.2 2000/06/07 13:39:43 simonb Exp $ +.\" $FreeBSD$ +.\" +.TH RPC_SOC 3 "16 February 1988" +.SH NAME +rpc_soc, +auth_destroy, +authnone_create, +authunix_create, +authunix_create_default, +callrpc, +clnt_broadcast, +clnt_call, +clnt_control, +clnt_create, +clnt_destroy, +clnt_freeres, +clnt_geterr, +clnt_pcreateerror, +clnt_perrno, +clnt_perror, +clnt_spcreateerror, +clnt_sperrno, +clnt_sperror, +clntraw_create, +clnttcp_create, +clntudp_bufcreate, +clntudp_create, +get_myaddress, +pmap_getmaps, +pmap_getport, +pmap_rmtcall, +pmap_set, +pmap_unset, +registerrpc, +rpc_createerr, +svc_destroy, +svc_fds, +svc_fdset, +svc_getargs, +svc_getcaller, +svc_getreg, +svc_getregset, +svc_register, +svc_run, +svc_sendreply, +svc_unregister, +svcerr_auth, +svcerr_decode, +svcerr_noproc, +svcerr_noprog, +svcerr_progvers, +svcerr_systemerr, +svcerr_weakauth, +svcfd_create, +svcraw_create, +xdr_accepted_reply, +xdr_authunix_parms, +xdr_callhdr, +xdr_callmsg, +xdr_opaque_auth, +xdr_pmap, +xdr_pmaplist, +xdr_rejected_reply, +xdr_replymsg, +xprt_register, +xprt_unregister \- library routines for remote procedure calls +.SH SYNOPSIS AND DESCRIPTION +.B The svc and clnt functions described in this page are the old, TS-RPC +.B interface to the XDR and RPC library, and exist +.B for backward compatibility. The new interface is described in the pages +.B referenced from +.BR rpc (3). +.PP +These routines allow C programs to make procedure +calls on other machines across the network. +First, the client calls a procedure to send a +data packet to the server. +Upon receipt of the packet, the server calls a dispatch routine +to perform the requested service, and then sends back a +reply. +Finally, the procedure call returns to the client. +.\" XXX: NOTYET +.\".LP +.\"Routines that are used for Secure RPC (DES authentication) are described in +.\".BR rpc_secure (3). +.\"Secure RPC can be used only if DES encryption is available. +.LP +.ft B +.nf +.sp .5 +#include <rpc/rpc.h> +.fi +.ft R +.br +.if t .ne 8 +.LP +.ft B +.nf +.sp .5 +void +auth_destroy(auth) +\s-1AUTH\s0 *auth; +.fi +.ft R +.IP +A macro that destroys the authentication information associated with +.IR auth . +Destruction usually involves deallocation of private data +structures. The use of +.I auth +is undefined after calling +.BR auth_destroy(\|) . +.br +.if t .ne 6 +.LP +.ft B +.nf +.sp .5 +\s-1AUTH\s0 * +authnone_create(\|) +.fi +.ft R +.IP +Create and returns an +.SM RPC +authentication handle that passes nonusable authentication +information with each remote procedure call. This is the +default authentication used by +.SM RPC. +.if t .ne 10 +.LP +.ft B +.nf +.sp .5 +\s-1AUTH\s0 * +authunix_create(host, uid, gid, len, aup_gids) +char *host; +int uid, gid, len, *aup.gids; +.fi +.ft R +.IP +Create and return an +.SM RPC +authentication handle that contains +.UX +authentication information. +The parameter +.I host +is the name of the machine on which the information was +created; +.I uid +is the user's user +.SM ID ; +.I gid +is the user's current group +.SM ID ; +.I len +and +.I aup_gids +refer to a counted array of groups to which the user belongs. +It is easy to impersonate a user. +.br +.if t .ne 5 +.LP +.ft B +.nf +.sp .5 +\s-1AUTH\s0 * +authunix_create_default(\|) +.fi +.ft R +.IP +Calls +.B authunix_create(\|) +with the appropriate parameters. +.br +.if t .ne 13 +.LP +.ft B +.nf +.sp .5 +callrpc(host, prognum, versnum, procnum, inproc, in, outproc, out) +char *host; +u_long prognum, versnum, procnum; +char *in, *out; +xdrproc_t inproc, outproc; +.fi +.ft R +.IP +Call the remote procedure associated with +.IR prognum , +.IR versnum , +and +.I procnum +on the machine, +.IR host . +The parameter +.I in +is the address of the procedure's argument(s), and +.I out +is the address of where to place the result(s); +.I inproc +is used to encode the procedure's parameters, and +.I outproc +is used to decode the procedure's results. +This routine returns zero if it succeeds, or the value of +.B "enum clnt_stat" +cast to an integer if it fails. +The routine +.B clnt_perrno(\|) +is handy for translating failure statuses into messages. +.IP +Warning: calling remote procedures with this routine +uses +.SM UDP/IP +as a transport; see +.B clntudp_create(\|) +for restrictions. +You do not have control of timeouts or authentication using +this routine. +.br +.if t .ne 16 +.LP +.ft B +.nf +.sp .5 +enum clnt_stat +clnt_broadcast(prognum, versnum, procnum, inproc, in, outproc, out, eachresult) +u_long prognum, versnum, procnum; +char *in, *out; +xdrproc_t inproc, outproc; +resultproc_t eachresult; +.fi +.ft R +.IP +Like +.BR callrpc(\|) , +except the call message is broadcast to all locally +connected broadcast nets. Each time it receives a +response, this routine calls +.BR eachresult(\|) , +whose form is: +.IP +.RS 1i +.ft B +.nf +eachresult(out, addr) +char *out; +struct sockaddr_in *addr; +.ft R +.fi +.RE +.IP +where +.I out +is the same as +.I out +passed to +.BR clnt_broadcast(\|) , +except that the remote procedure's output is decoded there; +.I addr +points to the address of the machine that sent the results. +If +.B eachresult(\|) +returns zero, +.B clnt_broadcast(\|) +waits for more replies; otherwise it returns with appropriate +status. +.IP +Warning: broadcast sockets are limited in size to the +maximum transfer unit of the data link. For ethernet, +this value is 1500 bytes. +.br +.if t .ne 13 +.LP +.ft B +.nf +.sp .5 +enum clnt_stat +clnt_call(clnt, procnum, inproc, in, outproc, out, tout) +\s-1CLIENT\s0 *clnt; +u_long +procnum; +xdrproc_t inproc, outproc; +char *in, *out; +struct timeval tout; +.fi +.ft R +.IP +A macro that calls the remote procedure +.I procnum +associated with the client handle, +.IR clnt , +which is obtained with an +.SM RPC +client creation routine such as +.BR clnt_create(\|) . +The parameter +.I in +is the address of the procedure's argument(s), and +.I out +is the address of where to place the result(s); +.I inproc +is used to encode the procedure's parameters, and +.I outproc +is used to decode the procedure's results; +.I tout +is the time allowed for results to come back. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +clnt_destroy(clnt) +\s-1CLIENT\s0 *clnt; +.fi +.ft R +.IP +A macro that destroys the client's +.SM RPC +handle. Destruction usually involves deallocation +of private data structures, including +.I clnt +itself. Use of +.I clnt +is undefined after calling +.BR clnt_destroy(\|) . +If the +.SM RPC +library opened the associated socket, it will close it also. +Otherwise, the socket remains open. +.br +.if t .ne 10 +.LP +.ft B +.nf +.sp .5 +\s-1CLIENT\s0 * +clnt_create(host, prog, vers, proto) +char *host; +u_long prog, vers; +char *proto; +.fi +.ft R +.IP +Generic client creation routine. +.I host +identifies the name of the remote host where the server +is located. +.I proto +indicates which kind of transport protocol to use. The +currently supported values for this field are \(lqudp\(rq +and \(lqtcp\(rq. +Default timeouts are set, but can be modified using +.BR clnt_control(\|) . +.IP +Warning: Using +.SM UDP +has its shortcomings. Since +.SM UDP\s0-based +.SM RPC +messages can only hold up to 8 Kbytes of encoded data, +this transport cannot be used for procedures that take +large arguments or return huge results. +.br +.if t .ne 10 +.LP +.ft B +.nf +.sp .5 +bool_t +clnt_control(cl, req, info) +\s-1CLIENT\s0 *cl; +char *info; +.fi +.ft R +.IP +A macro used to change or retrieve various information +about a client object. +.I req +indicates the type of operation, and +.I info +is a pointer to the information. For both +.SM UDP +and +.SM TCP\s0, +the supported values of +.I req +and their argument types and what they do are: +.IP +.nf +.ta +2.0i +2.0i +2.0i +.SM CLSET_TIMEOUT\s0 struct timeval set total timeout +.SM CLGET_TIMEOUT\s0 struct timeval get total timeout +.fi +.IP +Note: if you set the timeout using +.BR clnt_control(\|) , +the timeout parameter passed to +.B clnt_call(\|) +will be ignored in all future calls. +.IP +.nf +.SM CLGET_SERVER_ADDR\s0 struct sockaddr_in get server's address +.fi +.br +.IP +The following operations are valid for +.SM UDP +only: +.IP +.nf +.ta +2.0i +2.0i +2.0i +.SM CLSET_RETRY_TIMEOUT\s0 struct timeval set the retry timeout +.SM CLGET_RETRY_TIMEOUT\s0 struct timeval get the retry timeout +.fi +.br +.IP +The retry timeout is the time that +.SM "UDP RPC" +waits for the server to reply before +retransmitting the request. +.br +.if t .ne 10 +.LP +.ft B +.nf +.sp .5 +clnt_freeres(clnt, outproc, out) +\s-1CLIENT\s0 *clnt; +xdrproc_t outproc; +char *out; +.fi +.ft R +.IP +A macro that frees any data allocated by the +.SM RPC/XDR +system when it decoded the results of an +.SM RPC +call. The +parameter +.I out +is the address of the results, and +.I outproc +is the +.SM XDR +routine describing the results. +This routine returns one if the results were successfully +freed, +and zero otherwise. +.br +.if t .ne 6 +.LP +.ft B +.nf +.sp .5 +void +clnt_geterr(clnt, errp) +\s-1CLIENT\s0 *clnt; +struct rpc_err *errp; +.fi +.ft R +.IP +A macro that copies the error structure out of the client +handle +to the structure at address +.IR errp . +.br +.if t .ne 8 +.LP +.ft B +.nf +.sp .5 +void +clnt_pcreateerror(s) +char *s; +.fi +.ft R +.IP +Print a message to standard error indicating +why a client +.SM RPC +handle could not be created. +The message is prepended with string +.I s +and a colon. +A +.SM NEWLINE +is appended at the end of the message. +Used when a +.BR clnt_create(\|) , +.BR clntraw_create(\|) , +.BR clnttcp_create(\|) , +or +.B clntudp_create(\|) +call fails. +.br +.if t .ne 8 +.LP +.ft B +.nf +.sp .5 +void +clnt_perrno(stat) +enum clnt_stat stat; +.fi +.ft R +.IP +Print a message to standard error corresponding +to the condition indicated by +.IR stat . +A +.SM NEWLINE +is appended at the end of the message. +Used after +.BR callrpc(\|) . +.br +.if t .ne 8 +.LP +.ft B +.nf +.sp .5 +clnt_perror(clnt, s) +\s-1CLIENT\s0 *clnt; +char *s; +.fi +.ft R +.IP +Print a message to standard error indicating why an +.SM RPC +call failed; +.I clnt +is the handle used to do the call. +The message is prepended with string +.I s +and a colon. +A +.SM NEWLINE +is appended at the end of the message. +Used after +.BR clnt_call(\|) . +.br +.if t .ne 9 +.LP +.ft B +.nf +.sp .5 +char * +clnt_spcreateerror +char *s; +.fi +.ft R +.IP +Like +.BR clnt_pcreateerror(\|) , +except that it returns a string +instead of printing to the standard error. +.IP +Bugs: returns pointer to static data that is overwritten +on each call. +.br +.if t .ne 9 +.LP +.ft B +.nf +.sp .5 +char * +clnt_sperrno(stat) +enum clnt_stat stat; +.fi +.ft R +.IP +Take the same arguments as +.BR clnt_perrno(\|) , +but instead of sending a message to the standard error +indicating why an +.SM RPC +call failed, return a pointer to a string which contains +the message. +.IP +.B clnt_sperrno(\|) +is used instead of +.B clnt_perrno(\|) +if the program does not have a standard error (as a program +running as a server quite likely does not), or if the +programmer +does not want the message to be output with +.BR printf , +or if a message format different than that supported by +.B clnt_perrno(\|) +is to be used. +Note: unlike +.B clnt_sperror(\|) +and +.BR clnt_spcreateerror(\|) , +.B clnt_sperrno(\|) +returns pointer to static data, but the +result will not get overwritten on each call. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +char * +clnt_sperror(rpch, s) +\s-1CLIENT\s0 *rpch; +char *s; +.fi +.ft R +.IP +Like +.BR clnt_perror(\|) , +except that (like +.BR clnt_sperrno(\|) ) +it returns a string instead of printing to standard error. +.IP +Bugs: returns pointer to static data that is overwritten +on each call. +.br +.if t .ne 10 +.LP +.ft B +.nf +.sp .5 +\s-1CLIENT\s0 * +clntraw_create(prognum, versnum) +u_long prognum, versnum; +.fi +.ft R +.IP +This routine creates a toy +.SM RPC +client for the remote program +.IR prognum , +version +.IR versnum . +The transport used to pass messages to the service is +actually a buffer within the process's address space, so the +corresponding +.SM RPC +server should live in the same address space; see +.BR svcraw_create(\|) . +This allows simulation of +.SM RPC +and acquisition of +.SM RPC +overheads, such as round trip times, without any +kernel interference. This routine returns +.SM NULL +if it fails. +.br +.if t .ne 15 +.LP +.ft B +.nf +.sp .5 +\s-1CLIENT\s0 * +clnttcp_create(addr, prognum, versnum, sockp, sendsz, recvsz) +struct sockaddr_in *addr; +u_long prognum, versnum; +int *sockp; +u_int sendsz, recvsz; +.fi +.ft R +.IP +This routine creates an +.SM RPC +client for the remote program +.IR prognum , +version +.IR versnum ; +the client uses +.SM TCP/IP +as a transport. The remote program is located at Internet +address +.IR *addr . +If +.\"The following in-line font conversion is necessary for the hyphen indicator +\fB\%addr\->sin_port\fR +is zero, then it is set to the actual port that the remote +program is listening on (the remote +.B portmap +service is consulted for this information). The parameter +.I sockp +is a socket; if it is +.BR \s-1RPC_ANYSOCK\s0 , +then this routine opens a new one and sets +.IR sockp . +Since +.SM TCP\s0-based +.SM RPC +uses buffered +.SM I/O , +the user may specify the size of the send and receive buffers +with the parameters +.I sendsz +and +.IR recvsz ; +values of zero choose suitable defaults. +This routine returns +.SM NULL +if it fails. +.br +.if t .ne 15 +.LP +.ft B +.nf +.sp .5 +\s-1CLIENT\s0 * +clntudp_create(addr, prognum, versnum, wait, sockp) +struct sockaddr_in *addr; +u_long prognum, versnum; +struct timeval wait; +int *sockp; +.fi +.ft R +.IP +This routine creates an +.SM RPC +client for the remote program +.IR prognum , +version +.IR versnum ; +the client uses use +.SM UDP/IP +as a transport. The remote program is located at Internet +address +.IR addr . +If +\fB\%addr\->sin_port\fR +is zero, then it is set to actual port that the remote +program is listening on (the remote +.B portmap +service is consulted for this information). The parameter +.I sockp +is a socket; if it is +.BR \s-1RPC_ANYSOCK\s0 , +then this routine opens a new one and sets +.IR sockp . +The +.SM UDP +transport resends the call message in intervals of +.B wait +time until a response is received or until the call times +out. +The total time for the call to time out is specified by +.BR clnt_call(\|) . +.IP +Warning: since +.SM UDP\s0-based +.SM RPC +messages can only hold up to 8 Kbytes +of encoded data, this transport cannot be used for procedures +that take large arguments or return huge results. +.br +.if t .ne 8 +.LP +.ft B +.nf +.sp .5 +\s-1CLIENT\s0 * +clntudp_bufcreate(addr, prognum, versnum, wait, sockp, sendsize, recosize) +struct sockaddr_in *addr; +u_long prognum, versnum; +struct timeval wait; +int *sockp; +unsigned int sendsize; +unsigned int recosize; +.fi +.ft R +.IP +This routine creates an +.SM RPC +client for the remote program +.IR prognum , +on +.IR versnum ; +the client uses use +.SM UDP/IP +as a transport. The remote program is located at Internet +address +.IR addr . +If +\fB\%addr\->sin_port\fR +is zero, then it is set to actual port that the remote +program is listening on (the remote +.B portmap +service is consulted for this information). The parameter +.I sockp +is a socket; if it is +.BR \s-1RPC_ANYSOCK\s0 , +then this routine opens a new one and sets +.BR sockp . +The +.SM UDP +transport resends the call message in intervals of +.B wait +time until a response is received or until the call times +out. +The total time for the call to time out is specified by +.BR clnt_call(\|) . +.IP +This allows the user to specify the maximum packet size for sending and +receiving +.SM UDP\s0-based +.SM RPC +messages. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +int +get_myaddress(addr) +struct sockaddr_in *addr; +.fi +.ft R +.IP +Stuff the machine's +.SM IP +address into +.IR *addr , +without consulting the library routines that deal with +.BR /etc/hosts . +The port number is always set to +.BR htons(\s-1PMAPPORT\s0) . +Returns zero on success, non-zero on failure. +.br +.if t .ne 10 +.LP +.ft B +.nf +.sp .5 +struct pmaplist * +pmap_getmaps(addr) +struct sockaddr_in *addr; +.fi +.ft R +.IP +A user interface to the +.B portmap +service, which returns a list of the current +.SM RPC +program-to-port mappings +on the host located at +.SM IP +address +.IR *addr . +This routine can return +.SM NULL . +The command +.RB ` "rpcinfo \-p" ' +uses this routine. +.br +.if t .ne 12 +.LP +.ft B +.nf +.sp .5 +u_short +pmap_getport(addr, prognum, versnum, protocol) +struct sockaddr_in *addr; +u_long prognum, versnum, protocol; +.fi +.ft R +.IP +A user interface to the +.B portmap +service, which returns the port number +on which waits a service that supports program number +.IR prognum , +version +.IR versnum , +and speaks the transport protocol associated with +.IR protocol . +The value of +.I protocol +is most likely +.B +.SM IPPROTO_UDP +or +.BR \s-1IPPROTO_TCP\s0 . +A return value of zero means that the mapping does not exist +or that +the +.SM RPC +system failured to contact the remote +.B portmap +service. In the latter case, the global variable +.B rpc_createerr(\|) +contains the +.SM RPC +status. +.br +.if t .ne 15 +.LP +.ft B +.nf +.sp .5 +enum clnt_stat +pmap_rmtcall(addr, prognum, versnum, procnum, inproc, in, outproc, out, tout, portp) +struct sockaddr_in *addr; +u_long prognum, versnum, procnum; +char *in, *out; +xdrproc_t inproc, outproc; +struct timeval tout; +u_long *portp; +.fi +.ft R +.IP +A user interface to the +.B portmap +service, which instructs +.B portmap +on the host at +.SM IP +address +.I *addr +to make an +.SM RPC +call on your behalf to a procedure on that host. +The parameter +.I *portp +will be modified to the program's port number if the +procedure +succeeds. The definitions of other parameters are discussed +in +.B callrpc(\|) +and +.BR clnt_call(\|) . +This procedure should be used for a \(lqping\(rq and nothing +else. +See also +.BR clnt_broadcast(\|) . +.br +.if t .ne 9 +.LP +.ft B +.nf +.sp .5 +pmap_set(prognum, versnum, protocol, port) +u_long prognum, versnum, protocol; +u_short port; +.fi +.ft R +.IP +A user interface to the +.B portmap +service, which establishes a mapping between the triple +.RI [ prognum , versnum , protocol\fR] +and +.I port +on the machine's +.B portmap +service. The value of +.I protocol +is most likely +.B +.SM IPPROTO_UDP +or +.BR \s-1IPPROTO_TCP\s0 . +This routine returns one if it succeeds, zero otherwise. +Automatically done by +.BR svc_register(\|) . +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +pmap_unset(prognum, versnum) +u_long prognum, versnum; +.fi +.ft R +.IP +A user interface to the +.B portmap +service, which destroys all mapping between the triple +.RI [ prognum , versnum , *\fR] +and +.B ports +on the machine's +.B portmap +service. This routine returns one if it succeeds, zero +otherwise. +.br +.if t .ne 15 +.LP +.ft B +.nf +.sp .5 +registerrpc(prognum, versnum, procnum, procname, inproc, outproc) +u_long prognum, versnum, procnum; +char *(*procname) (\|) ; +xdrproc_t inproc, outproc; +.fi +.ft R +.IP +Register procedure +.I procname +with the +.SM RPC +service package. If a request arrives for program +.IR prognum , +version +.IR versnum , +and procedure +.IR procnum , +.I procname +is called with a pointer to its parameter(s); +.I progname +should return a pointer to its static result(s); +.I inproc +is used to decode the parameters while +.I outproc +is used to encode the results. +This routine returns zero if the registration succeeded, \-1 +otherwise. +.IP +Warning: remote procedures registered in this form +are accessed using the +.SM UDP/IP +transport; see +.B svcudp_create(\|) +for restrictions. +.br +.if t .ne 5 +.LP +.ft B +.nf +.sp .5 +struct rpc_createerr rpc_createerr; +.fi +.ft R +.IP +A global variable whose value is set by any +.SM RPC +client creation routine +that does not succeed. Use the routine +.B clnt_pcreateerror(\|) +to print the reason why. +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +svc_destroy(xprt) +\s-1SVCXPRT\s0 * +xprt; +.fi +.ft R +.IP +A macro that destroys the +.SM RPC +service transport handle, +.IR xprt . +Destruction usually involves deallocation +of private data structures, including +.I xprt +itself. Use of +.I xprt +is undefined after calling this routine. +.br +.if t .ne 8 +.LP +.ft B +.nf +.sp .5 +fd_set svc_fdset; +.fi +.ft R +.IP +A global variable reflecting the +.SM RPC +service side's +read file descriptor bit mask; it is suitable as a parameter +to the +.B select +system call. This is only of interest +if a service implementor does not call +.BR svc_run(\|) , +but rather does his own asynchronous event processing. +This variable is read-only (do not pass its address to +.BR select !), +yet it may change after calls to +.B svc_getreqset(\|) +or any creation routines. +.br +.if t .ne 6 +.LP +.ft B +.nf +.sp .5 +int svc_fds; +.fi +.ft R +.IP +Similar to +.BR svc_fedset(\|) , +but limited to 32 descriptors. This +interface is obsoleted by +.BR svc_fdset(\|) . +.br +.if t .ne 9 +.LP +.ft B +.nf +.sp .5 +svc_freeargs(xprt, inproc, in) +\s-1SVCXPRT\s0 *xprt; +xdrproc_t inproc; +char *in; +.fi +.ft R +.IP +A macro that frees any data allocated by the +.SM RPC/XDR +system when it decoded the arguments to a service procedure +using +.BR svc_getargs(\|) . +This routine returns 1 if the results were successfully +freed, +and zero otherwise. +.br +.if t .ne 10 +.LP +.ft B +.nf +.sp .5 +svc_getargs(xprt, inproc, in) +\s-1SVCXPRT\s0 *xprt; +xdrproc_t inproc; +char *in; +.fi +.ft R +.IP +A macro that decodes the arguments of an +.SM RPC +request +associated with the +.SM RPC +service transport handle, +.IR xprt . +The parameter +.I in +is the address where the arguments will be placed; +.I inproc +is the +.SM XDR +routine used to decode the arguments. +This routine returns one if decoding succeeds, and zero +otherwise. +.br +.if t .ne 9 +.LP +.ft B +.nf +.sp .5 +struct sockaddr_in * +svc_getcaller(xprt) +\s-1SVCXPRT\s0 *xprt; +.fi +.ft R +.IP +The approved way of getting the network address of the caller +of a procedure associated with the +.SM RPC +service transport handle, +.IR xprt . +.br +.if t .ne 9 +.LP +.ft B +.nf +.sp .5 +svc_getreqset(rdfds) +fd_set *rdfds; +.fi +.ft R +.IP +This routine is only of interest if a service implementor +does not call +.BR svc_run(\|) , +but instead implements custom asynchronous event processing. +It is called when the +.B select +system call has determined that an +.SM RPC +request has arrived on some +.SM RPC +.B socket(s) ; +.I rdfds +is the resultant read file descriptor bit mask. +The routine returns when all sockets associated with the +value of +.I rdfds +have been serviced. +.br +.if t .ne 6 +.LP +.ft B +.nf +.sp .5 +svc_getreq(rdfds) +int rdfds; +.fi +.ft R +.IP +Similar to +.BR svc_getreqset(\|) , +but limited to 32 descriptors. This interface is obsoleted by +.BR svc_getreqset(\|) . +.br +.if t .ne 17 +.LP +.ft B +.nf +.sp .5 +svc_register(xprt, prognum, versnum, dispatch, protocol) +\s-1SVCXPRT\s0 *xprt; +u_long prognum, versnum; +void (*dispatch) (\|); +u_long protocol; +.fi +.ft R +.IP +Associates +.I prognum +and +.I versnum +with the service dispatch procedure, +.IR dispatch . +If +.I protocol +is zero, the service is not registered with the +.B portmap +service. If +.I protocol +is non-zero, then a mapping of the triple +.RI [ prognum , versnum , protocol\fR] +to +\fB\%xprt\->xp_port\fR +is established with the local +.B portmap +service (generally +.I protocol +is zero, +.B +.SM IPPROTO_UDP +or +.B +.SM IPPROTO_TCP +). +The procedure +.I dispatch +has the following form: +.RS 1i +.ft B +.nf +dispatch(request, xprt) +struct svc_req *request; +\s-1SVCXPRT\s0 *xprt; +.ft R +.fi +.RE +.IP +The +.B svc_register(\|) +routine returns one if it succeeds, and zero otherwise. +.br +.if t .ne 6 +.LP +.ft B +.nf +.sp .5 +svc_run(\|) +.fi +.ft R +.IP +This routine never returns. It waits for +.SM RPC +requests to arrive, and calls the appropriate service +procedure using +.B svc_getreq(\|) +when one arrives. This procedure is usually waiting for a +.B select(\|) +system call to return. +.br +.if t .ne 9 +.LP +.ft B +.nf +.sp .5 +svc_sendreply(xprt, outproc, out) +\s-1SVCXPRT\s0 *xprt; +xdrproc_t outproc; +char *out; +.fi +.ft R +.IP +Called by an +.SM RPC +service's dispatch routine to send the results of a +remote procedure call. The parameter +.I xprt +is the request's associated transport handle; +.I outproc +is the +.SM XDR +routine which is used to encode the results; and +.I out +is the address of the results. +This routine returns one if it succeeds, zero otherwise. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +void +svc_unregister(prognum, versnum) +u_long prognum, versnum; +.fi +.ft R +.IP +Remove all mapping of the double +.RI [ prognum , versnum ] +to dispatch routines, and of the triple +.RI [ prognum , versnum , *\fR] +to port number. +.br +.if t .ne 9 +.LP +.ft B +.nf +.sp .5 +void +svcerr_auth(xprt, why) +\s-1SVCXPRT\s0 *xprt; +enum auth_stat why; +.fi +.ft R +.IP +Called by a service dispatch routine that refuses to perform +a remote procedure call due to an authentication error. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +void +svcerr_decode(xprt) +\s-1SVCXPRT\s0 *xprt; +.fi +.ft R +.IP +Called by a service dispatch routine that cannot successfully +decode its parameters. See also +.BR svc_getargs(\|) . +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +void +svcerr_noproc(xprt) +\s-1SVCXPRT\s0 *xprt; +.fi +.ft R +.IP +Called by a service dispatch routine that does not implement +the procedure number that the caller requests. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +void +svcerr_noprog(xprt) +\s-1SVCXPRT\s0 *xprt; +.fi +.ft R +.IP +Called when the desired program is not registered with the +.SM RPC +package. Service implementors usually do not need this routine. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +void +svcerr_progvers(xprt) +\s-1SVCXPRT\s0 *xprt; +.fi +.ft R +.IP +Called when the desired version of a program is not registered +with the +.SM RPC +package. Service implementors usually do not need this routine. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +void +svcerr_systemerr(xprt) +\s-1SVCXPRT\s0 *xprt; +.fi +.ft R +.IP +Called by a service dispatch routine when it detects a system +error +not covered by any particular protocol. +For example, if a service can no longer allocate storage, +it may call this routine. +.br +.if t .ne 8 +.LP +.ft B +.nf +.sp .5 +void +svcerr_weakauth(xprt) +\s-1SVCXPRT\s0 *xprt; +.fi +.ft R +.IP +Called by a service dispatch routine that refuses to perform +a remote procedure call due to insufficient +authentication parameters. The routine calls +.BR "svcerr_auth(xprt, \s-1AUTH_TOOWEAK\s0)" . +.br +.if t .ne 11 +.LP +.ft B +.nf +.sp .5 +\s-1SVCXPRT\s0 * +svcraw_create(\|) +.fi +.ft R +.IP +This routine creates a toy +.SM RPC +service transport, to which it returns a pointer. The +transport +is really a buffer within the process's address space, +so the corresponding +.SM RPC +client should live in the same +address space; +see +.BR clntraw_create(\|) . +This routine allows simulation of +.SM RPC +and acquisition of +.SM RPC +overheads (such as round trip times), without any kernel +interference. +This routine returns +.SM NULL +if it fails. +.br +.if t .ne 11 +.LP +.ft B +.nf +.sp .5 +\s-1SVCXPRT\s0 * +svctcp_create(sock, send_buf_size, recv_buf_size) +int sock; +u_int send_buf_size, recv_buf_size; +.fi +.ft R +.IP +This routine creates a +.SM TCP/IP\s0-based +.SM RPC +service transport, to which it returns a pointer. +The transport is associated with the socket +.IR sock , +which may be +.BR \s-1RPC_ANYSOCK\s0 , +in which case a new socket is created. +If the socket is not bound to a local +.SM TCP +port, then this routine binds it to an arbitrary port. Upon +completion, +\fB\%xprt\->xp_fd\fR +is the transport's socket descriptor, and +\fB\%xprt\->xp_port\fR +is the transport's port number. +This routine returns +.SM NULL +if it fails. Since +.SM TCP\s0-based +.SM RPC +uses buffered +.SM I/O , +users may specify the size of buffers; values of zero +choose suitable defaults. +.br +.if t .ne 11 +.LP +.ft B +.nf +.sp .5 +\s-1SVCXPRT\s0 * +svcfd_create(fd, sendsize, recvsize) +int fd; +u_int sendsize; +u_int recvsize; +.fi +.ft R +.IP +Create a service on top of any open descriptor. Typically, +this +descriptor is a connected socket for a stream protocol such +as +.SM TCP\s0. +.I sendsize +and +.I recvsize +indicate sizes for the send and receive buffers. If they are +zero, a reasonable default is chosen. +.br +.if t .ne 10 +.LP +.ft B +.nf +.sp .5 +\s-1SVCXPRT\s0 * +svcudp_bufcreate(sock, sendsize, recosize) +int sock; +.fi +.ft R +.IP +This routine creates a +.SM UDP/IP\s0-based +.SM RPC +service transport, to which it returns a pointer. +The transport is associated with the socket +.IR sock , +which may be +.B \s-1RPC_ANYSOCK\s0 , +in which case a new socket is created. +If the socket is not bound to a local +.SM UDP +port, then this routine binds it to an arbitrary port. Upon +completion, +\fB\%xprt\->xp_sock\fR +is the transport's socket descriptor, and +\fB\%xprt\->xp_port\fR +is the transport's port number. +This routine returns +.SM NULL +if it fails. +.IP +This allows the user to specify the maximum packet size for sending and +receiving +.SM UDP\s0-based +.SM RPC messages. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +xdr_accepted_reply(xdrs, ar) +\s-1XDR\s0 *xdrs; +struct accepted_reply *ar; +.fi +.ft R +.IP +Used for encoding +.SM RPC +reply messages. This routine is useful for users who +wish to generate +\s-1RPC\s0-style +messages without using the +.SM RPC +package. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +xdr_authunix_parms(xdrs, aupp) +\s-1XDR\s0 *xdrs; +struct authunix_parms *aupp; +.fi +.ft R +.IP +Used for describing +.SM UNIX +credentials. This routine is useful for users +who wish to generate these credentials without using the +.SM RPC +authentication package. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +void +xdr_callhdr(xdrs, chdr) +\s-1XDR\s0 *xdrs; +struct rpc_msg *chdr; +.fi +.ft R +.IP +Used for describing +.SM RPC +call header messages. +This routine is useful for users who wish to generate +.SM RPC\s0-style +messages without using the +.SM RPC +package. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +xdr_callmsg(xdrs, cmsg) +\s-1XDR\s0 *xdrs; +struct rpc_msg *cmsg; +.fi +.ft R +.IP +Used for describing +.SM RPC +call messages. +This routine is useful for users who wish to generate +.SM RPC\s0-style +messages without using the +.SM RPC +package. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +xdr_opaque_auth(xdrs, ap) +\s-1XDR\s0 *xdrs; +struct opaque_auth *ap; +.fi +.ft R +.IP +Used for describing +.SM RPC +authentication information messages. +This routine is useful for users who wish to generate +.SM RPC\s0-style +messages without using the +.SM RPC +package. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +xdr_pmap(xdrs, regs) +\s-1XDR\s0 *xdrs; +struct pmap *regs; +.fi +.ft R +.IP +Used for describing parameters to various +.B portmap +procedures, externally. +This routine is useful for users who wish to generate +these parameters without using the +.B pmap +interface. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +xdr_pmaplist(xdrs, rp) +\s-1XDR\s0 *xdrs; +struct pmaplist **rp; +.fi +.ft R +.IP +Used for describing a list of port mappings, externally. +This routine is useful for users who wish to generate +these parameters without using the +.B pmap +interface. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +xdr_rejected_reply(xdrs, rr) +\s-1XDR\s0 *xdrs; +struct rejected_reply *rr; +.fi +.ft R +.IP +Used for describing +.SM RPC +reply messages. +This routine is useful for users who wish to generate +.SM RPC\s0-style +messages without using the +.SM RPC +package. +.br +.if t .ne 8 +.LP +.ft B +.nf +.sp .5 +xdr_replymsg(xdrs, rmsg) +\s-1XDR\s0 *xdrs; +struct rpc_msg *rmsg; +.fi +.ft R +.IP +Used for describing +.SM RPC +reply messages. +This routine is useful for users who wish to generate +.SM RPC +style messages without using the +.SM RPC +package. +.br +.if t .ne 8 +.LP +.ft B +.nf +.sp .5 +void +xprt_register(xprt) +\s-1SVCXPRT\s0 *xprt; +.fi +.ft R +.IP +After +.SM RPC +service transport handles are created, +they should register themselves with the +.SM RPC +service package. +This routine modifies the global variable +.BR svc_fds(\|) . +Service implementors usually do not need this routine. +.br +.if t .ne 8 +.LP +.ft B +.nf +.sp .5 +void +xprt_unregister(xprt) +\s-1SVCXPRT\s0 *xprt; +.fi +.ft R +.IP +Before an +.SM RPC +service transport handle is destroyed, +it should unregister itself with the +.SM RPC +service package. +This routine modifies the global variable +.BR svc_fds(\|) . +Service implementors usually do not need this routine. +.SH SEE ALSO +.\".BR rpc_secure (3), +.BR xdr (3) +.br +The following manuals: +.RS +.ft I +Remote Procedure Calls: Protocol Specification +.br +Remote Procedure Call Programming Guide +.br +rpcgen Programming Guide +.br +.ft R +.RE +.IR "\s-1RPC\s0: Remote Procedure Call Protocol Specification" , +.SM RFC1050, Sun Microsystems, Inc., +.SM USC-ISI\s0. + diff --git a/lib/libc/rpc/rpc_soc.c b/lib/libc/rpc/rpc_soc.c new file mode 100644 index 000000000000..07783d67089c --- /dev/null +++ b/lib/libc/rpc/rpc_soc.c @@ -0,0 +1,453 @@ +/* $NetBSD: rpc_soc.c,v 1.6 2000/07/06 03:10:35 christos Exp $ */ +/* $FreeBSD$ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* #ident "@(#)rpc_soc.c 1.17 94/04/24 SMI" */ + +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + * In addition, portions of such source code were derived from Berkeley + * 4.3 BSD under license from the Regents of the University of + * California. + */ + +#if 0 +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)rpc_soc.c 1.41 89/05/02 Copyr 1988 Sun Micro"; +#endif +#endif + +#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 "reentrant.h" +#include "namespace.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 "un-namespace.h" + +#include "rpc_com.h" + +extern mutex_t rpcsoc_lock; + +static CLIENT *clnt_com_create __P((struct sockaddr_in *, rpcprog_t, rpcvers_t, + int *, u_int, u_int, char *)); +static SVCXPRT *svc_com_create __P((int, u_int, u_int, char *)); +static bool_t rpc_wrap_bcast __P((char *, struct netbuf *, struct netconfig *)); + +/* XXX */ +#define IN4_LOCALHOST_STRING "127.0.0.1" +#define IN6_LOCALHOST_STRING "::1" + +/* + * A common clnt create routine + */ +static CLIENT * +clnt_com_create(raddr, prog, vers, sockp, sendsz, recvsz, tp) + struct sockaddr_in *raddr; + rpcprog_t prog; + rpcvers_t vers; + int *sockp; + u_int sendsz; + u_int recvsz; + char *tp; +{ + 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) { + fd = __rpc_nconf2fd(nconf); + if (fd == -1) + goto syserror; + madefd = TRUE; + } + + if (raddr->sin_port == 0) { + u_int proto; + u_short sport; + + mutex_unlock(&rpcsoc_lock); /* pmap_getport is recursive */ + proto = strcmp(tp, "udp") == 0 ? IPPROTO_UDP : IPPROTO_TCP; + sport = pmap_getport(raddr, (u_long)prog, (u_long)vers, + proto); + if (sport == 0) { + goto err; + } + raddr->sin_port = htons(sport); + mutex_lock(&rpcsoc_lock); /* pmap_getport is recursive */ + } + + /* Transform sockaddr_in to netbuf */ + bindaddr.maxlen = bindaddr.len = sizeof (struct sockaddr_in); + bindaddr.buf = raddr; + + bindresvport(fd, NULL); + cl = clnt_tli_create(fd, nconf, &bindaddr, prog, vers, + sendsz, recvsz); + 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 * +clntudp_bufcreate(raddr, prog, vers, wait, sockp, sendsz, recvsz) + struct sockaddr_in *raddr; + u_long prog; + u_long vers; + struct timeval wait; + int *sockp; + u_int sendsz; + u_int recvsz; +{ + CLIENT *cl; + + cl = clnt_com_create(raddr, (rpcprog_t)prog, (rpcvers_t)vers, sockp, + sendsz, recvsz, "udp"); + if (cl == NULL) { + return (NULL); + } + (void) CLNT_CONTROL(cl, CLSET_RETRY_TIMEOUT, (char *)(void *)&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"); +} + +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; + struct sockaddr_in sin; + + if ((nconf = __rpc_getconfip(netid)) == NULL) { + (void) syslog(LOG_ERR, "Could not get %s transport", netid); + return (NULL); + } + if (fd == RPC_ANYSOCK) { + fd = __rpc_nconf2fd(nconf); + if (fd == -1) { + (void) freenetconfigent(nconf); + (void) syslog(LOG_ERR, + "svc%s_create: could not open connection", netid); + return (NULL); + } + madefd = TRUE; + } + + memset(&sin, 0, sizeof sin); + sin.sin_family = AF_INET; + bindresvport(fd, &sin); + _listen(fd, SOMAXCONN); + svc = svc_tli_create(fd, nconf, NULL, sendsize, recvsize); + (void) freenetconfigent(nconf); + if (svc == NULL) { + if (madefd) + (void)_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(); +} + +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) + char *host; + int prognum, versnum, procnum; + xdrproc_t inproc, outproc; + char *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) __P((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 + */ +static thread_key_t clnt_broadcast_key; +static resultproc_t clnt_broadcast_result_main; + +/* + * 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); + if (thr_main()) + clnt_broadcast_result = clnt_broadcast_result_main; + else + 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 */ + 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 */ +{ + extern mutex_t tsd_lock; + + if (thr_main()) + clnt_broadcast_result_main = eachresult; + else { + if (clnt_broadcast_key == 0) { + mutex_lock(&tsd_lock); + if (clnt_broadcast_key == 0) + 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"); +} + +/* + * Create the client des authentication object. Obsoleted by + * authdes_seccreate(). + */ +AUTH * +authdes_create(servername, window, syncaddr, ckey) + char *servername; /* network name of server */ + u_int window; /* time to live */ + struct sockaddr *syncaddr; /* optional hostaddr to sync with */ + des_block *ckey; /* optional conversation key to use */ +{ + AUTH *dummy; + AUTH *nauth; + char hostname[NI_MAXHOST]; + + if (syncaddr) { + /* + * Change addr to hostname, because that is the way + * new interface takes it. + */ + if (getnameinfo(syncaddr, syncaddr->sa_len, hostname, + sizeof hostname, NULL, 0, 0) != 0) + goto fallback; + + nauth = authdes_seccreate(servername, window, hostname, ckey); + return (nauth); + } +fallback: + dummy = authdes_seccreate(servername, window, NULL, ckey); + return (dummy); +} + +#endif /* PORTMAP */ diff --git a/lib/libc/rpc/rpc_svc_calls.3 b/lib/libc/rpc/rpc_svc_calls.3 new file mode 100644 index 000000000000..06ff75516ec4 --- /dev/null +++ b/lib/libc/rpc/rpc_svc_calls.3 @@ -0,0 +1,263 @@ +.\" @(#)rpc_svc_calls.3n 1.28 93/05/10 SMI; from SVr4 +.\" Copyright 1989 AT&T +.\" @(#)rpc_svc_calls 1.5 89/07/25 SMI; +.\" Copyright (c) 1988 Sun Microsystems, Inc. - All Rights Reserved. +.\" $NetBSD: rpc_svc_calls.3,v 1.1 2000/06/02 23:11:13 fvdl Exp $ +.\" $FreeBSD$ +.Dd May 3, 1993 +.Dt RPC_SVC_CALLS 3 +.Os +.Sh NAME +.Nm svc_dg_enablecache , +.Nm svc_exit , +.Nm svc_fdset , +.Nm svc_freeargs , +.Nm svc_getargs , +.Nm svc_getreq_common , +.Nm svc_getreq_poll , +.Nm svc_getreqset , +.Nm svc_getrpccaller , +.Nm svc_pollset , +.Nm svc_run , +.Nm svc_sendreply +.Nd library routines for RPC servers +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.Fd #include <rpc/rpc.h> +.Ft int +.Fn svc_dg_enablecache "SVCXPRT *xprt" "const unsigned cache_size" +.Ft void +.Fn svc_exit "void" +.Ft bool_t +.Fn svc_freeargs "const SVCXPRT *xprt" "const xdrproc_t inproc" "caddr_t in" +.Ft bool_t +.Fn svc_getargs "const SVCXPRT *xprt" "const xdrproc_t inproc" "caddr_t in" +.Ft void +.Fn svc_getreq_common "const int fd" +.Ft void +.Fn svc_getreq_poll "struct pollfd *pfdp" "const int pollretval" +.Ft void +.Fn svc_getreqset "fd_set * rdfds" +.Ft "struct netbuf *" +.Fn svc_getrpccaller "const SVCXPRT *xprt" +.Ft "struct cmsgcred *" +.Fn __svc_getcallercreds "const SVCXPRT *xprt" +.Vt struct pollfd svc_pollset[FD_SETSIZE]; +.Ft void +.Fn svc_run "void" +.Ft bool_t +.Fn svc_sendreply "const SVCXPRT *xprt" "const xdrproc_t outproc" "const caddr_t *out" +.Sh DESCRIPTION +These routines are part of the +RPC +library which allows C language programs to make procedure +calls on other machines across the network. +.Pp +These routines are associated with the server side of the +RPC mechanism. +Some of them are called by the server side dispatch function, +while others +(such as +.Fn svc_run ) +are called when the server is initiated. +.\" .Pp +.\" In the current implementation, the service transport handle, +.\" .Dv SVCXPRT , +.\" contains a single data area for decoding arguments and encoding results. +.\" Therefore, this structure cannot be freely shared between threads that call +.\" functions that do this. +.\" Routines on this page that are affected by this +.\" restriction are marked as unsafe for MT applications. +.Sh Routines +See +.Xr rpc 3 +for the definition of the +.Vt SVCXPRT +data structure. +.Bl -tag -width __svc_getcallercreds() +.It Fn svc_dg_enablecache +This function allocates a duplicate request cache for the +service endpoint +.Fa xprt , +large enough to hold +.Fa cache_size +entries. +Once enabled, there is no way to disable caching. +This routine returns 0 if space necessary for a cache of the given size +was successfully allocated, and 1 otherwise. +.It Fn svc_exit +This function, when called by any of the RPC server procedure or +otherwise, causes +.Fn svc_run +to return. +.Pp +As currently implemented, +.Fn svc_exit +zeroes the +.Va svc_fdset +global variable. +If RPC server activity is to be resumed, +services must be reregistered with the RPC library +either through one of the +.Fn rpc_svc_create +functions, or using +.Fn xprt_register . +.Fn svc_exit +has global scope and ends all RPC server activity. +.It Xo +.Vt fd_set Va svc_fdset +.Xc +A global variable reflecting the +RPC server's read file descriptor bit mask; it is suitable as a parameter +to the +.Xr select 2 +system call. +This is only of interest +if service implementors do not call +.Fn svc_run , +but rather do their own asynchronous event processing. +This variable is read-only (do not pass its address to +.Xr select 2 ! ) , +yet it may change after calls to +.Fn svc_getreqset +or any creation routines. +.It Fn svc_freeargs +A function macro that frees any data allocated by the +RPC/XDR system when it decoded the arguments to a service procedure +using +.Fn svc_getargs . +This routine returns +.Dv TRUE +if the results were successfully +freed, and +.Dv FALSE +otherwise. +.It Fn svc_getargs +A function macro that decodes the arguments of an +RPC request associated with the RPC +service transport handle +.Fa xprt . +The parameter +.Fa in +is the address where the arguments will be placed; +.Fa inproc +is the XDR +routine used to decode the arguments. +This routine returns +.Dv TRUE +if decoding succeeds, and +.Dv FALSE +otherwise. +.It Fn svc_getreq_common +This routine is called to handle a request on the given +file descriptor. +.It Fn svc_getreq_poll +This routine is only of interest if a service implementor +does not call +.Fn svc_run , +but instead implements custom asynchronous event processing. +It is called when +.Xr poll 2 +has determined that an RPC request has arrived on some RPC +file descriptors; +.Fa pollretval +is the return value from +.Xr poll 2 +and +.Fa pfdp +is the array of +.Vt pollfd +structures on which the +.Xr poll 2 +was done. +It is assumed to be an array large enough to +contain the maximal number of descriptors allowed. +.It Fn svc_getreqset +This routine is only of interest if a service implementor +does not call +.Fn svc_run , +but instead implements custom asynchronous event processing. +It is called when +.Xr poll 2 +has determined that an RPC +request has arrived on some RPC file descriptors; +.Fa rdfds +is the resultant read file descriptor bit mask. +The routine returns when all file descriptors +associated with the value of +.Fa rdfds +have been serviced. +.It Fn svc_getrpccaller +The approved way of getting the network address of the caller +of a procedure associated with the +RPC service transport handle +.Fa xprt . +.It Fn __svc_getcallercreds +.Em Warning : +this macro is specific to +.Fx +and thus not portable. +This macro returns a pointer to a +.Vt cmsgcred +structure, defined in +.Aq Pa sys/socket.h , +identifying the calling client. +This only works if the client is +calling the server over an +.Dv AF_LOCAL +socket. +.It Xo +.Vt struct pollfd Va svc_pollset[FD_SETSIZE] ; +.Xc +.Va svc_pollset +is an array of +.Vt pollfd +structures derived from +.Va svc_fdset[] . +It is suitable as a parameter to the +.Xr poll 2 +system call. +The derivation of +.Va svc_pollset +from +.Va svc_fdset +is made in the current implementation in +.Fn svc_run . +Service implementors who do not call +.Fn svc_run +and who wish to use this array must perform this derivation themselves. +.It Fn svc_run +This routine never returns. +It waits for RPC +requests to arrive, and calls the appropriate service +procedure using +.Fn svc_getreq_poll +when one arrives. +This procedure is usually waiting for the +.Xr poll 2 +system call to return. +.It Fn svc_sendreply +Called by an RPC service's dispatch routine to send the results of a +remote procedure call. +The parameter +.Fa xprt +is the request's associated transport handle; +.Fa outproc +is the XDR +routine which is used to encode the results; and +.Fa out +is the address of the results. +This routine returns +.Dv TRUE +if it succeeds, +.Dv FALSE +otherwise. +.El +.Sh SEE ALSO +.Xr poll 2 , +.Xr select 2 , +.Xr rpc 3 , +.Xr rpc_svc_create 3 , +.Xr rpc_svc_err 3 , +.Xr rpc_svc_reg 3 diff --git a/lib/libc/rpc/rpc_svc_create.3 b/lib/libc/rpc/rpc_svc_create.3 new file mode 100644 index 000000000000..b9788b2e3a70 --- /dev/null +++ b/lib/libc/rpc/rpc_svc_create.3 @@ -0,0 +1,622 @@ +.\" @(#)rpc_svc_create.3n 1.26 93/08/26 SMI; from SVr4 +.\" Copyright 1989 AT&T +.\" @(#)rpc_svc_create 1.3 89/06/28 SMI; +.\" Copyright (c) 1988 Sun Microsystems, Inc. - All Rights Reserved. +.\" $FreeBSD$ +.Dd May 3, 1993 +.Dt RPC_SVC_CREATE 3 +.Os +.Sh NAME +.Nm rpc_svc_create , +.Nm svc_control , +.Nm svc_create , +.Nm svc_destroy , +.Nm svc_dg_create , +.Nm svc_fd_create , +.Nm svc_raw_create , +.Nm svc_tli_create , +.Nm svc_tp_create , +.Nm svc_vc_create +.Nd library routines for the creation of server handles +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.Fd #include <rpc/rpc.h> +.Ft bool_t +.Fn svc_control "SVCXPRT *svc" "const u_int req" "void *info" +.Ft int +.Fn svc_create "const void (*dispatch)(struct svc_req *, SVCXPRT *)" "const rpcprog_t prognum" "const rpcvers_t versnum" "const char *nettype" +.Ft SVCXPRT *" +.Fn svc_dg_create "const int fildes" "const u_int sendsz" "const u_int recvsz" +.Ft void +.Fn svc_destroy "SVCXPRT *xprt" +.Ft "SVCXPRT *" +.Fn svc_fd_create "const int fildes" "const u_int sendsz" "const u_int recvsz" +.Ft "SVCXPRT *" +.Fn svc_raw_create "void" +.Ft "SVCXPRT *" +.Fn svc_tli_create "const int fildes" "const struct netconfig *netconf" "const struct t_bind *bindaddr" "const u_int sendsz" "const u_int recvsz" +.Ft "SVCXPRT *" +.Fn svc_tp_create "const void (*dispatch)(const struct svc_reg *, const SVCXPRT *)" "const rpcprog_t prognum" "const rpcvers_t versnum" "const struct netconfig *netconf" +.Ft "SVCXPRT *" +.Fn svc_vc_create "const int fildes" "const u_int sendsz" "const u_int recvsz" +.Sh DESCRIPTION +These routines are part of the RPC +library which allows C language programs to make procedure +calls on servers across the network. +These routines deal with the creation of service handles. +Once the handle is created, the server can be invoked by calling +.Fn svc_run . +.Sh Routines +See +.Xr rpc 3 +for the definition of the +.Vt SVCXPRT +data structure. +.Bl -tag -width XXXXX +.It Fn svc_control +A function to change or retrieve various information +about a service object. +.Fa req +indicates the type of operation and +.Fa info +is a pointer to the information. +The supported values of +.Fa req , +their argument types, and what they do are: +.Bl -tag -width SVCGET_XID +.It Dv SVCGET_VERSQUIET +If a request is received for a program number +served by this server but the version number +is outside the range registered with the server, +an +.Dv RPC_PROGVERSMISMATCH +error will normally +be returned. +.Fa info +should be a pointer to an +integer. +Upon successful completion of the +.Dv SVCGET_VERSQUIET +request, +.Fa *info +contains an +integer which describes the server's current +behavior: 0 indicates normal server behavior +(that is, an +.Dv RPC_PROGVERSMISMATCH +error +will be returned); 1 indicates that the out of +range request will be silently ignored. +.It Dv SVCSET_VERSQUIET +If a request is received for a program number +served by this server but the version number +is outside the range registered with the server, +an +.Dv RPC_PROGVERSMISMATCH +error will normally +be returned. +It is sometimes desirable to +change this behavior. +.Fa info +should be a +pointer to an integer which is either 0 +(indicating normal server behavior - an +.Dv RPC_PROGVERSMISMATCH +error will be returned), +or 1 (indicating that the out of range request +should be silently ignored). +.El +.It Fn svc_create +.Fn svc_create +creates server handles for all the transports +belonging to the class +.Fa nettype . +.Fa nettype +defines a class of transports which can be used +for a particular application. +The transports are tried in left to right order in +.Ev NETPATH +variable or in top to bottom order in the netconfig database. +If +.Fa nettype +is +.Dv NULL , +it defaults to +.Qq netpath . +.Pp +.Fn svc_create +registers itself with the rpcbind +service (see +.Xr rpcbind 8 ) . +.Fa dispatch +is called when there is a remote procedure call for the given +.Fa prognum +and +.Fa versnum ; +this requires calling +.Fn svc_run +(see +.Fn svc_run +in +.Xr rpc_svc_reg 3 ) . +If +.Fn svc_create +succeeds, it returns the number of server +handles it created, +otherwise it returns 0 and an error message is logged. +.It Fn svc_destroy +A function macro that destroys the RPC +service handle +.Fa xprt . +Destruction usually involves deallocation +of private data structures, +including +.Fa xprt +itself. +Use of +.Fa xprt +is undefined after calling this routine. +.It Fn svc_dg_create +This routine creates a connectionless RPC +service handle, and returns a pointer to it. +This routine returns +.Dv NULL +if it fails, and an error message is logged. +.Fa sendsz +and +.Fa recvsz +are parameters used to specify the size of the buffers. +If they are 0, suitable defaults are chosen. +The file descriptor +.Fa fildes +should be open and bound. +The server is not registered with +.Xr rpcbind 8 . +.Pp +Warning: +since connectionless-based RPC +messages can only hold limited amount of encoded data, +this transport cannot be used for procedures +that take large arguments or return huge results. +.It Fn svc_fd_create +This routine creates a service on top of an open and bound file descriptor, +and returns the handle to it. +Typically, this descriptor is a connected file descriptor for a +connection-oriented transport. +.Fa sendsz +and +.Fa recvsz +indicate sizes for the send and receive buffers. +If they are 0, reasonable defaults are chosen. +This routine returns +.Dv NULL +if it fails, and an error message is logged. +.It Fn svc_raw_create +This routine creates an RPC +service handle and returns a pointer to it. +The transport is really a buffer within the process's +address space, so the corresponding RPC +client should live in the same address space; +(see +.Fn clnt_raw_create +in +.Xr rpc_clnt_create 3 ) . +This routine allows simulation of RPC and acquisition of +RPC overheads (such as round trip times), +without any kernel and networking interference. +This routine returns +.Dv NULL +if it fails, and an error message is logged. +.Pp +Note: +.Fn svc_run +should not be called when the raw interface is being used. +.It Fn svc_tli_create +This routine creates an RPC +server handle, and returns a pointer to it. +.Fa fildes +is the file descriptor on which the service is listening. +If +.Fa fildes +is +.Dv RPC_ANYFD , +it opens a file descriptor on the transport specified by +.Fa netconf . +If the file descriptor is unbound and +.Fa bindaddr +is not +.Dv NULL , +.Fa fildes +is bound to the address specified by +.Fa bindaddr , +otherwise +.Fa fildes +is bound to a default address chosen by the transport. +.Pp +Note: the +.Vt t_bind +structure comes from the TLI/XTI SysV interface, which +.Nx +does not use. +The structure is defined in +.Aq Pa rpc/types.h +for compatibility as: +.Bd -literal +struct t_bind { + struct netbuf addr; /* network address, see rpc(3) */ + unsigned int qlen; /* queue length (for listen(2)) */ +}; +.Ed +.Pp +In the case where the default address is chosen, +the number of outstanding connect requests is set to 8 +for connection-oriented transports. +The user may specify the size of the send and receive buffers +with the parameters +.Fa sendsz +and +.Fa recvsz ; +values of 0 choose suitable defaults. +This routine returns +.Dv NULL +if it fails, +and an error message is logged. +The server is not registered with the +.Xr rpcbind 8 +service. +.It Fn svc_tp_create +.Fn svc_tp_create +creates a server handle for the network +specified by +.Fa netconf , +and registers itself with the rpcbind service. +.Fa dispatch +is called when there is a remote procedure call +for the given +.Fa prognum +and +.Fa versnum ; +this requires calling +.Fn svc_run . +.Fn svc_tp_create +returns the service handle if it succeeds, +otherwise a +.Dv NULL +is returned and an error message is logged. +.It Fn svc_vc_create +This routine creates a connection-oriented RPC +service and returns a pointer to it. +This routine returns +.Dv NULL +if it fails, and an error message is logged. +The users may specify the size of the send and receive buffers +with the parameters +.Fa sendsz +and +.Fa recvsz ; +values of 0 choose suitable defaults. +The file descriptor +.Fa fildes +should be open and bound. +The server is not registered with the +.Xr rpcbind 8 +service. +.El +.Sh SEE ALSO +.Xr rpc 3 , +.Xr rpc_svc_calls 3 , +.Xr rpc_svc_err 3 , +.Xr rpc_svc_reg 3 , +.Xr rpcbind 8 +.\" @(#)rpc_svc_create.3n 1.26 93/08/26 SMI; from SVr4 +.\" Copyright 1989 AT&T +.\" @(#)rpc_svc_create 1.3 89/06/28 SMI; +.\" Copyright (c) 1988 Sun Microsystems, Inc. - All Rights Reserved. +.\" $FreeBSD$ +.Dd May 3, 1993 +.Dt RPC_SVC_CREATE 3 +.Os +.Sh NAME +.Nm rpc_svc_create , +.Nm svc_control , +.Nm svc_create , +.Nm svc_destroy , +.Nm svc_dg_create , +.Nm svc_fd_create , +.Nm svc_raw_create , +.Nm svc_tli_create , +.Nm svc_tp_create , +.Nm svc_vc_create +.Nd library routines for the creation of server handles +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.Fd #include <rpc/rpc.h> +.Ft bool_t +.Fn svc_control "SVCXPRT *svc" "const u_int req" "void *info" +.Ft int +.Fn svc_create "const void (*dispatch)(struct svc_req *, SVCXPRT *)" "const rpcprog_t prognum" "const rpcvers_t versnum" "const char *nettype" +.Ft SVCXPRT *" +.Fn svc_dg_create "const int fildes" "const u_int sendsz" "const u_int recvsz" +.Ft void +.Fn svc_destroy "SVCXPRT *xprt" +.Ft "SVCXPRT *" +.Fn svc_fd_create "const int fildes" "const u_int sendsz" "const u_int recvsz" +.Ft "SVCXPRT *" +.Fn svc_raw_create "void" +.Ft "SVCXPRT *" +.Fn svc_tli_create "const int fildes" "const struct netconfig *netconf" "const struct t_bind *bindaddr" "const u_int sendsz" "const u_int recvsz" +.Ft "SVCXPRT *" +.Fn svc_tp_create "const void (*dispatch)(const struct svc_reg *, const SVCXPRT *)" "const rpcprog_t prognum" "const rpcvers_t versnum" "const struct netconfig *netconf" +.Ft "SVCXPRT *" +.Fn svc_vc_create "const int fildes" "const u_int sendsz" "const u_int recvsz" +.Sh DESCRIPTION +These routines are part of the RPC +library which allows C language programs to make procedure +calls on servers across the network. +These routines deal with the creation of service handles. +Once the handle is created, the server can be invoked by calling +.Fn svc_run . +.Sh Routines +See +.Xr rpc 3 +for the definition of the +.Vt SVCXPRT +data structure. +.Bl -tag -width XXXXX +.It Fn svc_control +A function to change or retrieve various information +about a service object. +.Fa req +indicates the type of operation and +.Fa info +is a pointer to the information. +The supported values of +.Fa req , +their argument types, and what they do are: +.Bl -tag -width SVCGET_XID +.It Dv SVCGET_VERSQUIET +If a request is received for a program number +served by this server but the version number +is outside the range registered with the server, +an +.Dv RPC_PROGVERSMISMATCH +error will normally +be returned. +.Fa info +should be a pointer to an +integer. +Upon successful completion of the +.Dv SVCGET_VERSQUIET +request, +.Fa *info +contains an +integer which describes the server's current +behavior: 0 indicates normal server behavior +(that is, an +.Dv RPC_PROGVERSMISMATCH +error +will be returned); 1 indicates that the out of +range request will be silently ignored. +.It Dv SVCSET_VERSQUIET +If a request is received for a program number +served by this server but the version number +is outside the range registered with the server, +an +.Dv RPC_PROGVERSMISMATCH +error will normally +be returned. +It is sometimes desirable to +change this behavior. +.Fa info +should be a +pointer to an integer which is either 0 +(indicating normal server behavior - an +.Dv RPC_PROGVERSMISMATCH +error will be returned), +or 1 (indicating that the out of range request +should be silently ignored). +.El +.It Fn svc_create +.Fn svc_create +creates server handles for all the transports +belonging to the class +.Fa nettype . +.Fa nettype +defines a class of transports which can be used +for a particular application. +The transports are tried in left to right order in +.Ev NETPATH +variable or in top to bottom order in the netconfig database. +If +.Fa nettype +is +.Dv NULL , +it defaults to +.Qq netpath . +.Pp +.Fn svc_create +registers itself with the rpcbind +service (see +.Xr rpcbind 8 ) . +.Fa dispatch +is called when there is a remote procedure call for the given +.Fa prognum +and +.Fa versnum ; +this requires calling +.Fn svc_run +(see +.Fn svc_run +in +.Xr rpc_svc_reg 3 ) . +If +.Fn svc_create +succeeds, it returns the number of server +handles it created, +otherwise it returns 0 and an error message is logged. +.It Fn svc_destroy +A function macro that destroys the RPC +service handle +.Fa xprt . +Destruction usually involves deallocation +of private data structures, +including +.Fa xprt +itself. +Use of +.Fa xprt +is undefined after calling this routine. +.It Fn svc_dg_create +This routine creates a connectionless RPC +service handle, and returns a pointer to it. +This routine returns +.Dv NULL +if it fails, and an error message is logged. +.Fa sendsz +and +.Fa recvsz +are parameters used to specify the size of the buffers. +If they are 0, suitable defaults are chosen. +The file descriptor +.Fa fildes +should be open and bound. +The server is not registered with +.Xr rpcbind 8 . +.Pp +Warning: +since connectionless-based RPC +messages can only hold limited amount of encoded data, +this transport cannot be used for procedures +that take large arguments or return huge results. +.It Fn svc_fd_create +This routine creates a service on top of an open and bound file descriptor, +and returns the handle to it. +Typically, this descriptor is a connected file descriptor for a +connection-oriented transport. +.Fa sendsz +and +.Fa recvsz +indicate sizes for the send and receive buffers. +If they are 0, reasonable defaults are chosen. +This routine returns +.Dv NULL +if it fails, and an error message is logged. +.It Fn svc_raw_create +This routine creates an RPC +service handle and returns a pointer to it. +The transport is really a buffer within the process's +address space, so the corresponding RPC +client should live in the same address space; +(see +.Fn clnt_raw_create +in +.Xr rpc_clnt_create 3 ) . +This routine allows simulation of RPC and acquisition of +RPC overheads (such as round trip times), +without any kernel and networking interference. +This routine returns +.Dv NULL +if it fails, and an error message is logged. +.Pp +Note: +.Fn svc_run +should not be called when the raw interface is being used. +.It Fn svc_tli_create +This routine creates an RPC +server handle, and returns a pointer to it. +.Fa fildes +is the file descriptor on which the service is listening. +If +.Fa fildes +is +.Dv RPC_ANYFD , +it opens a file descriptor on the transport specified by +.Fa netconf . +If the file descriptor is unbound and +.Fa bindaddr +is not +.Dv NULL , +.Fa fildes +is bound to the address specified by +.Fa bindaddr , +otherwise +.Fa fildes +is bound to a default address chosen by the transport. +.Pp +Note: the +.Vt t_bind +structure comes from the TLI/XTI SysV interface, which +.Nx +does not use. +The structure is defined in +.Aq Pa rpc/types.h +for compatibility as: +.Bd -literal +struct t_bind { + struct netbuf addr; /* network address, see rpc(3) */ + unsigned int qlen; /* queue length (for listen(2)) */ +}; +.Ed +.Pp +In the case where the default address is chosen, +the number of outstanding connect requests is set to 8 +for connection-oriented transports. +The user may specify the size of the send and receive buffers +with the parameters +.Fa sendsz +and +.Fa recvsz ; +values of 0 choose suitable defaults. +This routine returns +.Dv NULL +if it fails, +and an error message is logged. +The server is not registered with the +.Xr rpcbind 8 +service. +.It Fn svc_tp_create +.Fn svc_tp_create +creates a server handle for the network +specified by +.Fa netconf , +and registers itself with the rpcbind service. +.Fa dispatch +is called when there is a remote procedure call +for the given +.Fa prognum +and +.Fa versnum ; +this requires calling +.Fn svc_run . +.Fn svc_tp_create +returns the service handle if it succeeds, +otherwise a +.Dv NULL +is returned and an error message is logged. +.It Fn svc_vc_create +This routine creates a connection-oriented RPC +service and returns a pointer to it. +This routine returns +.Dv NULL +if it fails, and an error message is logged. +The users may specify the size of the send and receive buffers +with the parameters +.Fa sendsz +and +.Fa recvsz ; +values of 0 choose suitable defaults. +The file descriptor +.Fa fildes +should be open and bound. +The server is not registered with the +.Xr rpcbind 8 +service. +.El +.Sh SEE ALSO +.Xr rpc 3 , +.Xr rpc_svc_calls 3 , +.Xr rpc_svc_err 3 , +.Xr rpc_svc_reg 3 , +.Xr rpcbind 8 diff --git a/lib/libc/rpc/rpc_svc_err.3 b/lib/libc/rpc/rpc_svc_err.3 new file mode 100644 index 000000000000..3a6e0c9fd4f1 --- /dev/null +++ b/lib/libc/rpc/rpc_svc_err.3 @@ -0,0 +1,95 @@ +.\" @(#)rpc_svc_err.3n 1.23 93/08/31 SMI; from SVr4 +.\" Copyright 1989 AT&T +.\" @(#)rpc_svc_err 1.4 89/06/28 SMI; +.\" Copyright (c) 1988 Sun Microsystems, Inc. - All Rights Reserved. +.\" $NetBSD: rpc_svc_err.3,v 1.1 2000/06/02 23:11:14 fvdl Exp $ +.\" $FreeBSD$ +.Dd May 3, 1993 +.Dt RPC_SVC_ERR 3 +.Os +.Sh NAME +.Nm rpc_svc_err , +.Nm svcerr_auth , +.Nm svcerr_decode , +.Nm svcerr_noproc , +.Nm svcerr_noprog , +.Nm svcerr_progvers , +.Nm svcerr_systemerr , +.Nm svcerr_weakauth +.Nd library routines for server side remote procedure call errors +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.Fd #include <rpc/rpc.h> +.Ft void +.Fn svcerr_auth "const SVCXPRT1 *xprt" "const enum auth_stat why" +.Ft void +.Fn svcerr_decode "const SVCXPRT *xprt" +.Ft void +.Fn svcerr_noproc "const SVCXPRT *xprt" +.Ft void +.Fn svcerr_noprog "const SVCXPRT *xprt" +.Ft void +.Fn svcerr_progvers "const SVCXPRT *xprt" "rpcvers_t low_vers" "rpcvers_t high_vers" +.Ft void +.Fn svcerr_systemerr "const SVCXPRT *xprt" +.Ft void +.Fn svcerr_weakauth "const SVCXPRT *xprt" +.Sh DESCRIPTION +These routines are part of the RPC +library which allows C language programs to make procedure +calls on other machines across the network. +.Pp +These routines can be called by the server side +dispatch function if there is any error in the +transaction with the client. +.Sh Routines +See +.Xr rpc 3 +for the definition of the +.Vt SVCXPRT +data structure. +.Bl -tag -width XXXXX +.It Fn svcerr_auth +Called by a service dispatch routine that refuses to perform +a remote procedure call due to an authentication error. +.It Fn svcerr_decode +Called by a service dispatch routine that cannot successfully +decode the remote parameters +(see +.Fn svc_getargs +in +.Xr rpc_svc_reg 3 ) . +.It Fn svcerr_noproc +Called by a service dispatch routine that does not implement +the procedure number that the caller requests. +.It Fn svcerr_noprog +Called when the desired program is not registered with the +RPC package. +Service implementors usually do not need this routine. +.It Fn svcerr_progvers +Called when the desired version of a program is not registered with the +RPC package. +.Fa low_vers +is the lowest version number, +and +.Fa high_vers +is the highest version number. +Service implementors usually do not need this routine. +.It Fn svcerr_systemerr +Called by a service dispatch routine when it detects a system +error not covered by any particular protocol. +For example, if a service can no longer allocate storage, +it may call this routine. +.It Fn svcerr_weakauth +Called by a service dispatch routine that refuses to perform +a remote procedure call due to insufficient (but correct) +authentication parameters. +The routine calls +.Fn svcerr_auth "xprt" "AUTH_TOOWEAK" . +.El +.Sh SEE ALSO +.Xr rpc 3 , +.Xr rpc_svc_calls 3 , +.Xr rpc_svc_create 3 , +.Xr rpc_svc_reg 3 diff --git a/lib/libc/rpc/rpc_svc_reg.3 b/lib/libc/rpc/rpc_svc_reg.3 new file mode 100644 index 000000000000..2ab6f00e9bca --- /dev/null +++ b/lib/libc/rpc/rpc_svc_reg.3 @@ -0,0 +1,183 @@ +.\" @(#)rpc_svc_reg.3n 1.32 93/08/31 SMI; from SVr4 +.\" Copyright 1989 AT&T +.\" @(#)rpc_svc_call 1.6 89/07/20 SMI; +.\" Copyright (c) 1988 Sun Microsystems, Inc. - All Rights Reserved. +.\" $NetBSD: rpc_svc_reg.3,v 1.1 2000/06/02 23:11:14 fvdl Exp $ +.\" $FreeBSD$ +.Dd May 3, 1993 +.Dt RPC_SVC_REG 3 +.Os +.Sh NAME +.Nm rpc_svc_reg , +.Nm rpc_reg , +.Nm svc_reg , +.Nm svc_unreg , +.Nm svc_auth_reg , +.Nm xprt_register , +.Nm xprt_unregister +.Nd library routines for registering servers +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.Fd #include <rpc/rpc.h> +.Ft bool_t +.Fn rpc_reg "const rpcprog_t prognum" "const rpcvers_t versnum" "const rpcproc_t procnum" "const char *(*procname)()" "const xdrproc_t inproc" "const xdrproc_t outproc" "const char *nettype" +.Ft int +.Fn svc_reg "const SVCXPRT *xprt" "const rpcprog_t prognum" "const rpcvers_t versnum" "const void (*dispatch(struct svc_req *, SVCXPRT *)" "const struct netconfig *netconf" +.Ft void +.Fn svc_unreg "const rpcprog_t prognum" "const rpcvers_t versnum" +.Ft int +.Fn svc_auth_reg "const int cred_flavor" "const enum auth_stat (*handler(struct svc_req *, truct rpc_msg *))" +.Ft void +.Fn xprt_register "const SVCXPRT *xprt" +.Ft void +.Fn xprt_unregister "const SVCXPRT *xprt" +.Sh DESCRIPTION +These routines are a part of the RPC +library which allows the RPC +servers to register themselves with rpcbind +(see +.Xr rpcbind 8 ) , +and associate the given program and version +number with the dispatch function. +When the RPC server receives a RPC request, the library invokes the +dispatch routine with the appropriate arguments. +.Sh Routines +See +.Xr rpc 3 +for the definition of the +.Vt SVCXPRT +data structure. +.Bl -tag -width XXXXX +.It Fn rpc_reg +Register program +.Fa prognum , +procedure +.Fa procname , +and version +.Fa versnum +with the RPC +service package. +If a request arrives for program +.Fa prognum , +version +.Fa versnum , +and procedure +.Fa procnum , +.Fa procname +is called with a pointer to its parameter(s); +.Fa procname +should return a pointer to its static result(s); +.Fa inproc +is the XDR function used to decode the parameters while +.Fa outproc +is the XDR function used to encode the results. +Procedures are registered on all available transports of the class +.Fa nettype . +See +.Xr rpc 3 . +This routine returns 0 if the registration succeeded, +\-1 otherwise. +.It Fn svc_reg +Associates +.Fa prognum +and +.Fa versnum +with the service dispatch procedure, +.Fa dispatch . +If +.Fa netconf +is +.Dv NULL , +the service is not registered with the +.Xr rpcbind 8 +service. +If +.Fa netconf +is non-zero, +then a mapping of the triple +.Bq Fa prognum , versnum , netconf->nc_netid +to +.Fa xprt->xp_ltaddr +is established with the local rpcbind +service. +.Pp +The +.Fn svc_reg +routine returns 1 if it succeeds, +and 0 otherwise. +.It Fn svc_unreg +Remove from the rpcbind +service, all mappings of the triple +.Bq Fa prognum , versnum , No all-transports +to network address +and all mappings within the RPC service package +of the double +.Bq Fa prognum , versnum +to dispatch routines. +.It Fn svc_auth_reg +Registers the service authentication routine +.Fa handler +with the dispatch mechanism so that it can be +invoked to authenticate RPC requests received +with authentication type +.Fa cred_flavor . +This interface allows developers to add new authentication +types to their RPC applications without needing to modify +the libraries. +Service implementors usually do not need this routine. +.Pp +Typical service application would call +.Fn svc_auth_reg +after registering the service and prior to calling +.Fn svc_run . +When needed to process an RPC credential of type +.Fa cred_flavor , +the +.Fa handler +procedure will be called with two parameters, +.Fa "struct svc_req *rqst" +and +.Fa "struct rpc_msg *msg" , +and is expected to return a valid +.Vt "enum auth_stat" +value. +There is no provision to change or delete an authentication handler +once registered. +.Pp +The +.Fn svc_auth_reg +routine returns 0 if the registration is successful, +1 if +.Fa cred_flavor +already has an authentication handler registered for it, +and \-1 otherwise. +.It Fn xprt_register +After RPC service transport handle +.Fa xprt +is created, it is registered with the RPC +service package. +This routine modifies the global variable +.Va svc_fdset +(see +.Xr rpc_svc_calls 3 ) . +Service implementors usually do not need this routine. +.It Fn xprt_unregister +Before an RPC service transport handle +.Fa xprt +is destroyed, it unregisters itself with the +RPC service package. +This routine modifies the global variable +.Va svc_fdset +(see +.Xr rpc_svc_calls 3 ) . +Service implementors usually do not need this routine. +.El +.Sh SEE ALSO +.Xr select 2 , +.Xr rpc 3 , +.Xr rpc_svc_calls 3 , +.Xr rpc_svc_create 3 , +.Xr rpc_svc_err 3 , +.Xr rpcbind 3 , +.Xr rpcbind 8 diff --git a/lib/libc/rpc/rpc_xdr.3 b/lib/libc/rpc/rpc_xdr.3 new file mode 100644 index 000000000000..e021a330f8f7 --- /dev/null +++ b/lib/libc/rpc/rpc_xdr.3 @@ -0,0 +1,101 @@ +.\" @(#)rpc_xdr.3n 1.24 93/08/31 SMI; from SVr4 +.\" Copyright 1989 AT&T +.\" @(#)rpc_xdr.new 1.1 89/04/06 SMI; +.\" Copyright (c) 1988 Sun Microsystems, Inc. - All Rights Reserved. +.\" $FreeBSD$ +.Dd May 3, 1993 +.Dt RPC_XDR 3 +.Os +.Sh NAME +.Nm xdr_accepted_reply , +.Nm xdr_authsys_parms , +.Nm xdr_callhdr , +.Nm xdr_callmsg , +.Nm xdr_opaque_auth , +.Nm xdr_rejected_reply , +.Nm xdr_replymsg +.Nd XDR library routines for remote procedure calls +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.Fd #include <rpc/rpc.h> +.Ft bool_t +.Fn xdr_accepted_reply "XDR *xdrs" "const struct accepted_reply *ar" +.Ft bool_t +.Fn xdr_authsys_parms "XDR *xdrs" "struct authsys_parms *aupp" +.Ft void +.Fn xdr_callhdr "XDR *xdrs" "struct rpc_msg *chdr" +.Ft bool_t +.Fn xdr_callmsg "XDR *xdrs" "struct rpc_msg *cmsg" +.Ft bool_t +.Fn xdr_opaque_auth "XDR *xdrs" "struct opaque_auth *ap" +.Ft bool_t +.Fn xdr_rejected_reply "XDR *xdrs" "const struct rejected_reply *rr" +.Ft bool_t +.Fn xdr_replymsg "XDR *xdrs" "const struct rpc_msg *rmsg" +.Sh DESCRIPTION +These routines are used for describing the +RPC messages in XDR language. +They should normally be used by those who do not +want to use the RPC +package directly. +These routines return +.Dv TRUE +if they succeed, +.Dv FALSE +otherwise. +.Sh Routines +See +.Xr rpc 3 +for the definition of the +.Vt XDR +data structure. +.Bl -tag -width XXXXX +.It Fn xdr_accepted_reply +Used to translate between RPC +reply messages and their external representation. +It includes the status of the RPC +call in the XDR language format. +In the case of success, it also includes the call results. +.It Fn xdr_authsys_parms +Used for describing +.Ux +operating system credentials. +It includes machine-name, uid, gid list, etc. +.It Fn xdr_callhdr +Used for describing +RPC +call header messages. +It encodes the static part of the call message header in the +XDR language format. +It includes information such as transaction +ID, RPC version number, program and version number. +.It Fn xdr_callmsg +Used for describing +RPC call messages. +This includes all the RPC +call information such as transaction +ID, RPC version number, program number, version number, +authentication information, etc. +This is normally used by servers to determine information about the client +RPC call. +.It Fn xdr_opaque_auth +Used for describing RPC +opaque authentication information messages. +.It Fn xdr_rejected_reply +Used for describing RPC reply messages. +It encodes the rejected RPC message in the XDR language format. +The message could be rejected either because of version +number mis-match or because of authentication errors. +.It Fn xdr_replymsg +Used for describing RPC +reply messages. +It translates between the +RPC reply message and its external representation. +This reply could be either an acceptance, +rejection or +.Dv NULL . +.El +.Sh SEE ALSO +.Xr rpc 3 , +.Xr xdr 3 diff --git a/lib/libc/rpc/rpcb_clnt.c b/lib/libc/rpc/rpcb_clnt.c new file mode 100644 index 000000000000..2fdc74ff391c --- /dev/null +++ b/lib/libc/rpc/rpcb_clnt.c @@ -0,0 +1,1253 @@ +/* $NetBSD: rpcb_clnt.c,v 1.6 2000/07/16 06:41:43 itojun Exp $ */ +/* $FreeBSD$ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ + +/* #ident "@(#)rpcb_clnt.c 1.27 94/04/24 SMI" */ + + +#if 0 +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)rpcb_clnt.c 1.30 89/06/21 Copyr 1988 Sun Micro"; +#endif +#endif + +/* + * rpcb_clnt.c + * interface to rpcbind rpc service. + * + * Copyright (C) 1988, Sun Microsystems, Inc. + */ + +#include "reentrant.h" +#include "namespace.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 "un-namespace.h" + +#include "rpc_com.h" + +static struct timeval tottimeout = { 60, 0 }; +static const struct timeval rmttimeout = { 3, 0 }; + +extern bool_t xdr_wrapstring __P((XDR *, char **)); + +static const char nullstring[] = "\000"; + +#define CACHESIZE 6 + +struct address_cache { + char *ac_host; + char *ac_netid; + char *ac_uaddr; + struct netbuf *ac_taddr; + struct address_cache *ac_next; +}; + +static struct address_cache *front; +static int cachesize; + +#define CLCR_GET_RPCB_TIMEOUT 1 +#define CLCR_SET_RPCB_TIMEOUT 2 + + +extern int __rpc_lowvers; + +static struct address_cache *check_cache __P((const char *, const char *)); +static void delete_cache __P((struct netbuf *)); +static void add_cache __P((const char *, const char *, struct netbuf *, + char *)); +static CLIENT *getclnthandle __P((const char *, const struct netconfig *, + char **)); +static CLIENT *local_rpcb __P((void)); +static struct netbuf *got_entry __P((rpcb_entry_list_ptr, + const struct netconfig *)); + +/* + * This routine adjusts the timeout used for calls to the remote rpcbind. + * Also, this routine can be used to set the use of portmapper version 2 + * only when doing rpc_broadcasts + * These are private routines that may not be provided in future releases. + */ +bool_t +__rpc_control(request, info) + int request; + void *info; +{ + switch (request) { + case CLCR_GET_RPCB_TIMEOUT: + *(struct timeval *)info = tottimeout; + break; + case CLCR_SET_RPCB_TIMEOUT: + tottimeout = *(struct timeval *)info; + break; + case CLCR_SET_LOWVERS: + __rpc_lowvers = *(int *)info; + break; + case CLCR_GET_LOWVERS: + *(int *)info = __rpc_lowvers; + break; + default: + return (FALSE); + } + return (TRUE); +} + +/* + * It might seem that a reader/writer lock would be more reasonable here. + * However because getclnthandle(), the only user of the cache functions, + * may do a delete_cache() operation if a check_cache() fails to return an + * address useful to clnt_tli_create(), we may as well use a mutex. + */ +/* + * As it turns out, if the cache lock is *not* a reader/writer lock, we will + * block all clnt_create's if we are trying to connect to a host that's down, + * since the lock will be held all during that time. + */ +extern rwlock_t rpcbaddr_cache_lock; + +/* + * The routines check_cache(), add_cache(), delete_cache() manage the + * cache of rpcbind addresses for (host, netid). + */ + +static struct address_cache * +check_cache(host, netid) + const char *host, *netid; +{ + struct address_cache *cptr; + + /* READ LOCK HELD ON ENTRY: rpcbaddr_cache_lock */ + + for (cptr = front; cptr != NULL; cptr = cptr->ac_next) { + if (!strcmp(cptr->ac_host, host) && + !strcmp(cptr->ac_netid, netid)) { +#ifdef ND_DEBUG + fprintf(stderr, "Found cache entry for %s: %s\n", + host, netid); +#endif + return (cptr); + } + } + return ((struct address_cache *) NULL); +} + +static void +delete_cache(addr) + struct netbuf *addr; +{ + struct address_cache *cptr, *prevptr = NULL; + + /* WRITE LOCK HELD ON ENTRY: rpcbaddr_cache_lock */ + for (cptr = front; cptr != NULL; cptr = cptr->ac_next) { + if (!memcmp(cptr->ac_taddr->buf, addr->buf, addr->len)) { + free(cptr->ac_host); + free(cptr->ac_netid); + free(cptr->ac_taddr->buf); + free(cptr->ac_taddr); + if (cptr->ac_uaddr) + free(cptr->ac_uaddr); + if (prevptr) + prevptr->ac_next = cptr->ac_next; + else + front = cptr->ac_next; + free(cptr); + cachesize--; + break; + } + prevptr = cptr; + } +} + +static void +add_cache(host, netid, taddr, uaddr) + const char *host, *netid; + char *uaddr; + struct netbuf *taddr; +{ + struct address_cache *ad_cache, *cptr, *prevptr; + + ad_cache = (struct address_cache *) + malloc(sizeof (struct address_cache)); + if (!ad_cache) { + return; + } + ad_cache->ac_host = strdup(host); + ad_cache->ac_netid = strdup(netid); + ad_cache->ac_uaddr = uaddr ? strdup(uaddr) : NULL; + ad_cache->ac_taddr = (struct netbuf *)malloc(sizeof (struct netbuf)); + if (!ad_cache->ac_host || !ad_cache->ac_netid || !ad_cache->ac_taddr || + (uaddr && !ad_cache->ac_uaddr)) { + return; + } + ad_cache->ac_taddr->len = ad_cache->ac_taddr->maxlen = taddr->len; + ad_cache->ac_taddr->buf = (char *) malloc(taddr->len); + if (ad_cache->ac_taddr->buf == NULL) { + return; + } + memcpy(ad_cache->ac_taddr->buf, taddr->buf, taddr->len); +#ifdef ND_DEBUG + fprintf(stderr, "Added to cache: %s : %s\n", host, netid); +#endif + +/* VARIABLES PROTECTED BY rpcbaddr_cache_lock: cptr */ + + rwlock_wrlock(&rpcbaddr_cache_lock); + if (cachesize < CACHESIZE) { + ad_cache->ac_next = front; + front = ad_cache; + cachesize++; + } else { + /* Free the last entry */ + cptr = front; + prevptr = NULL; + while (cptr->ac_next) { + prevptr = cptr; + cptr = cptr->ac_next; + } + +#ifdef ND_DEBUG + fprintf(stderr, "Deleted from cache: %s : %s\n", + cptr->ac_host, cptr->ac_netid); +#endif + free(cptr->ac_host); + free(cptr->ac_netid); + free(cptr->ac_taddr->buf); + free(cptr->ac_taddr); + if (cptr->ac_uaddr) + free(cptr->ac_uaddr); + + if (prevptr) { + prevptr->ac_next = NULL; + ad_cache->ac_next = front; + front = ad_cache; + } else { + front = ad_cache; + ad_cache->ac_next = NULL; + } + free(cptr); + } + rwlock_unlock(&rpcbaddr_cache_lock); +} + +/* + * This routine will return a client handle that is connected to the + * rpcbind. Returns NULL on error and free's everything. + */ +static CLIENT * +getclnthandle(host, nconf, targaddr) + const char *host; + const struct netconfig *nconf; + char **targaddr; +{ + CLIENT *client; + struct netbuf *addr, taddr; + struct netbuf addr_to_delete; + struct __rpc_sockinfo si; + struct addrinfo hints, *res, *tres; + struct address_cache *ad_cache; + char *tmpaddr; + +/* VARIABLES PROTECTED BY rpcbaddr_cache_lock: ad_cache */ + + /* Get the address of the rpcbind. Check cache first */ + addr_to_delete.len = 0; + rwlock_rdlock(&rpcbaddr_cache_lock); + ad_cache = check_cache(host, nconf->nc_netid); + if (ad_cache != NULL) { + addr = ad_cache->ac_taddr; + client = clnt_tli_create(RPC_ANYFD, nconf, addr, + (rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS4, 0, 0); + if (client != NULL) { + if (targaddr) + *targaddr = ad_cache->ac_uaddr; + rwlock_unlock(&rpcbaddr_cache_lock); + return (client); + } + addr_to_delete.len = addr->len; + addr_to_delete.buf = (char *)malloc(addr->len); + if (addr_to_delete.buf == NULL) { + addr_to_delete.len = 0; + } else { + memcpy(addr_to_delete.buf, addr->buf, addr->len); + } + } + rwlock_unlock(&rpcbaddr_cache_lock); + if (addr_to_delete.len != 0) { + /* + * Assume this may be due to cache data being + * outdated + */ + rwlock_wrlock(&rpcbaddr_cache_lock); + delete_cache(&addr_to_delete); + rwlock_unlock(&rpcbaddr_cache_lock); + free(addr_to_delete.buf); + } + if (!__rpc_nconf2sockinfo(nconf, &si)) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return NULL; + } + + memset(&hints, 0, sizeof hints); + hints.ai_family = si.si_af; + hints.ai_socktype = si.si_socktype; + hints.ai_protocol = si.si_proto; + +#ifdef CLNT_DEBUG + printf("trying netid %s family %d proto %d socktype %d\n", + nconf->nc_netid, si.si_af, si.si_proto, si.si_socktype); +#endif + + if (getaddrinfo(host, "sunrpc", &hints, &res) != 0) { + rpc_createerr.cf_stat = RPC_UNKNOWNHOST; + return NULL; + } + + for (tres = res; tres != NULL; tres = tres->ai_next) { + taddr.buf = tres->ai_addr; + taddr.len = taddr.maxlen = tres->ai_addrlen; + +#ifdef ND_DEBUG + { + char *ua; + + ua = taddr2uaddr(nconf, &taddr); + fprintf(stderr, "Got it [%s]\n", ua); + free(ua); + } +#endif + +#ifdef ND_DEBUG + { + int i; + + fprintf(stderr, "\tnetbuf len = %d, maxlen = %d\n", + taddr.len, taddr.maxlen); + fprintf(stderr, "\tAddress is "); + for (i = 0; i < taddr.len; i++) + fprintf(stderr, "%u.", ((char *)(taddr.buf))[i]); + fprintf(stderr, "\n"); + } +#endif + client = clnt_tli_create(RPC_ANYFD, nconf, &taddr, + (rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS4, 0, 0); +#ifdef ND_DEBUG + if (! client) { + clnt_pcreateerror("rpcbind clnt interface"); + } +#endif + + if (client) { + tmpaddr = targaddr ? taddr2uaddr(nconf, &taddr) : NULL; + add_cache(host, nconf->nc_netid, &taddr, tmpaddr); + if (targaddr) + *targaddr = tmpaddr; + break; + } + } + freeaddrinfo(res); + return (client); +} + +/* XXX */ +#define IN4_LOCALHOST_STRING "127.0.0.1" +#define IN6_LOCALHOST_STRING "::1" + +/* + * This routine will return a client handle that is connected to the local + * rpcbind. Returns NULL on error and free's everything. + */ +static CLIENT * +local_rpcb() +{ + CLIENT *client; + static struct netconfig *loopnconf; + static char *hostname; + extern mutex_t loopnconf_lock; + 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.sun_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) + return client; + +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); + 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) { + 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 *)(void *)&parms, (xdrproc_t) xdr_bool, + (char *)(void *)&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); +} + +/* + * 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] != NULL)) { + na = uaddr2taddr(nconf, rmap->r_maddr); +#ifdef ND_DEBUG + fprintf(stderr, "\tRemote address is [%s].\n", + rmap->r_maddr); + if (!na) + fprintf(stderr, + "\tCouldn't resolve remote address!\n"); +#endif + break; + } + } + return (na); +} + +/* + * An internal function which optimizes rpcb_getaddr function. It also + * returns the client handle that it uses to contact the remote rpcbind. + * + * The algorithm used: If the transports is TCP or UDP, it first tries + * version 2 (portmap), 4 and then 3 (svr4). This order should be + * changed in the next OS release to 4, 2 and 3. We are assuming that by + * that time, version 4 would be available on many machines on the network. + * With this algorithm, we get performance as well as a plan for + * obsoleting version 2. + * + * For all other transports, the algorithm remains as 4 and then 3. + * + * XXX: Due to some problems with t_connect(), we do not reuse the same client + * handle for COTS cases and hence in these cases we do not return the + * client handle. This code will change if t_connect() ever + * starts working properly. Also look under clnt_vc.c. + */ +struct netbuf * +__rpcb_findaddr(program, version, nconf, host, clpp) + rpcprog_t program; + rpcvers_t version; + const struct netconfig *nconf; + const char *host; + CLIENT **clpp; +{ + CLIENT *client = NULL; + RPCB parms; + enum clnt_stat clnt_st; + char *ua = NULL; + rpcvers_t vers; + struct netbuf *address = NULL; + rpcvers_t start_vers = RPCBVERS4; + struct netbuf servaddr; + + /* parameter checking */ + if (nconf == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return (NULL); + } + + parms.r_addr = NULL; + +#ifdef PORTMAP + /* Try version 2 for TCP or UDP */ + if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { + u_short port = 0; + struct netbuf remote; + rpcvers_t pmapvers = 2; + struct pmap pmapparms; + + /* + * Try UDP only - there are some portmappers out + * there that use UDP only. + */ + if (strcmp(nconf->nc_proto, NC_TCP) == 0) { + struct netconfig *newnconf; + + if ((newnconf = getnetconfigent("udp")) == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return (NULL); + } + client = getclnthandle(host, newnconf, &parms.r_addr); + freenetconfigent(newnconf); + } else { + client = getclnthandle(host, nconf, &parms.r_addr); + } + if (client == NULL) { + return (NULL); + } + + /* Set the version */ + CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&pmapvers); + pmapparms.pm_prog = program; + pmapparms.pm_vers = version; + pmapparms.pm_prot = strcmp(nconf->nc_proto, NC_TCP) ? + IPPROTO_UDP : IPPROTO_TCP; + pmapparms.pm_port = 0; /* not needed */ + clnt_st = CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT, + (xdrproc_t) xdr_pmap, (caddr_t)(void *)&pmapparms, + (xdrproc_t) xdr_u_short, (caddr_t)(void *)&port, + tottimeout); + if (clnt_st != RPC_SUCCESS) { + if ((clnt_st == RPC_PROGVERSMISMATCH) || + (clnt_st == RPC_PROGUNAVAIL)) + goto try_rpcbind; /* Try different versions */ + rpc_createerr.cf_stat = RPC_PMAPFAILURE; + clnt_geterr(client, &rpc_createerr.cf_error); + goto error; + } else if (port == 0) { + address = NULL; + rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; + goto error; + } + port = htons(port); + CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)(void *)&remote); + if (((address = (struct netbuf *) + malloc(sizeof (struct netbuf))) == NULL) || + ((address->buf = (char *) + malloc(remote.len)) == NULL)) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + clnt_geterr(client, &rpc_createerr.cf_error); + if (address) { + free(address); + address = NULL; + } + goto error; + } + memcpy(address->buf, remote.buf, remote.len); + memcpy(&((char *)address->buf)[sizeof (short)], + (char *)(void *)&port, sizeof (short)); + address->len = address->maxlen = remote.len; + goto done; + } +#endif /* PORTMAP */ + +try_rpcbind: + /* + * Now we try version 4 and then 3. + * We also send the remote system the address we used to + * contact it in case it can help to connect back with us + */ + parms.r_prog = program; + parms.r_vers = version; + /*LINTED const castaway*/ + parms.r_owner = (char *) &nullstring[0]; /* not needed; */ + /* just for xdring */ + parms.r_netid = nconf->nc_netid; /* not really needed */ + + /* + * If a COTS transport is being used, try getting address via CLTS + * transport. This works only with version 4. + * NOTE: This is being done for all transports EXCEPT LOOPBACK + * because with loopback the cost to go to a COTS is same as + * the cost to go through CLTS, plus you get the advantage of + * finding out immediately if the local rpcbind process is dead. + */ +#if 1 + if ((nconf->nc_semantics == NC_TPI_COTS_ORD || + nconf->nc_semantics == NC_TPI_COTS) && + (strcmp(nconf->nc_protofmly, NC_LOOPBACK) != 0)) { +#else + if (client != NULL) { + CLNT_DESTROY(client); + client = NULL; + } + if (nconf->nc_semantics == NC_TPI_CLTS) { +#endif + void *handle; + struct netconfig *nconf_clts; + rpcb_entry_list_ptr relp = NULL; + + if (client == NULL) { + /* This did not go through the above PORTMAP/TCP code */ +#if 1 + if ((handle = __rpc_setconf("datagram_v")) != NULL) { +#else + if ((handle = __rpc_setconf("circuit_v")) != NULL) { +#endif + while ((nconf_clts = __rpc_getconf(handle)) + != NULL) { + if (strcmp(nconf_clts->nc_protofmly, + nconf->nc_protofmly) != 0) { + continue; + } + client = getclnthandle(host, nconf_clts, + &parms.r_addr); + break; + } + __rpc_endconf(handle); + } + if (client == NULL) + goto regular_rpcbind; /* Go the regular way */ + } else { + /* This is a UDP PORTMAP handle. Change to version 4 */ + vers = RPCBVERS4; + CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); + } + /* + * We also send the remote system the address we used to + * contact it in case it can help it connect back with us + */ + if (parms.r_addr == NULL) { + /*LINTED const castaway*/ + parms.r_addr = (char *) &nullstring[0]; /* for XDRing */ + } + clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDRLIST, + (xdrproc_t) xdr_rpcb, (char *)(void *)&parms, + (xdrproc_t) xdr_rpcb_entry_list_ptr, + (char *)(void *)&relp, tottimeout); + if (clnt_st == RPC_SUCCESS) { + if ((address = got_entry(relp, nconf)) != NULL) { + xdr_free((xdrproc_t) xdr_rpcb_entry_list_ptr, + (char *)(void *)&relp); + goto done; + } + /* Entry not found for this transport */ + xdr_free((xdrproc_t) xdr_rpcb_entry_list_ptr, + (char *)(void *)&relp); + /* + * XXX: should have perhaps returned with error but + * since the remote machine might not always be able + * to send the address on all transports, we try the + * regular way with regular_rpcbind + */ + goto regular_rpcbind; + } else if ((clnt_st == RPC_PROGVERSMISMATCH) || + (clnt_st == RPC_PROGUNAVAIL)) { + start_vers = RPCBVERS; /* Try version 3 now */ + goto regular_rpcbind; /* Try different versions */ + } else { + rpc_createerr.cf_stat = RPC_PMAPFAILURE; + clnt_geterr(client, &rpc_createerr.cf_error); + goto error; + } + } + +regular_rpcbind: + + /* Now the same transport is to be used to get the address */ +#if 1 + if (client && ((nconf->nc_semantics == NC_TPI_COTS_ORD) || + (nconf->nc_semantics == NC_TPI_COTS))) { +#else + if (client && nconf->nc_semantics == NC_TPI_CLTS) { +#endif + /* A CLTS type of client - destroy it */ + CLNT_DESTROY(client); + client = 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 and then version 3 (RPCBVERS) */ + 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, + tottimeout); + if (clnt_st == RPC_SUCCESS) { + if ((ua == NULL) || (ua[0] == NULL)) { + /* address unknown */ + rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; + goto error; + } + address = uaddr2taddr(nconf, ua); +#ifdef ND_DEBUG + fprintf(stderr, "\tRemote address is [%s]\n", ua); + if (!address) + fprintf(stderr, + "\tCouldn't resolve remote address!\n"); +#endif + xdr_free((xdrproc_t)xdr_wrapstring, + (char *)(void *)&ua); + + if (! address) { + /* We don't know about your universal address */ + rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE; + goto error; + } + CLNT_CONTROL(client, CLGET_SVC_ADDR, + (char *)(void *)&servaddr); + __rpc_fixup_addr(address, &servaddr); + goto done; + } else if (clnt_st == RPC_PROGVERSMISMATCH) { + struct rpc_err rpcerr; + + clnt_geterr(client, &rpcerr); + if (rpcerr.re_vers.low > RPCBVERS4) + goto error; /* a new version, can't handle */ + } else if (clnt_st != RPC_PROGUNAVAIL) { + /* Cant handle this error */ + rpc_createerr.cf_stat = clnt_st; + clnt_geterr(client, &rpc_createerr.cf_error); + goto error; + } + } + + if ((address == NULL) || (address->len == 0)) { + rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; + clnt_geterr(client, &rpc_createerr.cf_error); + } + +error: + if (client) { + CLNT_DESTROY(client); + client = NULL; + } +done: + if (nconf->nc_semantics != NC_TPI_CLTS) { + /* This client is the connectionless one */ + if (client) { + CLNT_DESTROY(client); + client = NULL; + } + } + if (clpp) { + *clpp = client; + } else if (client) { + CLNT_DESTROY(client); + } + 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(program, version, nconf, + host, (CLIENT **) 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; + + + 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] == NULL)) { + 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/lib/libc/rpc/rpcb_prot.c b/lib/libc/rpc/rpcb_prot.c new file mode 100644 index 000000000000..aa4651087694 --- /dev/null +++ b/lib/libc/rpc/rpcb_prot.c @@ -0,0 +1,329 @@ +/* $NetBSD: rpcb_prot.c,v 1.3 2000/07/14 08:40:42 fvdl Exp $ */ +/* $FreeBSD$ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ + +/* #ident "@(#)rpcb_prot.c 1.13 94/04/24 SMI" */ + +#if 0 +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)rpcb_prot.c 1.9 89/04/21 Copyr 1984 Sun Micro"; +#endif +#endif + +/* + * rpcb_prot.c + * XDR routines for the rpcbinder version 3. + * + * Copyright (C) 1984, 1988, Sun Microsystems, Inc. + */ + +#include "namespace.h" +#include <rpc/rpc.h> +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <rpc/rpcb_prot.h> +#include "un-namespace.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, (u_int)~0)) { + return (FALSE); + } + if (!xdr_string(xdrs, &objp->r_addr, (u_int)~0)) { + return (FALSE); + } + if (!xdr_string(xdrs, &objp->r_owner, (u_int)~0)) { + return (FALSE); + } + return (TRUE); +} + +/* + * rpcblist_ptr implements a linked list. The RPCL definition from + * rpcb_prot.x is: + * + * struct rpcblist { + * rpcb rpcb_map; + * struct rpcblist *rpcb_next; + * }; + * typedef rpcblist *rpcblist_ptr; + * + * Recall that "pointers" in XDR are encoded as a boolean, indicating whether + * there's any data behind the pointer, followed by the data (if any exists). + * The boolean can be interpreted as ``more data follows me''; if FALSE then + * nothing follows the boolean; if TRUE then the boolean is followed by an + * actual struct rpcb, and another rpcblist_ptr (declared in RPCL as "struct + * rpcblist *"). + * + * This could be implemented via the xdr_pointer type, though this would + * result in one recursive call per element in the list. Rather than do that + * we can ``unwind'' the recursion into a while loop and use xdr_reference to + * serialize the rpcb elements. + */ + +bool_t +xdr_rpcblist_ptr(xdrs, rp) + XDR *xdrs; + rpcblist_ptr *rp; +{ + /* + * more_elements is pre-computed in case the direction is + * XDR_ENCODE or XDR_FREE. more_elements is overwritten by + * xdr_bool when the direction is XDR_DECODE. + */ + bool_t more_elements; + int freeing = (xdrs->x_op == XDR_FREE); + rpcblist_ptr next; + rpcblist_ptr next_copy; + + for (;;) { + more_elements = (bool_t)(*rp != NULL); + if (! xdr_bool(xdrs, &more_elements)) { + return (FALSE); + } + if (! more_elements) { + return (TRUE); /* we are done */ + } + /* + * the unfortunate side effect of non-recursion is that in + * the case of freeing we must remember the next object + * before we free the current object ... + */ + if (freeing) + next = (*rp)->rpcb_next; + if (! xdr_reference(xdrs, (caddr_t *)rp, + (u_int)sizeof (rpcblist), (xdrproc_t)xdr_rpcb)) { + return (FALSE); + } + if (freeing) { + next_copy = next; + rp = &next_copy; + /* + * Note that in the subsequent iteration, next_copy + * gets nulled out by the xdr_reference + * but next itself survives. + */ + } else { + rp = &((*rp)->rpcb_next); + } + } + /*NOTREACHED*/ +} + +/* + * xdr_rpcblist() is specified to take a RPCBLIST **, but is identical in + * functionality to xdr_rpcblist_ptr(). + */ +bool_t +xdr_rpcblist(xdrs, rp) + XDR *xdrs; + RPCBLIST **rp; +{ + bool_t dummy; + + dummy = xdr_rpcblist_ptr(xdrs, (rpcblist_ptr *)rp); + return (dummy); +} + + +bool_t +xdr_rpcb_entry(xdrs, objp) + XDR *xdrs; + rpcb_entry *objp; +{ + if (!xdr_string(xdrs, &objp->r_maddr, (u_int)~0)) { + return (FALSE); + } + if (!xdr_string(xdrs, &objp->r_nc_netid, (u_int)~0)) { + return (FALSE); + } + if (!xdr_u_int32_t(xdrs, &objp->r_nc_semantics)) { + return (FALSE); + } + if (!xdr_string(xdrs, &objp->r_nc_protofmly, (u_int)~0)) { + return (FALSE); + } + if (!xdr_string(xdrs, &objp->r_nc_proto, (u_int)~0)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_rpcb_entry_list_ptr(xdrs, rp) + XDR *xdrs; + rpcb_entry_list_ptr *rp; +{ + /* + * more_elements is pre-computed in case the direction is + * XDR_ENCODE or XDR_FREE. more_elements is overwritten by + * xdr_bool when the direction is XDR_DECODE. + */ + bool_t more_elements; + int freeing = (xdrs->x_op == XDR_FREE); + rpcb_entry_list_ptr next; + rpcb_entry_list_ptr next_copy; + + for (;;) { + more_elements = (bool_t)(*rp != NULL); + if (! xdr_bool(xdrs, &more_elements)) { + return (FALSE); + } + if (! more_elements) { + return (TRUE); /* we are done */ + } + /* + * the unfortunate side effect of non-recursion is that in + * the case of freeing we must remember the next object + * before we free the current object ... + */ + if (freeing) + next = (*rp)->rpcb_entry_next; + if (! xdr_reference(xdrs, (caddr_t *)rp, + (u_int)sizeof (rpcb_entry_list), + (xdrproc_t)xdr_rpcb_entry)) { + return (FALSE); + } + if (freeing) { + next_copy = next; + rp = &next_copy; + /* + * Note that in the subsequent iteration, next_copy + * gets nulled out by the xdr_reference + * but next itself survives. + */ + } else { + rp = &((*rp)->rpcb_entry_next); + } + } + /*NOTREACHED*/ +} + +/* + * XDR remote call arguments + * written for XDR_ENCODE direction only + */ +bool_t +xdr_rpcb_rmtcallargs(xdrs, p) + XDR *xdrs; + struct rpcb_rmtcallargs *p; +{ + struct r_rpcb_rmtcallargs *objp = + (struct r_rpcb_rmtcallargs *)(void *)p; + u_int lenposition, argposition, position; + int32_t *buf; + + buf = XDR_INLINE(xdrs, 3 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_u_int32_t(xdrs, &objp->prog)) { + return (FALSE); + } + if (!xdr_u_int32_t(xdrs, &objp->vers)) { + return (FALSE); + } + if (!xdr_u_int32_t(xdrs, &objp->proc)) { + return (FALSE); + } + } else { + IXDR_PUT_U_INT32(buf, objp->prog); + IXDR_PUT_U_INT32(buf, objp->vers); + IXDR_PUT_U_INT32(buf, objp->proc); + } + + /* + * All the jugglery for just getting the size of the arguments + */ + lenposition = XDR_GETPOS(xdrs); + if (! xdr_u_int(xdrs, &(objp->args.args_len))) { + return (FALSE); + } + argposition = XDR_GETPOS(xdrs); + if (! (*objp->xdr_args)(xdrs, objp->args.args_val)) { + return (FALSE); + } + position = XDR_GETPOS(xdrs); + objp->args.args_len = (u_int)((u_long)position - (u_long)argposition); + XDR_SETPOS(xdrs, lenposition); + if (! xdr_u_int(xdrs, &(objp->args.args_len))) { + return (FALSE); + } + XDR_SETPOS(xdrs, position); + return (TRUE); +} + +/* + * XDR remote call results + * written for XDR_DECODE direction only + */ +bool_t +xdr_rpcb_rmtcallres(xdrs, p) + XDR *xdrs; + struct rpcb_rmtcallres *p; +{ + bool_t dummy; + struct r_rpcb_rmtcallres *objp = (struct r_rpcb_rmtcallres *)(void *)p; + + if (!xdr_string(xdrs, &objp->addr, (u_int)~0)) { + return (FALSE); + } + if (!xdr_u_int(xdrs, &objp->results.results_len)) { + return (FALSE); + } + dummy = (*(objp->xdr_res))(xdrs, objp->results.results_val); + return (dummy); +} + +bool_t +xdr_netbuf(xdrs, objp) + XDR *xdrs; + struct netbuf *objp; +{ + bool_t dummy; + + if (!xdr_u_int32_t(xdrs, (u_int32_t *) &objp->maxlen)) { + return (FALSE); + } + dummy = xdr_bytes(xdrs, (char **)&(objp->buf), + (u_int *)&(objp->len), objp->maxlen); + return (dummy); +} diff --git a/lib/libc/rpc/rpcb_st_xdr.c b/lib/libc/rpc/rpcb_st_xdr.c new file mode 100644 index 000000000000..c094e9974e62 --- /dev/null +++ b/lib/libc/rpc/rpcb_st_xdr.c @@ -0,0 +1,265 @@ +/* $NetBSD: rpcb_st_xdr.c,v 1.3 2000/07/14 08:40:42 fvdl Exp $ */ +/* $FreeBSD$ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* + * 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 "namespace.h" +#include <rpc/rpc.h> +#include "un-namespace.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, (u_int)~0)) { + return (FALSE); + } + + if (!xdr_pointer(xdrs, (char **)&objp->next, + sizeof (rpcbs_addrlist), + (xdrproc_t)xdr_rpcbs_addrlist)) { + return (FALSE); + } + + return (TRUE); +} + +/* Link list of all the stats about rmtcall */ + +bool_t +xdr_rpcbs_rmtcalllist(xdrs, objp) + XDR *xdrs; + rpcbs_rmtcalllist *objp; +{ + int32_t *buf; + + if (xdrs->x_op == XDR_ENCODE) { + buf = XDR_INLINE(xdrs, 6 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_u_int32_t(xdrs, &objp->prog)) { + return (FALSE); + } + if (!xdr_u_int32_t(xdrs, &objp->vers)) { + return (FALSE); + } + if (!xdr_u_int32_t(xdrs, &objp->proc)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->success)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->failure)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->indirect)) { + return (FALSE); + } + } else { + IXDR_PUT_U_INT32(buf, objp->prog); + IXDR_PUT_U_INT32(buf, objp->vers); + IXDR_PUT_U_INT32(buf, objp->proc); + IXDR_PUT_INT32(buf, objp->success); + IXDR_PUT_INT32(buf, objp->failure); + IXDR_PUT_INT32(buf, objp->indirect); + } + if (!xdr_string(xdrs, &objp->netid, (u_int)~0)) { + return (FALSE); + } + if (!xdr_pointer(xdrs, (char **)&objp->next, + sizeof (rpcbs_rmtcalllist), + (xdrproc_t)xdr_rpcbs_rmtcalllist)) { + return (FALSE); + } + return (TRUE); + } else if (xdrs->x_op == XDR_DECODE) { + buf = XDR_INLINE(xdrs, 6 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_u_int32_t(xdrs, &objp->prog)) { + return (FALSE); + } + if (!xdr_u_int32_t(xdrs, &objp->vers)) { + return (FALSE); + } + if (!xdr_u_int32_t(xdrs, &objp->proc)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->success)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->failure)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->indirect)) { + return (FALSE); + } + } else { + objp->prog = (rpcprog_t)IXDR_GET_U_INT32(buf); + objp->vers = (rpcvers_t)IXDR_GET_U_INT32(buf); + objp->proc = (rpcproc_t)IXDR_GET_U_INT32(buf); + objp->success = (int)IXDR_GET_INT32(buf); + objp->failure = (int)IXDR_GET_INT32(buf); + objp->indirect = (int)IXDR_GET_INT32(buf); + } + if (!xdr_string(xdrs, &objp->netid, (u_int)~0)) { + return (FALSE); + } + if (!xdr_pointer(xdrs, (char **)&objp->next, + sizeof (rpcbs_rmtcalllist), + (xdrproc_t)xdr_rpcbs_rmtcalllist)) { + return (FALSE); + } + return (TRUE); + } + if (!xdr_u_int32_t(xdrs, &objp->prog)) { + return (FALSE); + } + if (!xdr_u_int32_t(xdrs, &objp->vers)) { + return (FALSE); + } + if (!xdr_u_int32_t(xdrs, &objp->proc)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->success)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->failure)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->indirect)) { + return (FALSE); + } + if (!xdr_string(xdrs, &objp->netid, (u_int)~0)) { + return (FALSE); + } + if (!xdr_pointer(xdrs, (char **)&objp->next, + sizeof (rpcbs_rmtcalllist), + (xdrproc_t)xdr_rpcbs_rmtcalllist)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_rpcbs_proc(xdrs, objp) + XDR *xdrs; + rpcbs_proc objp; +{ + if (!xdr_vector(xdrs, (char *)(void *)objp, RPCBSTAT_HIGHPROC, + sizeof (int), (xdrproc_t)xdr_int)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_rpcbs_addrlist_ptr(xdrs, objp) + XDR *xdrs; + rpcbs_addrlist_ptr *objp; +{ + if (!xdr_pointer(xdrs, (char **)objp, sizeof (rpcbs_addrlist), + (xdrproc_t)xdr_rpcbs_addrlist)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_rpcbs_rmtcalllist_ptr(xdrs, objp) + XDR *xdrs; + rpcbs_rmtcalllist_ptr *objp; +{ + if (!xdr_pointer(xdrs, (char **)objp, sizeof (rpcbs_rmtcalllist), + (xdrproc_t)xdr_rpcbs_rmtcalllist)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_rpcb_stat(xdrs, objp) + XDR *xdrs; + rpcb_stat *objp; +{ + + if (!xdr_rpcbs_proc(xdrs, objp->info)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->setinfo)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->unsetinfo)) { + return (FALSE); + } + if (!xdr_rpcbs_addrlist_ptr(xdrs, &objp->addrinfo)) { + return (FALSE); + } + 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/lib/libc/rpc/rpcbind.3 b/lib/libc/rpc/rpcbind.3 new file mode 100644 index 000000000000..309269648607 --- /dev/null +++ b/lib/libc/rpc/rpcbind.3 @@ -0,0 +1,189 @@ +.\" @(#)rpcbind.3n 1.25 93/05/07 SMI; from SVr4 +.\" Copyright 1989 AT&T +.\" Copyright (c) 1988 Sun Microsystem's, Inc. - All Right's Reserved. +.\" $NetBSD: rpcbind.3,v 1.2 2000/06/03 18:47:28 fvdl Exp $ +.\" $FreeBSD$ +.Dd May 7, 1993 +.Dt RPCBIND 3 +.Os +.Sh NAME +.Nm rpcb_getmaps , +.Nm rpcb_getaddr , +.Nm rpcb_gettime , +.Nm rpcb_rmtcall , +.Nm rpcb_set , +.Nm rpcb_unset +.Nd library routines for RPC bind service +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.Fd #include <rpc/rpc.h> +.Ft "struct rpcblist *" +.Fn rpcb_getmaps "const struct netconfig *netconf" "const char *host" +.Ft bool_t +.Fn rpcb_getaddr "const rpcprog_t prognum" "const rpcvers_t versnum" "const struct netconfig *netconf" "struct netbuf *svcaddr" "const char *host" +.Ft bool_t +.Fn rpcb_gettime "const char *host" "time_t * timep" +.Ft "enum clnt_stat" +.Fn rpcb_rmtcall "const struct netconfig *netconf" "const char *host" "const rpcprog_t prognum, const rpcvers_t versnum" "const rpcproc_t procnum, const xdrproc_t inproc" "const caddr_t in" "const xdrproc_t outproc" "caddr_t out" "const struct timeval tout, struct netbuf *svcaddr" +.Ft bool_t +.Fn rpcb_set "const rpcprog_t prognum" "const rpcvers_t versnum" "const struct netconfig *netconf" "const struct netbuf *svcaddr" +.Ft bool_t +.Fn rpcb_unset "const rpcprog_t prognum" "const rpcvers_t versnum" "const struct netconfig *netconf" +.Sh DESCRIPTION +These routines allow client C programs to make procedure +calls to the RPC binder service. +(see +.Xr rpcbind 8 ) +maintains a list of mappings between programs +and their universal addresses. +.Sh Routines +.Bl -tag -width XXXXX +.It Fn rpcb_getmaps +An interface to the rpcbind service, +which returns a list of the current +RPC program-to-address mappings on +.Fa host . +It uses the transport specified through +.Fa netconf +to contact the remote rpcbind +service on +.Fa host . +This routine will return +.Dv NULL , +if the remote rpcbind could not be contacted. +.It Fn rpcb_getaddr +An interface to the rpcbind +service, which finds the address of the service on +.Fa host +that is registered with program number +.Fa prognum , +version +.Fa versnum , +and speaks the transport protocol associated with +.Fa netconf . +The address found is returned in +.Fa svcaddr . +.Fa svcaddr +should be preallocated. +This routine returns +.Dv TRUE +if it succeeds. +A return value of +.Dv FALSE +means that the mapping does not exist +or that the RPC +system failed to contact the remote +rpcbind service. +In the latter case, the global variable +.Va rpc_createerr +(see +.Xr rpc_clnt_create 3 ) +contains the +RPC status. +.It Fn rpcb_gettime +This routine returns the time on +.Fa host +in +.Fa timep . +If +.Fa host +is +.Dv NULL , +.Fn rpcb_gettime +returns the time on its own machine. +This routine returns +.Dv TRUE +if it succeeds, +.Dv FALSE +if it fails. +.Fn rpcb_gettime +can be used to synchronize the time between the +client and the remote server. +.It Fn rpcb_rmtcall +An interface to the rpcbind service, which instructs +rpcbind on +.Fa host +to make an RPC +call on your behalf to a procedure on that host. +The +.Fn netconfig +structure should correspond to a connectionless transport. +The parameter +.Fa svcaddr +will be modified to the server's address if the procedure succeeds +(see +.Fn rpc_call +and +.Fn clnt_call +in +.Xr rpc_clnt_calls 3 +for the definitions of other parameters). +.Pp +This procedure should normally be used for a +.Dq ping +and nothing else. +This routine allows programs to do lookup and call, all in one step. +.Pp +Note: Even if the server is not running +.Fn rpcb_rmtcall +does not return any error messages to the caller. +In such a case, the caller times out. +.Pp +Note: +.Fn rpcb_rmtcall +is only available for connectionless transports. +.It Fn rpcb_set +An interface to the rpcbind +service, which establishes a mapping between the triple +.Bq Fa prognum , versnum , netconf->nc_netid +and +.Fa svcaddr +on the machine's rpcbind +service. +The value of +.Fa nc_netid +must correspond to a network identifier that is defined by the +netconfig database. +This routine returns +.Dv TRUE +if it succeeds, +.Dv FALSE +otherwise. +(See also +.Fn svc_reg +in +.Xr rpc_svc_calls 3 . ) +If there already exists such an entry with rpcbind, +.Fn rpcb_set +will fail. +.It Fn rpcb_unset +An interface to the rpcbind +service, which destroys the mapping between the triple +.Bq Fa prognum , versnum , netconf->nc_netid +and the address on the machine's rpcbind +service. +If +.Fa netconf +is +.Dv NULL , +.Fn rpcb_unset +destroys all mapping between the triple +.Bq Fa prognum , versnum , No all-transports +and the addresses on the machine's rpcbind service. +This routine returns +.Dv TRUE +if it succeeds, +.Dv FALSE +otherwise. +Only the owner of the service or the super-user can destroy the mapping. +(See also +.Fn svc_unreg +in +.Xr rpc_svc_calls 3 . ) +.El +.Sh SEE ALSO +.Xr rpc_clnt_calls 3 , +.Xr rpc_svc_calls 3 , +.Xr rpcbind 8 , +.Xr rpcinfo 8 diff --git a/lib/libc/rpc/rpcdname.c b/lib/libc/rpc/rpcdname.c index f28b4fda9b8a..03d1b8542c54 100644 --- a/lib/libc/rpc/rpcdname.c +++ b/lib/libc/rpc/rpcdname.c @@ -30,15 +30,18 @@ #if !defined(lint) && defined(SCCSIDS) static char sccsid[] = "@(#)rpcdname.c 1.7 91/03/11 Copyr 1989 Sun Micro"; #endif +/* $FreeBSD$ */ /* * rpcdname.c * Gets the default domain name */ +#include "namespace.h" #include <stdlib.h> #include <unistd.h> #include <string.h> +#include "un-namespace.h" static char *default_domain = 0; diff --git a/lib/libc/rpc/svc.c b/lib/libc/rpc/svc.c index 94d6057e6004..6e57245a4dd5 100644 --- a/lib/libc/rpc/svc.c +++ b/lib/libc/rpc/svc.c @@ -1,3 +1,5 @@ +/* $NetBSD: svc.c,v 1.21 2000/07/06 03:10:35 christos Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -43,17 +45,30 @@ static char *rcsid = "$FreeBSD$"; * Copyright (C) 1984, Sun Microsystems, Inc. */ -#include <string.h> +#include "reentrant.h" +#include "namespace.h" +#include <sys/types.h> +#include <sys/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 "un-namespace.h" + +#include "rpc_com.h" static SVCXPRT **xports; -static int xportssize; -#define NULL_SVC ((struct svc_callout *)0) #define RQCRED_SIZE 400 /* this size is excessive */ +#define SVC_VERSQUIET 0x0001 /* keep quiet about vers mismatch */ +#define version_keepquiet(xp) ((u_long)(xp)->xp_p3 & SVC_VERSQUIET) + #define max(a, b) (a > b ? a : b) /* @@ -64,15 +79,17 @@ static int xportssize; */ static struct svc_callout { struct svc_callout *sc_next; - u_long sc_prog; - u_long sc_vers; - void (*sc_dispatch)(); + rpcprog_t sc_prog; + rpcvers_t sc_vers; + char *sc_netid; + void (*sc_dispatch) __P((struct svc_req *, SVCXPRT *)); } *svc_head; -static struct svc_callout *svc_find(); +extern rwlock_t svc_lock; +extern rwlock_t svc_fd_lock; -int __svc_fdsetsize = 0; -fd_set *__svc_fdset = NULL; +static struct svc_callout *svc_find __P((rpcprog_t, rpcvers_t, + struct svc_callout **, char *)); /* *************** SVCXPRT related stuff **************** */ @@ -83,75 +100,161 @@ void xprt_register(xprt) SVCXPRT *xprt; { - register int sock = xprt->xp_sock; + int sock; - if (sock + 1 > __svc_fdsetsize) { - int bytes = howmany(sock + 1, NFDBITS) * sizeof(fd_mask); - fd_set *fds; + assert(xprt != NULL); - fds = (fd_set *)malloc(bytes); - memset(fds, 0, bytes); - if (__svc_fdset) { - memcpy(fds, __svc_fdset, howmany(__svc_fdsetsize, - NFDBITS) * sizeof(fd_mask)); - free(__svc_fdset); - } - __svc_fdset = fds; - __svc_fdsetsize = howmany(sock+1, NFDBITS) * NFDBITS; - } + sock = xprt->xp_fd; - if (sock < FD_SETSIZE) + rwlock_wrlock(&svc_fd_lock); + if (xports == NULL) { + xports = (SVCXPRT **) + mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *)); + if (xports == NULL) + return; + memset(xports, '\0', FD_SETSIZE * sizeof(SVCXPRT *)); + } + if (sock < FD_SETSIZE) { + xports[sock] = xprt; FD_SET(sock, &svc_fdset); - FD_SET(sock, __svc_fdset); - - if (xports == NULL || sock + 1 > xportssize) { - SVCXPRT **xp; - int size = FD_SETSIZE; - - if (sock + 1 > size) - size = sock + 1; - xp = (SVCXPRT **)mem_alloc(size * sizeof(SVCXPRT *)); - memset(xp, 0, size * sizeof(SVCXPRT *)); - if (xports) { - memcpy(xp, xports, xportssize * sizeof(SVCXPRT *)); - free(xports); - } - xportssize = size; - xports = xp; + svc_maxfd = max(svc_maxfd, sock); } - xports[sock] = xprt; - svc_maxfd = max(svc_maxfd, sock); + rwlock_unlock(&svc_fd_lock); } /* * De-activate a transport handle. */ void -xprt_unregister(xprt) +xprt_unregister(xprt) SVCXPRT *xprt; { - register int sock = xprt->xp_sock; + int sock; + + assert(xprt != NULL); - if (xports[sock] == xprt) { - xports[sock] = (SVCXPRT *)0; - if (sock < FD_SETSIZE) - FD_CLR(sock, &svc_fdset); - FD_CLR(sock, __svc_fdset); - if (sock == svc_maxfd) { - for (svc_maxfd--; svc_maxfd >= 0; svc_maxfd--) + sock = xprt->xp_fd; + + rwlock_wrlock(&svc_fd_lock); + if ((sock < FD_SETSIZE) && (xports[sock] == xprt)) { + xports[sock] = NULL; + FD_CLR(sock, &svc_fdset); + if (sock >= svc_maxfd) { + for (svc_maxfd--; svc_maxfd>=0; svc_maxfd--) if (xports[svc_maxfd]) break; } - /* - * XXX could use svc_maxfd as a hint to - * decrease the size of __svc_fdset - */ } + rwlock_unlock(&svc_fd_lock); } +/* + * 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) __P((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 @@ -162,23 +265,27 @@ svc_register(xprt, prog, vers, dispatch, protocol) SVCXPRT *xprt; u_long prog; u_long vers; - void (*dispatch)(); + void (*dispatch) __P((struct svc_req *, SVCXPRT *)); int protocol; { struct svc_callout *prev; - register struct svc_callout *s; + struct svc_callout *s; + + assert(xprt != NULL); + assert(dispatch != NULL); - if ((s = svc_find(prog, vers, &prev)) != NULL_SVC) { + 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 = (struct svc_callout *)mem_alloc(sizeof(struct svc_callout)); - if (s == (struct svc_callout *)0) { + s = mem_alloc(sizeof(struct svc_callout)); + if (s == NULL) { return (FALSE); } - s->sc_prog = prog; - s->sc_vers = vers; + s->sc_prog = (rpcprog_t)prog; + s->sc_vers = (rpcvers_t)vers; s->sc_dispatch = dispatch; s->sc_next = svc_head; svc_head = s; @@ -199,40 +306,46 @@ svc_unregister(prog, vers) u_long vers; { struct svc_callout *prev; - register struct svc_callout *s; + struct svc_callout *s; - if ((s = svc_find(prog, vers, &prev)) == NULL_SVC) + if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) == + NULL) return; - if (prev == NULL_SVC) { + if (prev == NULL) { svc_head = s->sc_next; } else { prev->sc_next = s->sc_next; } - s->sc_next = NULL_SVC; - mem_free((char *) s, (u_int) sizeof(struct svc_callout)); + 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) - u_long prog; - u_long vers; +svc_find(prog, vers, prev, netid) + rpcprog_t prog; + rpcvers_t vers; struct svc_callout **prev; + char *netid; { - register struct svc_callout *s, *p; + struct svc_callout *s, *p; + + assert(prev != NULL); - p = NULL_SVC; - for (s = svc_head; s != NULL_SVC; s = s->sc_next) { - if ((s->sc_prog == prog) && (s->sc_vers == vers)) - goto done; + 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; } -done: *prev = p; return (s); } @@ -244,19 +357,21 @@ done: */ bool_t svc_sendreply(xprt, xdr_results, xdr_location) - register SVCXPRT *xprt; + SVCXPRT *xprt; xdrproc_t xdr_results; caddr_t xdr_location; { - struct rpc_msg rply; + struct rpc_msg rply; - rply.rm_direction = REPLY; - rply.rm_reply.rp_stat = MSG_ACCEPTED; - rply.acpted_rply.ar_verf = xprt->xp_verf; + 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)); + return (SVC_REPLY(xprt, &rply)); } /* @@ -264,10 +379,12 @@ svc_sendreply(xprt, xdr_results, xdr_location) */ void svcerr_noproc(xprt) - register SVCXPRT *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; @@ -280,15 +397,17 @@ svcerr_noproc(xprt) */ void svcerr_decode(xprt) - register SVCXPRT *xprt; + SVCXPRT *xprt; { - struct rpc_msg rply; + struct rpc_msg rply; - rply.rm_direction = REPLY; - rply.rm_reply.rp_stat = MSG_ACCEPTED; + 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); + SVC_REPLY(xprt, &rply); } /* @@ -296,17 +415,61 @@ svcerr_decode(xprt) */ void svcerr_systemerr(xprt) - register SVCXPRT *xprt; + SVCXPRT *xprt; { - struct rpc_msg rply; + struct rpc_msg rply; - rply.rm_direction = REPLY; - rply.rm_reply.rp_stat = MSG_ACCEPTED; + 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); + SVC_REPLY(xprt, &rply); +} + +#if 0 +/* + * Tell RPC package to not complain about version errors to the client. This + * is useful when revving broadcast protocols that sit on a fixed address. + * There is really one (or should be only one) example of this kind of + * protocol: the portmapper (or rpc binder). + */ +void +__svc_versquiet_on(xprt) + SVCXPRT *xprt; +{ + u_long tmp; + + tmp = ((u_long) xprt->xp_p3) | SVC_VERSQUIET; + xprt->xp_p3 = (caddr_t) tmp; +} + +void +__svc_versquiet_off(xprt) + SVCXPRT *xprt; +{ + u_long tmp; + + tmp = ((u_long) xprt->xp_p3) & ~SVC_VERSQUIET; + xprt->xp_p3 = (caddr_t) tmp; +} + +void +svc_versquiet(xprt) + SVCXPRT *xprt; +{ + __svc_versquiet_on(xprt); } +int +__svc_versquiet_get(xprt) + SVCXPRT *xprt; +{ + return ((int) xprt->xp_p3) & SVC_VERSQUIET; +} +#endif + /* * Authentication error reply */ @@ -317,6 +480,8 @@ svcerr_auth(xprt, 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; @@ -332,21 +497,25 @@ svcerr_weakauth(xprt) SVCXPRT *xprt; { + assert(xprt != NULL); + svcerr_auth(xprt, AUTH_TOOWEAK); } /* * Program unavailable error reply */ -void +void svcerr_noprog(xprt) - register SVCXPRT *xprt; + SVCXPRT *xprt; { - struct rpc_msg rply; + struct rpc_msg rply; - rply.rm_direction = REPLY; - rply.rm_reply.rp_stat = MSG_ACCEPTED; - rply.acpted_rply.ar_verf = xprt->xp_verf; + 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); } @@ -354,20 +523,22 @@ svcerr_noprog(xprt) /* * Program version mismatch error reply */ -void +void svcerr_progvers(xprt, low_vers, high_vers) - register SVCXPRT *xprt; - u_long low_vers; - u_long 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 = low_vers; - rply.acpted_rply.ar_vers.high = high_vers; + 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); } @@ -404,90 +575,142 @@ void svc_getreqset(readfds) fd_set *readfds; { - svc_getreqset2(readfds, FD_SETSIZE); + int bit, fd; + fd_mask mask, *maskp; + int sock; + + assert(readfds != NULL); + + maskp = readfds->fds_bits; + for (sock = 0; sock < FD_SETSIZE; sock += NFDBITS) { + for (mask = *maskp++; (bit = ffs(mask)) != 0; + mask ^= (1 << (bit - 1))) { + /* sock has input waiting */ + fd = sock + bit - 1; + svc_getreq_common(fd); + } + } } void -svc_getreqset2(readfds, width) - fd_set *readfds; - int width; +svc_getreq_common(fd) + int fd; { - enum xprt_stat stat; + SVCXPRT *xprt; + struct svc_req r; struct rpc_msg msg; int prog_found; - u_long low_vers; - u_long high_vers; - struct svc_req r; - register SVCXPRT *xprt; - register int bit; - register int sock; - register fd_mask mask, *maskp; + 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 = 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)) { - maskp = readfds->fds_bits; - for (sock = 0; sock < width; sock += NFDBITS) { - for (mask = *maskp++; (bit = ffs(mask)); mask ^= (1 << (bit - 1))) { - /* sock has input waiting */ - xprt = xports[sock + bit - 1]; - if (xprt == NULL) - /* But do we control sock? */ - continue; - /* now receive msgs from xprtprt (support batch calls) */ - do { - if (SVC_RECV(xprt, &msg)) { - - /* now find the exported program and call it */ - register struct svc_callout *s; - enum auth_stat why; + /* now find the exported program and call it */ + struct svc_callout *s; + enum auth_stat why; - r.rq_xprt = xprt; - r.rq_prog = msg.rm_call.cb_prog; - r.rq_vers = msg.rm_call.cb_vers; - r.rq_proc = msg.rm_call.cb_proc; - r.rq_cred = msg.rm_call.cb_cred; - /* first authenticate the message */ - if ((why= _authenticate(&r, &msg)) != AUTH_OK) { - svcerr_auth(xprt, why); - goto call_done; - } - /* now match message with a registered service*/ - prog_found = FALSE; - low_vers = (u_long) - 1; - high_vers = 0; - for (s = svc_head; s != NULL_SVC; 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 ... */ + r.rq_xprt = xprt; + r.rq_prog = msg.rm_call.cb_prog; + r.rq_vers = msg.rm_call.cb_vers; + r.rq_proc = msg.rm_call.cb_proc; + r.rq_cred = msg.rm_call.cb_cred; + /* first authenticate the message */ + if ((why = _authenticate(&r, &msg)) != AUTH_OK) { + svcerr_auth(xprt, why); + goto call_done; } - call_done: - if ((stat = SVC_STAT(xprt)) == XPRT_DIED){ - SVC_DESTROY(xprt); - break; + /* 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 */ } - } while (stat == XPRT_MOREREQS); - } + /* + * 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 != 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 i; + int fds_found; + + for (i = fds_found = 0; fds_found < pollretval; i++) { + struct pollfd *p = &pfdp[i]; + + if (p->revents) { + /* fd has input waiting */ + fds_found++; + /* + * We assume that this function is only called + * via someone _select()ing from svc_fdset or + * _poll()ing from svc_pollset[]. Thus it's safe + * to handle the POLLNVAL event by simply turning + * the corresponding bit off in svc_fdset. The + * svc_pollset[] array is derived from svc_fdset + * and so will also be updated eventually. + * + * XXX Should we do an xprt_unregister() instead? + */ + if (p->revents & POLLNVAL) { + rwlock_wrlock(&svc_fd_lock); + FD_CLR(p->fd, &svc_fdset); + rwlock_unlock(&svc_fd_lock); + } else + svc_getreq_common(p->fd); + } } } diff --git a/lib/libc/rpc/svc_auth.c b/lib/libc/rpc/svc_auth.c index fa1dca7ce7ec..48d65b0a839b 100644 --- a/lib/libc/rpc/svc_auth.c +++ b/lib/libc/rpc/svc_auth.c @@ -1,3 +1,5 @@ +/* $NetBSD: svc_auth.c,v 1.12 2000/07/06 03:10:35 christos Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -30,14 +32,12 @@ * Copyright (c) 1986-1991 by Sun Microsystems Inc. */ -#ident "@(#)svc_auth.c 1.16 94/04/24 SMI" +/* #ident "@(#)svc_auth.c 1.16 94/04/24 SMI" */ -#if !defined(lint) && defined(SCCSIDS) #if 0 +#if !defined(lint) && defined(SCCSIDS) static char sccsid[] = "@(#)svc_auth.c 1.26 89/02/07 Copyr 1984 Sun Micro"; -#else -static const char rcsid[] = - "$FreeBSD$"; +static const char rcsid[] = "$FreeBSD$"; #endif #endif @@ -46,20 +46,12 @@ static const char rcsid[] = * */ -#ifdef _KERNEL -#include <sys/param.h> -#include <rpc/types.h> -#include <rpc/xdr.h> -#include <rpc/auth.h> -#include <rpc/clnt.h> -#include <rpc/rpc_msg.h> -#include <rpc/svc.h> -#include <rpc/svc_auth.h> -#else -#include <stdlib.h> -#include <rpc/rpc.h> -#endif +#include "reentrant.h" +#include "namespace.h" #include <sys/types.h> +#include <rpc/rpc.h> +#include <stdlib.h> +#include "un-namespace.h" /* * svcauthsw is the bdevsw of server side authentication. @@ -71,20 +63,15 @@ static const char rcsid[] = * * enum auth_stat * flavorx_auth(rqst, msg) - * register struct svc_req *rqst; - * register struct rpc_msg *msg; + * struct svc_req *rqst; + * struct rpc_msg *msg; * */ -enum auth_stat _svcauth_null(); /* no authentication */ -enum auth_stat _svcauth_unix(); /* (system) unix style (uid, gids) */ -enum auth_stat _svcauth_short(); /* short hand unix style */ -enum auth_stat _svcauth_des(); /* des style */ - /* declarations to allow servers to specify new authentication flavors */ struct authsvc { int flavor; - enum auth_stat (*handler)(); + enum auth_stat (*handler) __P((struct svc_req *, struct rpc_msg *)); struct authsvc *next; }; static struct authsvc *Auths = NULL; @@ -109,11 +96,15 @@ static struct authsvc *Auths = NULL; */ enum auth_stat _authenticate(rqst, msg) - register struct svc_req *rqst; + struct svc_req *rqst; struct rpc_msg *msg; { - register int cred_flavor; - register struct authsvc *asp; + int cred_flavor; + struct authsvc *asp; + enum auth_stat dummy; + extern mutex_t authsvc_lock; + +/* VARIABLES PROTECTED BY authsvc_lock: asp, Auths */ rqst->rq_cred = msg->rm_call.cb_cred; rqst->rq_xprt->xp_verf.oa_flavor = _null_auth.oa_flavor; @@ -121,34 +112,35 @@ _authenticate(rqst, msg) cred_flavor = rqst->rq_cred.oa_flavor; switch (cred_flavor) { case AUTH_NULL: - return(_svcauth_null(rqst, msg)); - case AUTH_UNIX: - return(_svcauth_unix(rqst, msg)); + dummy = _svcauth_null(rqst, msg); + return (dummy); + case AUTH_SYS: + dummy = _svcauth_unix(rqst, msg); + return (dummy); case AUTH_SHORT: - return(_svcauth_short(rqst, msg)); - /* - * We leave AUTH_DES turned off by default because svcauth_des() - * needs getpublickey(), which is in librpcsvc, not libc. If we - * included AUTH_DES as a built-in flavor, programs that don't - * have -lrpcsvc in their Makefiles wouldn't link correctly, even - * though they don't use AUTH_DES. And I'm too lazy to go through - * the tree looking for all of them. - */ + dummy = _svcauth_short(rqst, msg); + return (dummy); #ifdef DES_BUILTIN case AUTH_DES: - return(_svcauth_des(rqst, msg)); + dummy = _svcauth_des(rqst, msg); + return (dummy); #endif + default: + break; } /* flavor doesn't match any of the builtin types, so try new ones */ + mutex_lock(&authsvc_lock); for (asp = Auths; asp; asp = asp->next) { if (asp->flavor == cred_flavor) { enum auth_stat as; as = (*asp->handler)(rqst, msg); + mutex_unlock(&authsvc_lock); return (as); } } + mutex_unlock(&authsvc_lock); return (AUTH_REJECTEDCRED); } @@ -178,14 +170,15 @@ _svcauth_null(rqst, msg) int svc_auth_reg(cred_flavor, handler) - register int cred_flavor; - enum auth_stat (*handler)(); + int cred_flavor; + enum auth_stat (*handler) __P((struct svc_req *, struct rpc_msg *)); { - register struct authsvc *asp; + struct authsvc *asp; + extern mutex_t authsvc_lock; switch (cred_flavor) { case AUTH_NULL: - case AUTH_UNIX: + case AUTH_SYS: case AUTH_SHORT: #ifdef DES_BUILTIN case AUTH_DES: @@ -194,22 +187,26 @@ svc_auth_reg(cred_flavor, handler) 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 = (struct authsvc *)mem_alloc(sizeof (*asp)); + 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/lib/libc/rpc/svc_auth_des.c b/lib/libc/rpc/svc_auth_des.c index f3af780f1683..0d363c132bac 100644 --- a/lib/libc/rpc/svc_auth_des.c +++ b/lib/libc/rpc/svc_auth_des.c @@ -46,6 +46,8 @@ * */ +#include "reentrant.h" +#include "namespace.h" #include <string.h> #include <stdlib.h> #include <stdio.h> @@ -60,6 +62,7 @@ #include <rpc/svc.h> #include <rpc/rpc_msg.h> #include <rpc/svc_auth.h> +#include "libc_private.h" #if defined(LIBC_SCCS) && !defined(lint) /* from: static char sccsid[] = "@(#)svcauth_des.c 2.3 89/07/11 4.0 RPCSRC; from 1.15 88/02/08 SMI"; */ @@ -190,7 +193,7 @@ _svcauth_des(rqst, msg) } } else { /* ADN_NICKNAME */ sid = (short)cred->adc_nickname; - if (sid >= AUTHDES_CACHESZ) { + if (sid < 0 || sid >= AUTHDES_CACHESZ) { debug("bad nickname"); return (AUTH_BADCRED); /* garbled credential */ } diff --git a/lib/libc/rpc/svc_auth_unix.c b/lib/libc/rpc/svc_auth_unix.c index 4e800e5e2aa3..ba6e483012b5 100644 --- a/lib/libc/rpc/svc_auth_unix.c +++ b/lib/libc/rpc/svc_auth_unix.c @@ -27,9 +27,10 @@ * Mountain View, California 94043 */ +#include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) -/*static char *sccsid = "from: @(#)svc_auth_unix.c 1.28 88/02/08 Copyr 1984 Sun Micro";*/ -/*static char *sccsid = "from: @(#)svc_auth_unix.c 2.3 88/08/01 4.0 RPCSRC";*/ +static char *sccsid = "@(#)svc_auth_unix.c 1.28 88/02/08 Copyr 1984 Sun Micro"; +static char *sccsid = "@(#)svc_auth_unix.c 2.3 88/08/01 4.0 RPCSRC"; static char *rcsid = "$FreeBSD$"; #endif @@ -44,30 +45,37 @@ static char *rcsid = "$FreeBSD$"; * Copyright (C) 1984, Sun Microsystems, Inc. */ +#include "namespace.h" +#include <assert.h> #include <stdio.h> #include <string.h> + #include <rpc/rpc.h> +#include "un-namespace.h" /* * Unix longhand authenticator */ enum auth_stat _svcauth_unix(rqst, msg) - register struct svc_req *rqst; - register struct rpc_msg *msg; + struct svc_req *rqst; + struct rpc_msg *msg; { - register enum auth_stat stat; + enum auth_stat stat; XDR xdrs; - register struct authunix_parms *aup; - register int32_t *buf; + struct authunix_parms *aup; + int32_t *buf; struct area { struct authunix_parms area_aup; char area_machname[MAX_MACHINE_NAME+1]; int area_gids[NGRPS]; } *area; u_int auth_len; - int str_len, gid_len; - register int i; + 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; @@ -77,34 +85,34 @@ _svcauth_unix(rqst, msg) 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_LONG(buf); - str_len = IXDR_GET_U_LONG(buf); + 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; } - memcpy(aup->aup_machname, (caddr_t)buf, (u_int)str_len); + 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 = IXDR_GET_LONG(buf); - aup->aup_gid = IXDR_GET_LONG(buf); - gid_len = IXDR_GET_U_LONG(buf); + 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] = IXDR_GET_LONG(buf); + 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 %d str %d auth %d\n", - gid_len, 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; } @@ -115,13 +123,13 @@ _svcauth_unix(rqst, msg) goto done; } - /* get the verifier */ + /* get the verifier */ if ((u_int)msg->rm_call.cb_verf.oa_length) { - rqst->rq_xprt->xp_verf.oa_flavor = + rqst->rq_xprt->xp_verf.oa_flavor = msg->rm_call.cb_verf.oa_flavor; - rqst->rq_xprt->xp_verf.oa_base = + rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base; - rqst->rq_xprt->xp_verf.oa_length = + rqst->rq_xprt->xp_verf.oa_length = msg->rm_call.cb_verf.oa_length; } else { rqst->rq_xprt->xp_verf.oa_flavor = AUTH_NULL; @@ -139,7 +147,7 @@ done: * Looks up longhand in a cache. */ /*ARGSUSED*/ -enum auth_stat +enum auth_stat _svcauth_short(rqst, msg) struct svc_req *rqst; struct rpc_msg *msg; diff --git a/lib/libc/rpc/svc_dg.c b/lib/libc/rpc/svc_dg.c new file mode 100644 index 000000000000..03ace97f964c --- /dev/null +++ b/lib/libc/rpc/svc_dg.c @@ -0,0 +1,603 @@ +/* $NetBSD: svc_dg.c,v 1.4 2000/07/06 03:10:35 christos Exp $ */ +/* $FreeBSD$ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ + +/* #ident "@(#)svc_dg.c 1.17 94/04/24 SMI" */ + + +/* + * svc_dg.c, Server side for connectionless RPC. + * + * Does some caching in the hopes of achieving execute-at-most-once semantics. + */ + +#include "reentrant.h" +#include "namespace.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> +#ifdef RPC_CACHE_DEBUG +#include <netconfig.h> +#include <netdir.h> +#endif +#include <err.h> +#include "un-namespace.h" + +#include "rpc_com.h" + +#define su_data(xprt) ((struct svc_dg_data *)(xprt->xp_p2)) +#define rpc_buffer(xprt) ((xprt)->xp_p1) + +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +static void svc_dg_ops __P((SVCXPRT *)); +static enum xprt_stat svc_dg_stat __P((SVCXPRT *)); +static bool_t svc_dg_recv __P((SVCXPRT *, struct rpc_msg *)); +static bool_t svc_dg_reply __P((SVCXPRT *, struct rpc_msg *)); +static bool_t svc_dg_getargs __P((SVCXPRT *, xdrproc_t, caddr_t)); +static bool_t svc_dg_freeargs __P((SVCXPRT *, xdrproc_t, caddr_t)); +static void svc_dg_destroy __P((SVCXPRT *)); +static bool_t svc_dg_control __P((SVCXPRT *, const u_int, void *)); +static int cache_get __P((SVCXPRT *, struct rpc_msg *, char **, size_t *)); +static void cache_set __P((SVCXPRT *, size_t)); +int svc_dg_enablecache __P((SVCXPRT *, u_int)); + +/* + * Usage: + * xprt = svc_dg_create(sock, sendsize, recvsize); + * Does other connectionless specific initializations. + * Once *xprt is initialized, it is registered. + * see (svc.h, xprt_register). If recvsize or sendsize are 0 suitable + * system defaults are chosen. + * The routines returns NULL if a problem occurred. + */ +static const char svc_dg_str[] = "svc_dg_create: %s"; +static const char svc_dg_err1[] = "could not get transport information"; +static const char svc_dg_err2[] = " transport does not support data transfer"; +static const char __no_mem_str[] = "out of memory"; + +SVCXPRT * +svc_dg_create(fd, sendsize, recvsize) + int fd; + u_int sendsize; + u_int recvsize; +{ + SVCXPRT *xprt; + struct svc_dg_data *su = NULL; + struct __rpc_sockinfo si; + struct sockaddr_storage ss; + socklen_t slen; + + if (!__rpc_fd2sockinfo(fd, &si)) { + 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)); + + 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 = (caddr_t)(void *)su; + xprt->xp_verf.oa_base = su->su_verfbody; + svc_dg_ops(xprt); + xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage); + + slen = sizeof ss; + if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) + goto freedata; + xprt->xp_ltaddr.buf = mem_alloc(sizeof (struct sockaddr_storage)); + xprt->xp_ltaddr.maxlen = sizeof (struct sockaddr_storage); + xprt->xp_ltaddr.len = slen; + memcpy(xprt->xp_ltaddr.buf, &ss, slen); + + xprt_register(xprt); + return (xprt); +freedata: + (void) warnx(svc_dg_str, __no_mem_str); + if (xprt) { + if (su) + (void) mem_free(su, sizeof (*su)); + (void) mem_free(xprt, sizeof (SVCXPRT)); + } + return (NULL); +} + +/*ARGSUSED*/ +static enum xprt_stat +svc_dg_stat(xprt) + SVCXPRT *xprt; +{ + return (XPRT_IDLE); +} + +static bool_t +svc_dg_recv(xprt, msg) + SVCXPRT *xprt; + struct rpc_msg *msg; +{ + struct svc_dg_data *su = su_data(xprt); + XDR *xdrs = &(su->su_xdrs); + char *reply; + struct sockaddr_storage ss; + socklen_t alen; + size_t replylen; + int rlen; + +again: + alen = sizeof (struct sockaddr_storage); + rlen = _recvfrom(xprt->xp_fd, rpc_buffer(xprt), su->su_iosz, 0, + (struct sockaddr *)(void *)&ss, &alen); + if (rlen == -1 && errno == EINTR) + goto again; + if (rlen == -1 || (rlen < 4 * sizeof (u_int32_t))) + return (FALSE); + if (xprt->xp_rtaddr.len < alen) { + if (xprt->xp_rtaddr.len != 0) + mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.len); + xprt->xp_rtaddr.buf = mem_alloc(alen); + xprt->xp_rtaddr.len = alen; + } + memcpy(xprt->xp_rtaddr.buf, &ss, alen); +#ifdef PORTMAP + if (ss.ss_family == AF_INET) { + xprt->xp_raddr = *(struct sockaddr_in *)xprt->xp_rtaddr.buf; + xprt->xp_addrlen = sizeof (struct sockaddr_in); + } +#endif /* PORTMAP */ + xdrs->x_op = XDR_DECODE; + XDR_SETPOS(xdrs, 0); + if (! xdr_callmsg(xdrs, msg)) { + return (FALSE); + } + su->su_xid = msg->rm_xid; + if (su->su_cache != NULL) { + if (cache_get(xprt, msg, &reply, &replylen)) { + (void)_sendto(xprt->xp_fd, reply, replylen, 0, + (struct sockaddr *)(void *)&ss, alen); + return (FALSE); + } + } + return (TRUE); +} + +static bool_t +svc_dg_reply(xprt, msg) + SVCXPRT *xprt; + struct rpc_msg *msg; +{ + struct svc_dg_data *su = su_data(xprt); + XDR *xdrs = &(su->su_xdrs); + bool_t stat = FALSE; + size_t slen; + + xdrs->x_op = XDR_ENCODE; + XDR_SETPOS(xdrs, 0); + msg->rm_xid = su->su_xid; + if (xdr_replymsg(xdrs, msg)) { + slen = XDR_GETPOS(xdrs); + if (_sendto(xprt->xp_fd, rpc_buffer(xprt), slen, 0, + (struct sockaddr *)xprt->xp_rtaddr.buf, + (socklen_t)xprt->xp_rtaddr.len) == 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; + caddr_t args_ptr; +{ + return (*xdr_args)(&(su_data(xprt)->su_xdrs), args_ptr); +} + +static bool_t +svc_dg_freeargs(xprt, xdr_args, args_ptr) + SVCXPRT *xprt; + xdrproc_t xdr_args; + caddr_t args_ptr; +{ + XDR *xdrs = &(su_data(xprt)->su_xdrs); + + xdrs->x_op = XDR_FREE; + return (*xdr_args)(xdrs, args_ptr); +} + +static void +svc_dg_destroy(xprt) + SVCXPRT *xprt; +{ + struct svc_dg_data *su = su_data(xprt); + + xprt_unregister(xprt); + if (xprt->xp_fd != -1) + (void)_close(xprt->xp_fd); + XDR_DESTROY(&(su->su_xdrs)); + (void) mem_free(rpc_buffer(xprt), su->su_iosz); + (void) mem_free(su, sizeof (*su)); + if (xprt->xp_rtaddr.buf) + (void) mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen); + if (xprt->xp_ltaddr.buf) + (void) mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen); + if (xprt->xp_tp) + (void) free(xprt->xp_tp); + (void) mem_free(xprt, sizeof (SVCXPRT)); +} + +static bool_t +/*ARGSUSED*/ +svc_dg_control(xprt, rq, in) + SVCXPRT *xprt; + const u_int rq; + void *in; +{ + return (FALSE); +} + +static void +svc_dg_ops(xprt) + SVCXPRT *xprt; +{ + static struct xp_ops ops; + static struct xp_ops2 ops2; + extern mutex_t ops_lock; + +/* VARIABLES PROTECTED BY ops_lock: ops */ + + mutex_lock(&ops_lock); + if (ops.xp_recv == NULL) { + ops.xp_recv = svc_dg_recv; + ops.xp_stat = svc_dg_stat; + ops.xp_getargs = svc_dg_getargs; + ops.xp_reply = svc_dg_reply; + ops.xp_freeargs = svc_dg_freeargs; + ops.xp_destroy = svc_dg_destroy; + ops2.xp_control = svc_dg_control; + } + xprt->xp_ops = &ops; + xprt->xp_ops2 = &ops2; + mutex_unlock(&ops_lock); +} + +/* The CACHING COMPONENT */ + +/* + * Could have been a separate file, but some part of it depends upon the + * private structure of the client handle. + * + * Fifo cache for cl server + * Copies pointers to reply buffers into fifo cache + * Buffers are sent again if retransmissions are detected. + */ + +#define SPARSENESS 4 /* 75% sparse */ + +#define ALLOC(type, size) \ + (type *) mem_alloc((sizeof (type) * (size))) + +#define MEMZERO(addr, type, size) \ + (void) memset((void *) (addr), 0, sizeof (type) * (int) (size)) + +#define FREE(addr, type, size) \ + mem_free((addr), (sizeof (type) * (size))) + +/* + * An entry in the cache + */ +typedef struct cache_node *cache_ptr; +struct cache_node { + /* + * Index into cache is xid, proc, vers, prog and address + */ + u_int32_t cache_xid; + rpcproc_t cache_proc; + rpcvers_t cache_vers; + rpcprog_t cache_prog; + struct netbuf cache_addr; + /* + * The cached reply and length + */ + char *cache_reply; + size_t cache_replylen; + /* + * Next node on the list, if there is a collision + */ + cache_ptr cache_next; +}; + +/* + * The entire cache + */ +struct cl_cache { + u_int uc_size; /* size of cache */ + cache_ptr *uc_entries; /* hash table of entries in cache */ + cache_ptr *uc_fifo; /* fifo list of entries in cache */ + u_int uc_nextvictim; /* points to next victim in fifo list */ + rpcprog_t uc_prog; /* saved program number */ + rpcvers_t uc_vers; /* saved version number */ + rpcproc_t uc_proc; /* saved procedure number */ +}; + + +/* + * the hashing function + */ +#define CACHE_LOC(transp, xid) \ + (xid % (SPARSENESS * ((struct cl_cache *) \ + su_data(transp)->su_cache)->uc_size)) + +extern mutex_t dupreq_lock; + +/* + * Enable use of the cache. Returns 1 on success, 0 on failure. + * Note: there is no disable. + */ +static const char cache_enable_str[] = "svc_enablecache: %s %s"; +static const char alloc_err[] = "could not allocate cache "; +static const char enable_err[] = "cache already enabled"; + +int +svc_dg_enablecache(transp, size) + SVCXPRT *transp; + u_int size; +{ + struct svc_dg_data *su = su_data(transp); + struct cl_cache *uc; + + mutex_lock(&dupreq_lock); + if (su->su_cache != NULL) { + (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; +#ifdef RPC_CACHE_DEBUG + struct netconfig *nconf; + char *uaddr; +#endif + + mutex_lock(&dupreq_lock); + /* + * Find space for the new entry, either by + * reusing an old entry, or by mallocing a new one + */ + victim = uc->uc_fifo[uc->uc_nextvictim]; + if (victim != NULL) { + loc = CACHE_LOC(xprt, victim->cache_xid); + for (vicp = &uc->uc_entries[loc]; + *vicp != NULL && *vicp != victim; + vicp = &(*vicp)->cache_next) + ; + if (*vicp == NULL) { + 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 + */ +#ifdef RPC_CACHE_DEBUG + if (nconf = getnetconfigent(xprt->xp_netid)) { + uaddr = taddr2uaddr(nconf, &xprt->xp_rtaddr); + freenetconfigent(nconf); + printf( + "cache set for xid= %x prog=%d vers=%d proc=%d for rmtaddr=%s\n", + su->su_xid, uc->uc_prog, uc->uc_vers, + uc->uc_proc, uaddr); + free(uaddr); + } +#endif + victim->cache_replylen = replylen; + victim->cache_reply = rpc_buffer(xprt); + rpc_buffer(xprt) = newbuf; + xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), + su->su_iosz, XDR_ENCODE); + victim->cache_xid = su->su_xid; + victim->cache_proc = uc->uc_proc; + victim->cache_vers = uc->uc_vers; + victim->cache_prog = uc->uc_prog; + victim->cache_addr = xprt->xp_rtaddr; + victim->cache_addr.buf = ALLOC(char, xprt->xp_rtaddr.len); + (void) memcpy(victim->cache_addr.buf, xprt->xp_rtaddr.buf, + (size_t)xprt->xp_rtaddr.len); + loc = CACHE_LOC(xprt, victim->cache_xid); + victim->cache_next = uc->uc_entries[loc]; + uc->uc_entries[loc] = victim; + uc->uc_fifo[uc->uc_nextvictim++] = victim; + uc->uc_nextvictim %= uc->uc_size; + mutex_unlock(&dupreq_lock); +} + +/* + * Try to get an entry from the cache + * return 1 if found, 0 if not found and set the stage for cache_set() + */ +static int +cache_get(xprt, msg, replyp, replylenp) + SVCXPRT *xprt; + struct rpc_msg *msg; + char **replyp; + size_t *replylenp; +{ + u_int loc; + cache_ptr ent; + struct svc_dg_data *su = su_data(xprt); + struct cl_cache *uc = (struct cl_cache *) su->su_cache; +#ifdef RPC_CACHE_DEBUG + struct netconfig *nconf; + char *uaddr; +#endif + + mutex_lock(&dupreq_lock); + loc = CACHE_LOC(xprt, su->su_xid); + for (ent = uc->uc_entries[loc]; ent != NULL; ent = ent->cache_next) { + if (ent->cache_xid == su->su_xid && + ent->cache_proc == msg->rm_call.cb_proc && + ent->cache_vers == msg->rm_call.cb_vers && + ent->cache_prog == msg->rm_call.cb_prog && + ent->cache_addr.len == xprt->xp_rtaddr.len && + (memcmp(ent->cache_addr.buf, xprt->xp_rtaddr.buf, + xprt->xp_rtaddr.len) == 0)) { +#ifdef RPC_CACHE_DEBUG + if (nconf = getnetconfigent(xprt->xp_netid)) { + uaddr = taddr2uaddr(nconf, &xprt->xp_rtaddr); + freenetconfigent(nconf); + printf( + "cache entry found for xid=%x prog=%d vers=%d proc=%d for rmtaddr=%s\n", + su->su_xid, msg->rm_call.cb_prog, + msg->rm_call.cb_vers, + msg->rm_call.cb_proc, uaddr); + free(uaddr); + } +#endif + *replyp = ent->cache_reply; + *replylenp = ent->cache_replylen; + mutex_unlock(&dupreq_lock); + return (1); + } + } + /* + * Failed to find entry + * Remember a few things so we can do a set later + */ + uc->uc_proc = msg->rm_call.cb_proc; + uc->uc_vers = msg->rm_call.cb_vers; + uc->uc_prog = msg->rm_call.cb_prog; + mutex_unlock(&dupreq_lock); + return (0); +} diff --git a/lib/libc/rpc/svc_generic.c b/lib/libc/rpc/svc_generic.c new file mode 100644 index 000000000000..773118d62e36 --- /dev/null +++ b/lib/libc/rpc/svc_generic.c @@ -0,0 +1,313 @@ +/* $NetBSD: svc_generic.c,v 1.3 2000/07/06 03:10:35 christos Exp $ */ +/* $FreeBSD$ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ + +/* #ident "@(#)svc_generic.c 1.19 94/04/24 SMI" */ + +#if 0 +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)svc_generic.c 1.21 89/02/28 Copyr 1988 Sun Micro"; +#endif +#endif + +/* + * svc_generic.c, Server side for RPC. + * + */ + +#include "reentrant.h" +#include "namespace.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 "un-namespace.h" + +#include "rpc_com.h" + +extern int __svc_vc_setflag __P((SVCXPRT *, int)); + +/* + * The highest level interface for server creation. + * It tries for all the nettokens in that particular class of token + * and returns the number of handles it can create and/or find. + * + * It creates a link list of all the handles it could create. + * If svc_create() is called multiple times, it uses the handle + * created earlier instead of creating a new handle every time. + */ +int +svc_create(dispatch, prognum, versnum, nettype) + void (*dispatch) __P((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); + 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) __P((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 (bindresvport(fd, NULL) < 0) { + memset(&ss, 0, sizeof ss); + ss.ss_family = si.si_af; + ss.ss_len = si.si_alen; + if (_bind(fd, (struct sockaddr *)(void *)&ss, + (socklen_t)si.si_alen) < 0) { + warnx( + "svc_tli_create: could not bind to anonymous port"); + goto freedata; + } + } + _listen(fd, SOMAXCONN); + } else { + if (_bind(fd, + (struct sockaddr *)(void *)&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) { + 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/lib/libc/rpc/svc_raw.c b/lib/libc/rpc/svc_raw.c index 472615253428..5ab10f8a77dc 100644 --- a/lib/libc/rpc/svc_raw.c +++ b/lib/libc/rpc/svc_raw.c @@ -1,3 +1,5 @@ +/* $NetBSD: svc_raw.c,v 1.14 2000/07/06 03:10:35 christos Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -26,12 +28,18 @@ * 2550 Garcia Avenue * Mountain View, California 94043 */ +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ -#if defined(LIBC_SCCS) && !defined(lint) -/*static char *sccsid = "from: @(#)svc_raw.c 1.15 87/08/11 Copyr 1984 Sun Micro";*/ -/*static char *sccsid = "from: @(#)svc_raw.c 2.1 88/07/29 4.0 RPCSRC";*/ +/* #ident "@(#)svc_raw.c 1.16 94/04/24 SMI" */ + +#if 0 +#if defined(SCCSIDS) && !defined(lint) +static char sccsid[] = "@(#)svc_raw.c 1.25 89/01/31 Copyr 1984 Sun Micro"; static char *rcsid = "$FreeBSD$"; #endif +#endif /* * svc_raw.c, This a toy for simple testing and timing. @@ -39,130 +47,214 @@ static char *rcsid = "$FreeBSD$"; * This lets us similate rpc and get rpc (round trip) overhead, without * any interference from the kernal. * - * Copyright (C) 1984, Sun Microsystems, Inc. */ +#include "reentrant.h" +#include "namespace.h" #include <rpc/rpc.h> +#include <sys/types.h> +#include <rpc/raw.h> #include <stdlib.h> +#include "un-namespace.h" + +#ifndef UDPMSGSIZE +#define UDPMSGSIZE 8800 +#endif /* * This is the "network" that we will be moving data over */ -static struct svcraw_private { - char _raw_buf[UDPMSGSIZE]; +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]; -} *svcraw_private; +} *svc_raw_private; -static bool_t svcraw_recv(); -static enum xprt_stat svcraw_stat(); -static bool_t svcraw_getargs(); -static bool_t svcraw_reply(); -static bool_t svcraw_freeargs(); -static void svcraw_destroy(); +extern mutex_t svcraw_lock; -static struct xp_ops server_ops = { - svcraw_recv, - svcraw_stat, - svcraw_getargs, - svcraw_reply, - svcraw_freeargs, - svcraw_destroy -}; +static enum xprt_stat svc_raw_stat __P((SVCXPRT *)); +static bool_t svc_raw_recv __P((SVCXPRT *, struct rpc_msg *)); +static bool_t svc_raw_reply __P((SVCXPRT *, struct rpc_msg *)); +static bool_t svc_raw_getargs __P((SVCXPRT *, xdrproc_t, caddr_t)); +static bool_t svc_raw_freeargs __P((SVCXPRT *, xdrproc_t, caddr_t)); +static void svc_raw_destroy __P((SVCXPRT *)); +static void svc_raw_ops __P((SVCXPRT *)); +static bool_t svc_raw_control __P((SVCXPRT *, const u_int, void *)); + +char *__rpc_rawcombuf = NULL; SVCXPRT * -svcraw_create() +svc_raw_create() { - register struct svcraw_private *srp = svcraw_private; + struct svc_raw_private *srp; +/* VARIABLES PROTECTED BY svcraw_lock: svc_raw_private, srp */ - if (srp == 0) { - srp = (struct svcraw_private *)calloc(1, sizeof (*srp)); - if (srp == 0) - return (0); + mutex_lock(&svcraw_lock); + srp = svc_raw_private; + if (srp == NULL) { + srp = (struct svc_raw_private *)calloc(1, sizeof (*srp)); + if (srp == NULL) { + mutex_unlock(&svcraw_lock); + return (NULL); + } + if (__rpc_rawcombuf == NULL) + __rpc_rawcombuf = calloc(UDPMSGSIZE, sizeof (char)); + srp->raw_buf = __rpc_rawcombuf; /* Share it with the client */ + svc_raw_private = srp; } - srp->server.xp_sock = 0; + srp->server.xp_fd = FD_SETSIZE; srp->server.xp_port = 0; - srp->server.xp_ops = &server_ops; + srp->server.xp_p3 = NULL; + svc_raw_ops(&srp->server); srp->server.xp_verf.oa_base = srp->verf_body; - xdrmem_create(&srp->xdr_stream, srp->_raw_buf, UDPMSGSIZE, XDR_FREE); + 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 -svcraw_stat() +svc_raw_stat(xprt) +SVCXPRT *xprt; /* args needed to satisfy ANSI-C typechecking */ { - return (XPRT_IDLE); } +/*ARGSUSED*/ static bool_t -svcraw_recv(xprt, msg) +svc_raw_recv(xprt, msg) SVCXPRT *xprt; struct rpc_msg *msg; { - register struct svcraw_private *srp = svcraw_private; - register XDR *xdrs; + 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); - if (srp == 0) - return (0); xdrs = &srp->xdr_stream; xdrs->x_op = XDR_DECODE; - XDR_SETPOS(xdrs, 0); - if (! xdr_callmsg(xdrs, msg)) - return (FALSE); + (void) XDR_SETPOS(xdrs, 0); + if (! xdr_callmsg(xdrs, msg)) { + return (FALSE); + } return (TRUE); } +/*ARGSUSED*/ static bool_t -svcraw_reply(xprt, msg) +svc_raw_reply(xprt, msg) SVCXPRT *xprt; struct rpc_msg *msg; { - register struct svcraw_private *srp = svcraw_private; - register XDR *xdrs; + struct svc_raw_private *srp; + XDR *xdrs; - if (srp == 0) + 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; - XDR_SETPOS(xdrs, 0); - if (! xdr_replymsg(xdrs, msg)) - return (FALSE); - (void)XDR_GETPOS(xdrs); /* called just for overhead */ + (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 -svcraw_getargs(xprt, xdr_args, args_ptr) +svc_raw_getargs(xprt, xdr_args, args_ptr) SVCXPRT *xprt; xdrproc_t xdr_args; caddr_t args_ptr; { - register struct svcraw_private *srp = svcraw_private; + struct svc_raw_private *srp; - if (srp == 0) + mutex_lock(&svcraw_lock); + srp = svc_raw_private; + if (srp == NULL) { + mutex_unlock(&svcraw_lock); return (FALSE); - return ((*xdr_args)(&srp->xdr_stream, args_ptr)); + } + mutex_unlock(&svcraw_lock); + return (*xdr_args)(&srp->xdr_stream, args_ptr); } +/*ARGSUSED*/ static bool_t -svcraw_freeargs(xprt, xdr_args, args_ptr) +svc_raw_freeargs(xprt, xdr_args, args_ptr) SVCXPRT *xprt; xdrproc_t xdr_args; caddr_t args_ptr; { - register struct svcraw_private *srp = svcraw_private; - register XDR *xdrs; + struct svc_raw_private *srp; + XDR *xdrs; - if (srp == 0) + 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)); + return (*xdr_args)(xdrs, args_ptr); } +/*ARGSUSED*/ static void -svcraw_destroy() +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/lib/libc/rpc/svc_run.c b/lib/libc/rpc/svc_run.c index bc5b48a7d0dd..78862fe0410d 100644 --- a/lib/libc/rpc/svc_run.c +++ b/lib/libc/rpc/svc_run.c @@ -1,3 +1,5 @@ +/* $NetBSD: svc_run.c,v 1.17 2000/07/06 03:10:35 christos Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -27,6 +29,7 @@ * Mountain View, California 94043 */ +#include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)svc_run.c 1.1 87/10/13 Copyr 1984 Sun Micro";*/ /*static char *sccsid = "from: @(#)svc_run.c 2.1 88/07/29 4.0 RPCSRC";*/ @@ -37,53 +40,54 @@ static char *rcsid = "$FreeBSD$"; * This is the rpc server side idle loop * Wait for input, call server program. */ +#include "reentrant.h" #include "namespace.h" +#include <err.h> +#include <errno.h> #include <rpc/rpc.h> #include <stdio.h> -#include <sys/errno.h> -#include <sys/types.h> -#include <sys/time.h> -#include <unistd.h> -#include <stdlib.h> #include <string.h> +#include <unistd.h> #include "un-namespace.h" -extern int __svc_fdsetsize; -extern fd_set *__svc_fdset; +#include <rpc/rpc.h> void svc_run() { - fd_set *fds; + fd_set readfds; + extern rwlock_t svc_fd_lock; for (;;) { - if (__svc_fdset) { - int bytes = howmany(__svc_fdsetsize, NFDBITS) * - sizeof(fd_mask); - fds = (fd_set *)malloc(bytes); - memcpy(fds, __svc_fdset, bytes); - } else - fds = NULL; - switch (_select(svc_maxfd + 1, fds, NULL, NULL, - (struct timeval *)0)) { + rwlock_rdlock(&svc_fd_lock); + readfds = svc_fdset; + rwlock_unlock(&svc_fd_lock); + switch (_select(svc_maxfd+1, &readfds, NULL, NULL, NULL)) { case -1: + FD_ZERO(&readfds); if (errno == EINTR) { - if (fds) - free(fds); continue; } - perror("svc_run: - select failed"); - if (fds) - free(fds); + warn("svc_run: - select failed"); return; case 0: - if (fds) - free(fds); continue; default: - /* if fds == NULL, _select() can't return a result */ - svc_getreqset2(fds, svc_maxfd + 1); - free(fds); + svc_getreqset(&readfds); } } } + +/* + * This function causes svc_run() to exit by telling it that it has no + * more work to do. + */ +void +svc_exit() +{ + extern rwlock_t svc_fd_lock; + + rwlock_wrlock(&svc_fd_lock); + FD_ZERO(&svc_fdset); + rwlock_unlock(&svc_fd_lock); +} diff --git a/lib/libc/rpc/svc_simple.c b/lib/libc/rpc/svc_simple.c index 1bfaf1c8cd45..fec87b7fcf29 100644 --- a/lib/libc/rpc/svc_simple.c +++ b/lib/libc/rpc/svc_simple.c @@ -1,3 +1,6 @@ +/* $NetBSD: svc_simple.c,v 1.20 2000/07/06 03:10:35 christos Exp $ */ +/* $FreeBSD$ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -26,125 +29,279 @@ * 2550 Garcia Avenue * Mountain View, California 94043 */ +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ -#if defined(LIBC_SCCS) && !defined(lint) -/*static char *sccsid = "from: @(#)svc_simple.c 1.18 87/08/11 Copyr 1984 Sun Micro";*/ -/*static char *sccsid = "from: @(#)svc_simple.c 2.2 88/08/01 4.0 RPCSRC";*/ -static char *rcsid = "$FreeBSD$"; -#endif +/* #pragma ident "@(#)svc_simple.c 1.18 94/04/24 SMI" */ /* * svc_simple.c * Simplified front end to rpc. - * - * Copyright (C) 1984, Sun Microsystems, Inc. */ +/* + * 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 "reentrant.h" +#include "namespace.h" +#include <sys/types.h> +#include <rpc/rpc.h> +#include <rpc/nettype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <rpc/rpc.h> -#include <rpc/pmap_clnt.h> -#include <sys/socket.h> -#include <netdb.h> +#include <err.h> +#include "un-namespace.h" + +#include "rpc_com.h" + +static void universal __P((struct svc_req *, SVCXPRT *)); static struct proglst { - char *(*p_progname)(); - int p_prognum; - int p_procnum; + char *(*p_progname) __P((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 void universal(); -static SVCXPRT *transp; -struct proglst *pl; + +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 -registerrpc(prognum, versnum, procnum, progname, inproc, outproc) - int prognum, versnum, procnum; - char *(*progname)(); - xdrproc_t inproc, outproc; +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) __P((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) { - (void) fprintf(stderr, - "can't reassign procedure number %ld\n", NULLPROC); + warnx("%s can't reassign procedure number %u", rpc_reg_msg, + NULLPROC); return (-1); } - if (transp == 0) { - transp = svcudp_create(RPC_ANYSOCK); - if (transp == NULL) { - (void) fprintf(stderr, "couldn't create an rpc server\n"); - return (-1); - } - } - (void) pmap_unset((u_long)prognum, (u_long)versnum); - if (!svc_register(transp, (u_long)prognum, (u_long)versnum, - universal, IPPROTO_UDP)) { - (void) fprintf(stderr, "couldn't register prog %d vers %d\n", - prognum, versnum); + + 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); } - pl = (struct proglst *)malloc(sizeof(struct proglst)); - if (pl == NULL) { - (void) fprintf(stderr, "registerrpc: out of memory\n"); +/* 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; + 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); + 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); } - pl->p_progname = progname; - pl->p_prognum = prognum; - pl->p_procnum = procnum; - pl->p_inproc = inproc; - pl->p_outproc = outproc; - pl->p_nxt = proglst; - proglst = pl; 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; { - int prog, proc; + rpcprog_t prog; + rpcvers_t vers; + rpcproc_t proc; char *outdata; - char xdrbuf[UDPMSGSIZE]; + 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, xdr_void, NULL) == FALSE) { - (void) fprintf(stderr, "xxx\n"); - exit(1); + 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; - for (pl = proglst; pl != NULL; pl = pl->p_nxt) - if (pl->p_prognum == prog && pl->p_procnum == 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 */ - memset(xdrbuf, 0, sizeof(xdrbuf)); /* required ! */ + 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 != xdr_void) + 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)) { - (void) fprintf(stderr, - "trouble replying to prog %d\n", - pl->p_prognum); - exit(1); + 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; } - (void) fprintf(stderr, "never registered prog %d\n", prog); - exit(1); + 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/lib/libc/rpc/svc_tcp.c b/lib/libc/rpc/svc_tcp.c deleted file mode 100644 index d7e425bf247d..000000000000 --- a/lib/libc/rpc/svc_tcp.c +++ /dev/null @@ -1,487 +0,0 @@ -/* - * Sun RPC is a product of Sun Microsystems, Inc. and is provided for - * unrestricted use provided that this legend is included on all tape - * media and as a part of the software program in whole or part. Users - * may copy or modify Sun RPC without charge, but are not authorized - * to license or distribute it to anyone else except as part of a product or - * program developed by the user. - * - * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE - * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR - * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. - * - * Sun RPC is provided with no support and without any obligation on the - * part of Sun Microsystems, Inc. to assist in its use, correction, - * modification or enhancement. - * - * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE - * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC - * OR ANY PART THEREOF. - * - * In no event will Sun Microsystems, Inc. be liable for any lost revenue - * or profits or other special, indirect and consequential damages, even if - * Sun has been advised of the possibility of such damages. - * - * Sun Microsystems, Inc. - * 2550 Garcia Avenue - * Mountain View, California 94043 - */ - -#if defined(LIBC_SCCS) && !defined(lint) -/*static char *sccsid = "from: @(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro";*/ -/*static char *sccsid = "from: @(#)svc_tcp.c 2.2 88/08/01 4.0 RPCSRC";*/ -static char *rcsid = "$FreeBSD$"; -#endif - -/* - * svc_tcp.c, Server side for TCP/IP based RPC. - * - * Copyright (C) 1984, Sun Microsystems, Inc. - * - * Actually implements two flavors of transporter - - * a tcp rendezvouser (a listner and connection establisher) - * and a record/tcp stream. - */ - -#include "namespace.h" -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <rpc/rpc.h> -#include <sys/socket.h> -#include <sys/ioctl.h> -#include <errno.h> -#include "un-namespace.h" - -/* - * Ops vector for TCP/IP based rpc service handle - */ -static bool_t svctcp_recv(); -static enum xprt_stat svctcp_stat(); -static bool_t svctcp_getargs(); -static bool_t svctcp_reply(); -static bool_t svctcp_freeargs(); -static void svctcp_destroy(); - -static struct xp_ops svctcp_op = { - svctcp_recv, - svctcp_stat, - svctcp_getargs, - svctcp_reply, - svctcp_freeargs, - svctcp_destroy -}; - -/* - * Ops vector for TCP/IP rendezvous handler - */ -static bool_t rendezvous_request(); -static enum xprt_stat rendezvous_stat(); - -static struct xp_ops svctcp_rendezvous_op = { - rendezvous_request, - rendezvous_stat, - (bool_t (*)())abort, - (bool_t (*)())abort, - (bool_t (*)())abort, - svctcp_destroy -}; - -static int readtcp(), writetcp(); -static SVCXPRT *makefd_xprt(); - -struct tcp_rendezvous { /* kept in xprt->xp_p1 */ - u_int sendsize; - u_int recvsize; -}; - -struct tcp_conn { /* kept in xprt->xp_p1 */ - enum xprt_stat strm_stat; - u_long x_id; - XDR xdrs; - char verf_body[MAX_AUTH_BYTES]; -}; - -/* - * Usage: - * xprt = svctcp_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. - * - * If sock<0 then a socket is created, else sock is used. - * If the socket, sock is not bound to a port then svctcp_create - * binds it to an arbitrary port. The routine then starts a tcp - * listener on the socket's associated port. In any (successful) case, - * xprt->xp_sock is the registered socket number and xprt->xp_port is the - * associated port number. - * - * Since tcp 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 * -svctcp_create(sock, sendsize, recvsize) - register int sock; - u_int sendsize; - u_int recvsize; -{ - bool_t madesock = FALSE; - register SVCXPRT *xprt; - register struct tcp_rendezvous *r; - struct sockaddr_in addr; - int len = sizeof(struct sockaddr_in); - int on; - - if (sock == RPC_ANYSOCK) { - if ((sock = _socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { - perror("svctcp_.c - udp socket creation problem"); - return ((SVCXPRT *)NULL); - } - madesock = TRUE; - } - on = 1; - if (_ioctl(sock, FIONBIO, &on) < 0) { - perror("svc_tcp.c - cannot turn on non-blocking mode"); - if (madesock) - (void)_close(sock); - return ((SVCXPRT *)NULL); - } - memset(&addr, 0, sizeof (addr)); - addr.sin_len = sizeof(struct sockaddr_in); - addr.sin_family = AF_INET; - if (bindresvport(sock, &addr)) { - addr.sin_port = 0; - (void)_bind(sock, (struct sockaddr *)&addr, len); - } - if ((_getsockname(sock, (struct sockaddr *)&addr, &len) != 0) || - (_listen(sock, 2) != 0)) { - perror("svctcp_.c - cannot getsockname or listen"); - if (madesock) - (void)_close(sock); - return ((SVCXPRT *)NULL); - } - r = (struct tcp_rendezvous *)mem_alloc(sizeof(*r)); - if (r == NULL) { - (void) fprintf(stderr, "svctcp_create: out of memory\n"); - return (NULL); - } - r->sendsize = sendsize; - r->recvsize = recvsize; - xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT)); - if (xprt == NULL) { - (void) fprintf(stderr, "svctcp_create: out of memory\n"); - return (NULL); - } - xprt->xp_p2 = NULL; - xprt->xp_p1 = (caddr_t)r; - xprt->xp_verf = _null_auth; - xprt->xp_ops = &svctcp_rendezvous_op; - xprt->xp_port = ntohs(addr.sin_port); - xprt->xp_sock = sock; - xprt_register(xprt); - return (xprt); -} - -/* - * Like svtcp_create(), except the routine takes any *open* UNIX file - * descriptor as its first input. - */ -SVCXPRT * -svcfd_create(fd, sendsize, recvsize) - int fd; - u_int sendsize; - u_int recvsize; -{ - - return (makefd_xprt(fd, sendsize, recvsize)); -} - -static SVCXPRT * -makefd_xprt(fd, sendsize, recvsize) - int fd; - u_int sendsize; - u_int recvsize; -{ - register SVCXPRT *xprt; - register struct tcp_conn *cd; - - xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT)); - if (xprt == (SVCXPRT *)NULL) { - (void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n"); - goto done; - } - cd = (struct tcp_conn *)mem_alloc(sizeof(struct tcp_conn)); - if (cd == (struct tcp_conn *)NULL) { - (void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n"); - mem_free((char *) xprt, sizeof(SVCXPRT)); - xprt = (SVCXPRT *)NULL; - goto done; - } - cd->strm_stat = XPRT_IDLE; - xdrrec_create(&(cd->xdrs), sendsize, recvsize, - (caddr_t)xprt, readtcp, writetcp); - xprt->xp_p2 = NULL; - xprt->xp_p1 = (caddr_t)cd; - xprt->xp_verf.oa_base = cd->verf_body; - xprt->xp_addrlen = 0; - xprt->xp_ops = &svctcp_op; /* truely deals with calls */ - xprt->xp_port = 0; /* this is a connection, not a rendezvouser */ - xprt->xp_sock = fd; - xprt_register(xprt); - done: - return (xprt); -} - -static bool_t -rendezvous_request(xprt) - register SVCXPRT *xprt; -{ - int sock; - struct tcp_rendezvous *r; - struct sockaddr_in addr; - int len; - int off; - - r = (struct tcp_rendezvous *)xprt->xp_p1; - again: - len = sizeof(struct sockaddr_in); - if ((sock = _accept(xprt->xp_sock, (struct sockaddr *)&addr, - &len)) < 0) { - if (errno == EINTR) - goto again; - return (FALSE); - } - /* - * Guard against FTP bounce attacks. - */ - if (addr.sin_port == htons(20)) { - _close(sock); - return (FALSE); - } - /* - * The listening socket is in FIONBIO mode and we inherit it. - */ - off = 0; - if (_ioctl(sock, FIONBIO, &off) < 0) { - _close(sock); - return (FALSE); - } - /* - * make a new transporter (re-uses xprt) - */ - xprt = makefd_xprt(sock, r->sendsize, r->recvsize); - xprt->xp_raddr = addr; - xprt->xp_addrlen = len; - return (FALSE); /* there is never an rpc msg to be processed */ -} - -static enum xprt_stat -rendezvous_stat() -{ - - return (XPRT_IDLE); -} - -static void -svctcp_destroy(xprt) - register SVCXPRT *xprt; -{ - register struct tcp_conn *cd = (struct tcp_conn *)xprt->xp_p1; - - xprt_unregister(xprt); - (void)_close(xprt->xp_sock); - if (xprt->xp_port != 0) { - /* a rendezvouser socket */ - xprt->xp_port = 0; - } else { - /* an actual connection socket */ - XDR_DESTROY(&(cd->xdrs)); - } - mem_free((caddr_t)cd, sizeof(struct tcp_conn)); - mem_free((caddr_t)xprt, sizeof(SVCXPRT)); -} - -/* - * All read operations timeout after 35 seconds. - * A timeout is fatal for the connection. - */ -static struct timeval wait_per_try = { 35, 0 }; - -/* - * reads data from the tcp conection. - * any error is fatal and the connection is closed. - * (And a read of zero bytes is a half closed stream => error.) - * - * Note: we have to be careful here not to allow ourselves to become - * blocked too long in this routine. While we're waiting for data from one - * client, another client may be trying to connect. To avoid this situation, - * some code from svc_run() is transplanted here: the _select() loop checks - * all RPC descriptors including the one we want and calls svc_getreqset2() - * to handle new requests if any are detected. - */ -static int -readtcp(xprt, buf, len) - register SVCXPRT *xprt; - caddr_t buf; - register int len; -{ - register int sock = xprt->xp_sock; - struct timeval start, delta, tv; - struct timeval tmp1, tmp2; - fd_set *fds; - extern fd_set *__svc_fdset; - extern int __svc_fdsetsize; - - delta = wait_per_try; - fds = NULL; - gettimeofday(&start, NULL); - do { - int bytes = howmany(__svc_fdsetsize, NFDBITS) * - sizeof(fd_mask); - if (fds != NULL) - free(fds); - fds = (fd_set *)malloc(bytes); - if (fds == NULL) - goto fatal_err; - memcpy(fds, __svc_fdset, bytes); - - /* XXX we know the other bits are still clear */ - FD_SET(sock, fds); - tv = delta; /* in case _select() implements writeback */ - switch (_select(svc_maxfd + 1, fds, NULL, NULL, &tv)) { - case -1: - FD_ZERO(fds); - if (errno != EINTR) - goto fatal_err; - gettimeofday(&tmp1, NULL); - timersub(&tmp1, &start, &tmp2); - timersub(&wait_per_try, &tmp2, &tmp1); - if (tmp1.tv_sec < 0 || !timerisset(&tmp1)) - goto fatal_err; - delta = tmp1; - continue; - case 0: - goto fatal_err; - default: - if (!FD_ISSET(sock, fds)) { - svc_getreqset2(fds, svc_maxfd + 1); - gettimeofday(&tmp1, NULL); - timersub(&tmp1, &start, &tmp2); - timersub(&wait_per_try, &tmp2, &tmp1); - if (tmp1.tv_sec < 0 || !timerisset(&tmp1)) - goto fatal_err; - delta = tmp1; - continue; - } - } - } while (!FD_ISSET(sock, fds)); - if ((len = _read(sock, buf, len)) > 0) { - if (fds != NULL) - free(fds); - return (len); - } -fatal_err: - ((struct tcp_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED; - if (fds != NULL) - free(fds); - return (-1); -} - -/* - * writes data to the tcp connection. - * Any error is fatal and the connection is closed. - */ -static int -writetcp(xprt, buf, len) - register SVCXPRT *xprt; - caddr_t buf; - int len; -{ - register int i, cnt; - - for (cnt = len; cnt > 0; cnt -= i, buf += i) { - if ((i = _write(xprt->xp_sock, buf, cnt)) < 0) { - ((struct tcp_conn *)(xprt->xp_p1))->strm_stat = - XPRT_DIED; - return (-1); - } - } - return (len); -} - -static enum xprt_stat -svctcp_stat(xprt) - SVCXPRT *xprt; -{ - register struct tcp_conn *cd = - (struct tcp_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 -svctcp_recv(xprt, msg) - SVCXPRT *xprt; - register struct rpc_msg *msg; -{ - register struct tcp_conn *cd = - (struct tcp_conn *)(xprt->xp_p1); - register XDR *xdrs = &(cd->xdrs); - - xdrs->x_op = XDR_DECODE; - (void)xdrrec_skiprecord(xdrs); - if (xdr_callmsg(xdrs, msg)) { - cd->x_id = msg->rm_xid; - return (TRUE); - } - cd->strm_stat = XPRT_DIED; /* XXXX */ - return (FALSE); -} - -static bool_t -svctcp_getargs(xprt, xdr_args, args_ptr) - SVCXPRT *xprt; - xdrproc_t xdr_args; - caddr_t args_ptr; -{ - - return ((*xdr_args)(&(((struct tcp_conn *)(xprt->xp_p1))->xdrs), args_ptr)); -} - -static bool_t -svctcp_freeargs(xprt, xdr_args, args_ptr) - SVCXPRT *xprt; - xdrproc_t xdr_args; - caddr_t args_ptr; -{ - register XDR *xdrs = - &(((struct tcp_conn *)(xprt->xp_p1))->xdrs); - - xdrs->x_op = XDR_FREE; - return ((*xdr_args)(xdrs, args_ptr)); -} - -static bool_t -svctcp_reply(xprt, msg) - SVCXPRT *xprt; - register struct rpc_msg *msg; -{ - register struct tcp_conn *cd = - (struct tcp_conn *)(xprt->xp_p1); - register XDR *xdrs = &(cd->xdrs); - register bool_t stat; - - xdrs->x_op = XDR_ENCODE; - msg->rm_xid = cd->x_id; - stat = xdr_replymsg(xdrs, msg); - (void)xdrrec_endofrecord(xdrs, TRUE); - return (stat); -} diff --git a/lib/libc/rpc/svc_udp.c b/lib/libc/rpc/svc_udp.c deleted file mode 100644 index 0abd48696bdb..000000000000 --- a/lib/libc/rpc/svc_udp.c +++ /dev/null @@ -1,482 +0,0 @@ -/* - * Sun RPC is a product of Sun Microsystems, Inc. and is provided for - * unrestricted use provided that this legend is included on all tape - * media and as a part of the software program in whole or part. Users - * may copy or modify Sun RPC without charge, but are not authorized - * to license or distribute it to anyone else except as part of a product or - * program developed by the user. - * - * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE - * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR - * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. - * - * Sun RPC is provided with no support and without any obligation on the - * part of Sun Microsystems, Inc. to assist in its use, correction, - * modification or enhancement. - * - * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE - * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC - * OR ANY PART THEREOF. - * - * In no event will Sun Microsystems, Inc. be liable for any lost revenue - * or profits or other special, indirect and consequential damages, even if - * Sun has been advised of the possibility of such damages. - * - * Sun Microsystems, Inc. - * 2550 Garcia Avenue - * Mountain View, California 94043 - */ - -#if defined(LIBC_SCCS) && !defined(lint) -/*static char *sccsid = "from: @(#)svc_udp.c 1.24 87/08/11 Copyr 1984 Sun Micro";*/ -/*static char *sccsid = "from: @(#)svc_udp.c 2.2 88/07/29 4.0 RPCSRC";*/ -static char *rcsid = "$FreeBSD$"; -#endif - -/* - * svc_udp.c, - * Server side for UDP/IP based RPC. (Does some caching in the hopes of - * achieving execute-at-most-once semantics.) - * - * Copyright (C) 1984, Sun Microsystems, Inc. - */ - -#include "namespace.h" -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <rpc/rpc.h> -#include <sys/socket.h> -#include <errno.h> -#include "un-namespace.h" - -#define rpc_buffer(xprt) ((xprt)->xp_p1) -#define MAX(a, b) ((a > b) ? a : b) - -static bool_t svcudp_recv(); -static bool_t svcudp_reply(); -static enum xprt_stat svcudp_stat(); -static bool_t svcudp_getargs(); -static bool_t svcudp_freeargs(); -static void svcudp_destroy(); -static void cache_set __P((SVCXPRT *, u_long)); -static int cache_get __P((SVCXPRT *, struct rpc_msg *, char **, u_long *)); - -static struct xp_ops svcudp_op = { - svcudp_recv, - svcudp_stat, - svcudp_getargs, - svcudp_reply, - svcudp_freeargs, - svcudp_destroy -}; - -/* - * kept in xprt->xp_p2 - */ -struct svcudp_data { - u_int su_iosz; /* byte size of send.recv buffer */ - u_long su_xid; /* transaction id */ - XDR su_xdrs; /* XDR handle */ - char su_verfbody[MAX_AUTH_BYTES]; /* verifier body */ - char * su_cache; /* cached data, NULL if no cache */ -}; -#define su_data(xprt) ((struct svcudp_data *)(xprt->xp_p2)) - -/* - * Usage: - * xprt = svcudp_create(sock); - * - * If sock<0 then a socket is created, else sock is used. - * If the socket, sock is not bound to a port then svcudp_create - * binds it to an arbitrary port. In any (successful) case, - * xprt->xp_sock is the registered socket number and xprt->xp_port is the - * associated port number. - * Once *xprt is initialized, it is registered as a transporter; - * see (svc.h, xprt_register). - * The routines returns NULL if a problem occurred. - */ -SVCXPRT * -svcudp_bufcreate(sock, sendsz, recvsz) - register int sock; - u_int sendsz, recvsz; -{ - bool_t madesock = FALSE; - register SVCXPRT *xprt; - register struct svcudp_data *su; - struct sockaddr_in addr; - int len = sizeof(struct sockaddr_in); - - if (sock == RPC_ANYSOCK) { - if ((sock = _socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { - perror("svcudp_create: socket creation problem"); - return ((SVCXPRT *)NULL); - } - madesock = TRUE; - } - memset((char *)&addr, 0, sizeof (addr)); - addr.sin_len = sizeof(struct sockaddr_in); - addr.sin_family = AF_INET; - if (bindresvport(sock, &addr)) { - addr.sin_port = 0; - (void)_bind(sock, (struct sockaddr *)&addr, len); - } - if (_getsockname(sock, (struct sockaddr *)&addr, &len) != 0) { - perror("svcudp_create - cannot getsockname"); - if (madesock) - (void)_close(sock); - return ((SVCXPRT *)NULL); - } - xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT)); - if (xprt == NULL) { - (void)fprintf(stderr, "svcudp_create: out of memory\n"); - return (NULL); - } - su = (struct svcudp_data *)mem_alloc(sizeof(*su)); - if (su == NULL) { - (void)fprintf(stderr, "svcudp_create: out of memory\n"); - return (NULL); - } - su->su_iosz = ((MAX(sendsz, recvsz) + 3) / 4) * 4; - if ((rpc_buffer(xprt) = mem_alloc(su->su_iosz)) == NULL) { - (void)fprintf(stderr, "svcudp_create: out of memory\n"); - return (NULL); - } - xdrmem_create( - &(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, XDR_DECODE); - su->su_cache = NULL; - xprt->xp_p2 = (caddr_t)su; - xprt->xp_verf.oa_base = su->su_verfbody; - xprt->xp_ops = &svcudp_op; - xprt->xp_port = ntohs(addr.sin_port); - xprt->xp_sock = sock; - xprt_register(xprt); - return (xprt); -} - -SVCXPRT * -svcudp_create(sock) - int sock; -{ - - return(svcudp_bufcreate(sock, UDPMSGSIZE, UDPMSGSIZE)); -} - -static enum xprt_stat -svcudp_stat(xprt) - SVCXPRT *xprt; -{ - - return (XPRT_IDLE); -} - -static bool_t -svcudp_recv(xprt, msg) - register SVCXPRT *xprt; - struct rpc_msg *msg; -{ - register struct svcudp_data *su = su_data(xprt); - register XDR *xdrs = &(su->su_xdrs); - register int rlen; - char *reply; - u_long replylen; - - again: - xprt->xp_addrlen = sizeof(struct sockaddr_in); - rlen = _recvfrom(xprt->xp_sock, rpc_buffer(xprt), (int) su->su_iosz, - 0, (struct sockaddr *)&(xprt->xp_raddr), &(xprt->xp_addrlen)); - if (rlen == -1 && errno == EINTR) - goto again; - if (rlen == -1 || rlen < 4*sizeof(u_int32_t)) - return (FALSE); - xdrs->x_op = XDR_DECODE; - XDR_SETPOS(xdrs, 0); - if (! xdr_callmsg(xdrs, msg)) - return (FALSE); - su->su_xid = msg->rm_xid; - if (su->su_cache != NULL) { - if (cache_get(xprt, msg, &reply, &replylen)) { - (void) _sendto(xprt->xp_sock, reply, (int) replylen, 0, - (struct sockaddr *) &xprt->xp_raddr, xprt->xp_addrlen); - return (TRUE); - } - } - return (TRUE); -} - -static bool_t -svcudp_reply(xprt, msg) - register SVCXPRT *xprt; - struct rpc_msg *msg; -{ - register struct svcudp_data *su = su_data(xprt); - register XDR *xdrs = &(su->su_xdrs); - register int slen; - register bool_t stat = FALSE; - - xdrs->x_op = XDR_ENCODE; - XDR_SETPOS(xdrs, 0); - msg->rm_xid = su->su_xid; - if (xdr_replymsg(xdrs, msg)) { - slen = (int)XDR_GETPOS(xdrs); - if (_sendto(xprt->xp_sock, rpc_buffer(xprt), slen, 0, - (struct sockaddr *)&(xprt->xp_raddr), xprt->xp_addrlen) - == slen) { - stat = TRUE; - if (su->su_cache && slen >= 0) { - cache_set(xprt, (u_long) slen); - } - } - } - return (stat); -} - -static bool_t -svcudp_getargs(xprt, xdr_args, args_ptr) - SVCXPRT *xprt; - xdrproc_t xdr_args; - caddr_t args_ptr; -{ - - return ((*xdr_args)(&(su_data(xprt)->su_xdrs), args_ptr)); -} - -static bool_t -svcudp_freeargs(xprt, xdr_args, args_ptr) - SVCXPRT *xprt; - xdrproc_t xdr_args; - caddr_t args_ptr; -{ - register XDR *xdrs = &(su_data(xprt)->su_xdrs); - - xdrs->x_op = XDR_FREE; - return ((*xdr_args)(xdrs, args_ptr)); -} - -static void -svcudp_destroy(xprt) - register SVCXPRT *xprt; -{ - register struct svcudp_data *su = su_data(xprt); - - xprt_unregister(xprt); - (void)_close(xprt->xp_sock); - XDR_DESTROY(&(su->su_xdrs)); - mem_free(rpc_buffer(xprt), su->su_iosz); - mem_free((caddr_t)su, sizeof(struct svcudp_data)); - mem_free((caddr_t)xprt, sizeof(SVCXPRT)); -} - - -/***********this could be a separate file*********************/ - -/* - * Fifo cache for udp server - * Copies pointers to reply buffers into fifo cache - * Buffers are sent again if retransmissions are detected. - */ - -#define SPARSENESS 4 /* 75% sparse */ - -#define CACHE_PERROR(msg) \ - (void) fprintf(stderr,"%s\n", msg) - -#define ALLOC(type, size) \ - (type *) mem_alloc((unsigned) (sizeof(type) * (size))) - -#define BZERO(addr, type, size) \ - memset((char *) addr, 0, sizeof(type) * (int) (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_long cache_xid; - u_long cache_proc; - u_long cache_vers; - u_long cache_prog; - struct sockaddr_in cache_addr; - /* - * The cached reply and length - */ - char * cache_reply; - u_long cache_replylen; - /* - * Next node on the list, if there is a collision - */ - cache_ptr cache_next; -}; - - - -/* - * The entire cache - */ -struct udp_cache { - u_long 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_long uc_nextvictim; /* points to next victim in fifo list */ - u_long uc_prog; /* saved program number */ - u_long uc_vers; /* saved version number */ - u_long uc_proc; /* saved procedure number */ - struct sockaddr_in uc_addr; /* saved caller's address */ -}; - - -/* - * the hashing function - */ -#define CACHE_LOC(transp, xid) \ - (xid % (SPARSENESS*((struct udp_cache *) su_data(transp)->su_cache)->uc_size)) - - -/* - * Enable use of the cache. - * Note: there is no disable. - */ -int svcudp_enablecache(transp, size) - SVCXPRT *transp; - u_long size; -{ - struct svcudp_data *su = su_data(transp); - struct udp_cache *uc; - - if (su->su_cache != NULL) { - CACHE_PERROR("enablecache: cache already enabled"); - return(0); - } - uc = ALLOC(struct udp_cache, 1); - if (uc == NULL) { - CACHE_PERROR("enablecache: could not allocate cache"); - return(0); - } - uc->uc_size = size; - uc->uc_nextvictim = 0; - uc->uc_entries = ALLOC(cache_ptr, size * SPARSENESS); - if (uc->uc_entries == NULL) { - CACHE_PERROR("enablecache: could not allocate cache data"); - return(0); - } - BZERO(uc->uc_entries, cache_ptr, size * SPARSENESS); - uc->uc_fifo = ALLOC(cache_ptr, size); - if (uc->uc_fifo == NULL) { - CACHE_PERROR("enablecache: could not allocate cache fifo"); - return(0); - } - BZERO(uc->uc_fifo, cache_ptr, size); - su->su_cache = (char *) uc; - return(1); -} - - -/* - * Set an entry in the cache - */ -static void -cache_set(xprt, replylen) - SVCXPRT *xprt; - u_long replylen; -{ - register cache_ptr victim; - register cache_ptr *vicp; - register struct svcudp_data *su = su_data(xprt); - struct udp_cache *uc = (struct udp_cache *) su->su_cache; - u_int loc; - char *newbuf; - - /* - * 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) { - CACHE_PERROR("cache_set: victim not found"); - return; - } - *vicp = victim->cache_next; /* remote from cache */ - newbuf = victim->cache_reply; - } else { - victim = ALLOC(struct cache_node, 1); - if (victim == NULL) { - CACHE_PERROR("cache_set: victim alloc failed"); - return; - } - newbuf = mem_alloc(su->su_iosz); - if (newbuf == NULL) { - CACHE_PERROR("cache_set: could not allocate new rpc_buffer"); - return; - } - } - - /* - * Store it away - */ - 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 = uc->uc_addr; - 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; -} - -/* - * Try to get an entry from the cache - * return 1 if found, 0 if not found - */ -static int -cache_get(xprt, msg, replyp, replylenp) - SVCXPRT *xprt; - struct rpc_msg *msg; - char **replyp; - u_long *replylenp; -{ - u_int loc; - register cache_ptr ent; - register struct svcudp_data *su = su_data(xprt); - register struct udp_cache *uc = (struct udp_cache *) su->su_cache; - -# define EQADDR(a1, a2) (memcmp(&a1, &a2, sizeof(a1)) == 0) - - 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 == uc->uc_proc && - ent->cache_vers == uc->uc_vers && - ent->cache_prog == uc->uc_prog && - EQADDR(ent->cache_addr, uc->uc_addr)) { - *replyp = ent->cache_reply; - *replylenp = ent->cache_replylen; - 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; - uc->uc_addr = xprt->xp_raddr; - return(0); -} - diff --git a/lib/libc/rpc/svc_unix.c b/lib/libc/rpc/svc_unix.c deleted file mode 100644 index 5e77c19287cc..000000000000 --- a/lib/libc/rpc/svc_unix.c +++ /dev/null @@ -1,533 +0,0 @@ -/* - * Sun RPC is a product of Sun Microsystems, Inc. and is provided for - * unrestricted use provided that this legend is included on all tape - * media and as a part of the software program in whole or part. Users - * may copy or modify Sun RPC without charge, but are not authorized - * to license or distribute it to anyone else except as part of a product or - * program developed by the user. - * - * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE - * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR - * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. - * - * Sun RPC is provided with no support and without any obligation on the - * part of Sun Microsystems, Inc. to assist in its use, correction, - * modification or enhancement. - * - * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE - * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC - * OR ANY PART THEREOF. - * - * In no event will Sun Microsystems, Inc. be liable for any lost revenue - * or profits or other special, indirect and consequential damages, even if - * Sun has been advised of the possibility of such damages. - * - * Sun Microsystems, Inc. - * 2550 Garcia Avenue - * Mountain View, California 94043 - */ - -#if defined(LIBC_SCCS) && !defined(lint) -/*static char *sccsid = "from: @(#)svc_unix.c 1.21 87/08/11 Copyr 1984 Sun Micro";*/ -/*static char *sccsid = "from: @(#)svc_unix.c 2.2 88/08/01 4.0 RPCSRC";*/ -static char *rcsid = "$FreeBSD$"; -#endif - -/* - * svc_unix.c, Server side for TCP/IP based RPC. - * - * Copyright (C) 1984, Sun Microsystems, Inc. - * - * Actually implements two flavors of transporter - - * a unix rendezvouser (a listner and connection establisher) - * and a record/unix stream. - */ - -#include "namespace.h" -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <rpc/rpc.h> -#include <sys/socket.h> -#include <sys/un.h> -#include <sys/uio.h> -#include <errno.h> -#include "un-namespace.h" - -/* - * Ops vector for AF_UNIX based rpc service handle - */ -static bool_t svcunix_recv(); -static enum xprt_stat svcunix_stat(); -static bool_t svcunix_getargs(); -static bool_t svcunix_reply(); -static bool_t svcunix_freeargs(); -static void svcunix_destroy(); - -static struct xp_ops svcunix_op = { - svcunix_recv, - svcunix_stat, - svcunix_getargs, - svcunix_reply, - svcunix_freeargs, - svcunix_destroy -}; - -/* - * Ops vector for TCP/IP rendezvous handler - */ -static bool_t rendezvous_request(); -static enum xprt_stat rendezvous_stat(); - -static struct xp_ops svcunix_rendezvous_op = { - rendezvous_request, - rendezvous_stat, - (bool_t (*)())abort, - (bool_t (*)())abort, - (bool_t (*)())abort, - svcunix_destroy -}; - -static int readunix(), writeunix(); -static SVCXPRT *makefd_xprt(); - -struct unix_rendezvous { /* kept in xprt->xp_p1 */ - u_int sendsize; - u_int recvsize; -}; - -struct unix_conn { /* kept in xprt->xp_p1 */ - enum xprt_stat strm_stat; - u_long x_id; - XDR xdrs; - char verf_body[MAX_AUTH_BYTES]; -}; - - -struct cmessage { - struct cmsghdr cmsg; - struct cmsgcred cmcred; -}; - -static struct cmessage cm; - -static int __msgread(sock, buf, cnt) - int sock; - void *buf; - size_t cnt; -{ - struct iovec iov[1]; - struct msghdr msg; - - bzero((char *)&cm, sizeof(cm)); - iov[0].iov_base = buf; - iov[0].iov_len = cnt; - - msg.msg_iov = iov; - msg.msg_iovlen = 1; - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_control = (caddr_t)&cm; - msg.msg_controllen = sizeof(struct cmessage); - msg.msg_flags = 0; - - return(_recvmsg(sock, &msg, 0)); -} - -static int __msgwrite(sock, buf, cnt) - int sock; - void *buf; - size_t cnt; -{ - struct iovec iov[1]; - struct msghdr msg; - - bzero((char *)&cm, sizeof(cm)); - iov[0].iov_base = buf; - iov[0].iov_len = cnt; - - cm.cmsg.cmsg_type = SCM_CREDS; - cm.cmsg.cmsg_level = SOL_SOCKET; - cm.cmsg.cmsg_len = sizeof(struct cmessage); - - msg.msg_iov = iov; - msg.msg_iovlen = 1; - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_control = (caddr_t)&cm; - msg.msg_controllen = sizeof(struct cmessage); - msg.msg_flags = 0; - - return(_sendmsg(sock, &msg, 0)); -} - -/* - * Usage: - * xprt = svcunix_create(sock, send_buf_size, recv_buf_size); - * - * Creates, registers, and returns a (rpc) unix 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. - * - * If sock<0 then a socket is created, else sock is used. - * If the socket, sock is not bound to a port then svcunix_create - * binds it to an arbitrary port. The routine then starts a unix - * listener on the socket's associated port. In any (successful) case, - * xprt->xp_sock is the registered socket number and xprt->xp_port is the - * associated port number. - * - * Since unix 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 * -svcunix_create(sock, sendsize, recvsize, path) - register int sock; - u_int sendsize; - u_int recvsize; - char *path; -{ - bool_t madesock = FALSE; - register SVCXPRT *xprt; - register struct unix_rendezvous *r; - struct sockaddr_un addr; - int len = sizeof(struct sockaddr_un); - - if (sock == RPC_ANYSOCK) { - if ((sock = _socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { - perror("svc_unix.c - AF_UNIX socket creation problem"); - return ((SVCXPRT *)NULL); - } - madesock = TRUE; - } - memset(&addr, 0, sizeof (addr)); - addr.sun_family = AF_UNIX; - strcpy(addr.sun_path, path); - len = strlen(addr.sun_path) + sizeof(addr.sun_family) + - sizeof(addr.sun_len) + 1; - addr.sun_len = len; - - _bind(sock, (struct sockaddr *)&addr, len); - - if ((_getsockname(sock, (struct sockaddr *)&addr, &len) != 0) || - (_listen(sock, 2) != 0)) { - perror("svc_unix.c - cannot getsockname or listen"); - if (madesock) - (void)_close(sock); - return ((SVCXPRT *)NULL); - } - r = (struct unix_rendezvous *)mem_alloc(sizeof(*r)); - if (r == NULL) { - (void) fprintf(stderr, "svcunix_create: out of memory\n"); - return (NULL); - } - r->sendsize = sendsize; - r->recvsize = recvsize; - xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT)); - if (xprt == NULL) { - (void) fprintf(stderr, "svcunix_create: out of memory\n"); - return (NULL); - } - xprt->xp_p2 = NULL; - xprt->xp_p1 = (caddr_t)r; - xprt->xp_verf = _null_auth; - xprt->xp_ops = &svcunix_rendezvous_op; - xprt->xp_port = -1 /*ntohs(addr.sin_port)*/; - xprt->xp_sock = sock; - xprt_register(xprt); - return (xprt); -} - -/* - * Like svunix_create(), except the routine takes any *open* UNIX file - * descriptor as its first input. - */ -SVCXPRT * -svcunixfd_create(fd, sendsize, recvsize) - int fd; - u_int sendsize; - u_int recvsize; -{ - - return (makefd_xprt(fd, sendsize, recvsize)); -} - -static SVCXPRT * -makefd_xprt(fd, sendsize, recvsize) - int fd; - u_int sendsize; - u_int recvsize; -{ - register SVCXPRT *xprt; - register struct unix_conn *cd; - - xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT)); - if (xprt == (SVCXPRT *)NULL) { - (void) fprintf(stderr, "svc_unix: makefd_xprt: out of memory\n"); - goto done; - } - cd = (struct unix_conn *)mem_alloc(sizeof(struct unix_conn)); - if (cd == (struct unix_conn *)NULL) { - (void) fprintf(stderr, "svc_unix: makefd_xprt: out of memory\n"); - mem_free((char *) xprt, sizeof(SVCXPRT)); - xprt = (SVCXPRT *)NULL; - goto done; - } - cd->strm_stat = XPRT_IDLE; - xdrrec_create(&(cd->xdrs), sendsize, recvsize, - (caddr_t)xprt, readunix, writeunix); - xprt->xp_p2 = NULL; - xprt->xp_p1 = (caddr_t)cd; - xprt->xp_verf.oa_base = cd->verf_body; - xprt->xp_addrlen = 0; - xprt->xp_ops = &svcunix_op; /* truely deals with calls */ - xprt->xp_port = 0; /* this is a connection, not a rendezvouser */ - xprt->xp_sock = fd; - xprt_register(xprt); - done: - return (xprt); -} - -static bool_t -rendezvous_request(xprt) - register SVCXPRT *xprt; -{ - int sock; - struct unix_rendezvous *r; - struct sockaddr_un addr; - struct sockaddr_in in_addr; - int len; - - r = (struct unix_rendezvous *)xprt->xp_p1; - again: - len = sizeof(struct sockaddr_in); - if ((sock = _accept(xprt->xp_sock, (struct sockaddr *)&addr, - &len)) < 0) { - if (errno == EINTR) - goto again; - return (FALSE); - } - - /* - * make a new transporter (re-uses xprt) - */ - bzero((char *)&in_addr, sizeof(in_addr)); - in_addr.sin_family = AF_UNIX; - xprt = makefd_xprt(sock, r->sendsize, r->recvsize); - xprt->xp_raddr = in_addr; - xprt->xp_addrlen = len; - return (FALSE); /* there is never an rpc msg to be processed */ -} - -static enum xprt_stat -rendezvous_stat() -{ - - return (XPRT_IDLE); -} - -static void -svcunix_destroy(xprt) - register SVCXPRT *xprt; -{ - register struct unix_conn *cd = (struct unix_conn *)xprt->xp_p1; - - xprt_unregister(xprt); - (void)_close(xprt->xp_sock); - if (xprt->xp_port != 0) { - /* a rendezvouser socket */ - xprt->xp_port = 0; - } else { - /* an actual connection socket */ - XDR_DESTROY(&(cd->xdrs)); - } - mem_free((caddr_t)cd, sizeof(struct unix_conn)); - mem_free((caddr_t)xprt, sizeof(SVCXPRT)); -} - -/* - * All read operations timeout after 35 seconds. - * A timeout is fatal for the connection. - */ -static struct timeval wait_per_try = { 35, 0 }; - -/* - * reads data from the unix conection. - * any error is fatal and the connection is closed. - * (And a read of zero bytes is a half closed stream => error.) - * - * Note: we have to be careful here not to allow ourselves to become - * blocked too long in this routine. While we're waiting for data from one - * client, another client may be trying to connect. To avoid this situation, - * some code from svc_run() is transplanted here: the _select() loop checks - * all RPC descriptors including the one we want and calls svc_getreqset2() - * to handle new requests if any are detected. - */ -static int -readunix(xprt, buf, len) - register SVCXPRT *xprt; - caddr_t buf; - register int len; -{ - register int sock = xprt->xp_sock; - struct timeval start, delta, tv; - struct timeval tmp1, tmp2; - fd_set *fds; - extern fd_set *__svc_fdset; - extern int __svc_fdsetsize; - - delta = wait_per_try; - fds = NULL; - gettimeofday(&start, NULL); - do { - int bytes = howmany(__svc_fdsetsize, NFDBITS) * - sizeof(fd_mask); - if (fds != NULL) - free(fds); - fds = (fd_set *)malloc(bytes); - if (fds == NULL) - goto fatal_err; - memcpy(fds, __svc_fdset, bytes); - - /* XXX we know the other bits are still clear */ - FD_SET(sock, fds); - tv = delta; /* in case _select() implements writeback */ - switch (_select(svc_maxfd + 1, fds, NULL, NULL, &tv)) { - case -1: - FD_ZERO(fds); - if (errno != EINTR) - goto fatal_err; - gettimeofday(&tmp1, NULL); - timersub(&tmp1, &start, &tmp2); - timersub(&wait_per_try, &tmp2, &tmp1); - if (tmp1.tv_sec < 0 || !timerisset(&tmp1)) - goto fatal_err; - delta = tmp1; - continue; - case 0: - goto fatal_err; - default: - if (!FD_ISSET(sock, fds)) { - svc_getreqset2(fds, svc_maxfd + 1); - gettimeofday(&tmp1, NULL); - timersub(&tmp1, &start, &tmp2); - timersub(&wait_per_try, &tmp2, &tmp1); - if (tmp1.tv_sec < 0 || !timerisset(&tmp1)) - goto fatal_err; - delta = tmp1; - continue; - } - } - } while (!FD_ISSET(sock, fds)); - if ((len = __msgread(sock, buf, len)) > 0) { - if (fds != NULL) - free(fds); - return (len); - } -fatal_err: - ((struct unix_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED; - if (fds != NULL) - free(fds); - return (-1); -} - -/* - * writes data to the unix connection. - * Any error is fatal and the connection is closed. - */ -static int -writeunix(xprt, buf, len) - register SVCXPRT *xprt; - caddr_t buf; - int len; -{ - register int i, cnt; - - for (cnt = len; cnt > 0; cnt -= i, buf += i) { - if ((i = __msgwrite(xprt->xp_sock, buf, cnt)) < 0) { - ((struct unix_conn *)(xprt->xp_p1))->strm_stat = - XPRT_DIED; - return (-1); - } - } - return (len); -} - -static enum xprt_stat -svcunix_stat(xprt) - SVCXPRT *xprt; -{ - register struct unix_conn *cd = - (struct unix_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 -svcunix_recv(xprt, msg) - SVCXPRT *xprt; - register struct rpc_msg *msg; -{ - register struct unix_conn *cd = - (struct unix_conn *)(xprt->xp_p1); - register XDR *xdrs = &(cd->xdrs); - - xdrs->x_op = XDR_DECODE; - (void)xdrrec_skiprecord(xdrs); - if (xdr_callmsg(xdrs, msg)) { - cd->x_id = msg->rm_xid; - /* set up verifiers */ - msg->rm_call.cb_verf.oa_flavor = AUTH_UNIX; - msg->rm_call.cb_verf.oa_base = (caddr_t)&cm; - msg->rm_call.cb_verf.oa_length = sizeof(cm); - return (TRUE); - } - cd->strm_stat = XPRT_DIED; /* XXXX */ - return (FALSE); -} - -static bool_t -svcunix_getargs(xprt, xdr_args, args_ptr) - SVCXPRT *xprt; - xdrproc_t xdr_args; - caddr_t args_ptr; -{ - - return ((*xdr_args)(&(((struct unix_conn *)(xprt->xp_p1))->xdrs), args_ptr)); -} - -static bool_t -svcunix_freeargs(xprt, xdr_args, args_ptr) - SVCXPRT *xprt; - xdrproc_t xdr_args; - caddr_t args_ptr; -{ - register XDR *xdrs = - &(((struct unix_conn *)(xprt->xp_p1))->xdrs); - - xdrs->x_op = XDR_FREE; - return ((*xdr_args)(xdrs, args_ptr)); -} - -static bool_t -svcunix_reply(xprt, msg) - SVCXPRT *xprt; - register struct rpc_msg *msg; -{ - register struct unix_conn *cd = - (struct unix_conn *)(xprt->xp_p1); - register XDR *xdrs = &(cd->xdrs); - register bool_t stat; - - xdrs->x_op = XDR_ENCODE; - msg->rm_xid = cd->x_id; - stat = xdr_replymsg(xdrs, msg); - (void)xdrrec_endofrecord(xdrs, TRUE); - return (stat); -} diff --git a/lib/libc/rpc/svc_vc.c b/lib/libc/rpc/svc_vc.c new file mode 100644 index 000000000000..add21ee8097e --- /dev/null +++ b/lib/libc/rpc/svc_vc.c @@ -0,0 +1,689 @@ +/* $NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $ */ +/* $FreeBSD$ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +static char *sccsid = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro"; +static char *sccsid = "@(#)svc_tcp.c 2.2 88/08/01 4.0 RPCSRC"; +#endif + +/* + * 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 "reentrant.h" +#include "namespace.h" +#include <sys/types.h> +#include <sys/param.h> +#include <sys/poll.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/uio.h> +#include <netinet/in.h> +#include <netinet/tcp.h> + +#include <assert.h> +#include <err.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <rpc/rpc.h> + +#include "rpc_com.h" +#include "un-namespace.h" + +#define SOCKCREDSIZE(ngrps) \ + (sizeof(struct cmsgcred) + (sizeof(gid_t) * ((ngrps) - 1))) + +static SVCXPRT *makefd_xprt __P((int, u_int, u_int)); +static bool_t rendezvous_request __P((SVCXPRT *, struct rpc_msg *)); +static enum xprt_stat rendezvous_stat __P((SVCXPRT *)); +static void svc_vc_destroy __P((SVCXPRT *)); +static int read_vc __P((caddr_t, caddr_t, int)); +static int write_vc __P((caddr_t, caddr_t, int)); +static enum xprt_stat svc_vc_stat __P((SVCXPRT *)); +static bool_t svc_vc_recv __P((SVCXPRT *, struct rpc_msg *)); +static bool_t svc_vc_getargs __P((SVCXPRT *, xdrproc_t, caddr_t)); +static bool_t svc_vc_freeargs __P((SVCXPRT *, xdrproc_t, caddr_t)); +static bool_t svc_vc_reply __P((SVCXPRT *, struct rpc_msg *)); +static void svc_vc_rendezvous_ops __P((SVCXPRT *)); +static void svc_vc_ops __P((SVCXPRT *)); +static bool_t svc_vc_control __P((SVCXPRT *xprt, const u_int rq, void *in)); +static int __msgwrite(int, void *, size_t); +static int __msgread(int, void *, size_t); + +struct cf_rendezvous { /* kept in xprt->xp_p1 for rendezvouser */ + u_int sendsize; + u_int recvsize; +}; + +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]; +}; + +struct cmessage { + struct cmsghdr cmsg; + struct cmsgcred cmcred; +}; + + +/* + * Usage: + * xprt = svc_vc_create(sock, send_buf_size, recv_buf_size); + * + * Creates, registers, and returns a (rpc) tcp based transporter. + * Once *xprt is initialized, it is registered as a transporter + * see (svc.h, xprt_register). This routine returns + * a NULL if a problem occurred. + * + * The filedescriptor passed in is expected to refer to a bound, but + * not yet connected socket. + * + * Since streams do buffered io similar to stdio, the caller can specify + * how big the send and receive buffers are via the second and third parms; + * 0 => use the system default. + */ +SVCXPRT * +svc_vc_create(fd, sendsize, recvsize) + int fd; + u_int sendsize; + u_int recvsize; +{ + SVCXPRT *xprt; + struct cf_rendezvous *r = NULL; + struct __rpc_sockinfo si; + struct sockaddr_storage sslocal; + socklen_t slen; + int one = 1; + + 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)) + return NULL; + r->sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize); + r->recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize); + xprt = mem_alloc(sizeof(SVCXPRT)); + if (xprt == NULL) { + warnx("svc_vc_create: out of memory"); + goto cleanup_svc_vc_create; + } + xprt->xp_tp = NULL; + xprt->xp_p1 = (caddr_t)(void *)r; + xprt->xp_p2 = NULL; + xprt->xp_p3 = NULL; + xprt->xp_verf = _null_auth; + svc_vc_rendezvous_ops(xprt); + xprt->xp_port = (u_short)-1; /* It is the rendezvouser */ + xprt->xp_fd = fd; + + slen = sizeof (struct sockaddr_storage); + if (_getsockname(fd, (struct sockaddr *)(void *)&sslocal, &slen) < 0) { + warnx("svc_vc_create: could not retrieve local addr"); + goto cleanup_svc_vc_create; + } + + xprt->xp_ltaddr.maxlen = xprt->xp_ltaddr.len = sslocal.ss_len; + xprt->xp_ltaddr.buf = mem_alloc((size_t)sslocal.ss_len); + if (xprt->xp_ltaddr.buf == NULL) { + warnx("svc_vc_create: no mem for local addr"); + goto cleanup_svc_vc_create; + } + memcpy(xprt->xp_ltaddr.buf, &sslocal, (size_t)sslocal.ss_len); + + xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage); + xprt_register(xprt); + return (xprt); +cleanup_svc_vc_create: + if (r != NULL) + mem_free(r, sizeof(*r)); + return (NULL); +} + +/* + * Like svtcp_create(), except the routine takes any *open* UNIX file + * descriptor as its first input. + */ +SVCXPRT * +svc_fd_create(fd, sendsize, recvsize) + 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; + } + ret->xp_ltaddr.maxlen = ret->xp_ltaddr.len = ss.ss_len; + ret->xp_ltaddr.buf = mem_alloc((size_t)ss.ss_len); + if (ret->xp_ltaddr.buf == NULL) { + warnx("svc_fd_create: no mem for local addr"); + goto freedata; + } + memcpy(ret->xp_ltaddr.buf, &ss, (size_t)ss.ss_len); + + 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; + } + ret->xp_rtaddr.maxlen = ret->xp_rtaddr.len = ss.ss_len; + ret->xp_rtaddr.buf = mem_alloc((size_t)ss.ss_len); + if (ret->xp_rtaddr.buf == NULL) { + warnx("svc_fd_create: no mem for local addr"); + goto freedata; + } + memcpy(ret->xp_rtaddr.buf, &ss, (size_t)ss.ss_len); +#ifdef PORTMAP + if (ss.ss_family == AF_INET) { + ret->xp_raddr = *(struct sockaddr_in *)ret->xp_rtaddr.buf; + ret->xp_addrlen = sizeof (struct sockaddr_in); + } +#endif /* PORTMAP */ + + return ret; + +freedata: + if (ret->xp_ltaddr.buf != NULL) + mem_free(ret->xp_ltaddr.buf, rep->xp_ltaddr.maxlen); + + return NULL; +} + +static SVCXPRT * +makefd_xprt(fd, sendsize, recvsize) + int fd; + u_int sendsize; + u_int recvsize; +{ + SVCXPRT *xprt; + 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); + cd = mem_alloc(sizeof(struct cf_conn)); + if (cd == NULL) { + warnx("svc_tcp: makefd_xprt: out of memory"); + mem_free(xprt, sizeof(SVCXPRT)); + xprt = NULL; + goto done; + } + cd->strm_stat = XPRT_IDLE; + xdrrec_create(&(cd->xdrs), sendsize, recvsize, + (caddr_t)(void *)xprt, read_vc, write_vc); + xprt->xp_p1 = (caddr_t)(void *)cd; + xprt->xp_verf.oa_base = cd->verf_body; + svc_vc_ops(xprt); /* truely deals with calls */ + xprt->xp_port = 0; /* this is a connection, not a rendezvouser */ + xprt->xp_fd = fd; + if (__rpc_fd2sockinfo(fd, &si) && __rpc_sockinfo2netid(&si, &netid)) + xprt->xp_netid = strdup(netid); + + xprt_register(xprt); +done: + return (xprt); +} + +/*ARGSUSED*/ +static bool_t +rendezvous_request(xprt, msg) + SVCXPRT *xprt; + struct rpc_msg *msg; +{ + int sock; + struct cf_rendezvous *r; + struct sockaddr_storage addr; + socklen_t len; + struct __rpc_sockinfo si; + + assert(xprt != NULL); + assert(msg != NULL); + + r = (struct cf_rendezvous *)xprt->xp_p1; +again: + len = sizeof addr; + if ((sock = _accept(xprt->xp_fd, (struct sockaddr *)(void *)&addr, + &len)) < 0) { + if (errno == EINTR) + goto again; + return (FALSE); + } + /* + * make a new transporter (re-uses xprt) + */ + xprt = makefd_xprt(sock, r->sendsize, r->recvsize); + xprt->xp_rtaddr.buf = mem_alloc(len); + if (xprt->xp_rtaddr.buf == NULL) + return (FALSE); + memcpy(xprt->xp_rtaddr.buf, &addr, len); + xprt->xp_rtaddr.len = len; +#ifdef PORTMAP + if (addr.ss_family == AF_INET) { + xprt->xp_raddr = *(struct sockaddr_in *)xprt->xp_rtaddr.buf; + xprt->xp_addrlen = sizeof (struct sockaddr_in); + } +#endif /* PORTMAP */ + 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)); + } + 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; +{ + struct cf_conn *cd; + struct cf_rendezvous *r; + + assert(xprt != NULL); + + cd = (struct cf_conn *)xprt->xp_p1; + + xprt_unregister(xprt); + if (xprt->xp_fd != RPC_ANYFD) + (void)_close(xprt->xp_fd); + if (xprt->xp_port != 0) { + /* a rendezvouser socket */ + r = (struct cf_rendezvous *)xprt->xp_p1; + mem_free(r, sizeof (struct cf_rendezvous)); + xprt->xp_port = 0; + } else { + /* an actual connection socket */ + XDR_DESTROY(&(cd->xdrs)); + mem_free(cd, sizeof(struct cf_conn)); + } + if (xprt->xp_rtaddr.buf) + mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen); + if (xprt->xp_ltaddr.buf) + mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen); + if (xprt->xp_tp) + free(xprt->xp_tp); + if (xprt->xp_netid) + free(xprt->xp_netid); + mem_free(xprt, sizeof(SVCXPRT)); +} + +/*ARGSUSED*/ +static bool_t +svc_vc_control(xprt, rq, in) + SVCXPRT *xprt; + const u_int rq; + void *in; +{ + return (FALSE); +} + +/* + * 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) + caddr_t xprtp; + caddr_t buf; + int len; +{ + SVCXPRT *xprt; + int sock; + int milliseconds = 35 * 1000; + struct pollfd pollfd; + struct sockaddr *sa; + struct cmessage *cm; + struct cmsghdr *cmp; + struct sockcred *sc; + + xprt = (SVCXPRT *)(void *)xprtp; + assert(xprt != NULL); + + sock = xprt->xp_fd; + + 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); + + sa = (struct sockaddr *)xprt->xp_rtaddr.buf; + if (sa->sa_family == AF_LOCAL) { + if ((len = __msgread(sock, buf, len)) > 0) { + cm = (struct cmessage *)xprt->xp_verf.oa_base; + cmp = &cm->cmsg; + sc = (struct sockcred *)(void *)CMSG_DATA(cmp); + xprt->xp_p2 = sc; + return (len); + } + } else { + if ((len = _read(sock, buf, (size_t)len)) > 0) + 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) + caddr_t xprtp; + caddr_t buf; + int len; +{ + SVCXPRT *xprt; + int i, cnt; + struct sockaddr *sa; + + xprt = (SVCXPRT *)(void *)xprtp; + assert(xprt != NULL); + + sa = (struct sockaddr *)xprt->xp_rtaddr.buf; + if (sa->sa_family == AF_LOCAL) { + for (cnt = len; cnt > 0; cnt -= i, buf += i) { + if ((i = __msgwrite(xprt->xp_fd, buf, + (size_t)cnt)) < 0) { + ((struct cf_conn *)(xprt->xp_p1))->strm_stat = + XPRT_DIED; + return (-1); + } + } + } else { + for (cnt = len; cnt > 0; cnt -= i, buf += i) { + if ((i = _write(xprt->xp_fd, buf, + (size_t)cnt)) < 0) { + ((struct cf_conn *)(xprt->xp_p1))->strm_stat = + XPRT_DIED; + return (-1); + } + } + } + + return (len); +} + +static enum xprt_stat +svc_vc_stat(xprt) + SVCXPRT *xprt; +{ + struct cf_conn *cd; + + assert(xprt != NULL); + + cd = (struct cf_conn *)(xprt->xp_p1); + + if (cd->strm_stat == XPRT_DIED) + return (XPRT_DIED); + if (! xdrrec_eof(&(cd->xdrs))) + return (XPRT_MOREREQS); + return (XPRT_IDLE); +} + +static bool_t +svc_vc_recv(xprt, msg) + SVCXPRT *xprt; + struct rpc_msg *msg; +{ + struct cf_conn *cd; + XDR *xdrs; + + assert(xprt != NULL); + assert(msg != NULL); + + cd = (struct cf_conn *)(xprt->xp_p1); + xdrs = &(cd->xdrs); + + xdrs->x_op = XDR_DECODE; + (void)xdrrec_skiprecord(xdrs); + if (xdr_callmsg(xdrs, msg)) { + cd->x_id = msg->rm_xid; + return (TRUE); + } + cd->strm_stat = XPRT_DIED; + return (FALSE); +} + +static bool_t +svc_vc_getargs(xprt, xdr_args, args_ptr) + SVCXPRT *xprt; + xdrproc_t xdr_args; + caddr_t args_ptr; +{ + + assert(xprt != NULL); + /* args_ptr may be NULL */ + return ((*xdr_args)(&(((struct cf_conn *)(xprt->xp_p1))->xdrs), + args_ptr)); +} + +static bool_t +svc_vc_freeargs(xprt, xdr_args, args_ptr) + SVCXPRT *xprt; + xdrproc_t xdr_args; + caddr_t 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 stat; + + assert(xprt != NULL); + assert(msg != NULL); + + cd = (struct cf_conn *)(xprt->xp_p1); + xdrs = &(cd->xdrs); + + xdrs->x_op = XDR_ENCODE; + msg->rm_xid = cd->x_id; + stat = xdr_replymsg(xdrs, msg); + (void)xdrrec_endofrecord(xdrs, TRUE); + return (stat); +} + +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 (*) __P((SVCXPRT *, xdrproc_t, caddr_t)))abort; + ops.xp_reply = + (bool_t (*) __P((SVCXPRT *, struct rpc_msg *)))abort; + ops.xp_freeargs = + (bool_t (*) __P((SVCXPRT *, xdrproc_t, caddr_t)))abort, + 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 int +__msgread(sock, buf, cnt) + int sock; + void *buf; + size_t cnt; +{ + struct iovec iov[1]; + struct msghdr msg; + struct cmessage cm; + + bzero((char *)&cm, sizeof(cm)); + iov[0].iov_base = buf; + iov[0].iov_len = cnt; + + msg.msg_iov = iov; + msg.msg_iovlen = 1; + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_control = (caddr_t)&cm; + msg.msg_controllen = sizeof(struct cmessage); + msg.msg_flags = 0; + + return(_recvmsg(sock, &msg, 0)); +} + +static int +__msgwrite(sock, buf, cnt) + int sock; + void *buf; + size_t cnt; +{ + struct iovec iov[1]; + struct msghdr msg; + struct cmessage cm; + + bzero((char *)&cm, sizeof(cm)); + iov[0].iov_base = buf; + iov[0].iov_len = cnt; + + cm.cmsg.cmsg_type = SCM_CREDS; + cm.cmsg.cmsg_level = SOL_SOCKET; + cm.cmsg.cmsg_len = sizeof(struct cmessage); + + msg.msg_iov = iov; + msg.msg_iovlen = 1; + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_control = (caddr_t)&cm; + msg.msg_controllen = sizeof(struct cmessage); + msg.msg_flags = 0; + + return(_sendmsg(sock, &msg, 0)); +} diff --git a/lib/libc/xdr/Makefile.inc b/lib/libc/xdr/Makefile.inc index 1837ef889a38..62ab805b4c18 100644 --- a/lib/libc/xdr/Makefile.inc +++ b/lib/libc/xdr/Makefile.inc @@ -3,12 +3,19 @@ .PATH: ${.CURDIR}/../libc/xdr ${.CURDIR}/. SRCS+= xdr.c xdr_array.c xdr_float.c xdr_mem.c \ - xdr_rec.c xdr_reference.c xdr_stdio.c xdr_sizeof.c + xdr_rec.c xdr_reference.c xdr_stdio.c .if ${LIB} == "c" MAN3+= xdr.3 -MLINKS+= xdr.3 xdr_array.3 \ +MLINKS+= rpc_xdr.3 xdr_accepted_reply.3 \ + rpc_xdr.3 xdr_authsys_parms.3 \ + rpc_xdr.3 xdr_callhdr.3 \ + rpc_xdr.3 xdr_callmsg.3 \ + rpc_xdr.3 xdr_opaque_auth.3 \ + rpc_xdr.3 xdr_rejected_reply.3 \ + rpc_xdr.3 xdr_replymsg.3 \ + xdr.3 xdr_array.3 \ xdr.3 xdr_bool.3 \ xdr.3 xdr_bytes.3 \ xdr.3 xdr_char.3 \ @@ -32,6 +39,8 @@ MLINKS+= xdr.3 xdr_array.3 \ xdr.3 xdr_setpos.3 \ xdr.3 xdr_short.3 \ xdr.3 xdrstdio_create.3 \ + xdr.3 xdr_short.3 \ + xdr.3 xdrstdio_create.3 \ xdr.3 xdr_string.3 \ xdr.3 xdr_u_char.3 \ xdr.3 xdr_u_long.3 \ @@ -39,5 +48,5 @@ MLINKS+= xdr.3 xdr_array.3 \ xdr.3 xdr_union.3 \ xdr.3 xdr_vector.3 \ xdr.3 xdr_void.3 \ - xdr.3 xdr_wrapstring.3 + xdr.3 xdr_wrapstring.3 .endif diff --git a/lib/libc/xdr/xdr.3 b/lib/libc/xdr/xdr.3 index 49266e5026c3..35554a7478ba 100644 --- a/lib/libc/xdr/xdr.3 +++ b/lib/libc/xdr/xdr.3 @@ -5,7 +5,44 @@ .Dt XDR 3 .Os .Sh NAME -.Nm xdr +.Nm xdr , +.Nm xdr_array , +.Nm xdr_bool , +.Nm xdr_bytes , +.Nm xdr_char , +.Nm xdr_destroy , +.Nm xdr_double , +.Nm xdr_enum , +.Nm xdr_float , +.Nm xdr_free , +.Nm xdr_getpos , +.Nm xdr_hyper , +.Nm xdr_inline , +.Nm xdr_int , +.Nm xdr_long , +.Nm xdr_longlong_t , +.Nm xdrmem_create , +.Nm xdr_opaque , +.Nm xdr_pointer , +.Nm xdrrec_create , +.Nm xdrrec_endofrecord , +.Nm xdrrec_eof , +.Nm xdrrec_skiprecord , +.Nm xdr_reference , +.Nm xdr_setpos , +.Nm xdr_short , +.Nm xdrstdio_create , +.Nm xdr_string , +.Nm xdr_u_char , +.Nm xdr_u_hyper , +.Nm xdr_u_int , +.Nm xdr_u_long , +.Nm xdr_u_longlong_t , +.Nm xdr_u_short , +.Nm xdr_union , +.Nm xdr_vector , +.Nm xdr_void , +.Nm xdr_wrapstring .Nd "library routines for external data representation" .Sh LIBRARY .Lb libc @@ -212,6 +249,17 @@ although the stream instances need not guarantee this. .Pp .It Xo +.Ft int +.Xc +.It Xo +.Fn xdr_hyper "XDR *xdrs" "longlong_t *llp" +.Xc +A filter primitive that translates between ANSI C +.Vt "long long" +integers and their external representations. +This routine returns one if it succeeds, zero otherwise. +.Pp +.It Xo .Ft "long *" .Xc .It Xo @@ -262,6 +310,17 @@ integers and their external representations. This routine returns one if it succeeds, zero otherwise. .Pp .It Xo +.Ft int +.Xc +.It Xo +.Fn xdr_longlong_t "XDR *xdrs" "longlong_t *llp" +.Xc +A filter primitive that translates between ANSI C +.Vt "long long" +integers and their external representations. +This routine returns one if it succeeds, zero otherwise. +.Pp +.It Xo .Ft void .Xc .It Xo @@ -568,6 +627,19 @@ This routine returns one if it succeeds, zero otherwise. .Ft int .Xc .It Xo +.Fn xdr_u_hyper "XDR *xdrs" "u_longlong_t *ullp" +.Xc +A filter primitive that translates between +.Vt unsigned +ANSI C +.Vt long long +integers and their external representations. +This routine returns one if it succeeds, zero otherwise. +.Pp +.It Xo +.Ft int +.Xc +.It Xo .Fn xdr_u_int "XDR *xdrs" "unsigned *up" .Xc .Pp @@ -592,6 +664,19 @@ This routine returns one if it succeeds, zero otherwise. .Ft int .Xc .It Xo +.Fn xdr_u_longlong_t "XDR *xdrs" "u_longlong_t *ullp" +.Xc +A filter primitive that translates between +.Vt unsigned +ANSI C +.Vt "long long" +integers and their external representations. +This routine returns one if it succeeds, zero otherwise. +.Pp +.It Xo +.Ft int +.Xc +.It Xo .Fn xdr_u_short "XDR *xdrs" "unsigned short *usp" .Xc .Pp diff --git a/lib/libc/xdr/xdr.c b/lib/libc/xdr/xdr.c index 50b68fb14755..113ac3cd0a68 100644 --- a/lib/libc/xdr/xdr.c +++ b/lib/libc/xdr/xdr.c @@ -1,3 +1,5 @@ +/* $NetBSD: xdr.c,v 1.22 2000/07/06 03:10:35 christos Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -27,6 +29,7 @@ * Mountain View, California 94043 */ +#include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)xdr.c 1.35 87/08/12";*/ /*static char *sccsid = "from: @(#)xdr.c 2.1 88/07/29 4.0 RPCSRC";*/ @@ -43,12 +46,18 @@ static char *rcsid = "$FreeBSD$"; * xdr. */ +#include "namespace.h" +#include <err.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <rpc/types.h> #include <rpc/xdr.h> +#include "un-namespace.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" @@ -60,7 +69,7 @@ static char *rcsid = "$FreeBSD$"; /* * for unit alignment */ -static char xdr_zero[BYTES_PER_XDR_UNIT] = { 0, 0, 0, 0 }; +static const char xdr_zero[BYTES_PER_XDR_UNIT] = { 0, 0, 0, 0 }; /* * Free a data structure using XDR @@ -72,7 +81,7 @@ xdr_free(proc, objp) char *objp; { XDR x; - + x.x_op = XDR_FREE; (*proc)(&x, objp); } @@ -116,6 +125,7 @@ xdr_int(xdrs, ip) case XDR_FREE: return (TRUE); } + /* NOTREACHED */ return (FALSE); } @@ -145,6 +155,7 @@ xdr_u_int(xdrs, up) case XDR_FREE: return (TRUE); } + /* NOTREACHED */ return (FALSE); } @@ -155,7 +166,7 @@ xdr_u_int(xdrs, up) */ bool_t xdr_long(xdrs, lp) - register XDR *xdrs; + XDR *xdrs; long *lp; { switch (xdrs->x_op) { @@ -166,7 +177,7 @@ xdr_long(xdrs, lp) case XDR_FREE: return (TRUE); } - + /* NOTREACHED */ return (FALSE); } @@ -176,7 +187,7 @@ xdr_long(xdrs, lp) */ bool_t xdr_u_long(xdrs, ulp) - register XDR *xdrs; + XDR *xdrs; u_long *ulp; { switch (xdrs->x_op) { @@ -187,6 +198,7 @@ xdr_u_long(xdrs, ulp) case XDR_FREE: return (TRUE); } + /* NOTREACHED */ return (FALSE); } @@ -197,7 +209,7 @@ xdr_u_long(xdrs, ulp) */ bool_t xdr_int32_t(xdrs, int32_p) - register XDR *xdrs; + XDR *xdrs; int32_t *int32_p; { long l; @@ -218,6 +230,7 @@ xdr_int32_t(xdrs, int32_p) case XDR_FREE: return (TRUE); } + /* NOTREACHED */ return (FALSE); } @@ -227,7 +240,7 @@ xdr_int32_t(xdrs, int32_p) */ bool_t xdr_u_int32_t(xdrs, u_int32_p) - register XDR *xdrs; + XDR *xdrs; u_int32_t *u_int32_p; { u_long l; @@ -248,71 +261,7 @@ xdr_u_int32_t(xdrs, u_int32_p) case XDR_FREE: return (TRUE); } - return (FALSE); -} - -/* - * XDR 64-bit integers - */ -bool_t -xdr_int64_t(xdrs, int64_p) - register XDR *xdrs; - int64_t *int64_p; -{ - u_long ul[2]; - - switch (xdrs->x_op) { - - case XDR_ENCODE: - ul[0] = (u_long)((u_int64_t)*int64_p >> 32) & 0xffffffff; - ul[1] = (u_long)((u_int64_t)*int64_p) & 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); - *int64_p = (int64_t) - (((u_int64_t)ul[0] << 32) | ((u_int64_t)ul[1])); - return (TRUE); - case XDR_FREE: - return (TRUE); - } - return (FALSE); -} - -/* - * XDR unsigned 64-bit integers - */ -bool_t -xdr_u_int64_t(xdrs, uint64_p) - register XDR *xdrs; - u_int64_t *uint64_p; -{ - u_long ul[2]; - - switch (xdrs->x_op) { - - case XDR_ENCODE: - ul[0] = (u_long)(*uint64_p >> 32) & 0xffffffff; - ul[1] = (u_long)(*uint64_p) & 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); - *uint64_p = (u_int64_t) - (((u_int64_t)ul[0] << 32) | ((u_int64_t)ul[1])); - return (TRUE); - case XDR_FREE: - return (TRUE); - } + /* NOTREACHED */ return (FALSE); } @@ -322,7 +271,7 @@ xdr_u_int64_t(xdrs, uint64_p) */ bool_t xdr_short(xdrs, sp) - register XDR *xdrs; + XDR *xdrs; short *sp; { long l; @@ -343,6 +292,7 @@ xdr_short(xdrs, sp) case XDR_FREE: return (TRUE); } + /* NOTREACHED */ return (FALSE); } @@ -351,7 +301,7 @@ xdr_short(xdrs, sp) */ bool_t xdr_u_short(xdrs, usp) - register XDR *xdrs; + XDR *xdrs; u_short *usp; { u_long l; @@ -372,6 +322,7 @@ xdr_u_short(xdrs, usp) case XDR_FREE: return (TRUE); } + /* NOTREACHED */ return (FALSE); } @@ -381,7 +332,7 @@ xdr_u_short(xdrs, usp) */ bool_t xdr_int16_t(xdrs, int16_p) - register XDR *xdrs; + XDR *xdrs; int16_t *int16_p; { long l; @@ -402,6 +353,7 @@ xdr_int16_t(xdrs, int16_p) case XDR_FREE: return (TRUE); } + /* NOTREACHED */ return (FALSE); } @@ -410,7 +362,7 @@ xdr_int16_t(xdrs, int16_p) */ bool_t xdr_u_int16_t(xdrs, u_int16_p) - register XDR *xdrs; + XDR *xdrs; u_int16_t *u_int16_p; { u_long l; @@ -431,6 +383,7 @@ xdr_u_int16_t(xdrs, u_int16_p) case XDR_FREE: return (TRUE); } + /* NOTREACHED */ return (FALSE); } @@ -476,7 +429,7 @@ xdr_u_char(xdrs, cp) */ bool_t xdr_bool(xdrs, bp) - register XDR *xdrs; + XDR *xdrs; bool_t *bp; { long lb; @@ -497,6 +450,7 @@ xdr_bool(xdrs, bp) case XDR_FREE: return (TRUE); } + /* NOTREACHED */ return (FALSE); } @@ -508,26 +462,20 @@ xdr_enum(xdrs, ep) XDR *xdrs; enum_t *ep; { -#ifndef lint enum sizecheck { SIZEVAL }; /* used to find the size of an enum */ /* * enums are treated as ints */ - if (sizeof (enum sizecheck) == sizeof (long)) { - return (xdr_long(xdrs, (long *)ep)); - } else if (sizeof (enum sizecheck) == sizeof (int)) { - return (xdr_int(xdrs, (int *)ep)); - } else if (sizeof (enum sizecheck) == sizeof (short)) { - return (xdr_short(xdrs, (short *)ep)); + /* 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); } -#else - (void) (xdr_short(xdrs, (short *)ep)); - (void) (xdr_int(xdrs, (int *)ep)); - return (xdr_long(xdrs, (long *)ep)); -#endif } /* @@ -537,12 +485,12 @@ xdr_enum(xdrs, ep) */ bool_t xdr_opaque(xdrs, cp, cnt) - register XDR *xdrs; + XDR *xdrs; caddr_t cp; - register u_int cnt; + u_int cnt; { - register u_int rndup; - static crud[BYTES_PER_XDR_UNIT]; + u_int rndup; + static int crud[BYTES_PER_XDR_UNIT]; /* * if no data we are done @@ -563,7 +511,7 @@ xdr_opaque(xdrs, cp, cnt) } if (rndup == 0) return (TRUE); - return (XDR_GETBYTES(xdrs, (caddr_t)crud, rndup)); + return (XDR_GETBYTES(xdrs, (caddr_t)(void *)crud, rndup)); } if (xdrs->x_op == XDR_ENCODE) { @@ -589,13 +537,13 @@ xdr_opaque(xdrs, cp, cnt) */ bool_t xdr_bytes(xdrs, cpp, sizep, maxsize) - register XDR *xdrs; + XDR *xdrs; char **cpp; - register u_int *sizep; + u_int *sizep; u_int maxsize; { - register char *sp = *cpp; /* sp is the actual string pointer */ - register u_int nodesize; + char *sp = *cpp; /* sp is the actual string pointer */ + u_int nodesize; /* * first deal with the length since xdr bytes are counted @@ -618,13 +566,13 @@ xdr_bytes(xdrs, cpp, sizep, maxsize) return (TRUE); } if (sp == NULL) { - *cpp = sp = (char *)mem_alloc(nodesize); + *cpp = sp = mem_alloc(nodesize); } if (sp == NULL) { - (void) fprintf(stderr, "xdr_bytes: out of memory\n"); + warnx("xdr_bytes: out of memory"); return (FALSE); } - /* fall into ... */ + /* FALLTHROUGH */ case XDR_ENCODE: return (xdr_opaque(xdrs, sp, nodesize)); @@ -636,6 +584,7 @@ xdr_bytes(xdrs, cpp, sizep, maxsize) } return (TRUE); } + /* NOTREACHED */ return (FALSE); } @@ -664,13 +613,13 @@ xdr_netobj(xdrs, np) */ bool_t xdr_union(xdrs, dscmp, unp, choices, dfault) - register XDR *xdrs; + XDR *xdrs; enum_t *dscmp; /* enum to decide which arm to work on */ char *unp; /* the union itself */ - struct xdr_discrim *choices; /* [value, xdr proc] for each arm */ + const struct xdr_discrim *choices; /* [value, xdr proc] for each arm */ xdrproc_t dfault; /* default xdr routine */ { - register enum_t dscm; + enum_t dscm; /* * we deal with the discriminator; it's an enum @@ -686,14 +635,14 @@ xdr_union(xdrs, dscmp, unp, choices, dfault) */ for (; choices->proc != NULL_xdrproc_t; choices++) { if (choices->value == dscm) - return ((*(choices->proc))(xdrs, unp, LASTUNSIGNED)); + 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, LASTUNSIGNED)); + (*dfault)(xdrs, unp)); } @@ -713,11 +662,11 @@ xdr_union(xdrs, dscmp, unp, choices, dfault) */ bool_t xdr_string(xdrs, cpp, maxsize) - register XDR *xdrs; + XDR *xdrs; char **cpp; u_int maxsize; { - register char *sp = *cpp; /* sp is the actual string pointer */ + char *sp = *cpp; /* sp is the actual string pointer */ u_int size; u_int nodesize; @@ -729,10 +678,12 @@ xdr_string(xdrs, cpp, maxsize) if (sp == NULL) { return(TRUE); /* already free */ } - /* fall through... */ + /* FALLTHROUGH */ case XDR_ENCODE: size = strlen(sp); break; + case XDR_DECODE: + break; } if (! xdr_u_int(xdrs, &size)) { return (FALSE); @@ -752,13 +703,13 @@ xdr_string(xdrs, cpp, maxsize) return (TRUE); } if (sp == NULL) - *cpp = sp = (char *)mem_alloc(nodesize); + *cpp = sp = mem_alloc(nodesize); if (sp == NULL) { - (void) fprintf(stderr, "xdr_string: out of memory\n"); + warnx("xdr_string: out of memory"); return (FALSE); } sp[size] = 0; - /* fall into ... */ + /* FALLTHROUGH */ case XDR_ENCODE: return (xdr_opaque(xdrs, sp, size)); @@ -768,11 +719,12 @@ xdr_string(xdrs, cpp, maxsize) *cpp = NULL; return (TRUE); } + /* NOTREACHED */ return (FALSE); } -/* - * Wrapper for xdr_string that can be called directly from +/* + * Wrapper for xdr_string that can be called directly from * routines like clnt_call */ bool_t @@ -782,3 +734,144 @@ xdr_wrapstring(xdrs, cpp) { return xdr_string(xdrs, cpp, LASTUNSIGNED); } + +/* + * NOTE: xdr_hyper(), xdr_u_hyper(), xdr_longlong_t(), and xdr_u_longlong_t() + * are in the "non-portable" section because they require that a `long long' + * be a 64-bit type. + * + * --thorpej@netbsd.org, November 30, 1999 + */ + +/* + * XDR 64-bit integers + */ +bool_t +xdr_int64_t(xdrs, llp) + XDR *xdrs; + int64_t *llp; +{ + u_long ul[2]; + + switch (xdrs->x_op) { + case XDR_ENCODE: + ul[0] = (u_long)((u_int64_t)*llp >> 32) & 0xffffffff; + ul[1] = (u_long)((u_int64_t)*llp) & 0xffffffff; + if (XDR_PUTLONG(xdrs, (long *)&ul[0]) == FALSE) + return (FALSE); + return (XDR_PUTLONG(xdrs, (long *)&ul[1])); + case XDR_DECODE: + if (XDR_GETLONG(xdrs, (long *)&ul[0]) == FALSE) + return (FALSE); + if (XDR_GETLONG(xdrs, (long *)&ul[1]) == FALSE) + return (FALSE); + *llp = (int64_t) + (((u_int64_t)ul[0] << 32) | ((u_int64_t)ul[1])); + return (TRUE); + case XDR_FREE: + return (TRUE); + } + /* NOTREACHED */ + return (FALSE); +} + + +/* + * XDR unsigned 64-bit integers + */ +bool_t +xdr_u_int64_t(xdrs, ullp) + XDR *xdrs; + u_int64_t *ullp; +{ + u_long ul[2]; + + switch (xdrs->x_op) { + case XDR_ENCODE: + ul[0] = (u_long)(*ullp >> 32) & 0xffffffff; + ul[1] = (u_long)(*ullp) & 0xffffffff; + if (XDR_PUTLONG(xdrs, (long *)&ul[0]) == FALSE) + return (FALSE); + return (XDR_PUTLONG(xdrs, (long *)&ul[1])); + case XDR_DECODE: + if (XDR_GETLONG(xdrs, (long *)&ul[0]) == FALSE) + return (FALSE); + if (XDR_GETLONG(xdrs, (long *)&ul[1]) == FALSE) + return (FALSE); + *ullp = (u_int64_t) + (((u_int64_t)ul[0] << 32) | ((u_int64_t)ul[1])); + return (TRUE); + case XDR_FREE: + return (TRUE); + } + /* NOTREACHED */ + return (FALSE); +} + + +/* + * XDR hypers + */ +bool_t +xdr_hyper(xdrs, llp) + XDR *xdrs; + longlong_t *llp; +{ + + /* + * Don't bother open-coding this; it's a fair amount of code. Just + * call xdr_int64_t(). + */ + return (xdr_int64_t(xdrs, (int64_t *)llp)); +} + + +/* + * XDR unsigned hypers + */ +bool_t +xdr_u_hyper(xdrs, ullp) + XDR *xdrs; + u_longlong_t *ullp; +{ + + /* + * Don't bother open-coding this; it's a fair amount of code. Just + * call xdr_u_int64_t(). + */ + return (xdr_u_int64_t(xdrs, (u_int64_t *)ullp)); +} + + +/* + * XDR longlong_t's + */ +bool_t +xdr_longlong_t(xdrs, llp) + XDR *xdrs; + longlong_t *llp; +{ + + /* + * Don't bother open-coding this; it's a fair amount of code. Just + * call xdr_int64_t(). + */ + return (xdr_int64_t(xdrs, (int64_t *)llp)); +} + + +/* + * XDR u_longlong_t's + */ +bool_t +xdr_u_longlong_t(xdrs, ullp) + XDR *xdrs; + u_longlong_t *ullp; +{ + + /* + * Don't bother open-coding this; it's a fair amount of code. Just + * call xdr_u_int64_t(). + */ + return (xdr_u_int64_t(xdrs, (u_int64_t *)ullp)); +} diff --git a/lib/libc/xdr/xdr_array.c b/lib/libc/xdr/xdr_array.c index b7d36fea5ca3..8e0a302441a0 100644 --- a/lib/libc/xdr/xdr_array.c +++ b/lib/libc/xdr/xdr_array.c @@ -1,3 +1,5 @@ +/* $NetBSD: xdr_array.c,v 1.12 2000/01/22 22:19:18 mycroft Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -27,6 +29,7 @@ * Mountain View, California 94043 */ +#include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)xdr_array.c 1.10 87/08/11 Copyr 1984 Sun Micro";*/ /*static char *sccsid = "from: @(#)xdr_array.c 2.1 88/07/29 4.0 RPCSRC";*/ @@ -42,13 +45,15 @@ static char *rcsid = "$FreeBSD$"; * arrays. See xdr.h for more info on the interface to xdr. */ +#include "namespace.h" +#include <err.h> #include <stdio.h> #include <stdlib.h> #include <string.h> + #include <rpc/types.h> #include <rpc/xdr.h> - -#define LASTUNSIGNED ((u_int) 0-1) +#include "un-namespace.h" /* * XDR an array of arbitrary elements @@ -59,18 +64,18 @@ static char *rcsid = "$FreeBSD$"; */ bool_t xdr_array(xdrs, addrp, sizep, maxsize, elsize, elproc) - register XDR *xdrs; + 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 */ { - register u_int i; - register caddr_t target = *addrp; - register u_int c; /* the actual element count */ - register bool_t stat = TRUE; - register u_int nodesize; + 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)) { @@ -93,8 +98,7 @@ xdr_array(xdrs, addrp, sizep, maxsize, elsize, elproc) return (TRUE); *addrp = target = mem_alloc(nodesize); if (target == NULL) { - (void) fprintf(stderr, - "xdr_array: out of memory\n"); + warnx("xdr_array: out of memory"); return (FALSE); } memset(target, 0, nodesize); @@ -102,13 +106,16 @@ xdr_array(xdrs, addrp, sizep, maxsize, elsize, elproc) 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, LASTUNSIGNED); + stat = (*elproc)(xdrs, target); target += elsize; } @@ -134,22 +141,21 @@ xdr_array(xdrs, addrp, sizep, maxsize, elsize, elproc) */ bool_t xdr_vector(xdrs, basep, nelem, elemsize, xdr_elem) - register XDR *xdrs; - register char *basep; - register u_int nelem; - register u_int elemsize; - register xdrproc_t xdr_elem; + XDR *xdrs; + char *basep; + u_int nelem; + u_int elemsize; + xdrproc_t xdr_elem; { - register u_int i; - register char *elptr; + u_int i; + char *elptr; elptr = basep; for (i = 0; i < nelem; i++) { - if (! (*xdr_elem)(xdrs, elptr, LASTUNSIGNED)) { + if (! (*xdr_elem)(xdrs, elptr)) { return(FALSE); } elptr += elemsize; } - return(TRUE); + return(TRUE); } - diff --git a/lib/libc/xdr/xdr_float.c b/lib/libc/xdr/xdr_float.c index 3966320b7298..024888f834a1 100644 --- a/lib/libc/xdr/xdr_float.c +++ b/lib/libc/xdr/xdr_float.c @@ -1,3 +1,5 @@ +/* $NetBSD: xdr_float.c,v 1.23 2000/07/17 04:59:51 matt Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -27,14 +29,15 @@ * Mountain View, California 94043 */ +#include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) -/*static char *sccsid = "from: @(#)xdr_float.c 1.12 87/08/11 Copyr 1984 Sun Micro";*/ -/*static char *sccsid = "from: @(#)xdr_float.c 2.1 88/07/29 4.0 RPCSRC";*/ +static char *sccsid = "@(#)xdr_float.c 1.12 87/08/11 Copyr 1984 Sun Micro"; +static char *sccsid = "@(#)xdr_float.c 2.1 88/07/29 4.0 RPCSRC"; static char *rcsid = "$FreeBSD$"; #endif /* - * xdr_float.c, Generic XDR routines impelmentation. + * xdr_float.c, Generic XDR routines implementation. * * Copyright (C) 1984, Sun Microsystems, Inc. * @@ -43,11 +46,15 @@ static char *rcsid = "$FreeBSD$"; * xdr. */ -#include <stdio.h> +#include "namespace.h" #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. @@ -56,12 +63,13 @@ static char *rcsid = "$FreeBSD$"; #if defined(__m68k__) || defined(__sparc__) || defined(__i386__) || \ defined(__mips__) || defined(__ns32k__) || defined(__alpha__) || \ - defined(__arm32__) || defined(__ppc__) || defined(__ia64__) + defined(__arm32__) || defined(__ppc__) || defined(__ia64__) || \ + defined(__arm26__) #include <machine/endian.h> #define IEEEFP #endif -#ifdef vax +#if defined(__vax__) /* What IEEE single precision floating point looks like on a Vax */ struct ieee_single { @@ -94,13 +102,10 @@ static struct sgl_limits { bool_t xdr_float(xdrs, fp) - register XDR *xdrs; - register float *fp; + XDR *xdrs; + float *fp; { -#ifdef IEEEFP - bool_t rv; - long tmpl; -#else +#ifndef IEEEFP struct ieee_single is; struct vax_single vs, *vsp; struct sgl_limits *lim; @@ -110,8 +115,7 @@ xdr_float(xdrs, fp) case XDR_ENCODE: #ifdef IEEEFP - tmpl = *(int32_t *)fp; - return (XDR_PUTLONG(xdrs, &tmpl)); + return (XDR_PUTINT32(xdrs, (int32_t *)fp)); #else vs = *((struct vax_single *)fp); for (i = 0, lim = sgl_limits; @@ -128,17 +132,15 @@ xdr_float(xdrs, fp) is.mantissa = (vs.mantissa1 << 16) | vs.mantissa2; shipit: is.sign = vs.sign; - return (XDR_PUTLONG(xdrs, (long *)&is)); + return (XDR_PUTINT32(xdrs, (int32_t *)&is)); #endif case XDR_DECODE: #ifdef IEEEFP - rv = XDR_GETLONG(xdrs, &tmpl); - *(int32_t *)fp = tmpl; - return (rv); + return (XDR_GETINT32(xdrs, (int32_t *)fp)); #else vsp = (struct vax_single *)fp; - if (!XDR_GETLONG(xdrs, (long *)&is)) + if (!XDR_GETINT32(xdrs, (int32_t *)&is)) return (FALSE); for (i = 0, lim = sgl_limits; i < sizeof(sgl_limits)/sizeof(struct sgl_limits); @@ -160,10 +162,11 @@ xdr_float(xdrs, fp) case XDR_FREE: return (TRUE); } + /* NOTREACHED */ return (FALSE); } -#ifdef vax +#if defined(__vax__) /* What IEEE double precision floating point looks like on a Vax */ struct ieee_double { unsigned int mantissa1 : 20; @@ -201,18 +204,17 @@ static struct dbl_limits { bool_t xdr_double(xdrs, dp) - register XDR *xdrs; + XDR *xdrs; double *dp; { #ifdef IEEEFP - register int32_t *i32p; + int32_t *i32p; bool_t rv; - long tmpl; #else - register long *lp; + int32_t *lp; struct ieee_double id; struct vax_double vd; - register struct dbl_limits *lim; + struct dbl_limits *lim; int i; #endif @@ -220,21 +222,17 @@ xdr_double(xdrs, dp) case XDR_ENCODE: #ifdef IEEEFP - i32p = (int32_t *)dp; + i32p = (int32_t *)(void *)dp; #if BYTE_ORDER == BIG_ENDIAN - tmpl = *i32p++; - rv = XDR_PUTLONG(xdrs, &tmpl); + rv = XDR_PUTINT32(xdrs, i32p); if (!rv) return (rv); - tmpl = *i32p; - rv = XDR_PUTLONG(xdrs, &tmpl); + rv = XDR_PUTINT32(xdrs, i32p+1); #else - tmpl = *(i32p+1); - rv = XDR_PUTLONG(xdrs, &tmpl); + rv = XDR_PUTINT32(xdrs, i32p+1); if (!rv) return (rv); - tmpl = *i32p; - rv = XDR_PUTLONG(xdrs, &tmpl); + rv = XDR_PUTINT32(xdrs, i32p); #endif return (rv); #else @@ -258,32 +256,28 @@ xdr_double(xdrs, dp) ((vd.mantissa4 >> 3) & MASK(13)); shipit: id.sign = vd.sign; - lp = (long *)&id; - return (XDR_PUTLONG(xdrs, lp++) && XDR_PUTLONG(xdrs, lp)); + lp = (int32_t *)&id; + return (XDR_PUTINT32(xdrs, lp++) && XDR_PUTINT32(xdrs, lp)); #endif case XDR_DECODE: #ifdef IEEEFP - i32p = (int32_t *)dp; + i32p = (int32_t *)(void *)dp; #if BYTE_ORDER == BIG_ENDIAN - rv = XDR_GETLONG(xdrs, &tmpl); - *i32p++ = tmpl; + rv = XDR_GETINT32(xdrs, i32p); if (!rv) return (rv); - rv = XDR_GETLONG(xdrs, &tmpl); - *i32p = tmpl; + rv = XDR_GETINT32(xdrs, i32p+1); #else - rv = XDR_GETLONG(xdrs, &tmpl); - *(i32p+1) = tmpl; + rv = XDR_GETINT32(xdrs, i32p+1); if (!rv) return (rv); - rv = XDR_GETLONG(xdrs, &tmpl); - *i32p = tmpl; + rv = XDR_GETINT32(xdrs, i32p); #endif return (rv); #else - lp = (long *)&id; - if (!XDR_GETLONG(xdrs, lp++) || !XDR_GETLONG(xdrs, lp)) + 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); @@ -310,5 +304,6 @@ xdr_double(xdrs, dp) case XDR_FREE: return (TRUE); } + /* NOTREACHED */ return (FALSE); } diff --git a/lib/libc/xdr/xdr_mem.c b/lib/libc/xdr/xdr_mem.c index 3193e64939dd..b54fc59c0a43 100644 --- a/lib/libc/xdr/xdr_mem.c +++ b/lib/libc/xdr/xdr_mem.c @@ -1,3 +1,5 @@ +/* $NetBSD: xdr_mem.c,v 1.15 2000/01/22 22:19:18 mycroft Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -27,6 +29,7 @@ * Mountain View, California 94043 */ +#include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)xdr_mem.c 1.19 87/08/11 Copyr 1984 Sun Micro";*/ /*static char *sccsid = "from: @(#)xdr_mem.c 2.1 88/07/29 4.0 RPCSRC";*/ @@ -44,24 +47,31 @@ static char *rcsid = "$FreeBSD$"; * */ +#include "namespace.h" +#include <sys/types.h> + +#include <netinet/in.h> + #include <string.h> + #include <rpc/types.h> #include <rpc/xdr.h> -#include <netinet/in.h> +#include "un-namespace.h" -static bool_t xdrmem_getlong_aligned(); -static bool_t xdrmem_putlong_aligned(); -static bool_t xdrmem_getlong_unaligned(); -static bool_t xdrmem_putlong_unaligned(); -static bool_t xdrmem_getbytes(); -static bool_t xdrmem_putbytes(); -static u_int xdrmem_getpos(); /* XXX w/64-bit pointers, u_int not enough! */ -static bool_t xdrmem_setpos(); -static int32_t *xdrmem_inline_aligned(); -static int32_t *xdrmem_inline_unaligned(); -static void xdrmem_destroy(); +static void xdrmem_destroy __P((XDR *)); +static bool_t xdrmem_getlong_aligned __P((XDR *, long *)); +static bool_t xdrmem_putlong_aligned __P((XDR *, const long *)); +static bool_t xdrmem_getlong_unaligned __P((XDR *, long *)); +static bool_t xdrmem_putlong_unaligned __P((XDR *, const long *)); +static bool_t xdrmem_getbytes __P((XDR *, char *, u_int)); +static bool_t xdrmem_putbytes __P((XDR *, const char *, u_int)); +/* XXX: w/64-bit pointers, u_int not enough! */ +static u_int xdrmem_getpos __P((XDR *)); +static bool_t xdrmem_setpos __P((XDR *, u_int)); +static int32_t *xdrmem_inline_aligned __P((XDR *, u_int)); +static int32_t *xdrmem_inline_unaligned __P((XDR *, u_int)); -static struct xdr_ops xdrmem_ops_aligned = { +static const struct xdr_ops xdrmem_ops_aligned = { xdrmem_getlong_aligned, xdrmem_putlong_aligned, xdrmem_getbytes, @@ -72,7 +82,7 @@ static struct xdr_ops xdrmem_ops_aligned = { xdrmem_destroy }; -static struct xdr_ops xdrmem_ops_unaligned = { +static const struct xdr_ops xdrmem_ops_unaligned = { xdrmem_getlong_unaligned, xdrmem_putlong_unaligned, xdrmem_getbytes, @@ -89,154 +99,156 @@ static struct xdr_ops xdrmem_ops_unaligned = { */ void xdrmem_create(xdrs, addr, size, op) - register XDR *xdrs; - caddr_t addr; + XDR *xdrs; + char *addr; u_int size; enum xdr_op op; { xdrs->x_op = op; - xdrs->x_ops = ((size_t)addr & (sizeof(int32_t) - 1)) - ? &xdrmem_ops_unaligned : &xdrmem_ops_aligned; + 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;*/ +xdrmem_destroy(xdrs) + XDR *xdrs; { } static bool_t xdrmem_getlong_aligned(xdrs, lp) - register XDR *xdrs; + XDR *xdrs; long *lp; { if ((xdrs->x_handy -= sizeof(int32_t)) < 0) return (FALSE); - *lp = ntohl(*(int32_t *)(xdrs->x_private)); - xdrs->x_private += 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) - register XDR *xdrs; - long *lp; + XDR *xdrs; + const long *lp; { if ((xdrs->x_handy -= sizeof(int32_t)) < 0) return (FALSE); - *(int32_t *)xdrs->x_private = htonl(*lp); - xdrs->x_private += 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) - register XDR *xdrs; + XDR *xdrs; long *lp; { - int32_t l; + u_int32_t l; if ((xdrs->x_handy -= sizeof(int32_t)) < 0) return (FALSE); - memcpy(&l, xdrs->x_private, sizeof(int32_t)); + memmove(&l, xdrs->x_private, sizeof(int32_t)); *lp = ntohl(l); - xdrs->x_private += sizeof(int32_t); + xdrs->x_private = (char *)xdrs->x_private + sizeof(int32_t); return (TRUE); } static bool_t xdrmem_putlong_unaligned(xdrs, lp) - register XDR *xdrs; - long *lp; + XDR *xdrs; + const long *lp; { - int32_t l; + u_int32_t l; if ((xdrs->x_handy -= sizeof(int32_t)) < 0) return (FALSE); - l = htonl(*lp); - memcpy(xdrs->x_private, &l, sizeof(int32_t)); - xdrs->x_private += 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) - register XDR *xdrs; - caddr_t addr; - register u_int len; + XDR *xdrs; + char *addr; + u_int len; { if ((xdrs->x_handy -= len) < 0) return (FALSE); - memcpy(addr, xdrs->x_private, len); - xdrs->x_private += 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) - register XDR *xdrs; - caddr_t addr; - register u_int len; + XDR *xdrs; + const char *addr; + u_int len; { if ((xdrs->x_handy -= len) < 0) return (FALSE); - memcpy(xdrs->x_private, addr, len); - xdrs->x_private += len; + memmove(xdrs->x_private, addr, len); + xdrs->x_private = (char *)xdrs->x_private + len; return (TRUE); } static u_int xdrmem_getpos(xdrs) - register XDR *xdrs; + XDR *xdrs; { /* XXX w/64-bit pointers, u_int not enough! */ - return ((u_long)xdrs->x_private - (u_long)xdrs->x_base); + return (u_int)((u_long)xdrs->x_private - (u_long)xdrs->x_base); } static bool_t xdrmem_setpos(xdrs, pos) - register XDR *xdrs; + XDR *xdrs; u_int pos; { - register caddr_t newaddr = xdrs->x_base + pos; - register caddr_t lastaddr = xdrs->x_private + xdrs->x_handy; + char *newaddr = xdrs->x_base + pos; + char *lastaddr = (char *)xdrs->x_private + xdrs->x_handy; if ((long)newaddr > (long)lastaddr) return (FALSE); xdrs->x_private = newaddr; - xdrs->x_handy = (long)lastaddr - (long)newaddr; + xdrs->x_handy = (int)((long)lastaddr - (long)newaddr); return (TRUE); } static int32_t * xdrmem_inline_aligned(xdrs, len) - register XDR *xdrs; - int 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 += 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) - register XDR *xdrs; - int len; + XDR *xdrs; + u_int len; { - + return (0); } diff --git a/lib/libc/xdr/xdr_rec.c b/lib/libc/xdr/xdr_rec.c index 7136463df545..616dbf618871 100644 --- a/lib/libc/xdr/xdr_rec.c +++ b/lib/libc/xdr/xdr_rec.c @@ -1,3 +1,5 @@ +/* $NetBSD: xdr_rec.c,v 1.18 2000/07/06 03:10:35 christos Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -26,7 +28,9 @@ * 2550 Garcia Avenue * Mountain View, California 94043 */ -#if defined(LIBC_SCCS) && !defined(lint) + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)xdr_rec.c 1.21 87/08/11 Copyr 1984 Sun Micro";*/ /*static char *sccsid = "from: @(#)xdr_rec.c 2.2 88/08/01 4.0 RPCSRC";*/ static char *rcsid = "$FreeBSD$"; @@ -45,33 +49,35 @@ static char *rcsid = "$FreeBSD$"; * 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. + * (1 => fragment is last, 0 => more fragments to follow. * The other 31 bits encode the byte length of the fragment. */ +#include "namespace.h" +#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 <netinet/in.h> +#include "un-namespace.h" -static u_int fix_buf_size(); -static bool_t flush_out(); -static bool_t get_input_bytes(); -static bool_t set_input_fragment(); -static bool_t skip_input_bytes(); +static bool_t xdrrec_getlong __P((XDR *, long *)); +static bool_t xdrrec_putlong __P((XDR *, const long *)); +static bool_t xdrrec_getbytes __P((XDR *, char *, u_int)); -static bool_t xdrrec_getlong(); -static bool_t xdrrec_putlong(); -static bool_t xdrrec_getbytes(); -static bool_t xdrrec_putbytes(); -static u_int xdrrec_getpos(); -static bool_t xdrrec_setpos(); -static int32_t *xdrrec_inline(); -static void xdrrec_destroy(); +static bool_t xdrrec_putbytes __P((XDR *, const char *, u_int)); +static u_int xdrrec_getpos __P((XDR *)); +static bool_t xdrrec_setpos __P((XDR *, u_int)); +static int32_t *xdrrec_inline __P((XDR *, u_int)); +static void xdrrec_destroy __P((XDR *)); -static struct xdr_ops xdrrec_ops = { +static const struct xdr_ops xdrrec_ops = { xdrrec_getlong, xdrrec_putlong, xdrrec_getbytes, @@ -98,31 +104,38 @@ static struct xdr_ops xdrrec_ops = { #define LAST_FRAG ((u_int32_t)(1 << 31)) typedef struct rec_strm { - caddr_t tcp_handle; - caddr_t the_buffer; + char *tcp_handle; + char *the_buffer; /* * out-goung bits */ - int (*writeit) __P((caddr_t, caddr_t, int)); - caddr_t out_base; /* output buffer (points to frag header) */ - caddr_t out_finger; /* next output position */ - caddr_t out_boundry; /* data cannot up to this address */ - u_int32_t *frag_header; /* beginning of current fragment */ + int (*writeit) __P((char *, char *, 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) __P((caddr_t, caddr_t, int)); + int (*readit) __P((char *, char *, int)); u_long in_size; /* fixed size of the input buffer */ - caddr_t in_base; - caddr_t in_finger; /* location of next byte to be had */ - caddr_t in_boundry; /* can read up to this location */ + 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; } RECSTREAM; +static u_int fix_buf_size __P((u_int)); +static bool_t flush_out __P((RECSTREAM *, bool_t)); +static bool_t fill_input_buf __P((RECSTREAM *)); +static bool_t get_input_bytes __P((RECSTREAM *, char *, int)); +static bool_t set_input_fragment __P((RECSTREAM *)); +static bool_t skip_input_bytes __P((RECSTREAM *, long)); + /* * Create an xdr handle for xdrrec @@ -135,20 +148,21 @@ typedef struct rec_strm { */ void xdrrec_create(xdrs, sendsize, recvsize, tcp_handle, readit, writeit) - register XDR *xdrs; - register u_int sendsize; - register u_int recvsize; - caddr_t tcp_handle; - int (*readit)(); /* like read, but pass it a tcp_handle, not sock */ - int (*writeit)(); /* like write, but pass it a tcp_handle, not sock */ + XDR *xdrs; + u_int sendsize; + u_int recvsize; + char *tcp_handle; + /* like read, but pass it a tcp_handle, not sock */ + int (*readit) __P((char *, char *, int)); + /* like write, but pass it a tcp_handle, not sock */ + int (*writeit) __P((char *, char *, int)); { - register RECSTREAM *rstrm = - (RECSTREAM *)mem_alloc(sizeof(RECSTREAM)); + RECSTREAM *rstrm = mem_alloc(sizeof(RECSTREAM)); if (rstrm == NULL) { - (void)fprintf(stderr, "xdrrec_create: out of memory\n"); - /* - * This is bad. Should rework xdrrec_create to + warnx("xdrrec_create: out of memory"); + /* + * This is bad. Should rework xdrrec_create to * return a handle, and in this case return NULL */ return; @@ -160,7 +174,7 @@ xdrrec_create(xdrs, sendsize, recvsize, tcp_handle, readit, writeit) rstrm->recvsize = recvsize = fix_buf_size(recvsize); rstrm->the_buffer = mem_alloc(sendsize + recvsize + BYTES_PER_XDR_UNIT); if (rstrm->the_buffer == NULL) { - (void)fprintf(stderr, "xdrrec_create: out of memory\n"); + warnx("xdrrec_create: out of memory"); return; } for (rstrm->out_base = rstrm->the_buffer; @@ -171,12 +185,12 @@ xdrrec_create(xdrs, sendsize, recvsize, tcp_handle, readit, writeit) * now the rest ... */ xdrs->x_ops = &xdrrec_ops; - xdrs->x_private = (caddr_t)rstrm; + 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 *)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; @@ -198,8 +212,8 @@ xdrrec_getlong(xdrs, lp) XDR *xdrs; long *lp; { - register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); - register int32_t *buflp = (int32_t *)(rstrm->in_finger); + RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); + int32_t *buflp = (int32_t *)(void *)(rstrm->in_finger); int32_t mylong; /* first try the inline, fast case */ @@ -209,7 +223,8 @@ xdrrec_getlong(xdrs, lp) rstrm->fbtbc -= sizeof(int32_t); rstrm->in_finger += sizeof(int32_t); } else { - if (! xdrrec_getbytes(xdrs, (caddr_t)&mylong, sizeof(int32_t))) + if (! xdrrec_getbytes(xdrs, (char *)(void *)&mylong, + sizeof(int32_t))) return (FALSE); *lp = (long)ntohl((u_int32_t)mylong); } @@ -219,10 +234,10 @@ xdrrec_getlong(xdrs, lp) static bool_t xdrrec_putlong(xdrs, lp) XDR *xdrs; - long *lp; + const long *lp; { - register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); - register int32_t *dest_lp = ((int32_t *)(rstrm->out_finger)); + 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) { /* @@ -233,7 +248,7 @@ xdrrec_putlong(xdrs, lp) rstrm->frag_sent = TRUE; if (! flush_out(rstrm, FALSE)) return (FALSE); - dest_lp = ((int32_t *)(rstrm->out_finger)); + dest_lp = ((int32_t *)(void *)(rstrm->out_finger)); rstrm->out_finger += sizeof(int32_t); } *dest_lp = (int32_t)htonl((u_int32_t)(*lp)); @@ -243,14 +258,14 @@ xdrrec_putlong(xdrs, lp) static bool_t /* must manage buffers, fragments, and records */ xdrrec_getbytes(xdrs, addr, len) XDR *xdrs; - register caddr_t addr; - register u_int len; + char *addr; + u_int len; { - register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); - register int current; + RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); + int current; while (len > 0) { - current = rstrm->fbtbc; + current = (int)rstrm->fbtbc; if (current == 0) { if (rstrm->last_frag) return (FALSE); @@ -261,7 +276,7 @@ xdrrec_getbytes(xdrs, addr, len) current = (len < current) ? len : current; if (! get_input_bytes(rstrm, addr, current)) return (FALSE); - addr += current; + addr += current; rstrm->fbtbc -= current; len -= current; } @@ -271,17 +286,17 @@ xdrrec_getbytes(xdrs, addr, len) static bool_t xdrrec_putbytes(xdrs, addr, len) XDR *xdrs; - register caddr_t addr; - register u_int len; + const char *addr; + u_int len; { - register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); - register long current; + RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); + size_t current; while (len > 0) { - current = (u_long)rstrm->out_boundry - - (u_long)rstrm->out_finger; + current = (size_t)((u_long)rstrm->out_boundry - + (u_long)rstrm->out_finger); current = (len < current) ? len : current; - memcpy(rstrm->out_finger, addr, current); + memmove(rstrm->out_finger, addr, current); rstrm->out_finger += current; addr += current; len -= current; @@ -296,12 +311,12 @@ xdrrec_putbytes(xdrs, addr, len) static u_int xdrrec_getpos(xdrs) - register XDR *xdrs; + XDR *xdrs; { - register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; - register long pos; + RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; + off_t pos; - pos = lseek((int)(long)rstrm->tcp_handle, (off_t) 0, 1); + pos = lseek((int)(u_long)rstrm->tcp_handle, (off_t)0, 1); if (pos != -1) switch (xdrs->x_op) { @@ -314,7 +329,7 @@ xdrrec_getpos(xdrs) break; default: - pos = -1; + pos = (off_t) -1; break; } return ((u_int) pos); @@ -322,20 +337,20 @@ xdrrec_getpos(xdrs) static bool_t xdrrec_setpos(xdrs, pos) - register XDR *xdrs; + XDR *xdrs; u_int pos; { - register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; + RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; u_int currpos = xdrrec_getpos(xdrs); int delta = currpos - pos; - caddr_t newpos; + char *newpos; if ((int)currpos != -1) switch (xdrs->x_op) { case XDR_ENCODE: newpos = rstrm->out_finger - delta; - if ((newpos > (caddr_t)(rstrm->frag_header)) && + if ((newpos > (char *)(void *)(rstrm->frag_header)) && (newpos < rstrm->out_boundry)) { rstrm->out_finger = newpos; return (TRUE); @@ -352,23 +367,26 @@ xdrrec_setpos(xdrs, pos) return (TRUE); } break; + + case XDR_FREE: + break; } return (FALSE); } static int32_t * xdrrec_inline(xdrs, len) - register XDR *xdrs; - int len; + XDR *xdrs; + u_int len; { - register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; - int32_t * buf = NULL; + 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 *) rstrm->out_finger; + buf = (int32_t *)(void *)rstrm->out_finger; rstrm->out_finger += len; } break; @@ -376,24 +394,27 @@ xdrrec_inline(xdrs, len) case XDR_DECODE: if ((len <= rstrm->fbtbc) && ((rstrm->in_finger + len) <= rstrm->in_boundry)) { - buf = (int32_t *) rstrm->in_finger; + 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) - register XDR *xdrs; + XDR *xdrs; { - register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; + RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; mem_free(rstrm->the_buffer, rstrm->sendsize + rstrm->recvsize + BYTES_PER_XDR_UNIT); - mem_free((caddr_t)rstrm, sizeof(RECSTREAM)); + mem_free(rstrm, sizeof(RECSTREAM)); } @@ -409,7 +430,7 @@ bool_t xdrrec_skiprecord(xdrs) XDR *xdrs; { - register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); + RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) { if (! skip_input_bytes(rstrm, rstrm->fbtbc)) @@ -423,7 +444,7 @@ xdrrec_skiprecord(xdrs) } /* - * Look ahead fuction. + * Look ahead function. * Returns TRUE iff there is no more input in the buffer * after consuming the rest of the current record. */ @@ -431,7 +452,7 @@ bool_t xdrrec_eof(xdrs) XDR *xdrs; { - register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); + RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) { if (! skip_input_bytes(rstrm, rstrm->fbtbc)) @@ -456,8 +477,8 @@ xdrrec_endofrecord(xdrs, sendnow) XDR *xdrs; bool_t sendnow; { - register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); - register u_long len; /* fragment length */ + 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) >= @@ -467,8 +488,8 @@ xdrrec_endofrecord(xdrs, sendnow) } len = (u_long)(rstrm->out_finger) - (u_long)(rstrm->frag_header) - sizeof(u_int32_t); - *(rstrm->frag_header) = htonl((u_long)len | LAST_FRAG); - rstrm->frag_header = (u_int32_t *)rstrm->out_finger; + *(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); } @@ -479,35 +500,36 @@ xdrrec_endofrecord(xdrs, sendnow) */ static bool_t flush_out(rstrm, eor) - register RECSTREAM *rstrm; + RECSTREAM *rstrm; bool_t eor; { - register u_long eormask = (eor == TRUE) ? LAST_FRAG : 0; - register u_int32_t len = (u_long)(rstrm->out_finger) - - (u_long)(rstrm->frag_header) - sizeof(u_int32_t); + 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_long)(rstrm->out_finger) - (u_long)(rstrm->out_base); + 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 *)rstrm->out_base; - rstrm->out_finger = (caddr_t)rstrm->out_base + sizeof(u_int32_t); + 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) - register RECSTREAM *rstrm; + RECSTREAM *rstrm; { - register caddr_t where; - u_long i; - register long len; + char *where; + u_int32_t i; + int len; where = rstrm->in_base; - i = (u_long)rstrm->in_boundry % BYTES_PER_XDR_UNIT; + i = (u_int32_t)((u_long)rstrm->in_boundry % BYTES_PER_XDR_UNIT); where += i; - len = rstrm->in_size - 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; @@ -518,21 +540,22 @@ fill_input_buf(rstrm) static bool_t /* knows nothing about records! Only about input buffers */ get_input_bytes(rstrm, addr, len) - register RECSTREAM *rstrm; - register caddr_t addr; - register int len; + RECSTREAM *rstrm; + char *addr; + int len; { - register long current; + size_t current; while (len > 0) { - current = (long)rstrm->in_boundry - (long)rstrm->in_finger; + 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; - memcpy(addr, rstrm->in_finger, current); + memmove(addr, rstrm->in_finger, current); rstrm->in_finger += current; addr += current; len -= current; @@ -542,13 +565,13 @@ get_input_bytes(rstrm, addr, len) static bool_t /* next two bytes of the input stream are treated as a header */ set_input_fragment(rstrm) - register RECSTREAM *rstrm; + RECSTREAM *rstrm; { u_int32_t header; - if (! get_input_bytes(rstrm, (caddr_t)&header, sizeof(header))) + if (! get_input_bytes(rstrm, (char *)(void *)&header, sizeof(header))) return (FALSE); - header = (long)ntohl(header); + header = ntohl(header); rstrm->last_frag = ((header & LAST_FRAG) == 0) ? FALSE : TRUE; /* * Sanity check. Try not to accept wildly incorrect @@ -566,19 +589,20 @@ set_input_fragment(rstrm) static bool_t /* consumes input bytes; knows nothing about records! */ skip_input_bytes(rstrm, cnt) - register RECSTREAM *rstrm; + RECSTREAM *rstrm; long cnt; { - register long current; + u_int32_t current; while (cnt > 0) { - current = (long)rstrm->in_boundry - (long)rstrm->in_finger; + current = (size_t)((long)rstrm->in_boundry - + (long)rstrm->in_finger); if (current == 0) { if (! fill_input_buf(rstrm)) return (FALSE); continue; } - current = (cnt < current) ? cnt : current; + current = (u_int32_t)((cnt < current) ? cnt : current); rstrm->in_finger += current; cnt -= current; } @@ -587,7 +611,7 @@ skip_input_bytes(rstrm, cnt) static u_int fix_buf_size(s) - register u_int s; + u_int s; { if (s < 100) diff --git a/lib/libc/xdr/xdr_reference.c b/lib/libc/xdr/xdr_reference.c index b0cdbce93008..60e7020413ef 100644 --- a/lib/libc/xdr/xdr_reference.c +++ b/lib/libc/xdr/xdr_reference.c @@ -1,3 +1,5 @@ +/* $NetBSD: xdr_reference.c,v 1.13 2000/01/22 22:19:18 mycroft Exp $ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -27,7 +29,8 @@ * Mountain View, California 94043 */ -#if defined(LIBC_SCCS) && !defined(lint) +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)xdr_reference.c 1.11 87/08/11 SMI";*/ /*static char *sccsid = "from: @(#)xdr_reference.c 2.1 88/07/29 4.0 RPCSRC";*/ static char *rcsid = "$FreeBSD$"; @@ -42,13 +45,15 @@ static char *rcsid = "$FreeBSD$"; * "pointers". See xdr.h for more info on the interface to xdr. */ +#include "namespace.h" +#include <err.h> #include <stdio.h> #include <stdlib.h> #include <string.h> + #include <rpc/types.h> #include <rpc/xdr.h> - -#define LASTUNSIGNED ((u_int) 0-1) +#include "libc_private.h" /* * XDR an indirect pointer @@ -61,13 +66,13 @@ static char *rcsid = "$FreeBSD$"; */ bool_t xdr_reference(xdrs, pp, size, proc) - register XDR *xdrs; + 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 */ { - register caddr_t loc = *pp; - register bool_t stat; + caddr_t loc = *pp; + bool_t stat; if (loc == NULL) switch (xdrs->x_op) { @@ -77,15 +82,17 @@ xdr_reference(xdrs, pp, size, proc) case XDR_DECODE: *pp = loc = (caddr_t) mem_alloc(size); if (loc == NULL) { - (void) fprintf(stderr, - "xdr_reference: out of memory\n"); + warnx("xdr_reference: out of memory"); return (FALSE); } - memset(loc, 0, (int)size); + memset(loc, 0, size); break; - } - stat = (*proc)(xdrs, loc, LASTUNSIGNED); + case XDR_ENCODE: + break; + } + + stat = (*proc)(xdrs, loc); if (xdrs->x_op == XDR_FREE) { mem_free(loc, size); @@ -116,7 +123,7 @@ xdr_reference(xdrs, pp, size, proc) */ bool_t xdr_pointer(xdrs,objpp,obj_size,xdr_obj) - register XDR *xdrs; + XDR *xdrs; char **objpp; u_int obj_size; xdrproc_t xdr_obj; diff --git a/lib/libc/xdr/xdr_sizeof.c b/lib/libc/xdr/xdr_sizeof.c index 5a4c1a78dc08..f90cc344798d 100644 --- a/lib/libc/xdr/xdr_sizeof.c +++ b/lib/libc/xdr/xdr_sizeof.c @@ -1,4 +1,6 @@ /* + * $FreeBSD$ + * * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape * media and as a part of the software program in whole or part. Users @@ -35,10 +37,12 @@ * when serialized using XDR. */ +#include "namespace.h" #include <rpc/types.h> #include <rpc/xdr.h> #include <sys/types.h> #include <stdlib.h> +#include "un-namespace.h" /* ARGSUSED */ static bool_t diff --git a/lib/libc/xdr/xdr_stdio.c b/lib/libc/xdr/xdr_stdio.c index 708573ccdf58..c4328ec181a8 100644 --- a/lib/libc/xdr/xdr_stdio.c +++ b/lib/libc/xdr/xdr_stdio.c @@ -1,3 +1,5 @@ +/* $NetBSD: xdr_stdio.c,v 1.14 2000/01/22 22:19:19 mycroft Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -27,6 +29,7 @@ * Mountain View, California 94043 */ +#include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)xdr_stdio.c 1.16 87/08/11 Copyr 1984 Sun Micro";*/ /*static char *sccsid = "from: @(#)xdr_stdio.c 2.1 88/07/29 4.0 RPCSRC";*/ @@ -43,23 +46,26 @@ static char *rcsid = "$FreeBSD$"; * from the stream. */ -#include <rpc/types.h> +#include "namespace.h" #include <stdio.h> + +#include <rpc/types.h> #include <rpc/xdr.h> +#include "un-namespace.h" -static bool_t xdrstdio_getlong(); -static bool_t xdrstdio_putlong(); -static bool_t xdrstdio_getbytes(); -static bool_t xdrstdio_putbytes(); -static u_int xdrstdio_getpos(); -static bool_t xdrstdio_setpos(); -static int32_t *xdrstdio_inline(); -static void xdrstdio_destroy(); +static void xdrstdio_destroy __P((XDR *)); +static bool_t xdrstdio_getlong __P((XDR *, long *)); +static bool_t xdrstdio_putlong __P((XDR *, const long *)); +static bool_t xdrstdio_getbytes __P((XDR *, char *, u_int)); +static bool_t xdrstdio_putbytes __P((XDR *, const char *, u_int)); +static u_int xdrstdio_getpos __P((XDR *)); +static bool_t xdrstdio_setpos __P((XDR *, u_int)); +static int32_t *xdrstdio_inline __P((XDR *, u_int)); /* * Ops vector for stdio type XDR */ -static struct xdr_ops xdrstdio_ops = { +static const struct xdr_ops xdrstdio_ops = { xdrstdio_getlong, /* deseraialize a long int */ xdrstdio_putlong, /* seraialize a long int */ xdrstdio_getbytes, /* deserialize counted bytes */ @@ -77,14 +83,14 @@ static struct xdr_ops xdrstdio_ops = { */ void xdrstdio_create(xdrs, file, op) - register XDR *xdrs; + XDR *xdrs; FILE *file; enum xdr_op op; { xdrs->x_op = op; xdrs->x_ops = &xdrstdio_ops; - xdrs->x_private = (caddr_t)file; + xdrs->x_private = file; xdrs->x_handy = 0; xdrs->x_base = 0; } @@ -95,35 +101,32 @@ xdrstdio_create(xdrs, file, op) */ static void xdrstdio_destroy(xdrs) - register XDR *xdrs; + XDR *xdrs; { (void)fflush((FILE *)xdrs->x_private); - /* xx should we close the file ?? */ + /* XXX: should we close the file ?? */ } static bool_t xdrstdio_getlong(xdrs, lp) XDR *xdrs; - register long *lp; + long *lp; { - if (fread((caddr_t)lp, sizeof(int32_t), 1, - (FILE *)xdrs->x_private) != 1) + if (fread(lp, sizeof(int32_t), 1, (FILE *)xdrs->x_private) != 1) return (FALSE); - *lp = (long)ntohl((int32_t)*lp); + *lp = (long)ntohl((u_int32_t)*lp); return (TRUE); } static bool_t xdrstdio_putlong(xdrs, lp) XDR *xdrs; - long *lp; + const long *lp; { + long mycopy = (long)htonl((u_int32_t)*lp); - long mycopy = (long)htonl((int32_t)*lp); - - if (fwrite((caddr_t)&mycopy, sizeof(int32_t), 1, - (FILE *)xdrs->x_private) != 1) + if (fwrite(&mycopy, sizeof(int32_t), 1, (FILE *)xdrs->x_private) != 1) return (FALSE); return (TRUE); } @@ -131,11 +134,11 @@ xdrstdio_putlong(xdrs, lp) static bool_t xdrstdio_getbytes(xdrs, addr, len) XDR *xdrs; - caddr_t addr; + char *addr; u_int len; { - if ((len != 0) && (fread(addr, (int)len, 1, (FILE *)xdrs->x_private) != 1)) + if ((len != 0) && (fread(addr, (size_t)len, 1, (FILE *)xdrs->x_private) != 1)) return (FALSE); return (TRUE); } @@ -143,11 +146,12 @@ xdrstdio_getbytes(xdrs, addr, len) static bool_t xdrstdio_putbytes(xdrs, addr, len) XDR *xdrs; - caddr_t addr; + const char *addr; u_int len; { - if ((len != 0) && (fwrite(addr, (int)len, 1, (FILE *)xdrs->x_private) != 1)) + if ((len != 0) && (fwrite(addr, (size_t)len, 1, + (FILE *)xdrs->x_private) != 1)) return (FALSE); return (TRUE); } @@ -161,15 +165,16 @@ xdrstdio_getpos(xdrs) } static bool_t -xdrstdio_setpos(xdrs, pos) +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; diff --git a/lib/libc_r/uthread/Makefile.inc b/lib/libc_r/uthread/Makefile.inc index fe19b0e081d3..cf9e154df50d 100644 --- a/lib/libc_r/uthread/Makefile.inc +++ b/lib/libc_r/uthread/Makefile.inc @@ -69,6 +69,7 @@ SRCS+= \ uthread_kevent.c \ uthread_kill.c \ uthread_listen.c \ + uthread_main_np.c \ uthread_mattr_init.c \ uthread_mattr_kind_np.c \ uthread_msync.c \ diff --git a/usr.sbin/portmap/pmap_check.h b/lib/libc_r/uthread/uthread_main_np.c index dc454a59d6d0..1ce336998f59 100644 --- a/usr.sbin/portmap/pmap_check.h +++ b/lib/libc_r/uthread/uthread_main_np.c @@ -1,5 +1,6 @@ -/*- - * Copyright (c) 2000 Brian Somers <brian@Awfulhak.org> +/* + * Copyright (c) 2001 Alfred Perlstein + * Author: Alfred Perlstein <alfred@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -23,19 +24,22 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#) pmap_check.h 1.3 93/11/21 16:18:53 - * - * $FreeBSD$ + * $FreeBSD$ */ -extern int from_local __P((struct sockaddr_in *)); -extern void check_startup __P((void)); -extern int check_default __P((struct sockaddr_in *, u_long, u_long)); -extern int check_setunset __P((struct sockaddr_in *, u_long, u_long, u_long)); -extern int check_privileged_port __P((struct sockaddr_in *, u_long, u_long, - u_long)); -extern int check_callit __P((struct sockaddr_in *, u_long, u_long, u_long)); +#include <pthread.h> +#include <pthread_np.h> +#include "pthread_private.h" + +/* + * Provide the equivelant to Solaris thr_main() function + */ +int +pthread_main_np() +{ -extern int verboselog; -extern int allow_severity; -extern int deny_severity; + if (!_thread_initial) + return (-1); + else + return (pthread_equal(pthread_self(), _thread_initial) ? 1 : 0); +} diff --git a/lib/libkse/thread/Makefile.inc b/lib/libkse/thread/Makefile.inc index fe19b0e081d3..cf9e154df50d 100644 --- a/lib/libkse/thread/Makefile.inc +++ b/lib/libkse/thread/Makefile.inc @@ -69,6 +69,7 @@ SRCS+= \ uthread_kevent.c \ uthread_kill.c \ uthread_listen.c \ + uthread_main_np.c \ uthread_mattr_init.c \ uthread_mattr_kind_np.c \ uthread_msync.c \ diff --git a/lib/libkse/thread/thr_main_np.c b/lib/libkse/thread/thr_main_np.c new file mode 100644 index 000000000000..1ce336998f59 --- /dev/null +++ b/lib/libkse/thread/thr_main_np.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2001 Alfred Perlstein + * Author: Alfred Perlstein <alfred@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <pthread.h> +#include <pthread_np.h> +#include "pthread_private.h" + +/* + * Provide the equivelant to Solaris thr_main() function + */ +int +pthread_main_np() +{ + + if (!_thread_initial) + return (-1); + else + return (pthread_equal(pthread_self(), _thread_initial) ? 1 : 0); +} diff --git a/lib/libpthread/thread/Makefile.inc b/lib/libpthread/thread/Makefile.inc index fe19b0e081d3..cf9e154df50d 100644 --- a/lib/libpthread/thread/Makefile.inc +++ b/lib/libpthread/thread/Makefile.inc @@ -69,6 +69,7 @@ SRCS+= \ uthread_kevent.c \ uthread_kill.c \ uthread_listen.c \ + uthread_main_np.c \ uthread_mattr_init.c \ uthread_mattr_kind_np.c \ uthread_msync.c \ diff --git a/lib/libpthread/thread/thr_main_np.c b/lib/libpthread/thread/thr_main_np.c new file mode 100644 index 000000000000..1ce336998f59 --- /dev/null +++ b/lib/libpthread/thread/thr_main_np.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2001 Alfred Perlstein + * Author: Alfred Perlstein <alfred@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <pthread.h> +#include <pthread_np.h> +#include "pthread_private.h" + +/* + * Provide the equivelant to Solaris thr_main() function + */ +int +pthread_main_np() +{ + + if (!_thread_initial) + return (-1); + else + return (pthread_equal(pthread_self(), _thread_initial) ? 1 : 0); +} diff --git a/lib/librpcsvc/Makefile b/lib/librpcsvc/Makefile index 077a33eadc69..d6f319de9169 100644 --- a/lib/librpcsvc/Makefile +++ b/lib/librpcsvc/Makefile @@ -12,7 +12,7 @@ RPCSRCS= klm_prot.x mount.x nfs_prot.x nlm_prot.x rex.x rnusers.x \ OTHERSRCS= rnusers.c rstat.c rwall.c yp_passwd.c yp_update.c SECRPCSRCS= secretkey.c xcrypt.c -RPCCOM = rpcgen -C +RPCCOM = rpcgen -CM INCDIRS= -I${DESTDIR}/usr/include/rpcsvc -I${DESTDIR}/usr/include diff --git a/lib/librpcsvc/yp_passwd.c b/lib/librpcsvc/yp_passwd.c index f3d42b7154d8..26104fb2e752 100644 --- a/lib/librpcsvc/yp_passwd.c +++ b/lib/librpcsvc/yp_passwd.c @@ -80,7 +80,7 @@ int _yppasswd(oldpass, newpw) } rval = callrpc(server, YPPASSWDPROG, YPPASSWDVERS, YPPASSWDPROC_UPDATE, - xdr_yppasswd, (char *)&yppasswd, xdr_int, &result); + xdr_yppasswd, (char *)&yppasswd, xdr_int, (char *)&result); free(server); if (rval || result) diff --git a/sbin/mount_nfs/mount_nfs.c b/sbin/mount_nfs/mount_nfs.c index 41873cace7a7..c1d746616901 100644 --- a/sbin/mount_nfs/mount_nfs.c +++ b/sbin/mount_nfs/mount_nfs.c @@ -50,6 +50,7 @@ static const char rcsid[] = #include <sys/param.h> #include <sys/mount.h> +#include <sys/socket.h> #include <sys/stat.h> #include <sys/syslog.h> @@ -72,6 +73,7 @@ static const char rcsid[] = #include <ctype.h> #include <err.h> #include <errno.h> +#include <fcntl.h> #include <netdb.h> #include <stdio.h> #include <stdlib.h> @@ -193,7 +195,7 @@ NFSKERBKEYSCHED_T kerb_keysched; #endif int getnfsargs __P((char *, struct nfs_args *)); -void set_rpc_maxgrouplist __P((int)); +/* void set_rpc_maxgrouplist __P((int)); */ void usage __P((void)) __dead2; int xdr_dir __P((XDR *, char *)); int xdr_fh __P((XDR *, struct nfhret *)); @@ -299,16 +301,16 @@ main(argc, argv) case 'd': nfsargsp->flags |= NFSMNT_DUMBTIMR; break; +#if 0 /* XXXX */ case 'g': num = strtol(optarg, &p, 10); if (*p || num <= 0) errx(1, "illegal -g value -- %s", optarg); -#ifdef __FreeBSD__ set_rpc_maxgrouplist(num); -#endif nfsargsp->maxgrouplist = num; nfsargsp->flags |= NFSMNT_MAXGRPS; break; +#endif case 'I': num = strtol(optarg, &p, 10); if (*p || num <= 0) @@ -456,7 +458,6 @@ main(argc, argv) /* resolve the mountpoint with realpath(3) */ (void)checkpath(name, mntpath); -#ifdef __FreeBSD__ error = getvfsbyname("nfs", &vfc); if (error && vfsisloadable("nfs")) { if(vfsload("nfs")) @@ -469,10 +470,6 @@ main(argc, argv) if (mount(vfc.vfc_name, mntpath, mntflags, nfsargsp)) err(1, "%s", mntpath); -#else - if (mount("nfs", mntpath, mntflags, nfsargsp)) - err(1, "%s", mntpath); -#endif if (nfsargsp->flags & (NFSMNT_NQNFS | NFSMNT_KERB)) { if ((opflags & ISBGRND) == 0) { if ((i = fork())) { @@ -577,75 +574,32 @@ main(argc, argv) exit(0); } -/* - * Return RPC_SUCCESS if server responds. - */ -enum clnt_stat -pingnfsserver(addr, version, sotype) - struct sockaddr_in *addr; - int version; - int sotype; -{ - struct sockaddr_in sin; - int tport; - CLIENT *clp; - int so = RPC_ANYSOCK; - enum clnt_stat stat; - struct timeval pertry, try; - - sin = *addr; - - if ((tport = port_no ? port_no : - pmap_getport(&sin, RPCPROG_NFS, version, nfsproto)) == 0) { - return rpc_createerr.cf_stat; - } - - sin.sin_port = htons(tport); - - pertry.tv_sec = 10; - pertry.tv_usec = 0; - if (sotype == SOCK_STREAM) - clp = clnttcp_create(&sin, RPCPROG_NFS, version, - &so, 0, 0); - else - clp = clntudp_create(&sin, RPCPROG_NFS, version, - pertry, &so); - if (clp == NULL) - return rpc_createerr.cf_stat; - - try.tv_sec = 10; - try.tv_usec = 0; - stat = clnt_call(clp, NFSPROC_NULL, - xdr_void, NULL, xdr_void, NULL, try); - - clnt_destroy(clp); - - return stat; -} - int getnfsargs(spec, nfsargsp) char *spec; struct nfs_args *nfsargsp; { - register CLIENT *clp; - struct hostent *hp; - static struct sockaddr_in saddr; + CLIENT *clp; + struct addrinfo hints, *ai_nfs, *ai; + int ecode; + char host[NI_MAXHOST], serv[NI_MAXSERV]; + static struct netbuf nfs_nb; + static struct sockaddr_storage nfs_ss; + struct netconfig *nconf; + char *netid; struct timeval pertry, try; enum clnt_stat clnt_stat; - int so = RPC_ANYSOCK, i, nfsvers, mntvers, orgcnt, speclen; + int so, i, nfsvers, mntvers, orgcnt, speclen; char *hostp, *delimp; #ifdef NFSKERB char *cp; #endif - u_short tport; size_t len; static struct nfhret nfhret; static char nam[MNAMELEN + 1]; - tport = 0; - - if ((delimp = strchr(spec, ':')) != NULL) { + so = i = 0; + if ((delimp = strrchr(spec, ':')) != NULL) { hostp = spec; spec = delimp + 1; } else if ((delimp = strrchr(spec, '@')) != NULL) { @@ -684,27 +638,29 @@ getnfsargs(spec, nfsargsp) * Handle an internet host address and reverse resolve it if * doing Kerberos. */ - if (isdigit(*hostp)) { - if ((saddr.sin_addr.s_addr = inet_addr(hostp)) == -1) { - warnx("bad net address %s", hostp); - return (0); + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_NUMERICHOST; + hints.ai_socktype = nfsargsp->sotype; + if (getaddrinfo(hostp, "nfs", &hints, &ai_nfs) == 0) { + if ((nfsargsp->flags & NFSMNT_KERB)) { + hints.ai_flags = 0; + if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host, + sizeof host, serv, sizeof serv, 0) != 0) { + warnx("can't reverse resolve net address"); + return (0); + } + hostp = host; } - } else if ((hp = gethostbyname(hostp)) != NULL) - memmove(&saddr.sin_addr, hp->h_addr, - MIN(hp->h_length, sizeof(saddr.sin_addr))); - else { - warnx("can't get net id for host"); - return (0); - } -#ifdef NFSKERB - if ((nfsargsp->flags & NFSMNT_KERB)) { - if ((hp = gethostbyaddr((char *)&saddr.sin_addr.s_addr, - sizeof (u_long), AF_INET)) == (struct hostent *)0) { - warnx("can't reverse resolve net address"); + } else { + hints.ai_flags = 0; + if ((ecode = getaddrinfo(hostp, "nfs", &hints, &ai_nfs)) != 0) { + warnx("can't get net id for host/nfs: %s", + gai_strerror(ecode)); return (0); } - memmove(&saddr.sin_addr, hp->h_addr, - MIN(hp->h_length, sizeof(saddr.sin_addr))); + } +#ifdef NFSKERB + if (nfsargsp->flags & NFSMNT_KERB) { strncpy(inst, hp->h_name, INST_SZ); inst[INST_SZ - 1] = '\0'; if (cp = strchr(inst, '.')) @@ -713,7 +669,7 @@ getnfsargs(spec, nfsargsp) #endif /* NFSKERB */ orgcnt = retrycnt; -tryagain: + if (mountmode == ANY || mountmode == V3) { nfsvers = 3; mntvers = 3; @@ -724,103 +680,125 @@ tryagain: nfsargsp->flags &= ~NFSMNT_NFSV3; } nfhret.stat = EACCES; /* Mark not yet successful */ - while (retrycnt > 0) { - saddr.sin_family = AF_INET; - saddr.sin_port = htons(PMAPPORT); - if ((tport = port_no ? port_no : - pmap_getport(&saddr, RPCPROG_NFS, - nfsvers, nfsproto)) == 0) { - if ((opflags & ISBGRND) == 0) - clnt_pcreateerror("NFS Portmap"); + ai = ai_nfs; + while (ai != NULL) { + /* + * XXX. Nead a generic (family, type, proto) -> nconf interface. + * __rpc_*2nconf exist, maybe they should be exported. + */ + if (nfsargsp->sotype == SOCK_STREAM) { + if (ai->ai_family == AF_INET6) + netid = "tcp6"; + else + netid = "tcp"; } else { - /* - * First ping the nfs server to see if it supports - * the version of the protocol we want to use. - */ - clnt_stat = pingnfsserver(&saddr, nfsvers, - nfsargsp->sotype); - if (clnt_stat == RPC_PROGVERSMISMATCH) { - if (mountmode == ANY) { - mountmode = V2; - goto tryagain; - } else { - errx(1, "can't contact NFS server"); - } - } - saddr.sin_port = 0; - pertry.tv_sec = 10; - pertry.tv_usec = 0; - if (mnttcp_ok && nfsargsp->sotype == SOCK_STREAM) - clp = clnttcp_create(&saddr, RPCPROG_MNT, mntvers, - &so, 0, 0); + if (ai->ai_family == AF_INET6) + netid = "udp6"; else - clp = clntudp_create(&saddr, RPCPROG_MNT, mntvers, - pertry, &so); - if (clp == NULL) { + netid = "udp"; + } + + nconf = getnetconfigent(netid); + +tryagain: + retrycnt = orgcnt; + + while (retrycnt > 0) { + nfs_nb.buf = &nfs_ss; + nfs_nb.maxlen = sizeof nfs_ss; + if (!rpcb_getaddr(RPCPROG_NFS, nfsvers, nconf, + &nfs_nb, hostp)){ + if (rpc_createerr.cf_stat == RPC_SYSTEMERROR) { + nfhret.stat = rpc_createerr.cf_error.re_errno; + break; + } + if (rpc_createerr.cf_stat == RPC_UNKNOWNPROTO) { + nfhret.stat = EPROTONOSUPPORT; + break; + } if ((opflags & ISBGRND) == 0) - clnt_pcreateerror("Cannot MNT RPC"); + clnt_pcreateerror( + "mount_nfs: rpcbind on server"); } else { - clp->cl_auth = authunix_create_default(); - try.tv_sec = 10; - try.tv_usec = 0; - if (nfsargsp->flags & NFSMNT_KERB) - nfhret.auth = RPCAUTH_KERB4; - else - nfhret.auth = RPCAUTH_UNIX; - nfhret.vers = mntvers; - clnt_stat = clnt_call(clp, RPCMNT_MOUNT, - xdr_dir, spec, xdr_fh, &nfhret, try); - if (clnt_stat != RPC_SUCCESS) { - if (clnt_stat == RPC_PROGVERSMISMATCH) { - if (mountmode == ANY) { - mountmode = V2; - goto tryagain; - } else { - errx(1, "%s", - clnt_sperror(clp, "MNT RPC")); - } - } + pertry.tv_sec = 10; + pertry.tv_usec = 0; + /* + * XXX relies on clnt_tcp_create to bind + * to a reserved socket. + */ + clp = clnt_tp_create(hostp, RPCPROG_MNT, mntvers, + mnttcp_ok ? nconf : getnetconfigent("udp")); + if (clp == NULL) { if ((opflags & ISBGRND) == 0) - warnx("%s", clnt_sperror(clp, - "bad MNT RPC")); + clnt_pcreateerror("Cannot MNT RPC"); } else { - retrycnt = 0; + CLNT_CONTROL(clp, CLSET_RETRY_TIMEOUT, + (char *)&pertry); + clp->cl_auth = authsys_create_default(); + try.tv_sec = 10; + try.tv_usec = 0; + if (nfsargsp->flags & NFSMNT_KERB) + nfhret.auth = RPCAUTH_KERB4; + else + nfhret.auth = RPCAUTH_UNIX; + nfhret.vers = mntvers; + clnt_stat = clnt_call(clp, RPCMNT_MOUNT, + xdr_dir, spec, xdr_fh, &nfhret, try); + if (clnt_stat != RPC_SUCCESS) { + if (clnt_stat == RPC_PROGVERSMISMATCH) { + if (mountmode == ANY) { + mountmode = V2; + goto tryagain; + } else { + errx(1, "%s", + clnt_sperror(clp, "MNT RPC")); + } + } + if ((opflags & ISBGRND) == 0) + warnx("%s", clnt_sperror(clp, + "bad MNT RPC")); + } else { + retrycnt = 0; + } + auth_destroy(clp->cl_auth); + clnt_destroy(clp); + so = RPC_ANYSOCK; } - auth_destroy(clp->cl_auth); - clnt_destroy(clp); - so = RPC_ANYSOCK; } - } - if (--retrycnt > 0) { - if (opflags & BGRND) { - warnx("Cannot immediately mount %s:%s, " - "backgrounding", hostp, spec); - opflags &= ~BGRND; - if ((i = fork())) { - if (i == -1) - err(1, "nqnfs 2"); - exit(0); + if (--retrycnt > 0) { + if (opflags & BGRND) { + warnx("Cannot immediately mount %s:%s, " + "backgrounding", hostp, spec); + opflags &= ~BGRND; + if ((i = fork())) { + if (i == -1) + err(1, "nqnfs 2"); + exit(0); + } + (void) setsid(); + (void) close(STDIN_FILENO); + (void) close(STDOUT_FILENO); + (void) close(STDERR_FILENO); + (void) chdir("/"); + opflags |= ISBGRND; } - (void) setsid(); - (void) close(STDIN_FILENO); - (void) close(STDOUT_FILENO); - (void) close(STDERR_FILENO); - (void) chdir("/"); - opflags |= ISBGRND; + sleep(60); } - sleep(60); } + if (nfhret.stat == 0) + break; + ai = ai->ai_next; } + freeaddrinfo(ai_nfs); if (nfhret.stat) { if (opflags & ISBGRND) exit(1); warnx("can't access %s: %s", spec, strerror(nfhret.stat)); return (0); } - saddr.sin_port = htons(tport); { - nfsargsp->addr = (struct sockaddr *) &saddr; - nfsargsp->addrlen = sizeof (saddr); + nfsargsp->addr = (struct sockaddr *) nfs_nb.buf; + nfsargsp->addrlen = nfs_nb.len; } nfsargsp->fh = nfhret.nfh; nfsargsp->fhsize = nfhret.fhsize; diff --git a/sbin/mountd/mountd.c b/sbin/mountd/mountd.c index 2f46a9f2ca9c..b5277656ac1e 100644 --- a/sbin/mountd/mountd.c +++ b/sbin/mountd/mountd.c @@ -50,12 +50,15 @@ static const char rcsid[] = #include <sys/param.h> #include <sys/mount.h> +#include <sys/fcntl.h> #include <sys/stat.h> #include <sys/syslog.h> #include <sys/sysctl.h> #include <rpc/rpc.h> #include <rpc/pmap_clnt.h> +#include <rpc/pmap_prot.h> +#include <rpcsvc/mount.h> #include <nfs/rpcv2.h> #include <nfs/nfsproto.h> #include <nfs/nfs.h> @@ -83,6 +86,10 @@ static const char rcsid[] = #include <stdarg.h> #endif +#ifndef MOUNTDLOCK +#define MOUNTDLOCK "/var/run/mountd.lock" +#endif + /* * Structures for keeping the mount list and export list */ @@ -117,13 +124,13 @@ struct exportlist { #define EX_LINKED 0x1 struct netmsk { - u_int32_t nt_net; + struct sockaddr_storage nt_net; u_int32_t nt_mask; char *nt_name; }; union grouptypes { - struct hostent *gt_hostent; + struct addrinfo *gt_addrinfo; struct netmsk gt_net; }; @@ -157,8 +164,8 @@ void add_dlist __P((struct dirlist **, struct dirlist *, void add_mlist __P((char *, char *)); int check_dirpath __P((char *)); int check_options __P((struct dirlist *)); -int chk_host __P((struct dirlist *, u_int32_t, int *, int *)); -void del_mlist __P((char *, char *)); +int chk_host __P((struct dirlist *, struct sockaddr *, int *, int *)); +int del_mlist __P((char *, char *, struct sockaddr *)); struct dirlist *dirp_search __P((struct dirlist *, char *)); int do_mount __P((struct exportlist *, struct grouplist *, int, struct xucred *, char *, int, struct statfs *)); @@ -186,18 +193,25 @@ void nextfield __P((char **, char **)); void out_of_mem __P((void)); void parsecred __P((char *, struct xucred *)); int put_exlist __P((struct dirlist *, XDR *, struct dirlist *, int *)); -int scan_tree __P((struct dirlist *, u_int32_t)); +int scan_tree __P((struct dirlist *, struct sockaddr *)); static void usage __P((void)); int xdr_dir __P((XDR *, char *)); int xdr_explist __P((XDR *, caddr_t)); int xdr_fhs __P((XDR *, caddr_t)); int xdr_mlist __P((XDR *, caddr_t)); +void terminate __P((int)); /* C library */ int getnetgrent(); void endnetgrent(); void setnetgrent(); +static int bitcmp __P((void *, void *, int)); +static int netpartcmp __P((struct sockaddr *, struct sockaddr *, int)); +static int sacmp __P((struct sockaddr *, struct sockaddr *)); +static int allones __P((struct sockaddr_storage *, int)); +static int countones __P((struct sockaddr *)); + struct exportlist *exphead; struct mountlist *mlhead; struct grouplist *grphead; @@ -213,7 +227,16 @@ int force_v2 = 0; int resvport_only = 1; int dir_only = 1; int log = 0; + int opt_flags; +static int have_v6 = 1; +#ifdef NI_WITHSCOPEID +static const int ninumeric = NI_NUMERICHOST | NI_WITHSCOPEID; +#else +static const int ninumeric = NI_NUMERICHOST; +#endif + +int mountdlockfd; /* Bits for above */ #define OP_MAPROOT 0x01 #define OP_MAPALL 0x02 @@ -221,6 +244,7 @@ int opt_flags; #define OP_MASK 0x08 #define OP_NET 0x10 #define OP_ALLDIRS 0x40 +#define OP_MASKLEN 0x200 #ifdef DEBUG int debug = 1; @@ -242,10 +266,26 @@ main(argc, argv) int argc; char **argv; { - SVCXPRT *udptransp, *tcptransp; + SVCXPRT *udptransp, *tcptransp, *udp6transp, *tcp6transp; + struct netconfig *udpconf, *tcpconf, *udp6conf, *tcp6conf; + int udpsock, tcpsock, udp6sock, tcp6sock; + int xcreated = 0, s; + int one = 1; int c, error, mib[3]; struct vfsconf vfc; + /* Check that another mountd isn't already running. */ + + if ((mountdlockfd = (open(MOUNTDLOCK, O_RDONLY|O_CREAT, 0444))) == -1) + err(1, "%s", MOUNTDLOCK); + + if(flock(mountdlockfd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK) + errx(1, "another rpc.mountd is already running. Aborting"); + s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (s < 0) + have_v6 = 0; + else + close(s); error = getvfsbyname("nfs", &vfc); if (error && vfsisloadable("nfs")) { if(vfsload("nfs")) @@ -301,12 +341,38 @@ main(argc, argv) signal(SIGQUIT, SIG_IGN); } signal(SIGHUP, (void (*) __P((int))) get_exportlist); + signal(SIGTERM, terminate); { FILE *pidfile = fopen(_PATH_MOUNTDPID, "w"); if (pidfile != NULL) { fprintf(pidfile, "%d\n", getpid()); fclose(pidfile); } } + rpcb_unset(RPCPROG_MNT, RPCMNT_VER1, NULL); + rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL); + udpsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + tcpsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + udp6sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + tcp6sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); + /* + * We're doing host-based access checks here, so don't allow + * v4-in-v6 to confuse things. The kernel will disable it + * by default on NFS sockets too. + */ + if (udp6sock != -1 && setsockopt(udp6sock, IPPROTO_IPV6, + IPV6_BINDV6ONLY, &one, sizeof one) < 0){ + syslog(LOG_ERR, "can't disable v4-in-v6 on UDP socket"); + exit(1); + } + if (tcp6sock != -1 && setsockopt(tcp6sock, IPPROTO_IPV6, + IPV6_BINDV6ONLY, &one, sizeof one) < 0){ + syslog(LOG_ERR, "can't disable v4-in-v6 on UDP socket"); + exit(1); + } + udpconf = getnetconfigent("udp"); + tcpconf = getnetconfigent("tcp"); + udp6conf = getnetconfigent("udp6"); + tcp6conf = getnetconfigent("tcp6"); if (!resvport_only) { mib[0] = CTL_VFS; mib[1] = vfc.vfc_typenum; @@ -322,17 +388,90 @@ main(argc, argv) syslog(LOG_ERR, "can't create socket"); exit(1); } - pmap_unset(RPCPROG_MNT, 1); - pmap_unset(RPCPROG_MNT, 3); - if (!force_v2) - if (!svc_register(udptransp, RPCPROG_MNT, 3, mntsrv, IPPROTO_UDP) || - !svc_register(tcptransp, RPCPROG_MNT, 3, mntsrv, IPPROTO_TCP)) { - syslog(LOG_ERR, "can't register mount"); - exit(1); - } - if (!svc_register(udptransp, RPCPROG_MNT, 1, mntsrv, IPPROTO_UDP) || - !svc_register(tcptransp, RPCPROG_MNT, 1, mntsrv, IPPROTO_TCP)) { - syslog(LOG_ERR, "can't register mount"); + if (udpsock != -1 && udpconf != NULL) { + bindresvport(udpsock, NULL); + udptransp = svc_dg_create(udpsock, 0, 0); + if (udptransp != NULL) { + if (!svc_reg(udptransp, RPCPROG_MNT, RPCMNT_VER1, + mntsrv, udpconf)) + syslog(LOG_WARNING, "can't register UDP RPCMNT_VER1 service"); + else + xcreated++; + if (!force_v2) { + if (!svc_reg(udptransp, RPCPROG_MNT, RPCMNT_VER3, + mntsrv, udpconf)) + syslog(LOG_WARNING, "can't register UDP RPCMNT_VER3 service"); + else + xcreated++; + } + } else + syslog(LOG_WARNING, "can't create UDP services"); + + } + if (tcpsock != -1 && tcpconf != NULL) { + bindresvport(tcpsock, NULL); + listen(tcpsock, SOMAXCONN); + tcptransp = svc_vc_create(tcpsock, 0, 0); + if (tcptransp != NULL) { + if (!svc_reg(tcptransp, RPCPROG_MNT, RPCMNT_VER1, + mntsrv, tcpconf)) + syslog(LOG_WARNING, "can't register TCP RPCMNT_VER1 service"); + else + xcreated++; + if (!force_v2) { + if (!svc_reg(tcptransp, RPCPROG_MNT, RPCMNT_VER3, + mntsrv, tcpconf)) + syslog(LOG_WARNING, "can't register TCP RPCMNT_VER3 service"); + else + xcreated++; + } + } else + syslog(LOG_WARNING, "can't create TCP service"); + + } + if (udp6sock != -1 && udp6conf != NULL) { + bindresvport(udp6sock, NULL); + udp6transp = svc_dg_create(udp6sock, 0, 0); + if (udp6transp != NULL) { + if (!svc_reg(udp6transp, RPCPROG_MNT, RPCMNT_VER1, + mntsrv, udp6conf)) + syslog(LOG_WARNING, "can't register UDP6 RPCMNT_VER1 service"); + else + xcreated++; + if (!force_v2) { + if (!svc_reg(udp6transp, RPCPROG_MNT, RPCMNT_VER3, + mntsrv, udp6conf)) + syslog(LOG_WARNING, "can't register UDP6 RPCMNT_VER3 service"); + else + xcreated++; + } + } else + syslog(LOG_WARNING, "can't create UDP6 service"); + + } + if (tcp6sock != -1 && tcp6conf != NULL) { + bindresvport(tcp6sock, NULL); + listen(tcp6sock, SOMAXCONN); + tcp6transp = svc_vc_create(tcp6sock, 0, 0); + if (tcp6transp != NULL) { + if (!svc_reg(tcp6transp, RPCPROG_MNT, RPCMNT_VER1, + mntsrv, tcp6conf)) + syslog(LOG_WARNING, "can't register TCP6 RPCMNT_VER1 service"); + else + xcreated++; + if (!force_v2) { + if (!svc_reg(tcp6transp, RPCPROG_MNT, RPCMNT_VER3, + mntsrv, tcp6conf)) + syslog(LOG_WARNING, "can't register TCP6 RPCMNT_VER3 service"); + else + xcreated++; + } + } else + syslog(LOG_WARNING, "can't create TCP6 service"); + + } + if (xcreated == 0) { + syslog(LOG_ERR, "could not create any services"); exit(1); } svc_run(); @@ -361,20 +500,38 @@ mntsrv(rqstp, transp) struct fhreturn fhr; struct stat stb; struct statfs fsb; - struct hostent *hp; - struct in_addr saddrin; - u_int32_t saddr; + struct addrinfo *ai; + char host[NI_MAXHOST], numerichost[NI_MAXHOST]; + int lookup_failed = 1; + struct sockaddr *saddr; u_short sport; char rpcpath[RPCMNT_PATHLEN + 1], dirpath[MAXPATHLEN]; int bad = 0, defset, hostset; sigset_t sighup_mask; + struct sockaddr_in6 *sin6; + struct sockaddr_in *sin; sigemptyset(&sighup_mask); sigaddset(&sighup_mask, SIGHUP); - saddr = transp->xp_raddr.sin_addr.s_addr; - saddrin = transp->xp_raddr.sin_addr; - sport = ntohs(transp->xp_raddr.sin_port); - hp = (struct hostent *)NULL; + saddr = svc_getrpccaller(transp)->buf; + switch (saddr->sa_family) { + case AF_INET6: + sin6 = (struct sockaddr_in6 *)saddr; + sport = ntohs(sin6->sin6_port); + break; + case AF_INET: + sin = (struct sockaddr_in *)saddr; + sport = ntohs(sin->sin_port); + break; + default: + syslog(LOG_ERR, "request from unknown address family"); + return; + } + lookup_failed = getnameinfo(saddr, saddr->sa_len, host, sizeof host, + NULL, 0, 0); + getnameinfo(saddr, saddr->sa_len, numerichost, + sizeof numerichost, NULL, 0, NI_NUMERICHOST); + ai = NULL; switch (rqstp->rq_proc) { case NULLPROC: if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) @@ -384,13 +541,13 @@ mntsrv(rqstp, transp) if (sport >= IPPORT_RESERVED && resvport_only) { syslog(LOG_NOTICE, "mount request from %s from unprivileged port", - inet_ntoa(saddrin)); + numerichost); svcerr_weakauth(transp); return; } if (!svc_getargs(transp, xdr_dir, rpcpath)) { syslog(LOG_NOTICE, "undecodable mount request from %s", - inet_ntoa(saddrin)); + numerichost); svcerr_decode(transp); return; } @@ -403,12 +560,12 @@ mntsrv(rqstp, transp) if (realpath(rpcpath, dirpath) == NULL || stat(dirpath, &stb) < 0 || (!S_ISDIR(stb.st_mode) && - (dir_only || !S_ISREG(stb.st_mode))) || + (dir_only || !S_ISREG(stb.st_mode))) || statfs(dirpath, &fsb) < 0) { chdir("/"); /* Just in case realpath doesn't */ syslog(LOG_NOTICE, "mount request from %s for non existent path %s", - inet_ntoa(saddrin), dirpath); + numerichost, dirpath); if (debug) warnx("stat failed on %s", dirpath); bad = ENOENT; /* We will send error reply later */ @@ -420,9 +577,9 @@ mntsrv(rqstp, transp) hostset = defset = 0; if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) || ((dp = dirp_search(ep->ex_dirl, dirpath)) && - chk_host(dp, saddr, &defset, &hostset)) || - (defset && scan_tree(ep->ex_defdir, saddr) == 0 && - scan_tree(ep->ex_dirl, saddr) == 0))) { + chk_host(dp, saddr, &defset, &hostset)) || + (defset && scan_tree(ep->ex_defdir, saddr) == 0 && + scan_tree(ep->ex_dirl, saddr) == 0))) { if (bad) { if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) @@ -448,25 +605,21 @@ mntsrv(rqstp, transp) } if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&fhr)) syslog(LOG_ERR, "can't send reply"); - if (hp == NULL) - hp = gethostbyaddr((caddr_t)&saddr, - sizeof(saddr), AF_INET); - if (hp) - add_mlist(hp->h_name, dirpath); + if (!lookup_failed) + add_mlist(host, dirpath); else - add_mlist(inet_ntoa(saddrin), - dirpath); + add_mlist(numerichost, dirpath); if (debug) warnx("mount successful"); if (log) syslog(LOG_NOTICE, "mount request succeeded from %s for %s", - inet_ntoa(saddrin), dirpath); + numerichost, dirpath); } else { bad = EACCES; syslog(LOG_NOTICE, "mount request denied from %s for %s", - inet_ntoa(saddrin), dirpath); + numerichost, dirpath); } if (bad && !svc_sendreply(transp, xdr_long, (caddr_t)&bad)) @@ -479,56 +632,54 @@ mntsrv(rqstp, transp) else if (log) syslog(LOG_NOTICE, "dump request succeeded from %s", - inet_ntoa(saddrin)); + numerichost); return; case RPCMNT_UMOUNT: if (sport >= IPPORT_RESERVED && resvport_only) { syslog(LOG_NOTICE, "umount request from %s from unprivileged port", - inet_ntoa(saddrin)); + numerichost); svcerr_weakauth(transp); return; } if (!svc_getargs(transp, xdr_dir, rpcpath)) { syslog(LOG_NOTICE, "undecodable umount request from %s", - inet_ntoa(saddrin)); + numerichost); svcerr_decode(transp); return; } if (realpath(rpcpath, dirpath) == NULL) { syslog(LOG_NOTICE, "umount request from %s " "for non existent path %s", - inet_ntoa(saddrin), dirpath); + numerichost, dirpath); } if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) syslog(LOG_ERR, "can't send reply"); - hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); - if (hp) - del_mlist(hp->h_name, dirpath); - del_mlist(inet_ntoa(saddrin), dirpath); + if (!lookup_failed) + del_mlist(host, dirpath, saddr); + del_mlist(numerichost, dirpath, saddr); if (log) syslog(LOG_NOTICE, "umount request succeeded from %s for %s", - inet_ntoa(saddrin), dirpath); + numerichost, dirpath); return; case RPCMNT_UMNTALL: if (sport >= IPPORT_RESERVED && resvport_only) { syslog(LOG_NOTICE, "umountall request from %s from unprivileged port", - inet_ntoa(saddrin)); + numerichost); svcerr_weakauth(transp); return; } if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) syslog(LOG_ERR, "can't send reply"); - hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); - if (hp) - del_mlist(hp->h_name, (char *)NULL); - del_mlist(inet_ntoa(saddrin), (char *)NULL); + if (!lookup_failed) + del_mlist(host, NULL, saddr); + del_mlist(numerichost, NULL, saddr); if (log) syslog(LOG_NOTICE, "umountall request succeeded from %s", - inet_ntoa(saddrin)); + numerichost); return; case RPCMNT_EXPORT: if (!svc_sendreply(transp, xdr_explist, (caddr_t)NULL)) @@ -536,7 +687,7 @@ mntsrv(rqstp, transp) if (log) syslog(LOG_NOTICE, "export request succeeded from %s", - inet_ntoa(saddrin)); + numerichost); return; default: svcerr_noproc(transp); @@ -690,7 +841,7 @@ put_exlist(dp, xdrsp, adp, putdefp) if (grp->gr_type == GT_HOST) { if (!xdr_bool(xdrsp, &true)) return (1); - strp = grp->gr_ptr.gt_hostent->h_name; + strp = grp->gr_ptr.gt_addrinfo->ai_canonname; if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) return (1); @@ -732,7 +883,7 @@ get_exportlist() struct exportlist **epp; struct dirlist *dirhead; struct statfs fsb, *fsp; - struct hostent *hpe; + struct addrinfo *ai; struct xucred anon; char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp; @@ -786,7 +937,7 @@ get_exportlist() fsp->f_flags | MNT_UPDATE, (caddr_t)&targs) < 0) syslog(LOG_ERR, "can't delete exports for %s", - fsp->f_mntonname); + fsp->f_mntonname); } fsp++; } @@ -874,9 +1025,9 @@ get_exportlist() else out_of_mem(); if (debug) - warnx("making new ep fs=0x%x,0x%x", - fsb.f_fsid.val[0], - fsb.f_fsid.val[1]); + warnx("making new ep fs=0x%x,0x%x", + fsb.f_fsid.val[0], + fsb.f_fsid.val[1]); } else if (debug) warnx("found ep fs=0x%x,0x%x", fsb.f_fsid.val[0], @@ -944,14 +1095,17 @@ get_exportlist() if (debug) warnx("adding a default entry"); /* add a default group and make the grp list NULL */ - hpe = (struct hostent *)malloc(sizeof(struct hostent)); - if (hpe == (struct hostent *)NULL) - out_of_mem(); - hpe->h_name = strdup("Default"); - hpe->h_addrtype = AF_INET; - hpe->h_length = sizeof (u_int32_t); - hpe->h_addr_list = (char **)NULL; - grp->gr_ptr.gt_hostent = hpe; + ai = malloc(sizeof(struct addrinfo)); + ai->ai_flags = 0; + ai->ai_family = AF_INET; /* XXXX */ + ai->ai_socktype = SOCK_DGRAM; + /* setting the length to 0 will match anything */ + ai->ai_addrlen = 0; + ai->ai_flags = AI_CANONNAME; + ai->ai_canonname = strdup("Default"); + ai->ai_addr = NULL; + ai->ai_next = NULL; + grp->gr_ptr.gt_addrinfo = ai; /* * Don't allow a network export coincide with a list of @@ -961,13 +1115,13 @@ get_exportlist() getexp_err(ep, tgrp); goto nextline; - /* - * If an export list was specified on this line, make sure + /* + * If an export list was specified on this line, make sure * that we have at least one valid entry, otherwise skip it. */ } else { grp = tgrp; - while (grp && grp->gr_type == GT_IGNORE) + while (grp && grp->gr_type == GT_IGNORE) grp = grp->gr_next; if (! grp) { getexp_err(ep, tgrp); @@ -1219,19 +1373,27 @@ add_dlist(dpp, newdp, grp, flags) /* * Search for a dirpath on the export point. */ +void * +test() +{ +} + +/* + * Search for a dirpath on the export point. + */ struct dirlist * -dirp_search(dp, dirpath) +dirp_search(dp, dirp) struct dirlist *dp; - char *dirpath; + char *dirp; { int cmp; if (dp) { - cmp = strcmp(dp->dp_dirp, dirpath); + cmp = strcmp(dp->dp_dirp, dirp); if (cmp > 0) - return (dirp_search(dp->dp_left, dirpath)); + return (dirp_search(dp->dp_left, dirp)); else if (cmp < 0) - return (dirp_search(dp->dp_right, dirpath)); + return (dirp_search(dp->dp_right, dirp)); else return (dp); } @@ -1239,18 +1401,59 @@ dirp_search(dp, dirpath) } /* + * Some helper functions for netmasks. They all assume masks in network + * order (big endian). + */ +static int +bitcmp(void *dst, void *src, int bitlen) +{ + int i; + u_int8_t *p1 = dst, *p2 = src; + u_int8_t bitmask; + int bytelen, bitsleft; + + bytelen = bitlen / 8; + bitsleft = bitlen % 8; + + if (debug) { + printf("comparing:\n"); + for (i = 0; i < (bitsleft ? bytelen + 1 : bytelen); i++) + printf("%02x", p1[i]); + printf("\n"); + for (i = 0; i < (bitsleft ? bytelen + 1 : bytelen); i++) + printf("%02x", p2[i]); + printf("\n"); + } + + for (i = 0; i < bytelen; i++) { + if (*p1 != *p2) + return 1; + p1++; + p2++; + } + + for (i = 0; i < bitsleft; i++) { + bitmask = 1 << (7 - i); + if ((*p1 & bitmask) != (*p2 & bitmask)) + return 1; + } + + return 0; +} + +/* * Scan for a host match in a directory tree. */ int chk_host(dp, saddr, defsetp, hostsetp) struct dirlist *dp; - u_int32_t saddr; + struct sockaddr *saddr; int *defsetp; int *hostsetp; { struct hostlist *hp; struct grouplist *grp; - u_int32_t **addrp; + struct addrinfo *ai; if (dp) { if (dp->dp_flag & DP_DEFSET) @@ -1260,22 +1463,22 @@ chk_host(dp, saddr, defsetp, hostsetp) grp = hp->ht_grp; switch (grp->gr_type) { case GT_HOST: - addrp = (u_int32_t **) - grp->gr_ptr.gt_hostent->h_addr_list; - while (*addrp) { - if (**addrp == saddr) { - *hostsetp = (hp->ht_flag | DP_HOSTSET); - return (1); + ai = grp->gr_ptr.gt_addrinfo; + for (; ai; ai = ai->ai_next) { + if (!sacmp(ai->ai_addr, saddr)) { + *hostsetp = + (hp->ht_flag | DP_HOSTSET); + return (1); + } } - addrp++; - } break; case GT_NET: - if ((saddr & grp->gr_ptr.gt_net.nt_mask) == - grp->gr_ptr.gt_net.nt_net) { - *hostsetp = (hp->ht_flag | DP_HOSTSET); - return (1); - } + if (!netpartcmp(saddr, + (struct sockaddr *) &grp->gr_ptr.gt_net.nt_net, + grp->gr_ptr.gt_net.nt_mask)) { + *hostsetp = (hp->ht_flag | DP_HOSTSET); + return (1); + } break; }; hp = hp->ht_next; @@ -1290,7 +1493,7 @@ chk_host(dp, saddr, defsetp, hostsetp) int scan_tree(dp, saddr) struct dirlist *dp; - u_int32_t saddr; + struct sockaddr *saddr; { int defset, hostset; @@ -1392,6 +1595,11 @@ do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr) opt_flags |= OP_MASK; } else if (cpoptarg && (!strcmp(cpopt, "network") || !strcmp(cpopt, "n"))) { + if (strchr(cpoptarg, '/') != NULL) { + if (debug) + fprintf(stderr, "setting OP_MASKLEN\n"); + opt_flags |= OP_MASKLEN; + } if (grp->gr_type != GT_NULL) { syslog(LOG_ERR, "network/host conflict"); return (1); @@ -1442,84 +1650,40 @@ get_host(cp, grp, tgrp) struct grouplist *tgrp; { struct grouplist *checkgrp; - struct hostent *hp, *nhp; - char **addrp, **naddrp; - struct hostent t_host; + struct addrinfo *ai, hints; + int ecode; + char host[NI_MAXHOST]; int i; - u_int32_t saddr; char *aptr[2]; - if (grp->gr_type != GT_NULL) + if (grp->gr_type != GT_NULL) { + syslog(LOG_ERR, "Bad netgroup type for ip host %s", cp); return (1); - if ((hp = gethostbyname(cp)) == NULL) { - if (isdigit(*cp)) { - saddr = inet_addr(cp); - if (saddr == -1) { - syslog(LOG_ERR, "inet_addr failed for %s", cp); - return (1); - } - if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr), - AF_INET)) == NULL) { - hp = &t_host; - hp->h_name = cp; - hp->h_addrtype = AF_INET; - hp->h_length = sizeof (u_int32_t); - hp->h_addr_list = aptr; - aptr[0] = (char *)&saddr; - aptr[1] = (char *)NULL; - } - } else { - syslog(LOG_ERR, "gethostbyname failed for %s", cp); - return (1); - } } - /* - * Sanity check: make sure we don't already have an entry - * for this host in the grouplist. - */ - checkgrp = tgrp; - while (checkgrp != NULL) { - if (checkgrp->gr_type == GT_HOST && - checkgrp->gr_ptr.gt_hostent != NULL && - (!strcmp(checkgrp->gr_ptr.gt_hostent->h_name, hp->h_name) - || *(u_int32_t *)checkgrp->gr_ptr.gt_hostent->h_addr == - *(u_int32_t *)hp->h_addr)) { - grp->gr_type = GT_IGNORE; - return(0); - } - checkgrp = checkgrp->gr_next; - } - + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_CANONNAME; + hints.ai_protocol = IPPROTO_UDP; + ecode = getaddrinfo(cp, NULL, &hints, &ai); + if (ecode != 0) { + syslog(LOG_ERR,"can't get address info for " + "host %s", cp); + return 1; + } grp->gr_type = GT_HOST; - nhp = grp->gr_ptr.gt_hostent = (struct hostent *) - malloc(sizeof(struct hostent)); - if (nhp == (struct hostent *)NULL) - out_of_mem(); - memmove(nhp, hp, sizeof(struct hostent)); - i = strlen(hp->h_name)+1; - nhp->h_name = (char *)malloc(i); - if (nhp->h_name == (char *)NULL) - out_of_mem(); - memmove(nhp->h_name, hp->h_name, i); - addrp = hp->h_addr_list; - i = 1; - while (*addrp++) - i++; - naddrp = nhp->h_addr_list = (char **)malloc(i*sizeof(char *)); - if (naddrp == (char **)NULL) - out_of_mem(); - addrp = hp->h_addr_list; - while (*addrp) { - *naddrp = (char *)malloc(hp->h_length); - if (*naddrp == (char *)NULL) - out_of_mem(); - memmove(*naddrp, *addrp, hp->h_length); - addrp++; - naddrp++; + grp->gr_ptr.gt_addrinfo = ai; + while (ai != NULL) { + if (ai->ai_canonname == NULL) { + if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host, + sizeof host, NULL, 0, ninumeric) != 0) + strlcpy(host, "?", sizeof(host)); + ai->ai_canonname = strdup(host); + ai->ai_flags |= AI_CANONNAME; + } else + ai->ai_flags &= ~AI_CANONNAME; + if (debug) + (void)fprintf(stderr, "got host %s\n", ai->ai_canonname); + ai = ai->ai_next; } - *naddrp = (char *)NULL; - if (debug) - warnx("got host %s", hp->h_name); return (0); } @@ -1597,68 +1761,64 @@ do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb) int dirplen; struct statfs *fsb; { - char *cp = (char *)NULL; - u_int32_t **addrp; + struct sockaddr *addrp; + struct sockaddr_storage ss; + struct addrinfo *ai; + int addrlen; + char *cp = NULL; int done; char savedc = '\0'; - struct sockaddr_in sin, imask; union { struct ufs_args ua; struct iso_args ia; struct mfs_args ma; #ifdef __NetBSD__ struct msdosfs_args da; + struct adosfs_args aa; #endif struct ntfs_args na; } args; - u_int32_t net; args.ua.fspec = 0; args.ua.export.ex_flags = exflags; args.ua.export.ex_anon = *anoncrp; args.ua.export.ex_indexfile = ep->ex_indexfile; - memset(&sin, 0, sizeof(sin)); - memset(&imask, 0, sizeof(imask)); - sin.sin_family = AF_INET; - sin.sin_len = sizeof(sin); - imask.sin_family = AF_INET; - imask.sin_len = sizeof(sin); - if (grp->gr_type == GT_HOST) - addrp = (u_int32_t **)grp->gr_ptr.gt_hostent->h_addr_list; - else - addrp = (u_int32_t **)NULL; + if (grp->gr_type == GT_HOST) { + ai = grp->gr_ptr.gt_addrinfo; + addrp = ai->ai_addr; + addrlen = ai->ai_addrlen; + } else + addrp = NULL; done = FALSE; while (!done) { switch (grp->gr_type) { case GT_HOST: - if (addrp) { - sin.sin_addr.s_addr = **addrp; - args.ua.export.ex_addrlen = sizeof(sin); - } else - args.ua.export.ex_addrlen = 0; - args.ua.export.ex_addr = (struct sockaddr *)&sin; + if (addrp != NULL && addrp->sa_family == AF_INET6 && + have_v6 == 0) + goto skip; + args.ua.export.ex_addr = addrp; + args.ua.export.ex_addrlen = addrlen; args.ua.export.ex_masklen = 0; break; case GT_NET: - if (grp->gr_ptr.gt_net.nt_mask) - imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask; - else { - net = ntohl(grp->gr_ptr.gt_net.nt_net); - if (IN_CLASSA(net)) - imask.sin_addr.s_addr = inet_addr("255.0.0.0"); - else if (IN_CLASSB(net)) - imask.sin_addr.s_addr = - inet_addr("255.255.0.0"); - else - imask.sin_addr.s_addr = - inet_addr("255.255.255.0"); - grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr; + args.ua.export.ex_addr = (struct sockaddr *) + &grp->gr_ptr.gt_net.nt_net; + if (args.ua.export.ex_addr->sa_family == AF_INET6 && + have_v6 == 0) + goto skip; + args.ua.export.ex_addrlen = + args.ua.export.ex_addr->sa_len; + memset(&ss, 0, sizeof ss); + ss.ss_family = args.ua.export.ex_addr->sa_family; + ss.ss_len = args.ua.export.ex_addr->sa_len; + if (allones(&ss, grp->gr_ptr.gt_net.nt_mask) != 0) { + syslog(LOG_ERR, "Bad network flag"); + if (cp) + *cp = savedc; + return (1); } - sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net; - args.ua.export.ex_addr = (struct sockaddr *)&sin; - args.ua.export.ex_addrlen = sizeof (sin); - args.ua.export.ex_mask = (struct sockaddr *)&imask; - args.ua.export.ex_masklen = sizeof (imask); + args.ua.export.ex_mask = (struct sockaddr *)&ss; + args.ua.export.ex_masklen = ss.ss_len; break; case GT_IGNORE: return(0); @@ -1678,7 +1838,7 @@ do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb) * exportable file systems and not just "ufs". */ while (mount(fsb->f_fstypename, dirp, - fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) { + fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) { if (cp) *cp-- = savedc; else @@ -1707,10 +1867,15 @@ do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb) savedc = *cp; *cp = '\0'; } +skip: if (addrp) { - ++addrp; - if (*addrp == (u_int32_t *)NULL) + ai = ai->ai_next; + if (ai == NULL) done = TRUE; + else { + addrp = ai->ai_addr; + addrlen = ai->ai_addrlen; + } } else done = TRUE; } @@ -1729,47 +1894,105 @@ get_net(cp, net, maskflg) int maskflg; { struct netent *np; - long netaddr; - struct in_addr inetaddr, inetaddr2; - char *name; + char *name, *p, *prefp; + struct sockaddr_in sin, *sinp; + struct sockaddr *sa; + struct addrinfo hints, *ai = NULL; + char netname[NI_MAXHOST]; + long preflen; + int ecode; - if (isdigit(*cp) && ((netaddr = inet_network(cp)) != -1)) { - inetaddr = inet_makeaddr(netaddr, 0); - /* - * Due to arbitrary subnet masks, you don't know how many - * bits to shift the address to make it into a network, - * however you do know how to make a network address into - * a host with host == 0 and then compare them. - * (What a pest) - */ - if (!maskflg) { - setnetent(0); - while ((np = getnetent())) { - inetaddr2 = inet_makeaddr(np->n_net, 0); - if (inetaddr2.s_addr == inetaddr.s_addr) - break; - } - endnetent(); - } - } else if ((np = getnetbyname(cp)) != NULL) { - inetaddr = inet_makeaddr(np->n_net, 0); + if ((opt_flags & OP_MASKLEN) && !maskflg) { + p = strchr(cp, '/'); + *p = '\0'; + prefp = p + 1; + } + + if ((np = getnetbyname(cp)) != NULL) { + sin.sin_family = AF_INET; + sin.sin_len = sizeof sin; + sin.sin_addr = inet_makeaddr(np->n_net, 0); + sa = (struct sockaddr *)&sin; + } else if (isdigit(*cp)) { + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_flags = AI_NUMERICHOST; + if (getaddrinfo(cp, NULL, &hints, &ai) != 0) { + /* + * If getaddrinfo() failed, try the inet4 network + * notation with less than 3 dots. + */ + sin.sin_family = AF_INET; + sin.sin_len = sizeof sin; + sin.sin_addr = inet_makeaddr(inet_network(cp),0); + if (debug) + fprintf(stderr, "get_net: v4 addr %x\n", + sin.sin_addr.s_addr); + sa = (struct sockaddr *)&sin; + } else + sa = ai->ai_addr; + } else if (isxdigit(*cp) || *cp == ':') { + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_flags = AI_NUMERICHOST; + if (getaddrinfo(cp, NULL, &hints, &ai) == 0) + sa = ai->ai_addr; + else + goto fail; } else - return (1); + goto fail; + + ecode = getnameinfo(sa, sa->sa_len, netname, sizeof netname, + NULL, 0, ninumeric); + if (ecode != 0) + goto fail; if (maskflg) - net->nt_mask = inetaddr.s_addr; + net->nt_mask = countones(sa); else { + if (opt_flags & OP_MASKLEN) { + preflen = strtol(prefp, NULL, 10); + if (preflen == LONG_MIN && errno == ERANGE) + goto fail; + net->nt_mask = (int)preflen; + *p = '/'; + } + if (np) name = np->n_name; + else { + if (getnameinfo(sa, sa->sa_len, netname, sizeof netname, + NULL, 0, ninumeric) != 0) + strlcpy(netname, "?", sizeof(netname)); + name = netname; + } + net->nt_name = strdup(name); + memcpy(&net->nt_net, sa, sa->sa_len); + } + + if (!maskflg && sa->sa_family == AF_INET && + !(opt_flags & (OP_MASK|OP_MASKLEN))) { + sinp = (struct sockaddr_in *)sa; + if (IN_CLASSA(sinp->sin_addr.s_addr)) + net->nt_mask = 8; + else if (IN_CLASSB(sinp->sin_addr.s_addr)) + net->nt_mask = 16; + else if (IN_CLASSC(sinp->sin_addr.s_addr)) + net->nt_mask = 24; + else if (IN_CLASSD(sinp->sin_addr.s_addr)) + net->nt_mask = 28; else - name = inet_ntoa(inetaddr); - net->nt_name = (char *)malloc(strlen(name) + 1); - if (net->nt_name == (char *)NULL) - out_of_mem(); - strcpy(net->nt_name, name); - net->nt_net = inetaddr.s_addr; + net->nt_mask = 32; /* XXX */ } - return (0); + + if (ai) + freeaddrinfo(ai); + return 0; + +fail: + if (ai) + freeaddrinfo(ai); + return 1; } /* @@ -1958,15 +2181,28 @@ get_mountlist() fclose(mlfile); } -void -del_mlist(hostp, dirp) +int +del_mlist(hostp, dirp, saddr) char *hostp, *dirp; + struct sockaddr *saddr; { struct mountlist *mlp, **mlpp; struct mountlist *mlp2; + u_short sport; FILE *mlfile; int fnd = 0; + char host[NI_MAXHOST]; + switch (saddr->sa_family) { + case AF_INET6: + sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port); + break; + case AF_INET: + sport = ntohs(((struct sockaddr_in *)saddr)->sin_port); + break; + default: + return -1; + } mlpp = &mlhead; mlp = mlhead; while (mlp) { @@ -2034,17 +2270,11 @@ void free_grp(grp) struct grouplist *grp; { - char **addrp; + struct addrinfo *ai; if (grp->gr_type == GT_HOST) { - if (grp->gr_ptr.gt_hostent->h_name) { - addrp = grp->gr_ptr.gt_hostent->h_addr_list; - while (addrp && *addrp) - free(*addrp++); - free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list); - free(grp->gr_ptr.gt_hostent->h_name); - } - free((caddr_t)grp->gr_ptr.gt_hostent); + if (grp->gr_ptr.gt_addrinfo != NULL) + freeaddrinfo(grp->gr_ptr.gt_addrinfo); } else if (grp->gr_type == GT_NET) { if (grp->gr_ptr.gt_net.nt_name) free(grp->gr_ptr.gt_net.nt_name); @@ -2093,7 +2323,6 @@ check_options(dp) /* * Check an absolute directory path for any symbolic links. Return true - * if no symbolic links are found. */ int check_dirpath(dirp) @@ -2134,3 +2363,146 @@ get_num(cp) } return (res); } + +static int +netpartcmp(struct sockaddr *s1, struct sockaddr *s2, int bitlen) +{ + void *src, *dst; + + if (s1->sa_family != s2->sa_family) + return 1; + + switch (s1->sa_family) { + case AF_INET: + src = &((struct sockaddr_in *)s1)->sin_addr; + dst = &((struct sockaddr_in *)s2)->sin_addr; + if (bitlen > sizeof(((struct sockaddr_in *)s1)->sin_addr) * 8) + return 1; + break; + case AF_INET6: + src = &((struct sockaddr_in6 *)s1)->sin6_addr; + dst = &((struct sockaddr_in6 *)s2)->sin6_addr; + if (((struct sockaddr_in6 *)s1)->sin6_scope_id != + ((struct sockaddr_in6 *)s2)->sin6_scope_id) + return 1; + if (bitlen > sizeof(((struct sockaddr_in6 *)s1)->sin6_addr) * 8) + return 1; + break; + default: + return 1; + } + + return bitcmp(src, dst, bitlen); +} + +static int +allones(struct sockaddr_storage *ssp, int bitlen) +{ + u_int8_t *p; + int bytelen, bitsleft, i; + int zerolen; + + switch (ssp->ss_family) { + case AF_INET: + p = (u_int8_t *)&((struct sockaddr_in *)ssp)->sin_addr; + zerolen = sizeof (((struct sockaddr_in *)ssp)->sin_addr); + break; + case AF_INET6: + p = (u_int8_t *)&((struct sockaddr_in6 *)ssp)->sin6_addr; + zerolen = sizeof (((struct sockaddr_in6 *)ssp)->sin6_addr); + break; + default: + return -1; + } + + memset(p, 0, zerolen); + + bytelen = bitlen / 8; + bitsleft = bitlen % 8; + + if (bytelen > zerolen) + return -1; + + for (i = 0; i < bytelen; i++) + *p++ = 0xff; + + for (i = 0; i < bitsleft; i++) + *p |= 1 << (7 - i); + + return 0; +} + +static int +countones(struct sockaddr *sa) +{ + void *mask; + int i, bits = 0, bytelen; + u_int8_t *p; + + switch (sa->sa_family) { + case AF_INET: + mask = (u_int8_t *)&((struct sockaddr_in *)sa)->sin_addr; + bytelen = 4; + break; + case AF_INET6: + mask = (u_int8_t *)&((struct sockaddr_in6 *)sa)->sin6_addr; + bytelen = 16; + break; + default: + return 0; + } + + p = mask; + + for (i = 0; i < bytelen; i++, p++) { + if (*p != 0xff) { + for (bits = 0; bits < 8; bits++) { + if (!(*p & (1 << (7 - bits)))) + break; + } + break; + } + } + + return (i * 8 + bits); +} + +static int +sacmp(struct sockaddr *sa1, struct sockaddr *sa2) +{ + void *p1, *p2; + int len; + + if (sa1->sa_family != sa2->sa_family) + return 1; + + switch (sa1->sa_family) { + case AF_INET: + p1 = &((struct sockaddr_in *)sa1)->sin_addr; + p2 = &((struct sockaddr_in *)sa2)->sin_addr; + len = 4; + break; + case AF_INET6: + p1 = &((struct sockaddr_in6 *)sa1)->sin6_addr; + p2 = &((struct sockaddr_in6 *)sa2)->sin6_addr; + len = 16; + if (((struct sockaddr_in6 *)sa1)->sin6_scope_id != + ((struct sockaddr_in6 *)sa2)->sin6_scope_id) + return 1; + break; + default: + return 1; + } + + return memcmp(p1, p2, len); +} + +void terminate(sig) +int sig; +{ + close(mountdlockfd); + unlink(MOUNTDLOCK); + pmap_unset(RPCPROG_MNT, 1); + pmap_unset(RPCPROG_MNT, 3); + exit (0); +} diff --git a/sbin/nfsd/nfsd.8 b/sbin/nfsd/nfsd.8 index fb44149bb4d8..0031ea1b926e 100644 --- a/sbin/nfsd/nfsd.8 +++ b/sbin/nfsd/nfsd.8 @@ -42,7 +42,7 @@ server .Sh SYNOPSIS .Nm -.Op Fl arut +.Op Fl ardut .Op Fl n Ar num_servers .Op Fl h Ar bindip .Sh DESCRIPTION @@ -64,13 +64,19 @@ The following options are available: Register the .Tn NFS service with -.Xr portmap 8 +.Xr rpcbind 8 without creating any servers. This option can be used along with the .Fl u or .Fl t -options to re-register NFS if the portmap server is restarted. +options to re-register NFS if the rpcbind server is restarted. +.It Fl d +Unregister the +.Tn NFS +service with +.Xr rpcbind 8 +without creating any servers. .It Fl n Specifies how many servers to create. .It Fl h Ar bindip @@ -147,6 +153,16 @@ that the NFS sockets can only be accessed by the inside interface. would then be used to block nfs-related packets that come in on the outside interface. .Pp +.Nm +has to be terminated with SIGUSR1 and cannot be killed with SIGTERM oder SIGQUIT. +.Nm +needs to ignore these signals in order to stay alive as long +as possible during a shutdown, otherwise loopback mounts will +not be able to unmount. If you have to kill +.Nm +just do a +.Dq Li "kill -USR1 <PID of master nfsd>" +.Pp The .Nm utility exits 0 on success, and >0 if an error occurs. @@ -156,7 +172,7 @@ utility exits 0 on success, and >0 if an error occurs. .Xr kldload 8 , .Xr mountd 8 , .Xr nfsiod 8 , -.Xr portmap 8 , +.Xr rpcbind 8 , .Xr ipfw 8 .Sh HISTORY The diff --git a/sbin/nfsd/nfsd.c b/sbin/nfsd/nfsd.c index 2d923a42652b..959f0fb04d18 100644 --- a/sbin/nfsd/nfsd.c +++ b/sbin/nfsd/nfsd.c @@ -58,9 +58,6 @@ static const char rcsid[] = #include <netdb.h> #include <arpa/inet.h> -#ifdef ISO -#include <netiso/iso.h> -#endif #include <nfs/rpcv2.h> #include <nfs/nfsproto.h> #include <nfs/nfs.h> @@ -76,6 +73,7 @@ static const char rcsid[] = #include <stdlib.h> #include <strings.h> #include <unistd.h> +#include <netdb.h> /* Global defs */ #ifdef DEBUG @@ -103,15 +101,23 @@ struct timeval ktv; NFSKERBKEYSCHED_T kerb_keysched; #endif -void nonfs __P((int)); -void reapchild __P((int)); -void setbindhost __P((struct sockaddr_in *ia, const char *bindhost)); +#define MAXNFSDCNT 20 +#define DEFNFSDCNT 4 +pid_t children[MAXNFSDCNT]; /* PIDs of children */ +int nfsdcnt; /* number of children */ + +void cleanup(int); +void killchildren(void); +void nonfs (int); +void reapchild (int); +int setbindhost (struct addrinfo **ia, const char *bindhost, struct addrinfo hints); #ifdef OLD_SETPROCTITLE #ifdef __FreeBSD__ -void setproctitle __P((char *)); +void setproctitle (char *); #endif #endif -void usage __P((void)); +void unregistration (void); +void usage (void); /* * Nfs server daemon mostly just a user context for nfssvc() @@ -119,7 +125,7 @@ void usage __P((void)); * 1 - do file descriptor and signal cleanup * 2 - fork the nfsd(s) * 3 - create server socket(s) - * 4 - register socket with portmap + * 4 - register socket with rpcbind * * For connectionless protocols, just pass the socket into the kernel via. * nfssvc(). @@ -127,7 +133,8 @@ void usage __P((void)); * socket from accept, pass the msgsock into the kernel via. nfssvc(). * The arguments are: * -c - support iso cltp clients - * -r - reregister with portmapper + * -r - reregister with rpcbind + * -d - unregister with rpcbind * -t - support tcp nfs clients * -u - support udp nfs clients * followed by "n" which is the number of nfsds' to fork off @@ -138,20 +145,20 @@ main(argc, argv, envp) char *argv[], *envp[]; { struct nfsd_args nfsdargs; - struct sockaddr_in inetaddr, inetpeer; -#ifdef ISO - struct sockaddr_iso isoaddr, isopeer; - char *cp; -#endif + struct addrinfo *ai_udp, *ai_tcp, *ai_udp6, *ai_tcp6, hints; + struct netconfig *nconf_udp, *nconf_tcp, *nconf_udp6, *nconf_tcp6; + struct netbuf nb_udp, nb_tcp, nb_udp6, nb_tcp6; + struct sockaddr_in inetpeer; + struct sockaddr_in6 inet6peer; fd_set ready, sockbits; + fd_set v4bits, v6bits; int ch, cltpflag, connect_type_cnt, i, len, maxsock, msgsock; - int nfsdcnt, nfssvc_flag, on, reregister, sock, tcpflag, tcpsock; - int tp4cnt, tp4flag, tpipcnt, tpipflag, udpflag; - int bindhostc = 0, bindanyflag; + int nfssvc_flag, on = 1, unregister, reregister, sock; + int tcp6sock, ip6flag, tcpflag, tcpsock; + int udpflag, ecode, s; + int bindhostc = 0, bindanyflag, rpcbreg, rpcbregcnt; char **bindhost = NULL; -#ifdef notyet - int tp4sock, tpipsock; -#endif + pid_t pid; #ifdef NFSKERB struct group *grp; struct passwd *pwd; @@ -184,18 +191,11 @@ main(argc, argv, envp) LastArg = envp[-1] + strlen(envp[-1]); #endif -#define MAXNFSDCNT 20 -#define DEFNFSDCNT 4 nfsdcnt = DEFNFSDCNT; - cltpflag = reregister = tcpflag = tp4cnt = tp4flag = tpipcnt = 0; - bindanyflag = tpipflag = udpflag = 0; -#ifdef ISO -#define GETOPT "ach:n:rtu" -#define USAGE "[-acrtu] [-n num_servers] [-h bindip]" -#else -#define GETOPT "ah:n:rtu" -#define USAGE "[-artu] [-n num_servers] [-h bindip]" -#endif + cltpflag = unregister = reregister = tcpflag = 0; + bindanyflag = udpflag = ip6flag = 0; +#define GETOPT "ah:n:rdtu" +#define USAGE "[-ardtu] [-n num_servers] [-h bindip]" while ((ch = getopt(argc, argv, GETOPT)) != -1) switch (ch) { case 'a': @@ -221,25 +221,15 @@ main(argc, argv, envp) case 'r': reregister = 1; break; + case 'd': + unregister = 1; + break; case 't': tcpflag = 1; break; case 'u': udpflag = 1; break; -#ifdef ISO - case 'c': - cltpflag = 1; - break; -#ifdef notyet - case 'i': - tp4cnt = 1; - break; - case 'p': - tpipcnt = 1; - break; -#endif /* notyet */ -#endif /* ISO */ default: case '?': usage(); @@ -263,6 +253,13 @@ main(argc, argv, envp) nfsdcnt = DEFNFSDCNT; } } + ip6flag = 1; + s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (s < 0 && (errno == EPROTONOSUPPORT || + errno == EPFNOSUPPORT || errno == EAFNOSUPPORT)) + ip6flag = 0; + else + close(s); if (bindhostc == 0 || bindanyflag) { bindhostc++; @@ -278,33 +275,126 @@ main(argc, argv, envp) daemon(0, 0); (void)signal(SIGHUP, SIG_IGN); (void)signal(SIGINT, SIG_IGN); - (void)signal(SIGQUIT, SIG_IGN); (void)signal(SIGSYS, nonfs); + (void)signal(SIGUSR1, cleanup); + /* + * nfsd sits in the kernel most of the time. It needs + * to ignore SIGTERM/SIGQUIT in order to stay alive as long + * as possible during a shutdown, otherwise loopback + * mounts will not be able to unmount. + */ (void)signal(SIGTERM, SIG_IGN); + (void)signal(SIGQUIT, SIG_IGN); } (void)signal(SIGCHLD, reapchild); - + if (unregister) { + unregistration(); + exit (0); + } if (reregister) { - if (udpflag && - (!pmap_set(RPCPROG_NFS, 2, IPPROTO_UDP, NFS_PORT) || - !pmap_set(RPCPROG_NFS, 3, IPPROTO_UDP, NFS_PORT))) - err(1, "can't register with portmap for UDP"); - if (tcpflag && - (!pmap_set(RPCPROG_NFS, 2, IPPROTO_TCP, NFS_PORT) || - !pmap_set(RPCPROG_NFS, 3, IPPROTO_TCP, NFS_PORT))) - err(1, "can't register with portmap for TCP"); - exit(0); + if (udpflag) { + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp); + if (ecode != 0) { + syslog(LOG_ERR, "getaddrinfo udp: %s", + gai_strerror(ecode)); + exit(1); + } + nconf_udp = getnetconfigent("udp"); + if (nconf_udp == NULL) + err(1, "getnetconfigent udp failed"); + nb_udp.buf = ai_udp->ai_addr; + nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen; + if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp, &nb_udp)) || + (!rpcb_set(RPCPROG_NFS, 3, nconf_udp, &nb_udp))) + err(1, "rpcb_set udp failed"); + freeaddrinfo(ai_udp); + } + if (udpflag && ip6flag) { + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6); + if (ecode != 0) { + syslog(LOG_ERR, "getaddrinfo udp6: %s", + gai_strerror(ecode)); + exit(1); + } + nconf_udp6 = getnetconfigent("udp6"); + if (nconf_udp6 == NULL) + err(1, "getnetconfigent udp6 failed"); + nb_udp6.buf = ai_udp6->ai_addr; + nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen; + if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp6, &nb_udp6)) || + (!rpcb_set(RPCPROG_NFS, 3, nconf_udp6, &nb_udp6))) + err(1, "rpcb_set udp6 failed"); + freeaddrinfo(ai_udp6); + } + if (tcpflag) { + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp); + if (ecode != 0) { + syslog(LOG_ERR, "getaddrinfo tcp: %s", + gai_strerror(ecode)); + exit(1); + } + nconf_tcp = getnetconfigent("tcp"); + if (nconf_tcp == NULL) + err(1, "getnetconfigent tcp failed"); + nb_tcp.buf = ai_tcp->ai_addr; + nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen; + if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp, &nb_tcp)) || + (!rpcb_set(RPCPROG_NFS, 3, nconf_tcp, &nb_tcp))) + err(1, "rpcb_set tcp failed"); + freeaddrinfo(ai_tcp); + } + if (tcpflag && ip6flag) { + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6); + if (ecode != 0) { + syslog(LOG_ERR, "getaddrinfo tcp6: %s", + gai_strerror(ecode)); + exit(1); + } + nconf_tcp6 = getnetconfigent("tcp6"); + if (nconf_tcp6 == NULL) + err(1, "getnetconfigent tcp6 failed"); + nb_tcp6.buf = ai_tcp6->ai_addr; + nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen; + if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp6, &nb_tcp6)) || + (!rpcb_set(RPCPROG_NFS, 3, nconf_tcp6, &nb_tcp6))) + err(1, "rpcb_set tcp6 failed"); + freeaddrinfo(ai_tcp6); + } + exit (0); } + openlog("nfsd:", LOG_PID, LOG_DAEMON); for (i = 0; i < nfsdcnt; i++) { - switch (fork()) { + switch ((pid = fork())) { case -1: syslog(LOG_ERR, "fork: %m"); + killchildren(); exit (1); case 0: break; default: + children[i] = pid; continue; } @@ -399,182 +489,295 @@ main(argc, argv, envp) exit(0); } - /* If we are serving udp, set up the socket. */ - for (i = 0; udpflag && i < bindhostc; i++) { - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - syslog(LOG_ERR, "can't create udp socket"); - exit(1); - } - setbindhost(&inetaddr, bindhost[i]); - if (bind(sock, - (struct sockaddr *)&inetaddr, sizeof(inetaddr)) < 0) { - syslog(LOG_ERR, "can't bind udp addr %s: %m", bindhost[i]); - exit(1); - } - if (!pmap_set(RPCPROG_NFS, 2, IPPROTO_UDP, NFS_PORT) || - !pmap_set(RPCPROG_NFS, 3, IPPROTO_UDP, NFS_PORT)) { - syslog(LOG_ERR, "can't register with udp portmap"); - exit(1); + if (atexit(killchildren) == -1) { + syslog(LOG_ERR, "atexit: %s", strerror(errno)); + exit(1); + } + FD_ZERO(&v4bits); + FD_ZERO(&v6bits); + + rpcbregcnt = 0; + /* Set up the socket for udp and rpcb register it. */ + if (udpflag) { + rpcbreg = 0; + for (i = 0; i < bindhostc; i++) { + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + if (setbindhost(&ai_udp, bindhost[i], hints) == 0) { + rpcbreg = 1; + rpcbregcnt++; + if ((sock = socket(ai_udp->ai_family, + ai_udp->ai_socktype, + ai_udp->ai_protocol)) < 0) { + syslog(LOG_ERR, + "can't create udp socket"); + exit(1); + } + if (bind(sock, ai_udp->ai_addr, + ai_udp->ai_addrlen) < 0) { + syslog(LOG_ERR, + "can't bind udp addr %s: %m", + bindhost[i]); + exit(1); + } + freeaddrinfo(ai_udp); + nfsdargs.sock = sock; + nfsdargs.name = NULL; + nfsdargs.namelen = 0; + if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) { + syslog(LOG_ERR, "can't Add UDP socket"); + exit(1); + } + (void)close(sock); + } } - nfsdargs.sock = sock; - nfsdargs.name = NULL; - nfsdargs.namelen = 0; - if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) { - syslog(LOG_ERR, "can't Add UDP socket"); - exit(1); + if (rpcbreg == 1) { + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp); + if (ecode != 0) { + syslog(LOG_ERR, "getaddrinfo udp: %s", + gai_strerror(ecode)); + exit(1); + } + nconf_udp = getnetconfigent("udp"); + if (nconf_udp == NULL) + err(1, "getnetconfigent udp failed"); + nb_udp.buf = ai_udp->ai_addr; + nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen; + if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp, &nb_udp)) || + (!rpcb_set(RPCPROG_NFS, 3, nconf_udp, &nb_udp))) + err(1, "rpcb_set udp failed"); + freeaddrinfo(ai_udp); } - (void)close(sock); } -#ifdef ISO - /* If we are serving cltp, set up the socket. */ - if (cltpflag) { - if ((sock = socket(AF_ISO, SOCK_DGRAM, 0)) < 0) { - syslog(LOG_ERR, "can't create cltp socket"); - exit(1); - } - memset(&isoaddr, 0, sizeof(isoaddr)); - isoaddr.siso_family = AF_ISO; - isoaddr.siso_tlen = 2; - cp = TSEL(&isoaddr); - *cp++ = (NFS_PORT >> 8); - *cp = (NFS_PORT & 0xff); - isoaddr.siso_len = sizeof(isoaddr); - if (bind(sock, - (struct sockaddr *)&isoaddr, sizeof(isoaddr)) < 0) { - syslog(LOG_ERR, "can't bind cltp addr"); - exit(1); - } -#ifdef notyet - /* - * XXX - * Someday this should probably use "rpcbind", the son of - * portmap. - */ - if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, NFS_PORT)) { - syslog(LOG_ERR, "can't register with udp portmap"); - exit(1); + /* Set up the socket for udp6 and rpcb register it. */ + if (udpflag && ip6flag) { + rpcbreg = 0; + for (i = 0; i < bindhostc; i++) { + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + if (setbindhost(&ai_udp6, bindhost[i], hints) == 0) { + rpcbreg = 1; + rpcbregcnt++; + if ((sock = socket(ai_udp6->ai_family, + ai_udp6->ai_socktype, + ai_udp6->ai_protocol)) < 0) { + syslog(LOG_ERR, + "can't create udp6 socket"); + exit(1); + } + if (setsockopt(sock, IPPROTO_IPV6, + IPV6_BINDV6ONLY, + &on, sizeof on) < 0) { + syslog(LOG_ERR, + "can't set v6-only binding for " + "udp6 socket: %m"); + exit(1); + } + if (bind(sock, ai_udp6->ai_addr, + ai_udp6->ai_addrlen) < 0) { + syslog(LOG_ERR, + "can't bind udp6 addr %s: %m", + bindhost[i]); + exit(1); + } + freeaddrinfo(ai_udp6); + nfsdargs.sock = sock; + nfsdargs.name = NULL; + nfsdargs.namelen = 0; + if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) { + syslog(LOG_ERR, + "can't add UDP6 socket"); + exit(1); + } + (void)close(sock); + } } -#endif /* notyet */ - nfsdargs.sock = sock; - nfsdargs.name = NULL; - nfsdargs.namelen = 0; - if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) { - syslog(LOG_ERR, "can't add UDP socket"); - exit(1); + if (rpcbreg == 1) { + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6); + if (ecode != 0) { + syslog(LOG_ERR, "getaddrinfo udp6: %s", + gai_strerror(ecode)); + exit(1); + } + nconf_udp6 = getnetconfigent("udp6"); + if (nconf_udp6 == NULL) + err(1, "getnetconfigent udp6 failed"); + nb_udp6.buf = ai_udp6->ai_addr; + nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen; + if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp6, &nb_udp6)) || + (!rpcb_set(RPCPROG_NFS, 3, nconf_udp6, &nb_udp6))) + err(1, "rpcb_set udp6 failed"); + freeaddrinfo(ai_udp6); } - close(sock); } -#endif /* ISO */ - /* Now set up the master server socket waiting for tcp connections. */ - on = 1; - FD_ZERO(&sockbits); - connect_type_cnt = 0; - for (i = 0; tcpflag && i < bindhostc; i++) { - if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - syslog(LOG_ERR, "can't create tcp socket"); - exit(1); - } - if (setsockopt(tcpsock, - SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) - syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m"); - setbindhost(&inetaddr, bindhost[i]); - if (bind(tcpsock, - (struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0) { - syslog(LOG_ERR, "can't bind tcp addr %s: %m", bindhost[i]); - exit(1); - } - if (listen(tcpsock, 5) < 0) { - syslog(LOG_ERR, "listen failed"); - exit(1); + /* Set up the socket for tcp and rpcb register it. */ + if (tcpflag) { + rpcbreg = 0; + for (i = 0; i < bindhostc; i++) { + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + if (setbindhost(&ai_tcp, bindhost[i], hints) == 0) { + rpcbreg = 1; + rpcbregcnt++; + if ((tcpsock = socket(AF_INET, SOCK_STREAM, + 0)) < 0) { + syslog(LOG_ERR, + "can't create tpc socket"); + exit(1); + } + if (setsockopt(tcpsock, SOL_SOCKET, + SO_REUSEADDR, + (char *)&on, sizeof(on)) < 0) + syslog(LOG_ERR, + "setsockopt SO_REUSEADDR: %m"); + if (bind(tcpsock, ai_tcp->ai_addr, + ai_tcp->ai_addrlen) < 0) { + syslog(LOG_ERR, + "can't bind tcp addr %s: %m", + bindhost[i]); + exit(1); + } + if (listen(tcpsock, 5) < 0) { + syslog(LOG_ERR, "listen failed"); + exit(1); + } + freeaddrinfo(ai_tcp); + FD_SET(tcpsock, &sockbits); + FD_SET(tcpsock, &v4bits); + maxsock = tcpsock; + connect_type_cnt++; + } } - if (!pmap_set(RPCPROG_NFS, 2, IPPROTO_TCP, NFS_PORT) || - !pmap_set(RPCPROG_NFS, 3, IPPROTO_TCP, NFS_PORT)) { - syslog(LOG_ERR, "can't register tcp with portmap"); - exit(1); + if (rpcbreg == 1) { + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + ecode = getaddrinfo(NULL, "nfs", &hints, + &ai_tcp); + if (ecode != 0) { + syslog(LOG_ERR, "getaddrinfo tcp: %s", + gai_strerror(ecode)); + exit(1); + } + nconf_tcp = getnetconfigent("tcp"); + if (nconf_tcp == NULL) + err(1, "getnetconfigent tcp failed"); + nb_tcp.buf = ai_tcp->ai_addr; + nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen; + if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp, + &nb_tcp)) || (!rpcb_set(RPCPROG_NFS, 3, + nconf_tcp, &nb_tcp))) + err(1, "rpcb_set tcp failed"); + freeaddrinfo(ai_tcp); } - FD_SET(tcpsock, &sockbits); - maxsock = tcpsock; - connect_type_cnt++; } -#ifdef notyet - /* Now set up the master server socket waiting for tp4 connections. */ - if (tp4flag) { - if ((tp4sock = socket(AF_ISO, SOCK_SEQPACKET, 0)) < 0) { - syslog(LOG_ERR, "can't create tp4 socket"); - exit(1); - } - if (setsockopt(tp4sock, - SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) - syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m"); - memset(&isoaddr, 0, sizeof(isoaddr)); - isoaddr.siso_family = AF_ISO; - isoaddr.siso_tlen = 2; - cp = TSEL(&isoaddr); - *cp++ = (NFS_PORT >> 8); - *cp = (NFS_PORT & 0xff); - isoaddr.siso_len = sizeof(isoaddr); - if (bind(tp4sock, - (struct sockaddr *)&isoaddr, sizeof (isoaddr)) < 0) { - syslog(LOG_ERR, "can't bind tp4 addr"); - exit(1); - } - if (listen(tp4sock, 5) < 0) { - syslog(LOG_ERR, "listen failed"); - exit(1); + /* Set up the socket for tcp6 and rpcb register it. */ + if (tcpflag && ip6flag) { + rpcbreg = 0; + for (i = 0; i < bindhostc; i++) { + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + if (setbindhost(&ai_tcp6, bindhost[i], hints) == 0) { + rpcbreg = 1; + rpcbregcnt++; + if ((tcp6sock = socket(ai_tcp6->ai_family, + ai_tcp6->ai_socktype, + ai_tcp6->ai_protocol)) < 0) { + syslog(LOG_ERR, + "can't create tcp6 socket"); + exit(1); + } + if (setsockopt(tcp6sock, SOL_SOCKET, + SO_REUSEADDR, + (char *)&on, sizeof(on)) < 0) + syslog(LOG_ERR, + "setsockopt SO_REUSEADDR: %m"); + if (setsockopt(tcp6sock, IPPROTO_IPV6, + IPV6_BINDV6ONLY, &on, sizeof on) < 0) { + syslog(LOG_ERR, + "can't set v6-only binding for tcp6 " + "socket: %m"); + exit(1); + } + if (bind(tcp6sock, ai_tcp6->ai_addr, + ai_tcp6->ai_addrlen) < 0) { + syslog(LOG_ERR, + "can't bind tcp6 addr %s: %m", + bindhost[i]); + exit(1); + } + if (listen(tcp6sock, 5) < 0) { + syslog(LOG_ERR, "listen failed"); + exit(1); + } + freeaddrinfo(ai_tcp6); + FD_SET(tcp6sock, &sockbits); + FD_SET(tcp6sock, &v6bits); + if (maxsock < tcp6sock) + maxsock = tcp6sock; + connect_type_cnt++; + } } - /* - * XXX - * Someday this should probably use "rpcbind", the son of - * portmap. - */ - if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) { - syslog(LOG_ERR, "can't register tcp with portmap"); - exit(1); + if (rpcbreg == 1) { + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6); + if (ecode != 0) { + syslog(LOG_ERR, "getaddrinfo tcp6: %s", + gai_strerror(ecode)); + exit(1); + } + nconf_tcp6 = getnetconfigent("tcp6"); + if (nconf_tcp6 == NULL) + err(1, "getnetconfigent tcp6 failed"); + nb_tcp6.buf = ai_tcp6->ai_addr; + nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen; + if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp6, &nb_tcp6)) || + (!rpcb_set(RPCPROG_NFS, 3, nconf_tcp6, &nb_tcp6))) + err(1, "rpcb_set tcp6 failed"); + freeaddrinfo(ai_tcp6); } - FD_SET(tp4sock, &sockbits); - maxsock = tp4sock; - connect_type_cnt++; } - /* Now set up the master server socket waiting for tpip connections. */ - for (i = 0; tpipflag && i < bindhostc; i++) { - if ((tpipsock = socket(AF_INET, SOCK_SEQPACKET, 0)) < 0) { - syslog(LOG_ERR, "can't create tpip socket"); - exit(1); - } - if (setsockopt(tpipsock, - SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) - syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m"); - setbindhost(&inetaddr, bindhost[i]); - if (bind(tpipsock, - (struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0) { - syslog(LOG_ERR, "can't bind tcp addr %s: %m", bindhost[i]); - exit(1); - } - if (listen(tpipsock, 5) < 0) { - syslog(LOG_ERR, "listen failed"); - exit(1); - } - /* - * XXX - * Someday this should probably use "rpcbind", the son of - * portmap. - */ - if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) { - syslog(LOG_ERR, "can't register tcp with portmap"); - exit(1); - } - FD_SET(tpipsock, &sockbits); - maxsock = tpipsock; - connect_type_cnt++; + if (rpcbregcnt == 0) { + syslog(LOG_ERR, "rpcb_set() failed, nothing to do: %m"); + exit(1); } -#endif /* notyet */ - if (connect_type_cnt == 0) - exit(0); + if ((tcpflag) && (connect_type_cnt == 0)) { + syslog(LOG_ERR, "tcp connects == 0, nothing to do: %m"); + exit(1); + } setproctitle("master"); @@ -591,82 +794,94 @@ main(argc, argv, envp) exit(1); } } - if (tcpflag && FD_ISSET(tcpsock, &ready)) { - len = sizeof(inetpeer); - if ((msgsock = accept(tcpsock, - (struct sockaddr *)&inetpeer, &len)) < 0) { - syslog(LOG_ERR, "accept failed: %m"); - exit(1); - } - memset(inetpeer.sin_zero, 0, sizeof(inetpeer.sin_zero)); - if (setsockopt(msgsock, SOL_SOCKET, - SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0) - syslog(LOG_ERR, - "setsockopt SO_KEEPALIVE: %m"); - nfsdargs.sock = msgsock; - nfsdargs.name = (caddr_t)&inetpeer; - nfsdargs.namelen = sizeof(inetpeer); - nfssvc(NFSSVC_ADDSOCK, &nfsdargs); - (void)close(msgsock); - } -#ifdef notyet - if (tp4flag && FD_ISSET(tp4sock, &ready)) { - len = sizeof(isopeer); - if ((msgsock = accept(tp4sock, - (struct sockaddr *)&isopeer, &len)) < 0) { - syslog(LOG_ERR, "accept failed: %m"); - exit(1); - } - if (setsockopt(msgsock, SOL_SOCKET, - SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0) - syslog(LOG_ERR, - "setsockopt SO_KEEPALIVE: %m"); - nfsdargs.sock = msgsock; - nfsdargs.name = (caddr_t)&isopeer; - nfsdargs.namelen = len; - nfssvc(NFSSVC_ADDSOCK, &nfsdargs); - (void)close(msgsock); - } - if (tpipflag && FD_ISSET(tpipsock, &ready)) { - len = sizeof(inetpeer); - if ((msgsock = accept(tpipsock, - (struct sockaddr *)&inetpeer, &len)) < 0) { - syslog(LOG_ERR, "accept failed: %m"); - exit(1); + for (tcpsock = 0; tcpsock <= maxsock; tcpsock++) { + if (FD_ISSET(tcpsock, &ready)) { + if (FD_ISSET(tcpsock, &v4bits)) { + len = sizeof(inetpeer); + if ((msgsock = accept(tcpsock, + (struct sockaddr *)&inetpeer, &len)) < 0) { + syslog(LOG_ERR, "accept failed: %m"); + exit(1); + } + memset(inetpeer.sin_zero, 0, + sizeof(inetpeer.sin_zero)); + if (setsockopt(msgsock, SOL_SOCKET, + SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0) + syslog(LOG_ERR, + "setsockopt SO_KEEPALIVE: %m"); + nfsdargs.sock = msgsock; + nfsdargs.name = (caddr_t)&inetpeer; + nfsdargs.namelen = sizeof(inetpeer); + nfssvc(NFSSVC_ADDSOCK, &nfsdargs); + (void)close(msgsock); + } else if (FD_ISSET(tcpsock, &v6bits)) { + len = sizeof(inet6peer); + if ((msgsock = accept(tcpsock, + (struct sockaddr *)&inet6peer, + &len)) < 0) { + syslog(LOG_ERR, + "accept failed: %m"); + exit(1); + } + if (setsockopt(msgsock, SOL_SOCKET, + SO_KEEPALIVE, (char *)&on, + sizeof(on)) < 0) + syslog(LOG_ERR, "setsockopt " + "SO_KEEPALIVE: %m"); + nfsdargs.sock = msgsock; + nfsdargs.name = (caddr_t)&inet6peer; + nfsdargs.namelen = sizeof(inet6peer); + nfssvc(NFSSVC_ADDSOCK, &nfsdargs); + (void)close(msgsock); + } } - if (setsockopt(msgsock, SOL_SOCKET, - SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0) - syslog(LOG_ERR, "setsockopt SO_KEEPALIVE: %m"); - nfsdargs.sock = msgsock; - nfsdargs.name = (caddr_t)&inetpeer; - nfsdargs.namelen = len; - nfssvc(NFSSVC_ADDSOCK, &nfsdargs); - (void)close(msgsock); } -#endif /* notyet */ } } -void -setbindhost(struct sockaddr_in *ia, const char *bindhost) +int +setbindhost(struct addrinfo **ai, const char *bindhost, struct addrinfo hints) { - ia->sin_family = AF_INET; - ia->sin_port = htons(NFS_PORT); - ia->sin_len = sizeof(*ia); - if (bindhost == NULL || strcmp(bindhost,"*") == 0) { - ia->sin_addr.s_addr = INADDR_ANY; - } else { - if (inet_aton(bindhost, &ia->sin_addr) == 0) { - struct hostent *he; + int ecode; + u_int32_t host_addr[4]; /* IPv4 or IPv6 */ + const char *hostptr; - he = gethostbyname2(bindhost, ia->sin_family); - if (he == NULL) { - syslog(LOG_ERR, "gethostbyname of %s failed", bindhost); - exit(1); + if (bindhost == NULL || strcmp("*", bindhost) == 0) + hostptr = NULL; + else + hostptr = bindhost; + + if (hostptr != NULL) { + switch (hints.ai_family) { + case AF_INET: + if (inet_pton(AF_INET, hostptr, host_addr) == 1) { + hints.ai_flags = AI_NUMERICHOST; + } else { + if (inet_pton(AF_INET6, hostptr, + host_addr) == 1) + return (1); + } + break; + case AF_INET6: + if (inet_pton(AF_INET6, hostptr, host_addr) == 1) { + hints.ai_flags = AI_NUMERICHOST; + } else { + if (inet_pton(AF_INET, hostptr, + host_addr) == 1) + return (1); } - bcopy(he->h_addr, &ia->sin_addr, he->h_length); + break; + default: } } + + ecode = getaddrinfo(hostptr, "nfs", &hints, ai); + if (ecode != 0) { + syslog(LOG_ERR, "getaddrinfo %s: %s", bindhost, + gai_strerror(ecode)); + return (1); + } + return (0); } void @@ -691,6 +906,48 @@ reapchild(signo) while (wait3(NULL, WNOHANG, NULL) > 0); } +void +unregistration() +{ + if ((!rpcb_unset(RPCPROG_NFS, 2, NULL)) || + (!rpcb_unset(RPCPROG_NFS, 3, NULL))) + syslog(LOG_ERR, "rpcb_unset failed"); +} + +void +killchildren() +{ + int i; + sigset_t sigs; + + sigemptyset(&sigs); + /* + * Block SIGCHLD to avoid killing a reaped process (although it is + * unlikely, the pid might have been reused). + */ + sigaddset(&sigs, SIGCHLD); + if (sigprocmask(SIG_BLOCK, &sigs, NULL) == -1) { + syslog(LOG_ERR, "sigprocmask: %s", + strerror(errno)); + return; + } + for (i = 0; i < nfsdcnt; i++) { + if (children[i] > 0) + kill(children[i], SIGKILL); + } + if (sigprocmask(SIG_UNBLOCK, &sigs, NULL) == -1) { + syslog(LOG_ERR, "sigprocmask: %s", strerror(errno)); + } + unregistration(); +} + +void +cleanup(signo) +{ + killchildren(); + exit (0); +} + #ifdef OLD_SETPROCTITLE #ifdef __FreeBSD__ void diff --git a/sbin/umount/umount.c b/sbin/umount/umount.c index e9ef990cc2d2..2a3a3373e2e5 100644 --- a/sbin/umount/umount.c +++ b/sbin/umount/umount.c @@ -47,6 +47,7 @@ static const char rcsid[] = #include <sys/param.h> #include <sys/mount.h> +#include <sys/socket.h> #include <netdb.h> #include <rpc/rpc.h> @@ -68,6 +69,7 @@ typedef enum { MNTON, MNTFROM, NOTHING } mntwhat; typedef enum { MARK, UNMARK, NAME, COUNT, FREE } dowhat; struct mtablist *mtabhead; +struct addrinfo *nfshost_ai = NULL; int fflag, vflag; char *nfshost; @@ -78,19 +80,22 @@ char *getmntname (const char *, const char *, char *getrealname(char *, char *resolved_path); char **makevfslist (const char *); size_t mntinfo (struct statfs **); -int namematch (struct hostent *); +int namematch (struct addrinfo *); +int sacmp (struct sockaddr *, struct sockaddr *); int umountall (char **); -int umountfs (char *, char **); +int checkname (char *, char **); +int umountfs (char *, char *, char *); void usage (void); int xdr_dir (XDR *, char *); int main(int argc, char *argv[]) { - int all, errs, ch, mntsize; + int all, errs, ch, mntsize, error; char **typelist = NULL, *mntonname, *mntfromname; char *type, *mntfromnamerev, *mntonnamerev; struct statfs *mntbuf; + struct addrinfo hints; /* Start disks transferring immediately. */ sync(); @@ -133,6 +138,15 @@ main(int argc, char *argv[]) if ((nfshost != NULL) && (typelist == NULL)) typelist = makevfslist("nfs"); + if (nfshost != NULL) { + memset(&hints, 0, sizeof hints); + error = getaddrinfo(nfshost, NULL, &hints, &nfshost_ai); + if (error) { + fprintf(stderr, "ndp: %s: %s\n", nfshost, + gai_strerror(error)); + } + } + switch (all) { case 2: if ((mntsize = mntinfo(&mntbuf)) <= 0) @@ -165,7 +179,7 @@ main(int argc, char *argv[]) "is mounted there, umount it first", mntonname, mntfromnamerev); - if (umountfs(mntbuf[mntsize].f_mntonname, + if (checkname(mntbuf[mntsize].f_mntonname, typelist) != 0) errs = 1; } @@ -178,7 +192,7 @@ main(int argc, char *argv[]) break; case 0: for (errs = 0; *argv != NULL; ++argv) - if (umountfs(*argv, typelist) != 0) + if (checkname(*argv, typelist) != 0) errs = 1; break; } @@ -228,33 +242,29 @@ umountall(char **typelist) err(1, "malloc failed"); (void)strcpy(cp, fs->fs_file); rval = umountall(typelist); - rval = umountfs(cp, typelist) || rval; + rval = checkname(cp, typelist) || rval; free(cp); return (rval); } while ((fs = getfsent()) != NULL); return (0); } +/* + * Do magic checks on mountpoint and device or hand over + * it to unmount(2) if everything fails. + */ int -umountfs(char *name, char **typelist) +checkname(char *name, char **typelist) { - enum clnt_stat clnt_stat; - struct hostent *hp; - struct mtablist *mtab; - struct sockaddr_in saddr; - struct timeval pertry, try; - CLIENT *clp; size_t len; - int so, speclen, do_rpc; + int speclen; char *mntonname, *mntfromname; char *mntfromnamerev; - char *nfsdirname, *orignfsdirname; char *resolved, realname[MAXPATHLEN]; - char *type, *delimp, *hostp, *origname; + char *type, *hostp, *delimp, *origname; len = 0; - mtab = NULL; - mntfromname = mntonname = delimp = hostp = orignfsdirname = NULL; + mntfromname = mntonname = delimp = hostp = NULL; /* * 1. Check if the name exists in the mounttable. @@ -323,14 +333,29 @@ umountfs(char *name, char **typelist) resolved = realname; } /* - * All tests failed, return to main() + * 5. All tests failed, just hand over the + * mountpoint to the kernel, maybe the statfs + * structure has been truncated or is not + * useful anymore because of a chroot(2). + * Please note that nfs will not be able to + * notify the nfs-server about unmounting. + * These things can change in future when the + * fstat structure get's more reliable, + * but at the moment we cannot thrust it. */ if (mntfromname == NULL && mntonname == NULL) { (void)strcpy(name, origname); - warnx("%s: not currently mounted", - origname); - free(origname); - return (1); + if (umountfs(NULL, origname, + "none") == 0) {; + warnx("%s not found in " + "mount table, " + "unmounted it anyway", + origname); + free(origname); + return (0); + } else + free(origname); + return (1); } } } @@ -341,21 +366,6 @@ umountfs(char *name, char **typelist) if (checkvfsname(type, typelist)) return (1); - hp = NULL; - nfsdirname = NULL; - if (!strcmp(type, "nfs")) { - if ((nfsdirname = strdup(mntfromname)) == NULL) - err(1, "strdup"); - orignfsdirname = nfsdirname; - if ((delimp = strchr(nfsdirname, ':')) != NULL) { - *delimp = '\0'; - hostp = nfsdirname; - if ((hp = gethostbyname(hostp)) == NULL) { - warnx("can't get net id for host"); - } - nfsdirname = delimp + 1; - } - } /* * Check if the reverse entrys of the mounttable are really the * same as the normal ones. @@ -383,6 +393,43 @@ umountfs(char *name, char **typelist) return (1); } free(mntfromnamerev); + umountfs(mntfromname, mntonname, type); +} + +/* + * NFS stuff and unmount(2) call + */ +int +umountfs(char *mntfromname, char *mntonname, char *type) +{ + enum clnt_stat clnt_stat; + struct timeval try; + struct mtablist *mtab; + struct addrinfo *ai, hints; + int do_rpc; + CLIENT *clp; + char *nfsdirname, *orignfsdirname; + char *hostp, *delimp; + + mtab = NULL; + ai = NULL; + nfsdirname = delimp = orignfsdirname = NULL; + memset(&hints, 0, sizeof hints); + + if (!strcmp(type, "nfs")) { + if ((nfsdirname = strdup(mntfromname)) == NULL) + err(1, "strdup"); + orignfsdirname = nfsdirname; + if ((delimp = strrchr(nfsdirname, ':')) != NULL) { + *delimp = '\0'; + hostp = nfsdirname; + getaddrinfo(hostp, NULL, &hints, &ai); + if (ai == NULL) { + warnx("can't get net id for host"); + } + nfsdirname = delimp + 1; + } + } /* * Check if we have to start the rpc-call later. * If there are still identical nfs-names mounted, @@ -395,7 +442,8 @@ umountfs(char *name, char **typelist) do_rpc = 1; else do_rpc = 0; - if (!namematch(hp)) + + if (!namematch(ai)) return (1); if (unmount(mntonname, fflag) != 0 ) { warn("unmount of %s failed", mntonname); @@ -407,21 +455,13 @@ umountfs(char *name, char **typelist) * Report to mountd-server which nfsname * has been unmounted. */ - if (hp != NULL && !(fflag & MNT_FORCE) && do_rpc) { - memset(&saddr, 0, sizeof(saddr)); - saddr.sin_family = AF_INET; - saddr.sin_port = 0; - memmove(&saddr.sin_addr, hp->h_addr, - MIN(hp->h_length, sizeof(saddr.sin_addr))); - pertry.tv_sec = 3; - pertry.tv_usec = 0; - so = RPC_ANYSOCK; - if ((clp = clntudp_create(&saddr, - RPCPROG_MNT, RPCMNT_VER1, pertry, &so)) == NULL) { + if (ai != NULL && !(fflag & MNT_FORCE) && do_rpc) { + clp = clnt_create(hostp, RPCPROG_MNT, RPCMNT_VER1, "udp"); + if (clp == NULL) { clnt_pcreateerror("Cannot MNT PRC"); return (1); } - clp->cl_auth = authunix_create_default(); + clp->cl_auth = authsys_create_default(); try.tv_sec = 20; try.tv_usec = 0; clnt_stat = clnt_call(clp, RPCMNT_UMOUNT, xdr_dir, @@ -554,30 +594,53 @@ getmntname(const char *fromname, const char *onname, } int -namematch(struct hostent *hp) +sacmp(struct sockaddr *sa1, struct sockaddr *sa2) { - char *cp, **np; + void *p1, *p2; + int len; - if ((hp == NULL) || (nfshost == NULL)) + if (sa1->sa_family != sa2->sa_family) return (1); - if (strcasecmp(nfshost, hp->h_name) == 0) - return (1); - - if ((cp = strchr(hp->h_name, '.')) != NULL) { - *cp = '\0'; - if (strcasecmp(nfshost, hp->h_name) == 0) + switch (sa1->sa_family) { + case AF_INET: + p1 = &((struct sockaddr_in *)sa1)->sin_addr; + p2 = &((struct sockaddr_in *)sa2)->sin_addr; + len = 4; + break; + case AF_INET6: + p1 = &((struct sockaddr_in6 *)sa1)->sin6_addr; + p2 = &((struct sockaddr_in6 *)sa2)->sin6_addr; + len = 16; + if (((struct sockaddr_in6 *)sa1)->sin6_scope_id != + ((struct sockaddr_in6 *)sa2)->sin6_scope_id) return (1); + break; + default: + return (1); } - for (np = hp->h_aliases; *np; np++) { - if (strcasecmp(nfshost, *np) == 0) - return (1); - if ((cp = strchr(*np, '.')) != NULL) { - *cp = '\0'; - if (strcasecmp(nfshost, *np) == 0) + + return memcmp(p1, p2, len); +} + +int +namematch(struct addrinfo *ai) +{ + struct addrinfo *aip; + + if (nfshost == NULL || nfshost_ai == NULL) + return (1); + + while (ai != NULL) { + aip = nfshost_ai; + while (aip != NULL) { + if (sacmp(ai->ai_addr, aip->ai_addr) == 0) return (1); + aip = aip->ai_next; } + ai = ai->ai_next; } + return (0); } diff --git a/sys/rpc/types.h b/sys/rpc/types.h index e2ceec5b3df7..4a5c6564b270 100644 --- a/sys/rpc/types.h +++ b/sys/rpc/types.h @@ -1,3 +1,5 @@ +/* $NetBSD: types.h,v 1.13 2000/06/13 01:02:44 thorpej Exp $ */ + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -37,8 +39,18 @@ #ifndef _RPC_TYPES_H #define _RPC_TYPES_H -#define bool_t int32_t -#define enum_t int32_t +#include <sys/types.h> + +typedef int32_t bool_t; +typedef int32_t enum_t; + +typedef u_int32_t rpcprog_t; +typedef u_int32_t rpcvers_t; +typedef u_int32_t rpcproc_t; +typedef u_int32_t rpcprot_t; +typedef u_int32_t rpcport_t; +typedef int32_t rpc_inline_t; + #define __dontcare__ -1 #ifndef FALSE @@ -51,12 +63,46 @@ # define NULL 0 #endif -#define mem_alloc(bsize) malloc(bsize) +#define mem_alloc(bsize) calloc(1, bsize) #define mem_free(ptr, bsize) free(ptr) -#ifndef makedev /* ie, we haven't already included it */ -#include <sys/types.h> -#endif #include <sys/time.h> +#include <netconfig.h> + +/* + * The netbuf structure is defined here, because FreeBSD / NetBSD only use + * it inside the RPC code. It's in <xti.h> on SVR4, but it would be confusing + * to have an xti.h, since FreeBSD / NetBSD does not support XTI/TLI. + */ + +/* + * The netbuf structure is used for transport-independent address storage. + */ +struct netbuf { + unsigned int maxlen; + unsigned int len; + void *buf; +}; + +/* + * The format of the addres and options arguments of the XTI t_bind call. + * Only provided for compatibility, it should not be used. + */ + +struct t_bind { + struct netbuf addr; + unsigned int qlen; +}; + +/* + * Internal library and rpcbind use. This is not an exported interface, do + * not use. + */ +struct __rpc_sockinfo { + int si_af; + int si_proto; + int si_socktype; + int si_alen; +}; #endif /* !_RPC_TYPES_H */ diff --git a/usr.bin/keylogin/keylogin.c b/usr.bin/keylogin/keylogin.c index 55529c85aeb8..15b62e1bce66 100644 --- a/usr.bin/keylogin/keylogin.c +++ b/usr.bin/keylogin/keylogin.c @@ -1,3 +1,4 @@ +/* $FreeBSD$ */ /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -49,7 +50,7 @@ int main() { char fullname[MAXNETNAMELEN + 1]; - struct netstarg netst; + struct key_netstarg netst; if (!getnetname(fullname)) { fprintf(stderr, "netname lookup failed -- make sure the "); diff --git a/usr.bin/rpcgen/rpc_main.c b/usr.bin/rpcgen/rpc_main.c index 5e2ebf70d271..2674b3a8788b 100644 --- a/usr.bin/rpcgen/rpc_main.c +++ b/usr.bin/rpcgen/rpc_main.c @@ -152,11 +152,7 @@ int newstyle; /* newstyle of passing arguments (by value) */ int Cflag = 0; /* ANSI C syntax */ int CCflag = 0; /* C++ files */ static int allfiles; /* generate all files */ -#if defined(__FreeBSD__) || defined(__NetBSD__) -int tirpcflag = 0; /* generating code for tirpc, by default */ -#else int tirpcflag = 1; /* generating code for tirpc, by default */ -#endif xdrfunc *xdrfunc_head = NULL; /* xdr function list */ xdrfunc *xdrfunc_tail = NULL; /* xdr function list */ pid_t childpid; @@ -692,9 +688,10 @@ s_output(argc, argv, infile, define, extend, outfile, nomain, netflag) f_print(fout, "#include <memory.h>\n"); #if defined(__FreeBSD__) || defined(__NetBSD__) +#else if (tirpcflag) -#endif f_print(fout, "#include <stropts.h>\n"); +#endif if (inetdflag || !tirpcflag) { f_print(fout, "#include <sys/socket.h>\n"); f_print(fout, "#include <netinet/in.h>\n"); @@ -1173,11 +1170,7 @@ parseargs(argc, argv, cmd) * generating backward compatible * code */ -#if defined(__FreeBSD__) || defined(__NetBSD__) - tirpcflag = 1; -#else tirpcflag = 0; -#endif break; case 'I': @@ -1273,9 +1266,7 @@ parseargs(argc, argv, cmd) } } else { /* 4.1 mode */ pmflag = 0; /* set pmflag only in tirpcmode */ -#if !defined(__FreeBSD__) && !defined(__NetBSD__) inetdflag = 1; /* inetdflag is TRUE by default */ -#endif if (cmd->nflag) { /* netid needs TIRPC */ warnx("cannot use netid flag without TIRPC"); return (0); diff --git a/usr.bin/rpcgen/rpc_parse.c b/usr.bin/rpcgen/rpc_parse.c index 1d952cc0eec2..a4a44c86014d 100644 --- a/usr.bin/rpcgen/rpc_parse.c +++ b/usr.bin/rpcgen/rpc_parse.c @@ -1,3 +1,4 @@ +/* $FreeBSD$ */ /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -593,7 +594,11 @@ get_type(prefixp, typep, dkind) (void) peekscan(TOK_INT, &tok); break; case TOK_HYPER: +#ifdef __FreeBSD__ *typep = "int64_t"; +#else + *typep = "longlong_t"; +#endif (void) peekscan(TOK_INT, &tok); break; @@ -642,7 +647,12 @@ unsigned_dec(typep) break; case TOK_HYPER: get_token(&tok); +#ifdef __FreeBSD__ *typep = "u_int64_t"; +#else + *typep = "longlong_t"; +#endif + (void) peekscan(TOK_INT, &tok); break; case TOK_INT: diff --git a/usr.bin/rpcgen/rpc_svcout.c b/usr.bin/rpcgen/rpc_svcout.c index 62b2ab1aa550..86ff5a260b94 100644 --- a/usr.bin/rpcgen/rpc_svcout.c +++ b/usr.bin/rpcgen/rpc_svcout.c @@ -1,4 +1,6 @@ /* + * $FreeBSD$ + * * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape * media and as a part of the software program in whole or part. Users @@ -635,7 +637,7 @@ printif(proc, transp, prefix, arg) char *prefix; char *arg; { - f_print(fout, "\tif (!svc_%s(%s, xdr_%s, %s%s)) {\n", + f_print(fout, "\tif (!svc_%s(%s, xdr_%s, (char *)%s%s)) {\n", proc, transp, arg, prefix, arg); } diff --git a/usr.bin/rpcgen/rpcgen.1 b/usr.bin/rpcgen/rpcgen.1 index d8ecd96c0aa5..c00dda4bf187 100644 --- a/usr.bin/rpcgen/rpcgen.1 +++ b/usr.bin/rpcgen/rpcgen.1 @@ -233,7 +233,7 @@ If this routine does not exist in the library, it must be provided. Providing an undefined data type allows customization of -.Xr XDR +.Xr xdr 3 routines. .Sh OPTIONS The following options are available: @@ -246,15 +246,6 @@ Generate transport specific .Tn RPC code for older versions of the operating system. -.Pp -Note: in -.Fx , -this compatibility flag is turned on by -default since -.Fx -supports only the older -.Tn ONC RPC -library. .It Fl c Compile into .Tn XDR @@ -510,9 +501,10 @@ use: .Sh SEE ALSO .Xr cc 1 , .Xr rpc 3 , +.Xr rpc_svc_calls 3 , .Xr syslog 3 , +.Xr xdr 3 , .Xr inetd 8 -.\" .BR rpc_svc_calls (3) .Rs .%T The rpcgen chapter in the NETP manual .Re diff --git a/usr.bin/rpcinfo/Makefile b/usr.bin/rpcinfo/Makefile index 045c37cf1188..6c75c8f67135 100644 --- a/usr.bin/rpcinfo/Makefile +++ b/usr.bin/rpcinfo/Makefile @@ -2,7 +2,15 @@ # $FreeBSD$ PROG= rpcinfo -MAN8 = rpcinfo.8 +MAN8= rpcinfo.8 +SRCS= rpcinfo.c rpc_generic.c +LIBCDIR= ${.CURDIR}/../../lib/libc +LIBCRPCDIR= ${LIBCDIR}/rpc +LIBCINCLUDE= ${LIBCDIR}/include + +CFLAGS+= -I${LIBCRPCDIR} -I${LIBCINCLUDE} -DPORTMAP -DINET6 + +.PATH: ${LIBCRPCDIR} .include <bsd.prog.mk> diff --git a/usr.bin/rpcinfo/rpcinfo.8 b/usr.bin/rpcinfo/rpcinfo.8 index 38da63093815..9976a14ce89f 100644 --- a/usr.bin/rpcinfo/rpcinfo.8 +++ b/usr.bin/rpcinfo/rpcinfo.8 @@ -1,7 +1,9 @@ -.\" from: @(#)rpcinfo.8c 2.2 88/08/03 4.0 RPCSRC; from 1.24 88/02/25 SMI +.\" @(#)rpcinfo.1m 1.23 93/03/29 SMI; from SVr4 +.\" Copyright 1989 AT&T +.\" Copyright 1991 Sun Microsystems, Inc. +.\" $NetBSD: rpcinfo.8,v 1.6 2000/06/02 23:19:38 fvdl Exp $ .\" $FreeBSD$ -.\" -.Dd December 17, 1987 +.Dd August 18, 1992 .Dt RPCINFO 8 .Os .Sh NAME @@ -9,158 +11,330 @@ .Nd report RPC information .Sh SYNOPSIS .Nm -.Fl p +.Op Fl m | s .Op Ar host .Nm +.Op Ar host +.Nm +.Fl T Ar transport +.Ar host prognum +.Op Ar versnum +.Nm +.Fl l +.Op Fl T Ar transport +.Ar host prognum +.Op Ar versnum +.Nm .Op Fl n Ar portnum -.Fl u Ar host -.Ar program -.Op Ar version +.Fl u +.Ar host prognum +.Op Ar versnum .Nm .Op Fl n Ar portnum -.Fl t Ar host -.Ar program -.Op Ar version +.Op Fl t +.Ar host prognum +.Op Ar versnum +.Nm +.Fl a Ar serv_address +.Fl T Ar transport +.Ar prognum +.Op Ar versnum .Nm .Fl b -.Ar program version +.Op Fl T Ar transport +.Ar prognum versnum .Nm .Fl d -.Ar program version +.Op Fl T Ar transport +.Ar prognum versnum .Sh DESCRIPTION -.Nm Rpcinfo -makes an -.Tn RPC -call to an -.Tn RPC +.Nm +makes an RPC call to an RPC server and reports what it finds. -.Sh OPTIONS -.Bl -tag -width indent -.It Fl p -Probe the portmapper on -.Ar host , -and print a list of all registered -.Tn RPC -programs. If -.Ar host -is not specified, it defaults to the value returned by -.Xr hostname 1 . -.It Fl u -Make an -.Tn RPC -call to procedure 0 of -.Ar program -on the specified +.Pp +In the first synopsis, +.Nm +lists all the registered RPC services with +.Nm rpcbind +on +.Ar host . +If .Ar host -using -.Tn UDP , -and report whether a response was received. -.It Fl t -Make an -.Tn RPC -call to procedure 0 of -.Ar program +is not specified, the local host is the default. +If +.Fl s +is used, the information is displayed in a concise format. +.Pp +In the second synopsis, +.Nm +lists all the RPC services registered with +.Nm rpcbind , +version 2. +Also note that the format of the information +is different in the first and the second synopsis. +This is because the second synopsis is an older protocol used to +collect the information displayed (version 2 of the +.Nm rpcbind +protocol). +.Pp +The third synopsis makes an RPC call to procedure 0 +of +.Ar prognum +and +.Ar versnum on the specified .Ar host -using -.Tn TCP , -and report whether a response was received. -.It Fl n -Use -.Ar portnum -as the port number for the -.Fl t -and -.Fl u -options instead of the port number given by the portmapper. -.It Fl b -Make an -.Tn RPC -broadcast to procedure 0 of the specified -.Ar program -and -.Ar version -using -.Tn UDP -and report all hosts that respond. -.It Fl d -Delete registration for the -.Tn RPC -service of the specified -.Ar program -and -.Ar version . -This option can be exercised only by the super-user. -.El +and reports whether a response was received. +.Ar transport +is the transport which has to be used for contacting the +given service. +The remote address of the service is obtained by +making a call to the remote +.Nm rpcbind . .Pp The -.Ar program -argument can be either a name or a number. -.Pp +.Ar prognum +argument is a number that represents an RPC program number If a -.Ar version +.Ar versnum is specified, .Nm attempts to call that version of the specified -.Ar program . +.Ar prognum . Otherwise, .Nm attempts to find all the registered version numbers for the specified -.Ar program -by calling version 0 (which is presumed not -to exist; if it does exist, +.Ar prognum +by calling version 0, +which is presumed not to exist; +if it does exist, .Nm attempts to obtain this information by calling -an extremely high version -number instead) and attempts to call each registered version. -Note: the version number is required for +an extremely high version number instead, +and attempts to call each registered version. +Note: +the version number is required for .Fl b and .Fl d options. +.Sh OPTIONS +.Bl -tag -width indent +.It Fl T Ar transport +Specify the transport on which the service is required. +If this option is not specified, +.Nm +uses the transport specified in the +.Ev NETPATH +environment variable, or if that is unset or empty, the transport +in the +.Xr netconfig 5 +database is used. +This is a generic option, +and can be used in conjunction with other options as +shown in the +.Sx SYNOPSIS . +.It Fl a Ar serv_address +Use +.Ar serv_address +as the (universal) address for the service on +.Ar transport +to ping procedure 0 +of the specified +.Ar prognum +and report whether a response was received. +The +.Fl T +option is required with the +.Fl a +option. +.Pp +If +.Ar versnum +is not specified, +.Nm +tries to ping all +available version numbers for that program number. +This option avoids calls to remote +.Nm rpcbind +to find the address of the service. +The +.Ar serv_address +is specified in universal address format of the given transport. +.It Fl b +Make an RPC broadcast to procedure 0 +of the specified +.Ar prognum +and +.Ar versnum +and report all hosts that respond. +If +.Ar transport +is specified, it broadcasts its request only on the +specified transport. +If broadcasting is not supported by any +transport, +an error message is printed. +Use of broadcasting should be limited because of the potential for adverse +effect on other systems. +.It Fl d +Delete registration for the RPC service of the specified +.Ar prognum +and +.Ar versnum . +If +.Ar transport +is specified, +unregister the service on only that transport, +otherwise unregister the service on all +the transports on which it was registered. +Only the owner of a service can delete a registration, except the +super-user who can delete any service. +.It Fl l +Display a list of entries with a given +.Ar prognum +and +.Ar versnum +on the specified +.Ar host . +Entries are returned for all transports +in the same protocol family as that used to contact the remote +.Nm rpcbind . +.It Fl m +Display a table of statistics of +.Nm rpcbind +operations on the given +.Ar host . +The table shows statistics for each version of +.Nm rpcbind +(versions 2, 3 and 4), giving the number of times each procedure was +requested and successfully serviced, the number and type of remote call +requests that were made, and information about RPC address lookups that were +handled. +This is useful for monitoring RPC activities on +.Ar host . +.It Fl n Ar portnum +Use +.Ar portnum +as the port number for the +.Fl t +and +.Fl u +options instead of the port number given by +.Nm rpcbind . +Use of this option avoids a call to the remote +.Nm rpcbind +to find out the address of the service. +This option is made +obsolete by the +.Fl a +option. +.It Fl p +Probe +.Nm rpcbind +on +.Ar host +using version 2 of the +.Nm rpcbind +protocol, +and display a list of all registered RPC programs. +If +.Ar host +is not specified, it defaults to the local host. +Note: Version 2 of the +.Nm rpcbind +protocol was previously known as the portmapper protocol. +.It Fl s +Display a concise list of all registered RPC programs on +.Ar host . +If +.Ar host +is not specified, it defaults to the local host. +.It Fl t +Make an RPC call to procedure 0 of +.Ar prognum +on the specified +.Ar host +using TCP, +and report whether a response was received. +This option is made +obsolete by the +.Fl T +option as shown in the third synopsis. +.It Fl u +Make an RPC call to procedure 0 of +.Ar prognum +on the specified +.Ar host +using UDP, +and report whether a response was received. +This option is made +obsolete by the +.Fl T +option as shown in the third synopsis. +.El .Sh EXAMPLES -To show all of the -.Tn RPC -services registered on the local machine use: +To show all of the RPC services registered on the local machine use: .Pp -.Dl example% rpcinfo -p +.Dl "example% rpcinfo" .Pp -To show all of the -.Tn RPC -services registered on the machine named -.Ar klaxon +To show all of the RPC +services registered with +.Nm rpcbind +on the machine named +.Dq klaxon use: .Pp -.Dl example% rpcinfo -p klaxon +.Dl "example% rpcinfo klaxon" .Pp -To show all machines on the local net that are running the Yellow Pages -service use: +The information displayed by the above commands can be quite lengthy. +Use the +.Fl s +option to display a more concise list: .Pp -.Dl example% rpcinfo -b ypserv 'version' | uniq +.Dl "example$ rpcinfo -s klaxon" +.Bl -column "program" "version(s)" "unix,tcp,udp,tcp6,udp6" "nlockmgr" "super-user" +.It "program version(s) netid(s) service owner" +.It "100000 2,3,4 unix,tcp,udp,tcp6,udp6 rpcbind super-user" +.It "100008 1 udp,tcp,udp6,tcp6 walld super-user" +.It "100002 2,1 udp,udp6 rusersd super-user" +.It "100001 2,3,4 udp,udp6 rstatd super-user" +.It "100012 1 udp,tcp sprayd super-user" +.It "100007 3 udp,tcp ypbind super-user" +.El .Pp -where 'version' is the current Yellow Pages version obtained from the -results of the -.Fl p -switch above. +To show whether the RPC +service with program number +.Ar prognum +and version +.Ar versnum +is +registered on the machine named +.Dq klaxon +for the transport TCP +use: .Pp -To delete the registration for version 1 of the +.Dl "example% rpcinfo -T tcp klaxon prognum versnum" +.Pp +To show all RPC +services registered with version 2 of the +.Nm rpcbind +protocol on the local machine use: +.Pp +.Dl "example% rpcinfo -p" +.Pp +To delete the registration for version +1 of the .Nm walld -service use: +(program number 100008) +service for all transports use: .Pp -.Dl example% rpcinfo -d walld 1 +.Dl "example# rpcinfo -d 100008 1" +or +.Dl "example# rpcinfo -d walld 1" .Sh SEE ALSO +.Xr rpc 3 , +.Xr netconfig 5 , .Xr rpc 5 , -.Xr portmap 8 -.Rs -.%T "RPC Programming Guide" -.Re -.Sh BUGS -In releases prior to SunOS 3.0, the Network File System (NFS) did not -register itself with the portmapper; -.Nm -cannot be used to make -.Tn RPC -calls to the -.Tn NFS -server on hosts running such releases. +.Xr rpcbind 8 diff --git a/usr.bin/rpcinfo/rpcinfo.c b/usr.bin/rpcinfo/rpcinfo.c index 622ea819a0c2..38abe2f7f11b 100644 --- a/usr.bin/rpcinfo/rpcinfo.c +++ b/usr.bin/rpcinfo/rpcinfo.c @@ -1,18 +1,5 @@ -#ifndef lint -/*static char sccsid[] = "from: @(#)rpcinfo.c 1.22 87/08/12 SMI";*/ -/*static char sccsid[] = "from: @(#)rpcinfo.c 2.2 88/08/11 4.0 RPCSRC";*/ -static char rcsid[] = - "$FreeBSD$"; -#endif - -/* - * Copyright (C) 1986, Sun Microsystems, Inc. - */ - -/* - * rpcinfo: ping a particular rpc program - * or dump the portmapper - */ +/* $NetBSD: rpcinfo.c,v 1.15 2000/10/04 20:09:05 mjl Exp $ */ +/* $FreeBSD$ */ /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for @@ -43,36 +30,64 @@ static char rcsid[] = * Mountain View, California 94043 */ -#include <err.h> -#include <ctype.h> +/* + * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. + */ + +/* #ident "@(#)rpcinfo.c 1.18 93/07/05 SMI" */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)rpcinfo.c 1.16 89/04/05 Copyr 1986 Sun Micro"; +#endif +#endif + +/* + * rpcinfo: ping a particular rpc program + * or dump the the registered programs on the remote machine. + */ + +/* + * We are for now defining PORTMAP here. It doesnt even compile + * unless it is defined. + */ +#ifndef PORTMAP +#define PORTMAP +#endif + +/* + * If PORTMAP is defined, rpcinfo will talk to both portmapper and + * rpcbind programs; else it talks only to rpcbind. In the latter case + * all the portmapper specific options such as -u, -t, -p become void. + */ +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/un.h> #include <rpc/rpc.h> #include <stdio.h> -#include <sys/socket.h> +#include <rpc/rpcb_prot.h> +#include <rpc/rpcent.h> +#include <rpc/nettype.h> +#include <rpc/rpc_com.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <err.h> +#include <ctype.h> + +#ifdef PORTMAP /* Support for version 2 portmapper */ +#include <netinet/in.h> #include <netdb.h> +#include <arpa/inet.h> #include <rpc/pmap_prot.h> #include <rpc/pmap_clnt.h> -#include <signal.h> -#include <ctype.h> -#include <unistd.h> -#include <sys/param.h> -#include <arpa/inet.h> +#endif #define MAXHOSTLEN 256 - #define MIN_VERS ((u_long) 0) #define MAX_VERS ((u_long) 4294967295UL) - -static void udpping(/*u_short portflag, int argc, char **argv*/); -static void tcpping(/*u_short portflag, int argc, char **argv*/); -static int pstatus(/*CLIENT *client, u_long prognum, u_long vers*/); -static void pmapdump(/*int argc, char **argv*/); -static bool_t reply_proc(/*void *res, struct sockaddr_in *who*/); -static void brdcst(/*int argc, char **argv*/); -static void deletereg(/* int argc, char **argv */) ; -static void usage(/*void*/); -static u_long getprognum(/*char *arg*/); -static u_long getvers(/*char *arg*/); -static void get_inet_address(/*struct sockaddr_in *addr, char *host*/); +#define UNKNOWN "unknown" /* * Functions to be performed. @@ -81,25 +96,90 @@ static void get_inet_address(/*struct sockaddr_in *addr, char *host*/); #define PMAPDUMP 1 /* dump portmapper registrations */ #define TCPPING 2 /* ping TCP service */ #define UDPPING 3 /* ping UDP service */ -#define BRDCST 4 /* ping broadcast UDP service */ -#define DELETES 5 /* delete registration for the service */ +#define BROADCAST 4 /* ping broadcast service */ +#define DELETES 5 /* delete registration for the service */ +#define ADDRPING 6 /* pings at the given address */ +#define PROGPING 7 /* pings a program on a given host */ +#define RPCBDUMP 8 /* dump rpcbind registrations */ +#define RPCBDUMP_SHORT 9 /* dump rpcbind registrations - short version */ +#define RPCBADDRLIST 10 /* dump addr list about one prog */ +#define RPCBGETSTAT 11 /* Get statistics */ + +struct netidlist { + char *netid; + struct netidlist *next; +}; + +struct verslist { + int vers; + struct verslist *next; +}; + +struct rpcbdump_short { + u_long prog; + struct verslist *vlist; + struct netidlist *nlist; + struct rpcbdump_short *next; + char *owner; +}; + + + +#ifdef PORTMAP +static void ip_ping(u_short, char *, int, char **); +static CLIENT *clnt_com_create(struct sockaddr_in *, u_long, u_long, int *, + char *); +static void pmapdump(int, char **); +static void get_inet_address(struct sockaddr_in *, char *); +#endif + +static bool_t reply_proc(void *, struct netbuf *, struct netconfig *); +static void brdcst(int, char **); +static void addrping(char *, char *, int, char **); +static void progping(char *, int, char **); +static CLIENT *clnt_addr_create(char *, struct netconfig *, u_long, u_long); +static CLIENT *clnt_rpcbind_create(char *, int, struct netbuf **); +static CLIENT *getclnthandle(char *, struct netconfig *, u_long, + struct netbuf **); +static CLIENT *local_rpcb(u_long, u_long); +static int pstatus(CLIENT *, u_long, u_long); +static void rpcbdump(int, char *, int, char **); +static void rpcbgetstat(int, char **); +static void rpcbaddrlist(char *, int, char **); +static void deletereg(char *, int, char **); +static void print_rmtcallstat(int, rpcb_stat *); +static void print_getaddrstat(int, rpcb_stat *); +static void usage(void); +static u_long getprognum(char *); +static u_long getvers(char *); +static char *spaces(int); +static bool_t add_version(struct rpcbdump_short *, u_long); +static bool_t add_netid(struct rpcbdump_short *, char *); + +int main(int argc, char **argv); int -main(argc, argv) - int argc; - char **argv; +main(int argc, char **argv) { register int c; int errflg; int function; - u_short portnum; + char *netid = NULL; + char *address = NULL; +#ifdef PORTMAP + char *strptr; + u_short portnum = 0; +#endif function = NONE; - portnum = 0; errflg = 0; - while ((c = getopt(argc, argv, "ptubdn:")) != -1) { +#ifdef PORTMAP + while ((c = getopt(argc, argv, "a:bdlmn:pstT:u")) != -1) { +#else + while ((c = getopt(argc, argv, "a:bdlmn:sT:")) != -1) { +#endif switch (c) { - +#ifdef PORTMAP case 'p': if (function != NONE) errflg = 1; @@ -121,15 +201,28 @@ main(argc, argv) function = UDPPING; break; - case 'b': + case 'n': + portnum = (u_short) strtol(optarg, &strptr, 10); + if (strptr == optarg || *strptr != '\0') { + fprintf(stderr, + "rpcinfo: %s is illegal port number\n", + optarg); + exit(1); + } + break; +#endif + case 'a': + address = optarg; if (function != NONE) errflg = 1; else - function = BRDCST; + function = ADDRPING; break; - - case 'n': - portnum = (u_short) atoi(optarg); /* hope we don't get bogus # */ + case 'b': + if (function != NONE) + errflg = 1; + else + function = BROADCAST; break; case 'd': @@ -139,18 +232,50 @@ main(argc, argv) function = DELETES; break; + case 'l': + if (function != NONE) + errflg = 1; + else + function = RPCBADDRLIST; + break; + + case 'm': + if (function != NONE) + errflg = 1; + else + function = RPCBGETSTAT; + break; + + case 's': + if (function != NONE) + errflg = 1; + else + function = RPCBDUMP_SHORT; + break; + + case 'T': + netid = optarg; + break; case '?': errflg = 1; + break; } } - if (errflg || function == NONE) { + if (errflg || ((function == ADDRPING) && !netid)) { usage(); return (1); } - switch (function) { + if (function == NONE) { + if (argc - optind > 1) + function = PROGPING; + else + function = RPCBDUMP; + } + switch (function) { +#ifdef PORTMAP case PMAPDUMP: if (portnum != 0) { usage(); @@ -160,375 +285,270 @@ main(argc, argv) break; case UDPPING: - udpping(portnum, argc - optind, argv + optind); + ip_ping(portnum, "udp", argc - optind, argv + optind); break; case TCPPING: - tcpping(portnum, argc - optind, argv + optind); + ip_ping(portnum, "tcp", argc - optind, argv + optind); break; - - case BRDCST: - if (portnum != 0) { - usage(); - return (1); - } +#endif + case BROADCAST: brdcst(argc - optind, argv + optind); break; - case DELETES: - deletereg(argc - optind, argv + optind); + deletereg(netid, argc - optind, argv + optind); + break; + case ADDRPING: + addrping(address, netid, argc - optind, argv + optind); + break; + case PROGPING: + progping(netid, argc - optind, argv + optind); + break; + case RPCBDUMP: + case RPCBDUMP_SHORT: + rpcbdump(function, netid, argc - optind, argv + optind); + break; + case RPCBGETSTAT: + rpcbgetstat(argc - optind, argv + optind); + break; + case RPCBADDRLIST: + rpcbaddrlist(netid, argc - optind, argv + optind); break; } - return (0); } -static void -udpping(portnum, argc, argv) - u_short portnum; - int argc; - char **argv; +static CLIENT * +local_rpcb(u_long prog, u_long vers) { - struct timeval to; - struct sockaddr_in addr; - enum clnt_stat rpc_stat; - CLIENT *client; - u_long prognum, vers, minvers, maxvers; - int sock = RPC_ANYSOCK; - struct rpc_err rpcerr; - int failure; + struct netbuf nbuf; + struct sockaddr_un sun; + int sock; + + memset(&sun, 0, sizeof sun); + sock = socket(AF_LOCAL, SOCK_STREAM, 0); + if (sock < 0) + return NULL; + + sun.sun_family = AF_LOCAL; + strcpy(sun.sun_path, _PATH_RPCBINDSOCK); + nbuf.len = sun.sun_len = SUN_LEN(&sun); + nbuf.maxlen = sizeof (struct sockaddr_un); + nbuf.buf = &sun; + + return clnt_vc_create(sock, &nbuf, prog, vers, 0, 0); +} + +#ifdef PORTMAP +static CLIENT * +clnt_com_create(struct sockaddr_in *addr, u_long prog, u_long vers, + int *fdp, char *trans) +{ + CLIENT *clnt; + + if (strcmp(trans, "tcp") == 0) { + clnt = clnttcp_create(addr, prog, vers, fdp, 0, 0); + } else { + struct timeval to; - if (argc < 2 || argc > 3) { - usage(); - exit(1); - } - prognum = getprognum(argv[1]); - get_inet_address(&addr, argv[0]); - /* Open the socket here so it will survive calls to clnt_destroy */ - sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (sock < 0) { - perror("rpcinfo: socket"); - exit(1); - } - failure = 0; - if (argc == 2) { - /* - * A call to version 0 should fail with a program/version - * mismatch, and give us the range of versions supported. - */ - addr.sin_port = htons(portnum); to.tv_sec = 5; to.tv_usec = 0; - if ((client = clntudp_create(&addr, prognum, (u_long)0, - to, &sock)) == NULL) { - clnt_pcreateerror("rpcinfo"); - printf("program %lu is not available\n", - prognum); - exit(1); - } - to.tv_sec = 10; - to.tv_usec = 0; - rpc_stat = clnt_call(client, NULLPROC, xdr_void, (char *)NULL, - xdr_void, (char *)NULL, to); - if (rpc_stat == RPC_PROGVERSMISMATCH) { - clnt_geterr(client, &rpcerr); - minvers = rpcerr.re_vers.low; - maxvers = rpcerr.re_vers.high; - } else if (rpc_stat == RPC_SUCCESS) { - /* - * Oh dear, it DOES support version 0. - * Let's try version MAX_VERS. - */ - addr.sin_port = htons(portnum); - to.tv_sec = 5; - to.tv_usec = 0; - if ((client = clntudp_create(&addr, prognum, MAX_VERS, - to, &sock)) == NULL) { - clnt_pcreateerror("rpcinfo"); - printf("program %lu version %lu is not available\n", - prognum, MAX_VERS); - exit(1); - } - to.tv_sec = 10; - to.tv_usec = 0; - rpc_stat = clnt_call(client, NULLPROC, xdr_void, - (char *)NULL, xdr_void, (char *)NULL, to); - if (rpc_stat == RPC_PROGVERSMISMATCH) { - clnt_geterr(client, &rpcerr); - minvers = rpcerr.re_vers.low; - maxvers = rpcerr.re_vers.high; - } else if (rpc_stat == RPC_SUCCESS) { - /* - * It also supports version MAX_VERS. - * Looks like we have a wise guy. - * OK, we give them information on all - * 4 billion versions they support... - */ - minvers = 0; - maxvers = MAX_VERS; - } else { - (void) pstatus(client, prognum, MAX_VERS); - exit(1); - } - } else { - (void) pstatus(client, prognum, (u_long)0); - exit(1); - } - clnt_destroy(client); - for (vers = minvers; vers <= maxvers; vers++) { - addr.sin_port = htons(portnum); - to.tv_sec = 5; - to.tv_usec = 0; - if ((client = clntudp_create(&addr, prognum, vers, - to, &sock)) == NULL) { - clnt_pcreateerror("rpcinfo"); - printf("program %lu version %lu is not available\n", - prognum, vers); - exit(1); - } - to.tv_sec = 10; - to.tv_usec = 0; - rpc_stat = clnt_call(client, NULLPROC, xdr_void, - (char *)NULL, xdr_void, (char *)NULL, to); - if (pstatus(client, prognum, vers) < 0) - failure = 1; - clnt_destroy(client); - } + clnt = clntudp_create(addr, prog, vers, to, fdp); } - else { - vers = getvers(argv[2]); - addr.sin_port = htons(portnum); - to.tv_sec = 5; - to.tv_usec = 0; - if ((client = clntudp_create(&addr, prognum, vers, - to, &sock)) == NULL) { - clnt_pcreateerror("rpcinfo"); + if (clnt == (CLIENT *)NULL) { + clnt_pcreateerror("rpcinfo"); + if (vers == MIN_VERS) + printf("program %lu is not available\n", prog); + else printf("program %lu version %lu is not available\n", - prognum, vers); - exit(1); - } - to.tv_sec = 10; - to.tv_usec = 0; - rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL, - xdr_void, (char *)NULL, to); - if (pstatus(client, prognum, vers) < 0) - failure = 1; - } - (void) close(sock); /* Close it up again */ - if (failure) + prog, vers); exit(1); + } + return (clnt); } +/* + * If portnum is 0, then go and get the address from portmapper, which happens + * transparently through clnt*_create(); If version number is not given, it + * tries to find out the version number by making a call to version 0 and if + * that fails, it obtains the high order and the low order version number. If + * version 0 calls succeeds, it tries for MAXVERS call and repeats the same. + */ static void -tcpping(portnum, argc, argv) - u_short portnum; - int argc; - char **argv; +ip_ping(u_short portnum, char *trans, int argc, char **argv) { + CLIENT *client; + int fd = RPC_ANYFD; struct timeval to; struct sockaddr_in addr; enum clnt_stat rpc_stat; - CLIENT *client; u_long prognum, vers, minvers, maxvers; - int sock = RPC_ANYSOCK; struct rpc_err rpcerr; - int failure; + int failure = 0; if (argc < 2 || argc > 3) { usage(); exit(1); } + to.tv_sec = 10; + to.tv_usec = 0; prognum = getprognum(argv[1]); get_inet_address(&addr, argv[0]); - failure = 0; - if (argc == 2) { + if (argc == 2) { /* Version number not known */ /* * A call to version 0 should fail with a program/version * mismatch, and give us the range of versions supported. */ - addr.sin_port = htons(portnum); - if ((client = clnttcp_create(&addr, prognum, MIN_VERS, - &sock, 0, 0)) == NULL) { - clnt_pcreateerror("rpcinfo"); - printf("program %lu is not available\n", - prognum); + vers = MIN_VERS; + } else { + vers = getvers(argv[2]); + } + addr.sin_port = htons(portnum); + client = clnt_com_create(&addr, prognum, vers, &fd, trans); + rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void, + (char *)NULL, (xdrproc_t) xdr_void, (char *)NULL, + to); + if (argc != 2) { + /* Version number was known */ + if (pstatus(client, prognum, vers) < 0) exit(1); - } - to.tv_sec = 10; - to.tv_usec = 0; - rpc_stat = clnt_call(client, NULLPROC, xdr_void, (char *)NULL, - xdr_void, (char *)NULL, to); + (void) CLNT_DESTROY(client); + return; + } + /* Version number not known */ + (void) CLNT_CONTROL(client, CLSET_FD_NCLOSE, (char *)NULL); + if (rpc_stat == RPC_PROGVERSMISMATCH) { + clnt_geterr(client, &rpcerr); + minvers = rpcerr.re_vers.low; + maxvers = rpcerr.re_vers.high; + } else if (rpc_stat == RPC_SUCCESS) { + /* + * Oh dear, it DOES support version 0. + * Let's try version MAX_VERS. + */ + (void) CLNT_DESTROY(client); + addr.sin_port = htons(portnum); + client = clnt_com_create(&addr, prognum, MAX_VERS, &fd, trans); + rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void, + (char *)NULL, (xdrproc_t) xdr_void, + (char *)NULL, to); if (rpc_stat == RPC_PROGVERSMISMATCH) { clnt_geterr(client, &rpcerr); minvers = rpcerr.re_vers.low; maxvers = rpcerr.re_vers.high; } else if (rpc_stat == RPC_SUCCESS) { /* - * Oh dear, it DOES support version 0. - * Let's try version MAX_VERS. + * It also supports version MAX_VERS. + * Looks like we have a wise guy. + * OK, we give them information on all + * 4 billion versions they support... */ - addr.sin_port = htons(portnum); - if ((client = clnttcp_create(&addr, prognum, MAX_VERS, - &sock, 0, 0)) == NULL) { - clnt_pcreateerror("rpcinfo"); - printf("program %lu version %lu is not available\n", - prognum, MAX_VERS); - exit(1); - } - to.tv_sec = 10; - to.tv_usec = 0; - rpc_stat = clnt_call(client, NULLPROC, xdr_void, - (char *)NULL, xdr_void, (char *)NULL, to); - if (rpc_stat == RPC_PROGVERSMISMATCH) { - clnt_geterr(client, &rpcerr); - minvers = rpcerr.re_vers.low; - maxvers = rpcerr.re_vers.high; - } else if (rpc_stat == RPC_SUCCESS) { - /* - * It also supports version MAX_VERS. - * Looks like we have a wise guy. - * OK, we give them information on all - * 4 billion versions they support... - */ - minvers = 0; - maxvers = MAX_VERS; - } else { - (void) pstatus(client, prognum, MAX_VERS); - exit(1); - } + minvers = 0; + maxvers = MAX_VERS; } else { - (void) pstatus(client, prognum, MIN_VERS); + (void) pstatus(client, prognum, MAX_VERS); exit(1); } - clnt_destroy(client); - (void) close(sock); - sock = RPC_ANYSOCK; /* Re-initialize it for later */ - for (vers = minvers; vers <= maxvers; vers++) { - addr.sin_port = htons(portnum); - if ((client = clnttcp_create(&addr, prognum, vers, - &sock, 0, 0)) == NULL) { - clnt_pcreateerror("rpcinfo"); - printf("program %lu version %lu is not available\n", - prognum, vers); - exit(1); - } - to.tv_usec = 0; - to.tv_sec = 10; - rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL, - xdr_void, (char *)NULL, to); - if (pstatus(client, prognum, vers) < 0) - failure = 1; - clnt_destroy(client); - (void) close(sock); - sock = RPC_ANYSOCK; - } + } else { + (void) pstatus(client, prognum, (u_long)0); + exit(1); } - else { - vers = getvers(argv[2]); + (void) CLNT_DESTROY(client); + for (vers = minvers; vers <= maxvers; vers++) { addr.sin_port = htons(portnum); - if ((client = clnttcp_create(&addr, prognum, vers, &sock, - 0, 0)) == NULL) { - clnt_pcreateerror("rpcinfo"); - printf("program %lu version %lu is not available\n", - prognum, vers); - exit(1); - } - to.tv_usec = 0; - to.tv_sec = 10; - rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL, - xdr_void, (char *)NULL, to); + client = clnt_com_create(&addr, prognum, vers, &fd, trans); + rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void, + (char *)NULL, (xdrproc_t) xdr_void, + (char *)NULL, to); if (pstatus(client, prognum, vers) < 0) - failure = 1; + failure = 1; + (void) CLNT_DESTROY(client); } if (failure) exit(1); + (void) close(fd); + return; } /* - * This routine should take a pointer to an "rpc_err" structure, rather than - * a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to - * a CLIENT structure rather than a pointer to an "rpc_err" structure. - * As such, we have to keep the CLIENT structure around in order to print - * a good error message. + * Dump all the portmapper registerations */ -static int -pstatus(client, prognum, vers) - register CLIENT *client; - u_long prognum; - u_long vers; -{ - struct rpc_err rpcerr; - - clnt_geterr(client, &rpcerr); - if (rpcerr.re_status != RPC_SUCCESS) { - clnt_perror(client, "rpcinfo"); - printf("program %lu version %lu is not available\n", - prognum, vers); - return (-1); - } else { - printf("program %lu version %lu ready and waiting\n", - prognum, vers); - return (0); - } -} - static void -pmapdump(argc, argv) - int argc; - char **argv; +pmapdump(int argc, char **argv) { struct sockaddr_in server_addr; - register struct hostent *hp; struct pmaplist *head = NULL; int socket = RPC_ANYSOCK; struct timeval minutetimeout; register CLIENT *client; struct rpcent *rpc; + enum clnt_stat clnt_st; + struct rpc_err err; + char *host; if (argc > 1) { usage(); exit(1); } - if (argc == 1) - get_inet_address(&server_addr, argv[0]); - else { - bzero((char *)&server_addr, sizeof server_addr); - server_addr.sin_family = AF_INET; - if ((hp = gethostbyname("localhost")) != NULL) - bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr, - MIN(hp->h_length,sizeof(server_addr.sin_addr))); - else - server_addr.sin_addr.s_addr = inet_addr("0.0.0.0"); - } - minutetimeout.tv_sec = 60; - minutetimeout.tv_usec = 0; - server_addr.sin_port = htons(PMAPPORT); - if ((client = clnttcp_create(&server_addr, PMAPPROG, - PMAPVERS, &socket, 50, 500)) == NULL) { + if (argc == 1) { + host = argv[0]; + get_inet_address(&server_addr, host); + server_addr.sin_port = htons(PMAPPORT); + client = clnttcp_create(&server_addr, PMAPPROG, PMAPVERS, + &socket, 50, 500); + } else + client = local_rpcb(PMAPPROG, PMAPVERS); + + if (client == NULL) { + if (rpc_createerr.cf_stat == RPC_TLIERROR) { + /* + * "Misc. TLI error" is not too helpful. Most likely + * the connection to the remote server timed out, so + * this error is at least less perplexing. + */ + rpc_createerr.cf_stat = RPC_PMAPFAILURE; + rpc_createerr.cf_error.re_status = RPC_FAILED; + } clnt_pcreateerror("rpcinfo: can't contact portmapper"); exit(1); } - if (clnt_call(client, PMAPPROC_DUMP, xdr_void, NULL, - xdr_pmaplist, &head, minutetimeout) != RPC_SUCCESS) { - fprintf(stderr, "rpcinfo: can't contact portmapper: "); - clnt_perror(client, "rpcinfo"); + + minutetimeout.tv_sec = 60; + minutetimeout.tv_usec = 0; + + clnt_st = CLNT_CALL(client, PMAPPROC_DUMP, (xdrproc_t) xdr_void, + NULL, (xdrproc_t) xdr_pmaplist_ptr, (char *)&head, + minutetimeout); + if (clnt_st != RPC_SUCCESS) { + if ((clnt_st == RPC_PROGVERSMISMATCH) || + (clnt_st == RPC_PROGUNAVAIL)) { + CLNT_GETERR(client, &err); + if (err.re_vers.low > PMAPVERS) + fprintf(stderr, + "%s does not support portmapper. Try rpcinfo %s instead\n", + host, host); + exit(1); + } + clnt_perror(client, "rpcinfo: can't contact portmapper"); exit(1); } if (head == NULL) { printf("No remote programs registered.\n"); } else { - printf(" program vers proto port\n"); + printf(" program vers proto port service\n"); for (; head != NULL; head = head->pml_next) { printf("%10ld%5ld", - head->pml_map.pm_prog, - head->pml_map.pm_vers); + head->pml_map.pm_prog, + head->pml_map.pm_vers); if (head->pml_map.pm_prot == IPPROTO_UDP) - printf("%6s", "udp"); + printf("%6s", "udp"); else if (head->pml_map.pm_prot == IPPROTO_TCP) printf("%6s", "tcp"); + else if (head->pml_map.pm_prot == IPPROTO_ST) + printf("%6s", "unix"); else - printf("%6ld", head->pml_map.pm_prot); - printf("%7ld", head->pml_map.pm_port); + printf("%6ld", head->pml_map.pm_prot); + printf("%7ld", head->pml_map.pm_port); rpc = getrpcbynumber(head->pml_map.pm_prog); if (rpc) printf(" %s\n", rpc->r_name); @@ -538,6 +558,41 @@ pmapdump(argc, argv) } } +static void +get_inet_address(struct sockaddr_in *addr, char *host) +{ + struct netconfig *nconf; + struct addrinfo hints, *res; + int error; + + (void) memset((char *)addr, 0, sizeof (*addr)); + addr->sin_addr.s_addr = inet_addr(host); + if (addr->sin_addr.s_addr == -1 || addr->sin_addr.s_addr == 0) { + if ((nconf = __rpc_getconfip("udp")) == NULL && + (nconf = __rpc_getconfip("tcp")) == NULL) { + fprintf(stderr, + "rpcinfo: couldn't find a suitable transport\n"); + exit(1); + } else { + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_INET; + if ((error = getaddrinfo(host, "rpcbind", &hints, &res)) + != 0) { + fprintf(stderr, "rpcinfo: %s: %s\n", + host, gai_strerror(error)); + exit(1); + } else { + memcpy(addr, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + } + (void) freenetconfigent(nconf); + } + } else { + addr->sin_family = AF_INET; + } +} +#endif /* PORTMAP */ + /* * reply_proc collects replies from the broadcast. * to get a unique list of responses the output of rpcinfo should @@ -546,23 +601,32 @@ pmapdump(argc, argv) /*ARGSUSED*/ static bool_t -reply_proc(res, who) - void *res; /* Nothing comes back */ - struct sockaddr_in *who; /* Who sent us the reply */ +reply_proc(void *res, struct netbuf *who, struct netconfig *nconf) + /* void *res; Nothing comes back */ + /* struct netbuf *who; Who sent us the reply */ + /* struct netconfig *nconf; On which transport the reply came */ { - register struct hostent *hp; + char *uaddr; + char hostbuf[NI_MAXHOST]; + char *hostname; + struct sockaddr *sa = (struct sockaddr *)who->buf; - hp = gethostbyaddr((char *) &who->sin_addr, sizeof who->sin_addr, - AF_INET); - printf("%s %s\n", inet_ntoa(who->sin_addr), - (hp == NULL) ? "(unknown)" : hp->h_name); - return(FALSE); + if (getnameinfo(sa, sa->sa_len, hostbuf, NI_MAXHOST, NULL, 0, 0)) { + hostname = UNKNOWN; + } else { + hostname = hostbuf; + } + if (!(uaddr = taddr2uaddr(nconf, who))) { + uaddr = UNKNOWN; + } + printf("%s\t%s\n", uaddr, hostname); + if (strcmp(uaddr, UNKNOWN)) + free((char *)uaddr); + return (FALSE); } static void -brdcst(argc, argv) - int argc; - char **argv; +brdcst(int argc, char **argv) { enum clnt_stat rpc_stat; u_long prognum, vers; @@ -573,89 +637,1079 @@ brdcst(argc, argv) } prognum = getprognum(argv[0]); vers = getvers(argv[1]); - rpc_stat = clnt_broadcast(prognum, vers, NULLPROC, xdr_void, - (char *)NULL, xdr_void, (char *)NULL, reply_proc); + rpc_stat = rpc_broadcast(prognum, vers, NULLPROC, + (xdrproc_t) xdr_void, (char *)NULL, (xdrproc_t) xdr_void, + (char *)NULL, (resultproc_t) reply_proc, NULL); if ((rpc_stat != RPC_SUCCESS) && (rpc_stat != RPC_TIMEDOUT)) { fprintf(stderr, "rpcinfo: broadcast failed: %s\n", - clnt_sperrno(rpc_stat)); + clnt_sperrno(rpc_stat)); exit(1); } exit(0); } +static bool_t +add_version(struct rpcbdump_short *rs, u_long vers) +{ + struct verslist *vl; + + for (vl = rs->vlist; vl; vl = vl->next) + if (vl->vers == vers) + break; + if (vl) + return (TRUE); + vl = (struct verslist *)malloc(sizeof (struct verslist)); + if (vl == NULL) + return (FALSE); + vl->vers = vers; + vl->next = rs->vlist; + rs->vlist = vl; + return (TRUE); +} + +static bool_t +add_netid(struct rpcbdump_short *rs, char *netid) +{ + struct netidlist *nl; + + for (nl = rs->nlist; nl; nl = nl->next) + if (strcmp(nl->netid, netid) == 0) + break; + if (nl) + return (TRUE); + nl = (struct netidlist *)malloc(sizeof (struct netidlist)); + if (nl == NULL) + return (FALSE); + nl->netid = netid; + nl->next = rs->nlist; + rs->nlist = nl; + return (TRUE); +} + +static void +rpcbdump(int dumptype, char *netid, int argc, char **argv) +{ + rpcblist_ptr head = NULL; + struct timeval minutetimeout; + register CLIENT *client; + struct rpcent *rpc; + char *host; + struct netidlist *nl; + struct verslist *vl; + struct rpcbdump_short *rs, *rs_tail; + char buf[256]; + enum clnt_stat clnt_st; + struct rpc_err err; + struct rpcbdump_short *rs_head = NULL; + + if (argc > 1) { + usage(); + exit(1); + } + if (argc == 1) { + host = argv[0]; + if (netid == NULL) { + client = clnt_rpcbind_create(host, RPCBVERS, NULL); + } else { + struct netconfig *nconf; + + nconf = getnetconfigent(netid); + if (nconf == NULL) { + nc_perror("rpcinfo: invalid transport"); + exit(1); + } + client = getclnthandle(host, nconf, RPCBVERS, NULL); + if (nconf) + (void) freenetconfigent(nconf); + } + } else + client = local_rpcb(PMAPPROG, RPCBVERS); + + if (client == (CLIENT *)NULL) { + clnt_pcreateerror("rpcinfo: can't contact rpcbind"); + exit(1); + } + + minutetimeout.tv_sec = 60; + minutetimeout.tv_usec = 0; + clnt_st = CLNT_CALL(client, RPCBPROC_DUMP, (xdrproc_t) xdr_void, + NULL, (xdrproc_t) xdr_rpcblist_ptr, (char *) &head, + minutetimeout); + if (clnt_st != RPC_SUCCESS) { + if ((clnt_st == RPC_PROGVERSMISMATCH) || + (clnt_st == RPC_PROGUNAVAIL)) { + int vers; + + CLNT_GETERR(client, &err); + if (err.re_vers.low == RPCBVERS4) { + vers = RPCBVERS4; + clnt_control(client, CLSET_VERS, (char *)&vers); + clnt_st = CLNT_CALL(client, RPCBPROC_DUMP, + (xdrproc_t) xdr_void, NULL, + (xdrproc_t) xdr_rpcblist_ptr, (char *) &head, + minutetimeout); + if (clnt_st != RPC_SUCCESS) + goto failed; + } else { + if (err.re_vers.high == PMAPVERS) { + int high, low; + struct pmaplist *pmaphead = NULL; + rpcblist_ptr list, prev; + + vers = PMAPVERS; + clnt_control(client, CLSET_VERS, (char *)&vers); + clnt_st = CLNT_CALL(client, PMAPPROC_DUMP, + (xdrproc_t) xdr_void, NULL, + (xdrproc_t) xdr_pmaplist_ptr, + (char *)&pmaphead, minutetimeout); + if (clnt_st != RPC_SUCCESS) + goto failed; + /* + * convert to rpcblist_ptr format + */ + for (head = NULL; pmaphead != NULL; + pmaphead = pmaphead->pml_next) { + list = (rpcblist *)malloc(sizeof (rpcblist)); + if (list == NULL) + goto error; + if (head == NULL) + head = list; + else + prev->rpcb_next = (rpcblist_ptr) list; + + list->rpcb_next = NULL; + list->rpcb_map.r_prog = pmaphead->pml_map.pm_prog; + list->rpcb_map.r_vers = pmaphead->pml_map.pm_vers; + if (pmaphead->pml_map.pm_prot == IPPROTO_UDP) + list->rpcb_map.r_netid = "udp"; + else if (pmaphead->pml_map.pm_prot == IPPROTO_TCP) + list->rpcb_map.r_netid = "tcp"; + else { +#define MAXLONG_AS_STRING "2147483648" + list->rpcb_map.r_netid = + malloc(strlen(MAXLONG_AS_STRING) + 1); + if (list->rpcb_map.r_netid == NULL) + goto error; + sprintf(list->rpcb_map.r_netid, "%6ld", + pmaphead->pml_map.pm_prot); + } + list->rpcb_map.r_owner = UNKNOWN; + low = pmaphead->pml_map.pm_port & 0xff; + high = (pmaphead->pml_map.pm_port >> 8) & 0xff; + list->rpcb_map.r_addr = strdup("0.0.0.0.XXX.XXX"); + sprintf(&list->rpcb_map.r_addr[8], "%d.%d", + high, low); + prev = list; + } + } + } + } else { /* any other error */ +failed: + clnt_perror(client, "rpcinfo: can't contact rpcbind: "); + exit(1); + } + } + if (head == NULL) { + printf("No remote programs registered.\n"); + } else if (dumptype == RPCBDUMP) { + printf( +" program version netid address service owner\n"); + for (; head != NULL; head = head->rpcb_next) { + printf("%10u%5u ", + head->rpcb_map.r_prog, head->rpcb_map.r_vers); + printf("%-9s ", head->rpcb_map.r_netid); + printf("%-22s", head->rpcb_map.r_addr); + rpc = getrpcbynumber(head->rpcb_map.r_prog); + if (rpc) + printf(" %-10s", rpc->r_name); + else + printf(" %-10s", "-"); + printf(" %s\n", head->rpcb_map.r_owner); + } + } else if (dumptype == RPCBDUMP_SHORT) { + for (; head != NULL; head = head->rpcb_next) { + for (rs = rs_head; rs; rs = rs->next) + if (head->rpcb_map.r_prog == rs->prog) + break; + if (rs == NULL) { + rs = (struct rpcbdump_short *) + malloc(sizeof (struct rpcbdump_short)); + if (rs == NULL) + goto error; + rs->next = NULL; + if (rs_head == NULL) { + rs_head = rs; + rs_tail = rs; + } else { + rs_tail->next = rs; + rs_tail = rs; + } + rs->prog = head->rpcb_map.r_prog; + rs->owner = head->rpcb_map.r_owner; + rs->nlist = NULL; + rs->vlist = NULL; + } + if (add_version(rs, head->rpcb_map.r_vers) == FALSE) + goto error; + if (add_netid(rs, head->rpcb_map.r_netid) == FALSE) + goto error; + } + printf( +" program version(s) netid(s) service owner\n"); + for (rs = rs_head; rs; rs = rs->next) { + char *p = buf; + + printf("%10ld ", rs->prog); + for (vl = rs->vlist; vl; vl = vl->next) { + sprintf(p, "%d", vl->vers); + p = p + strlen(p); + if (vl->next) + sprintf(p++, ","); + } + printf("%-10s", buf); + buf[0] = NULL; + for (nl = rs->nlist; nl; nl = nl->next) { + strcat(buf, nl->netid); + if (nl->next) + strcat(buf, ","); + } + printf("%-32s", buf); + rpc = getrpcbynumber(rs->prog); + if (rpc) + printf(" %-11s", rpc->r_name); + else + printf(" %-11s", "-"); + printf(" %s\n", rs->owner); + } + } + clnt_destroy(client); + return; +error: fprintf(stderr, "rpcinfo: no memory\n"); + return; +} + +static char nullstring[] = "\000"; + static void -deletereg(argc, argv) - int argc; - char **argv; -{ u_long prog_num, version_num ; +rpcbaddrlist(char *netid, int argc, char **argv) +{ + rpcb_entry_list_ptr head = NULL; + struct timeval minutetimeout; + register CLIENT *client; + struct rpcent *rpc; + char *host; + RPCB parms; + struct netbuf *targaddr; + + if (argc != 3) { + usage(); + exit(1); + } + host = argv[0]; + if (netid == NULL) { + client = clnt_rpcbind_create(host, RPCBVERS4, &targaddr); + } else { + struct netconfig *nconf; + + nconf = getnetconfigent(netid); + if (nconf == NULL) { + nc_perror("rpcinfo: invalid transport"); + exit(1); + } + client = getclnthandle(host, nconf, RPCBVERS4, &targaddr); + if (nconf) + (void) freenetconfigent(nconf); + } + if (client == (CLIENT *)NULL) { + clnt_pcreateerror("rpcinfo: can't contact rpcbind"); + exit(1); + } + minutetimeout.tv_sec = 60; + minutetimeout.tv_usec = 0; + + parms.r_prog = getprognum(argv[1]); + parms.r_vers = getvers(argv[2]); + parms.r_netid = client->cl_netid; + if (targaddr == NULL) { + parms.r_addr = nullstring; /* for XDRing */ + } else { + /* + * We also send the remote system the address we + * used to contact it in case it can help it + * connect back with us + */ + struct netconfig *nconf; + + nconf = getnetconfigent(client->cl_netid); + if (nconf != NULL) { + parms.r_addr = taddr2uaddr(nconf, targaddr); + if (parms.r_addr == NULL) + parms.r_addr = nullstring; + freenetconfigent(nconf); + } else { + parms.r_addr = nullstring; /* for XDRing */ + } + free(targaddr->buf); + free(targaddr); + } + parms.r_owner = nullstring; + + if (CLNT_CALL(client, RPCBPROC_GETADDRLIST, (xdrproc_t) xdr_rpcb, + (char *) &parms, (xdrproc_t) xdr_rpcb_entry_list_ptr, + (char *) &head, minutetimeout) != RPC_SUCCESS) { + clnt_perror(client, "rpcinfo: can't contact rpcbind: "); + exit(1); + } + if (head == NULL) { + printf("No remote programs registered.\n"); + } else { + printf( + " program vers tp_family/name/class address\t\t service\n"); + for (; head != NULL; head = head->rpcb_entry_next) { + rpcb_entry *re; + char buf[128]; + + re = &head->rpcb_entry_map; + printf("%10u%3u ", + parms.r_prog, parms.r_vers); + sprintf(buf, "%s/%s/%s ", + re->r_nc_protofmly, re->r_nc_proto, + re->r_nc_semantics == NC_TPI_CLTS ? "clts" : + re->r_nc_semantics == NC_TPI_COTS ? "cots" : + "cots_ord"); + printf("%-24s", buf); + printf("%-24s", re->r_maddr); + rpc = getrpcbynumber(parms.r_prog); + if (rpc) + printf(" %-13s", rpc->r_name); + else + printf(" %-13s", "-"); + printf("\n"); + } + } + clnt_destroy(client); + return; +} + +/* + * monitor rpcbind + */ +static void +rpcbgetstat(int argc, char **argv) +{ + rpcb_stat_byvers inf; + struct timeval minutetimeout; + register CLIENT *client; + char *host; + int i, j; + rpcbs_addrlist *pa; + rpcbs_rmtcalllist *pr; + int cnt, flen; +#define MAXFIELD 64 + char fieldbuf[MAXFIELD]; +#define MAXLINE 256 + char linebuf[MAXLINE]; + char *cp, *lp; + char *pmaphdr[] = { + "NULL", "SET", "UNSET", "GETPORT", + "DUMP", "CALLIT" + }; + char *rpcb3hdr[] = { + "NULL", "SET", "UNSET", "GETADDR", "DUMP", "CALLIT", "TIME", + "U2T", "T2U" + }; + char *rpcb4hdr[] = { + "NULL", "SET", "UNSET", "GETADDR", "DUMP", "CALLIT", "TIME", + "U2T", "T2U", "VERADDR", "INDRECT", "GETLIST", "GETSTAT" + }; + +#define TABSTOP 8 + + if (argc >= 1) { + host = argv[0]; + client = clnt_rpcbind_create(host, RPCBVERS4, NULL); + } else + client = local_rpcb(PMAPPROG, RPCBVERS4); + if (client == (CLIENT *)NULL) { + clnt_pcreateerror("rpcinfo: can't contact rpcbind"); + exit(1); + } + minutetimeout.tv_sec = 60; + minutetimeout.tv_usec = 0; + memset((char *)&inf, 0, sizeof (rpcb_stat_byvers)); + if (CLNT_CALL(client, RPCBPROC_GETSTAT, (xdrproc_t) xdr_void, NULL, + (xdrproc_t) xdr_rpcb_stat_byvers, (char *)&inf, minutetimeout) + != RPC_SUCCESS) { + clnt_perror(client, "rpcinfo: can't contact rpcbind: "); + exit(1); + } + printf("PORTMAP (version 2) statistics\n"); + lp = linebuf; + for (i = 0; i <= rpcb_highproc_2; i++) { + fieldbuf[0] = '\0'; + switch (i) { + case PMAPPROC_SET: + sprintf(fieldbuf, "%d/", inf[RPCBVERS_2_STAT].setinfo); + break; + case PMAPPROC_UNSET: + sprintf(fieldbuf, "%d/", + inf[RPCBVERS_2_STAT].unsetinfo); + break; + case PMAPPROC_GETPORT: + cnt = 0; + for (pa = inf[RPCBVERS_2_STAT].addrinfo; pa; + pa = pa->next) + cnt += pa->success; + sprintf(fieldbuf, "%d/", cnt); + break; + case PMAPPROC_CALLIT: + cnt = 0; + for (pr = inf[RPCBVERS_2_STAT].rmtinfo; pr; + pr = pr->next) + cnt += pr->success; + sprintf(fieldbuf, "%d/", cnt); + break; + default: break; /* For the remaining ones */ + } + cp = &fieldbuf[0] + strlen(fieldbuf); + sprintf(cp, "%d", inf[RPCBVERS_2_STAT].info[i]); + flen = strlen(fieldbuf); + printf("%s%s", pmaphdr[i], + spaces((TABSTOP * (1 + flen / TABSTOP)) + - strlen(pmaphdr[i]))); + sprintf(lp, "%s%s", fieldbuf, + spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP)) + - flen))); + lp += (flen + cnt); + } + printf("\n%s\n\n", linebuf); + + if (inf[RPCBVERS_2_STAT].info[PMAPPROC_CALLIT]) { + printf("PMAP_RMTCALL call statistics\n"); + print_rmtcallstat(RPCBVERS_2_STAT, &inf[RPCBVERS_2_STAT]); + printf("\n"); + } + + if (inf[RPCBVERS_2_STAT].info[PMAPPROC_GETPORT]) { + printf("PMAP_GETPORT call statistics\n"); + print_getaddrstat(RPCBVERS_2_STAT, &inf[RPCBVERS_2_STAT]); + printf("\n"); + } + + printf("RPCBIND (version 3) statistics\n"); + lp = linebuf; + for (i = 0; i <= rpcb_highproc_3; i++) { + fieldbuf[0] = '\0'; + switch (i) { + case RPCBPROC_SET: + sprintf(fieldbuf, "%d/", inf[RPCBVERS_3_STAT].setinfo); + break; + case RPCBPROC_UNSET: + sprintf(fieldbuf, "%d/", + inf[RPCBVERS_3_STAT].unsetinfo); + break; + case RPCBPROC_GETADDR: + cnt = 0; + for (pa = inf[RPCBVERS_3_STAT].addrinfo; pa; + pa = pa->next) + cnt += pa->success; + sprintf(fieldbuf, "%d/", cnt); + break; + case RPCBPROC_CALLIT: + cnt = 0; + for (pr = inf[RPCBVERS_3_STAT].rmtinfo; pr; + pr = pr->next) + cnt += pr->success; + sprintf(fieldbuf, "%d/", cnt); + break; + default: break; /* For the remaining ones */ + } + cp = &fieldbuf[0] + strlen(fieldbuf); + sprintf(cp, "%d", inf[RPCBVERS_3_STAT].info[i]); + flen = strlen(fieldbuf); + printf("%s%s", rpcb3hdr[i], + spaces((TABSTOP * (1 + flen / TABSTOP)) + - strlen(rpcb3hdr[i]))); + sprintf(lp, "%s%s", fieldbuf, + spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP)) + - flen))); + lp += (flen + cnt); + } + printf("\n%s\n\n", linebuf); + + if (inf[RPCBVERS_3_STAT].info[RPCBPROC_CALLIT]) { + printf("RPCB_RMTCALL (version 3) call statistics\n"); + print_rmtcallstat(RPCBVERS_3_STAT, &inf[RPCBVERS_3_STAT]); + printf("\n"); + } + + if (inf[RPCBVERS_3_STAT].info[RPCBPROC_GETADDR]) { + printf("RPCB_GETADDR (version 3) call statistics\n"); + print_getaddrstat(RPCBVERS_3_STAT, &inf[RPCBVERS_3_STAT]); + printf("\n"); + } + + printf("RPCBIND (version 4) statistics\n"); + + for (j = 0; j <= 9; j += 9) { /* Just two iterations for printing */ + lp = linebuf; + for (i = j; i <= MAX(8, rpcb_highproc_4 - 9 + j); i++) { + fieldbuf[0] = '\0'; + switch (i) { + case RPCBPROC_SET: + sprintf(fieldbuf, "%d/", + inf[RPCBVERS_4_STAT].setinfo); + break; + case RPCBPROC_UNSET: + sprintf(fieldbuf, "%d/", + inf[RPCBVERS_4_STAT].unsetinfo); + break; + case RPCBPROC_GETADDR: + cnt = 0; + for (pa = inf[RPCBVERS_4_STAT].addrinfo; pa; + pa = pa->next) + cnt += pa->success; + sprintf(fieldbuf, "%d/", cnt); + break; + case RPCBPROC_CALLIT: + cnt = 0; + for (pr = inf[RPCBVERS_4_STAT].rmtinfo; pr; + pr = pr->next) + cnt += pr->success; + sprintf(fieldbuf, "%d/", cnt); + break; + default: break; /* For the remaining ones */ + } + cp = &fieldbuf[0] + strlen(fieldbuf); + /* + * XXX: We also add RPCBPROC_GETADDRLIST queries to + * RPCB_GETADDR because rpcbind includes the + * RPCB_GETADDRLIST successes in RPCB_GETADDR. + */ + if (i != RPCBPROC_GETADDR) + sprintf(cp, "%d", inf[RPCBVERS_4_STAT].info[i]); + else + sprintf(cp, "%d", inf[RPCBVERS_4_STAT].info[i] + + inf[RPCBVERS_4_STAT].info[RPCBPROC_GETADDRLIST]); + flen = strlen(fieldbuf); + printf("%s%s", rpcb4hdr[i], + spaces((TABSTOP * (1 + flen / TABSTOP)) + - strlen(rpcb4hdr[i]))); + sprintf(lp, "%s%s", fieldbuf, + spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP)) + - flen))); + lp += (flen + cnt); + } + printf("\n%s\n", linebuf); + } + + if (inf[RPCBVERS_4_STAT].info[RPCBPROC_CALLIT] || + inf[RPCBVERS_4_STAT].info[RPCBPROC_INDIRECT]) { + printf("\n"); + printf("RPCB_RMTCALL (version 4) call statistics\n"); + print_rmtcallstat(RPCBVERS_4_STAT, &inf[RPCBVERS_4_STAT]); + } + + if (inf[RPCBVERS_4_STAT].info[RPCBPROC_GETADDR]) { + printf("\n"); + printf("RPCB_GETADDR (version 4) call statistics\n"); + print_getaddrstat(RPCBVERS_4_STAT, &inf[RPCBVERS_4_STAT]); + } + clnt_destroy(client); +} + +/* + * Delete registeration for this (prog, vers, netid) + */ +static void +deletereg(char *netid, int argc, char **argv) +{ + struct netconfig *nconf = NULL; if (argc != 2) { - usage() ; - exit(1) ; + usage(); + exit(1); + } + if (netid) { + nconf = getnetconfigent(netid); + if (nconf == NULL) { + fprintf(stderr, "rpcinfo: netid %s not supported\n", + netid); + exit(1); + } + } + if ((rpcb_unset(getprognum(argv[0]), getvers(argv[1]), nconf)) == 0) { + fprintf(stderr, + "rpcinfo: Could not delete registration for prog %s version %s\n", + argv[0], argv[1]); + exit(1); + } +} + +/* + * Create and return a handle for the given nconf. + * Exit if cannot create handle. + */ +static CLIENT * +clnt_addr_create(char *address, struct netconfig *nconf, + u_long prog, u_long vers) +{ + CLIENT *client; + static struct netbuf *nbuf; + static int fd = RPC_ANYFD; + + if (fd == RPC_ANYFD) { + if ((fd = __rpc_nconf2fd(nconf)) == -1) { + rpc_createerr.cf_stat = RPC_TLIERROR; + clnt_pcreateerror("rpcinfo"); + exit(1); + } + /* Convert the uaddr to taddr */ + nbuf = uaddr2taddr(nconf, address); + if (nbuf == NULL) { + errx(1, "rpcinfo: no address for client handle"); + exit(1); + } + } + client = clnt_tli_create(fd, nconf, nbuf, prog, vers, 0, 0); + if (client == (CLIENT *)NULL) { + clnt_pcreateerror("rpcinfo"); + exit(1); + } + return (client); +} + +/* + * If the version number is given, ping that (prog, vers); else try to find + * the version numbers supported for that prog and ping all the versions. + * Remote rpcbind is not contacted for this service. The requests are + * sent directly to the services themselves. + */ +static void +addrping(char *address, char *netid, int argc, char **argv) +{ + CLIENT *client; + struct timeval to; + enum clnt_stat rpc_stat; + u_long prognum, versnum, minvers, maxvers; + struct rpc_err rpcerr; + int failure = 0; + struct netconfig *nconf; + int fd; + + if (argc < 1 || argc > 2 || (netid == NULL)) { + usage(); + exit(1); } - if (getuid()) /* This command allowed only to root */ - errx(1, "sorry, you are not root") ; - prog_num = getprognum(argv[0]); - version_num = getvers(argv[1]); - if ((pmap_unset(prog_num, version_num)) == 0) - errx(1, "could not delete registration for prog %s version %s", - argv[0], argv[1]) ; + nconf = getnetconfigent(netid); + if (nconf == (struct netconfig *)NULL) { + fprintf(stderr, "rpcinfo: Could not find %s\n", netid); + exit(1); + } + to.tv_sec = 10; + to.tv_usec = 0; + prognum = getprognum(argv[0]); + if (argc == 1) { /* Version number not known */ + /* + * A call to version 0 should fail with a program/version + * mismatch, and give us the range of versions supported. + */ + versnum = MIN_VERS; + } else { + versnum = getvers(argv[1]); + } + client = clnt_addr_create(address, nconf, prognum, versnum); + rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void, + (char *)NULL, (xdrproc_t) xdr_void, + (char *)NULL, to); + if (argc == 2) { + /* Version number was known */ + if (pstatus(client, prognum, versnum) < 0) + failure = 1; + (void) CLNT_DESTROY(client); + if (failure) + exit(1); + return; + } + /* Version number not known */ + (void) CLNT_CONTROL(client, CLSET_FD_NCLOSE, (char *)NULL); + (void) CLNT_CONTROL(client, CLGET_FD, (char *)&fd); + if (rpc_stat == RPC_PROGVERSMISMATCH) { + clnt_geterr(client, &rpcerr); + minvers = rpcerr.re_vers.low; + maxvers = rpcerr.re_vers.high; + } else if (rpc_stat == RPC_SUCCESS) { + /* + * Oh dear, it DOES support version 0. + * Let's try version MAX_VERS. + */ + (void) CLNT_DESTROY(client); + client = clnt_addr_create(address, nconf, prognum, MAX_VERS); + rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void, + (char *)NULL, (xdrproc_t) xdr_void, + (char *)NULL, to); + if (rpc_stat == RPC_PROGVERSMISMATCH) { + clnt_geterr(client, &rpcerr); + minvers = rpcerr.re_vers.low; + maxvers = rpcerr.re_vers.high; + } else if (rpc_stat == RPC_SUCCESS) { + /* + * It also supports version MAX_VERS. + * Looks like we have a wise guy. + * OK, we give them information on all + * 4 billion versions they support... + */ + minvers = 0; + maxvers = MAX_VERS; + } else { + (void) pstatus(client, prognum, MAX_VERS); + exit(1); + } + } else { + (void) pstatus(client, prognum, (u_long)0); + exit(1); + } + (void) CLNT_DESTROY(client); + for (versnum = minvers; versnum <= maxvers; versnum++) { + client = clnt_addr_create(address, nconf, prognum, versnum); + rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void, + (char *)NULL, (xdrproc_t) xdr_void, + (char *)NULL, to); + if (pstatus(client, prognum, versnum) < 0) + failure = 1; + (void) CLNT_DESTROY(client); + } + (void) close(fd); + if (failure) + exit(1); + return; +} + +/* + * If the version number is given, ping that (prog, vers); else try to find + * the version numbers supported for that prog and ping all the versions. + * Remote rpcbind is *contacted* for this service. The requests are + * then sent directly to the services themselves. + */ +static void +progping(char *netid, int argc, char **argv) +{ + CLIENT *client; + struct timeval to; + enum clnt_stat rpc_stat; + u_long prognum, versnum, minvers, maxvers; + struct rpc_err rpcerr; + int failure = 0; + struct netconfig *nconf; + + if (argc < 2 || argc > 3 || (netid == NULL)) { + usage(); + exit(1); + } + prognum = getprognum(argv[1]); + if (argc == 2) { /* Version number not known */ + /* + * A call to version 0 should fail with a program/version + * mismatch, and give us the range of versions supported. + */ + versnum = MIN_VERS; + } else { + versnum = getvers(argv[2]); + } + if (netid) { + nconf = getnetconfigent(netid); + if (nconf == (struct netconfig *)NULL) { + fprintf(stderr, "rpcinfo: Could not find %s\n", netid); + exit(1); + } + client = clnt_tp_create(argv[0], prognum, versnum, nconf); + } else { + client = clnt_create(argv[0], prognum, versnum, "NETPATH"); + } + if (client == (CLIENT *)NULL) { + clnt_pcreateerror("rpcinfo"); + exit(1); + } + to.tv_sec = 10; + to.tv_usec = 0; + rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void, + (char *)NULL, (xdrproc_t) xdr_void, + (char *)NULL, to); + if (argc == 3) { + /* Version number was known */ + if (pstatus(client, prognum, versnum) < 0) + failure = 1; + (void) CLNT_DESTROY(client); + if (failure) + exit(1); + return; + } + /* Version number not known */ + if (rpc_stat == RPC_PROGVERSMISMATCH) { + clnt_geterr(client, &rpcerr); + minvers = rpcerr.re_vers.low; + maxvers = rpcerr.re_vers.high; + } else if (rpc_stat == RPC_SUCCESS) { + /* + * Oh dear, it DOES support version 0. + * Let's try version MAX_VERS. + */ + versnum = MAX_VERS; + (void) CLNT_CONTROL(client, CLSET_VERS, (char *)&versnum); + rpc_stat = CLNT_CALL(client, NULLPROC, + (xdrproc_t) xdr_void, (char *)NULL, + (xdrproc_t) xdr_void, (char *)NULL, to); + if (rpc_stat == RPC_PROGVERSMISMATCH) { + clnt_geterr(client, &rpcerr); + minvers = rpcerr.re_vers.low; + maxvers = rpcerr.re_vers.high; + } else if (rpc_stat == RPC_SUCCESS) { + /* + * It also supports version MAX_VERS. + * Looks like we have a wise guy. + * OK, we give them information on all + * 4 billion versions they support... + */ + minvers = 0; + maxvers = MAX_VERS; + } else { + (void) pstatus(client, prognum, MAX_VERS); + exit(1); + } + } else { + (void) pstatus(client, prognum, (u_long)0); + exit(1); + } + for (versnum = minvers; versnum <= maxvers; versnum++) { + (void) CLNT_CONTROL(client, CLSET_VERS, (char *)&versnum); + rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void, + (char *)NULL, (xdrproc_t) xdr_void, + (char *)NULL, to); + if (pstatus(client, prognum, versnum) < 0) + failure = 1; + } + (void) CLNT_DESTROY(client); + if (failure) + exit(1); + return; } static void usage() { - fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n", - "usage: rpcinfo [-n portnum] -u host prognum [versnum]", - " rpcinfo [-n portnum] -t host prognum [versnum]", - " rpcinfo -p [host]", - " rpcinfo -b prognum versnum", - " rpcinfo -d prognum versnum"); + fprintf(stderr, "Usage: rpcinfo [-m | -s] [host]\n"); +#ifdef PORTMAP + fprintf(stderr, " rpcinfo -p [host]\n"); +#endif + fprintf(stderr, " rpcinfo -T netid host prognum [versnum]\n"); + fprintf(stderr, " rpcinfo -l host prognum versnum\n"); +#ifdef PORTMAP + fprintf(stderr, +" rpcinfo [-n portnum] -u | -t host prognum [versnum]\n"); +#endif + fprintf(stderr, +" rpcinfo -a serv_address -T netid prognum [version]\n"); + fprintf(stderr, " rpcinfo -b prognum versnum\n"); + fprintf(stderr, " rpcinfo -d [-T netid] prognum versnum\n"); } static u_long -getprognum(arg) - char *arg; +getprognum (char *arg) { + char *strptr; register struct rpcent *rpc; register u_long prognum; + char *tptr = arg; - if (isalpha(*arg)) { + while (*tptr && isdigit(*tptr++)); + if (*tptr || isalpha(*(tptr - 1))) { rpc = getrpcbyname(arg); - if (rpc == NULL) - errx(1, "%s is unknown service", arg); + if (rpc == NULL) { + fprintf(stderr, "rpcinfo: %s is unknown service\n", + arg); + exit(1); + } prognum = rpc->r_number; } else { - prognum = (u_long) atoi(arg); + prognum = strtol(arg, &strptr, 10); + if (strptr == arg || *strptr != '\0') { + fprintf(stderr, + "rpcinfo: %s is illegal program number\n", arg); + exit(1); + } } - return (prognum); } static u_long -getvers(arg) - char *arg; +getvers(char *arg) { + char *strptr; register u_long vers; - vers = (int) atoi(arg); + vers = (int) strtol(arg, &strptr, 10); + if (strptr == arg || *strptr != '\0') { + fprintf(stderr, "rpcinfo: %s is illegal version number\n", + arg); + exit(1); + } return (vers); } +/* + * This routine should take a pointer to an "rpc_err" structure, rather than + * a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to + * a CLIENT structure rather than a pointer to an "rpc_err" structure. + * As such, we have to keep the CLIENT structure around in order to print + * a good error message. + */ +static int +pstatus(register CLIENT *client, u_long prog, u_long vers) +{ + struct rpc_err rpcerr; + + clnt_geterr(client, &rpcerr); + if (rpcerr.re_status != RPC_SUCCESS) { + clnt_perror(client, "rpcinfo"); + printf("program %lu version %lu is not available\n", + prog, vers); + return (-1); + } else { + printf("program %lu version %lu ready and waiting\n", + prog, vers); + return (0); + } +} + +static CLIENT * +clnt_rpcbind_create(char *host, int rpcbversnum, struct netbuf **targaddr) +{ + static char *tlist[3] = { + "circuit_n", "circuit_v", "datagram_v" + }; + int i; + struct netconfig *nconf; + CLIENT *clnt = NULL; + void *handle; + + rpc_createerr.cf_stat = RPC_SUCCESS; + for (i = 0; i < 3; i++) { + if ((handle = __rpc_setconf(tlist[i])) == NULL) + continue; + while (clnt == (CLIENT *)NULL) { + if ((nconf = __rpc_getconf(handle)) == NULL) { + if (rpc_createerr.cf_stat == RPC_SUCCESS) + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + break; + } + clnt = getclnthandle(host, nconf, rpcbversnum, + targaddr); + } + if (clnt) + break; + __rpc_endconf(handle); + } + return (clnt); +} + +static CLIENT* +getclnthandle(char *host, struct netconfig *nconf, + u_long rpcbversnum, struct netbuf **targaddr) +{ + struct netbuf addr; + struct addrinfo hints, *res; + CLIENT *client = NULL; + + /* Get the address of the rpcbind */ + memset(&hints, 0, sizeof hints); + if (getaddrinfo(host, "rpcbind", &hints, &res) != 0) { + rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE; + return (NULL); + } + addr.len = addr.maxlen = res->ai_addrlen; + addr.buf = res->ai_addr; + client = clnt_tli_create(RPC_ANYFD, nconf, &addr, RPCBPROG, + rpcbversnum, 0, 0); + if (client) { + if (targaddr != NULL) { + *targaddr = + (struct netbuf *)malloc(sizeof (struct netbuf)); + if (*targaddr != NULL) { + (*targaddr)->maxlen = addr.maxlen; + (*targaddr)->len = addr.len; + (*targaddr)->buf = (char *)malloc(addr.len); + if ((*targaddr)->buf != NULL) { + memcpy((*targaddr)->buf, addr.buf, + addr.len); + } + } + } + } else { + if (rpc_createerr.cf_stat == RPC_TLIERROR) { + /* + * Assume that the other system is dead; this is a + * better error to display to the user. + */ + rpc_createerr.cf_stat = RPC_RPCBFAILURE; + rpc_createerr.cf_error.re_status = RPC_FAILED; + } + } + freeaddrinfo(res); + return (client); +} + static void -get_inet_address(addr, host) - struct sockaddr_in *addr; - char *host; +print_rmtcallstat(int rtype, rpcb_stat *infp) { - register struct hostent *hp; + register rpcbs_rmtcalllist_ptr pr; + struct rpcent *rpc; - bzero((char *)addr, sizeof *addr); - addr->sin_addr.s_addr = (u_long) inet_addr(host); - if (addr->sin_addr.s_addr == -1 || addr->sin_addr.s_addr == 0) { - if ((hp = gethostbyname(host)) == NULL) - errx(1, "%s is unknown host\n", host); - bcopy(hp->h_addr, (char *)&addr->sin_addr, - MIN(hp->h_length,sizeof(addr->sin_addr))); + if (rtype == RPCBVERS_4_STAT) + printf( + "prog\t\tvers\tproc\tnetid\tindirect success failure\n"); + else + printf("prog\t\tvers\tproc\tnetid\tsuccess\tfailure\n"); + for (pr = infp->rmtinfo; pr; pr = pr->next) { + rpc = getrpcbynumber(pr->prog); + if (rpc) + printf("%-16s", rpc->r_name); + else + printf("%-16d", pr->prog); + printf("%d\t%d\t%s\t", + pr->vers, pr->proc, pr->netid); + if (rtype == RPCBVERS_4_STAT) + printf("%d\t ", pr->indirect); + printf("%d\t%d\n", pr->success, pr->failure); + } +} + +static void +print_getaddrstat(int rtype, rpcb_stat *infp) +{ + rpcbs_addrlist_ptr al; + register struct rpcent *rpc; + + printf("prog\t\tvers\tnetid\t success\tfailure\n"); + for (al = infp->addrinfo; al; al = al->next) { + rpc = getrpcbynumber(al->prog); + if (rpc) + printf("%-16s", rpc->r_name); + else + printf("%-16d", al->prog); + printf("%d\t%s\t %-12d\t%d\n", + al->vers, al->netid, + al->success, al->failure); + } +} + +static char * +spaces(int howmany) +{ + static char space_array[] = /* 64 spaces */ + " "; + + if (howmany <= 0 || howmany > sizeof (space_array)) { + return (""); } - addr->sin_family = AF_INET; + return (&space_array[sizeof (space_array) - howmany - 1]); } diff --git a/usr.bin/rup/rup.c b/usr.bin/rup/rup.c index aeadfc56ef17..6d414b059be8 100644 --- a/usr.bin/rup/rup.c +++ b/usr.bin/rup/rup.c @@ -85,7 +85,7 @@ void remember_host(struct in_addr addr) } int -rstat_reply(char *replyp, struct sockaddr_in *raddrp) +rstat_reply(caddr_t replyp, struct sockaddr_in *raddrp) { struct tm *tmp_time; struct tm host_time; @@ -180,7 +180,7 @@ onehost(char *host) } addr.sin_addr.s_addr = *(int *)hp->h_addr; - rstat_reply((char *)&host_stat, &addr); + rstat_reply((caddr_t)&host_stat, &addr); return (0); } diff --git a/usr.bin/rusers/rusers.c b/usr.bin/rusers/rusers.c index a59abd62872d..9b83cb7e3b55 100644 --- a/usr.bin/rusers/rusers.c +++ b/usr.bin/rusers/rusers.c @@ -90,7 +90,7 @@ remember_host(struct in_addr addr) } int -rusers_reply(char *replyp, struct sockaddr_in *raddrp) +rusers_reply(caddr_t replyp, struct sockaddr_in *raddrp) { int x, idle; char date[32], idle_time[64], remote[64]; @@ -192,7 +192,7 @@ onehost(char *host) if (clnt_call(rusers_clnt, RUSERSPROC_NAMES, xdr_void, NULL, xdr_utmpidlearr, &up, tv) != RPC_SUCCESS) errx(1, "%s", clnt_sperror(rusers_clnt, "")); addr.sin_addr.s_addr = *(int *)hp->h_addr; - rusers_reply((char *)&up, &addr); + rusers_reply((caddr_t)&up, &addr); } void diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index c51b87aa035d..7a41e40b0713 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -66,7 +66,6 @@ SUBDIR= IPXrouted \ pim6sd \ pkg_install \ pnpinfo \ - portmap \ ppp \ pppctl \ pppd \ @@ -84,6 +83,7 @@ SUBDIR= IPXrouted \ rip6query \ rmt \ route6d \ + rpcbind \ rpc.lockd \ rpc.statd \ rpc.umntall \ diff --git a/usr.sbin/bootparamd/callbootd/callbootd.c b/usr.sbin/bootparamd/callbootd/callbootd.c index 7a09168ac3a9..b7827ac5b95a 100644 --- a/usr.sbin/bootparamd/callbootd/callbootd.c +++ b/usr.sbin/bootparamd/callbootd/callbootd.c @@ -118,8 +118,9 @@ char **argv; } else { clnt_stat=clnt_broadcast(BOOTPARAMPROG, BOOTPARAMVERS, BOOTPARAMPROC_WHOAMI, - xdr_bp_whoami_arg, &whoami_arg, - xdr_bp_whoami_res, &stat_whoami_res, eachres_whoami); + (xdrproc_t)xdr_bp_whoami_arg, (char *)&whoami_arg, + xdr_bp_whoami_res, (char *)&stat_whoami_res, + (resultproc_t)eachres_whoami); exit(0); } @@ -138,8 +139,9 @@ char **argv; } else { clnt_stat=clnt_broadcast(BOOTPARAMPROG, BOOTPARAMVERS, BOOTPARAMPROC_GETFILE, - xdr_bp_getfile_arg, &getfile_arg, - xdr_bp_getfile_res, &stat_getfile_res,eachres_getfile); + xdr_bp_getfile_arg, (char *)&getfile_arg, + xdr_bp_getfile_res, (char *)&stat_getfile_res, + (resultproc_t)eachres_getfile); exit(0); } diff --git a/usr.sbin/keyserv/keyserv.c b/usr.sbin/keyserv/keyserv.c index 72a334af1d05..9a156d51f1be 100644 --- a/usr.sbin/keyserv/keyserv.c +++ b/usr.sbin/keyserv/keyserv.c @@ -56,7 +56,6 @@ static const char rcsid[] = #include <sys/stat.h> #include <sys/types.h> #include <rpc/rpc.h> -#include <rpc/pmap_clnt.h> #include <sys/param.h> #include <sys/file.h> #include <rpc/des_crypt.h> @@ -162,46 +161,24 @@ main(argc, argv) setmodulus(HEXMODULUS); getrootkey(&masterkey, nflag); - - /* Create services. */ - - (void) pmap_unset(KEY_PROG, KEY_VERS); - (void) pmap_unset(KEY_PROG, KEY_VERS2); - unlink(KEYSERVSOCK); - - transp = svcudp_create(RPC_ANYSOCK); - if (transp == NULL) - errx(1, "cannot create udp service"); - if (!svc_register(transp, KEY_PROG, KEY_VERS, keyprogram, IPPROTO_UDP)) - errx(1, "unable to register (KEY_PROG, KEY_VERS, udp)"); - if (!svc_register(transp, KEY_PROG, KEY_VERS2, keyprogram, IPPROTO_UDP)) - errx(1, "unable to register (KEY_PROG, KEY_VERS2, udp)"); - - transp = svctcp_create(RPC_ANYSOCK, 0, 0); - if (transp == NULL) - errx(1, "cannot create tcp service"); - if (!svc_register(transp, KEY_PROG, KEY_VERS, keyprogram, IPPROTO_TCP)) - errx(1, "unable to register (KEY_PROG, KEY_VERS, tcp)"); - if (!svc_register(transp, KEY_PROG, KEY_VERS2, keyprogram, IPPROTO_TCP)) - errx(1, "unable to register (KEY_PROG, KEY_VERS2, tcp)"); - - transp = svcunix_create(sock, 0, 0, KEYSERVSOCK); - chmod(KEYSERVSOCK, 0666); - if (transp == NULL) - errx(1, "cannot create AF_UNIX service"); - if (!svc_register(transp, KEY_PROG, KEY_VERS, keyprogram, 0)) - errx(1, "unable to register (KEY_PROG, KEY_VERS, unix)"); - if (!svc_register(transp, KEY_PROG, KEY_VERS2, keyprogram, 0)) - errx(1, "unable to register (KEY_PROG, KEY_VERS2, unix)"); - if (!svc_register(transp, CRYPT_PROG, CRYPT_VERS, crypt_prog_1, 0)) - errx(1, "unable to register (CRYPT_PROG, CRYPT_VERS, unix)"); + if (svc_create(keyprogram, KEY_PROG, KEY_VERS, + "netpath") == 0) { + (void) fprintf(stderr, + "%s: unable to create service\n", argv[0]); + exit(1); + } + + if (svc_create(keyprogram, KEY_PROG, KEY_VERS2, + "netpath") == 0) { + (void) fprintf(stderr, + "%s: unable to create service\n", argv[0]); + exit(1); + } if (!debugging) { daemon(0,0); } - signal(SIGPIPE, SIG_IGN); - svc_run(); abort(); /* NOTREACHED */ diff --git a/usr.sbin/mountd/mountd.c b/usr.sbin/mountd/mountd.c index 2f46a9f2ca9c..b5277656ac1e 100644 --- a/usr.sbin/mountd/mountd.c +++ b/usr.sbin/mountd/mountd.c @@ -50,12 +50,15 @@ static const char rcsid[] = #include <sys/param.h> #include <sys/mount.h> +#include <sys/fcntl.h> #include <sys/stat.h> #include <sys/syslog.h> #include <sys/sysctl.h> #include <rpc/rpc.h> #include <rpc/pmap_clnt.h> +#include <rpc/pmap_prot.h> +#include <rpcsvc/mount.h> #include <nfs/rpcv2.h> #include <nfs/nfsproto.h> #include <nfs/nfs.h> @@ -83,6 +86,10 @@ static const char rcsid[] = #include <stdarg.h> #endif +#ifndef MOUNTDLOCK +#define MOUNTDLOCK "/var/run/mountd.lock" +#endif + /* * Structures for keeping the mount list and export list */ @@ -117,13 +124,13 @@ struct exportlist { #define EX_LINKED 0x1 struct netmsk { - u_int32_t nt_net; + struct sockaddr_storage nt_net; u_int32_t nt_mask; char *nt_name; }; union grouptypes { - struct hostent *gt_hostent; + struct addrinfo *gt_addrinfo; struct netmsk gt_net; }; @@ -157,8 +164,8 @@ void add_dlist __P((struct dirlist **, struct dirlist *, void add_mlist __P((char *, char *)); int check_dirpath __P((char *)); int check_options __P((struct dirlist *)); -int chk_host __P((struct dirlist *, u_int32_t, int *, int *)); -void del_mlist __P((char *, char *)); +int chk_host __P((struct dirlist *, struct sockaddr *, int *, int *)); +int del_mlist __P((char *, char *, struct sockaddr *)); struct dirlist *dirp_search __P((struct dirlist *, char *)); int do_mount __P((struct exportlist *, struct grouplist *, int, struct xucred *, char *, int, struct statfs *)); @@ -186,18 +193,25 @@ void nextfield __P((char **, char **)); void out_of_mem __P((void)); void parsecred __P((char *, struct xucred *)); int put_exlist __P((struct dirlist *, XDR *, struct dirlist *, int *)); -int scan_tree __P((struct dirlist *, u_int32_t)); +int scan_tree __P((struct dirlist *, struct sockaddr *)); static void usage __P((void)); int xdr_dir __P((XDR *, char *)); int xdr_explist __P((XDR *, caddr_t)); int xdr_fhs __P((XDR *, caddr_t)); int xdr_mlist __P((XDR *, caddr_t)); +void terminate __P((int)); /* C library */ int getnetgrent(); void endnetgrent(); void setnetgrent(); +static int bitcmp __P((void *, void *, int)); +static int netpartcmp __P((struct sockaddr *, struct sockaddr *, int)); +static int sacmp __P((struct sockaddr *, struct sockaddr *)); +static int allones __P((struct sockaddr_storage *, int)); +static int countones __P((struct sockaddr *)); + struct exportlist *exphead; struct mountlist *mlhead; struct grouplist *grphead; @@ -213,7 +227,16 @@ int force_v2 = 0; int resvport_only = 1; int dir_only = 1; int log = 0; + int opt_flags; +static int have_v6 = 1; +#ifdef NI_WITHSCOPEID +static const int ninumeric = NI_NUMERICHOST | NI_WITHSCOPEID; +#else +static const int ninumeric = NI_NUMERICHOST; +#endif + +int mountdlockfd; /* Bits for above */ #define OP_MAPROOT 0x01 #define OP_MAPALL 0x02 @@ -221,6 +244,7 @@ int opt_flags; #define OP_MASK 0x08 #define OP_NET 0x10 #define OP_ALLDIRS 0x40 +#define OP_MASKLEN 0x200 #ifdef DEBUG int debug = 1; @@ -242,10 +266,26 @@ main(argc, argv) int argc; char **argv; { - SVCXPRT *udptransp, *tcptransp; + SVCXPRT *udptransp, *tcptransp, *udp6transp, *tcp6transp; + struct netconfig *udpconf, *tcpconf, *udp6conf, *tcp6conf; + int udpsock, tcpsock, udp6sock, tcp6sock; + int xcreated = 0, s; + int one = 1; int c, error, mib[3]; struct vfsconf vfc; + /* Check that another mountd isn't already running. */ + + if ((mountdlockfd = (open(MOUNTDLOCK, O_RDONLY|O_CREAT, 0444))) == -1) + err(1, "%s", MOUNTDLOCK); + + if(flock(mountdlockfd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK) + errx(1, "another rpc.mountd is already running. Aborting"); + s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (s < 0) + have_v6 = 0; + else + close(s); error = getvfsbyname("nfs", &vfc); if (error && vfsisloadable("nfs")) { if(vfsload("nfs")) @@ -301,12 +341,38 @@ main(argc, argv) signal(SIGQUIT, SIG_IGN); } signal(SIGHUP, (void (*) __P((int))) get_exportlist); + signal(SIGTERM, terminate); { FILE *pidfile = fopen(_PATH_MOUNTDPID, "w"); if (pidfile != NULL) { fprintf(pidfile, "%d\n", getpid()); fclose(pidfile); } } + rpcb_unset(RPCPROG_MNT, RPCMNT_VER1, NULL); + rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL); + udpsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + tcpsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + udp6sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + tcp6sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); + /* + * We're doing host-based access checks here, so don't allow + * v4-in-v6 to confuse things. The kernel will disable it + * by default on NFS sockets too. + */ + if (udp6sock != -1 && setsockopt(udp6sock, IPPROTO_IPV6, + IPV6_BINDV6ONLY, &one, sizeof one) < 0){ + syslog(LOG_ERR, "can't disable v4-in-v6 on UDP socket"); + exit(1); + } + if (tcp6sock != -1 && setsockopt(tcp6sock, IPPROTO_IPV6, + IPV6_BINDV6ONLY, &one, sizeof one) < 0){ + syslog(LOG_ERR, "can't disable v4-in-v6 on UDP socket"); + exit(1); + } + udpconf = getnetconfigent("udp"); + tcpconf = getnetconfigent("tcp"); + udp6conf = getnetconfigent("udp6"); + tcp6conf = getnetconfigent("tcp6"); if (!resvport_only) { mib[0] = CTL_VFS; mib[1] = vfc.vfc_typenum; @@ -322,17 +388,90 @@ main(argc, argv) syslog(LOG_ERR, "can't create socket"); exit(1); } - pmap_unset(RPCPROG_MNT, 1); - pmap_unset(RPCPROG_MNT, 3); - if (!force_v2) - if (!svc_register(udptransp, RPCPROG_MNT, 3, mntsrv, IPPROTO_UDP) || - !svc_register(tcptransp, RPCPROG_MNT, 3, mntsrv, IPPROTO_TCP)) { - syslog(LOG_ERR, "can't register mount"); - exit(1); - } - if (!svc_register(udptransp, RPCPROG_MNT, 1, mntsrv, IPPROTO_UDP) || - !svc_register(tcptransp, RPCPROG_MNT, 1, mntsrv, IPPROTO_TCP)) { - syslog(LOG_ERR, "can't register mount"); + if (udpsock != -1 && udpconf != NULL) { + bindresvport(udpsock, NULL); + udptransp = svc_dg_create(udpsock, 0, 0); + if (udptransp != NULL) { + if (!svc_reg(udptransp, RPCPROG_MNT, RPCMNT_VER1, + mntsrv, udpconf)) + syslog(LOG_WARNING, "can't register UDP RPCMNT_VER1 service"); + else + xcreated++; + if (!force_v2) { + if (!svc_reg(udptransp, RPCPROG_MNT, RPCMNT_VER3, + mntsrv, udpconf)) + syslog(LOG_WARNING, "can't register UDP RPCMNT_VER3 service"); + else + xcreated++; + } + } else + syslog(LOG_WARNING, "can't create UDP services"); + + } + if (tcpsock != -1 && tcpconf != NULL) { + bindresvport(tcpsock, NULL); + listen(tcpsock, SOMAXCONN); + tcptransp = svc_vc_create(tcpsock, 0, 0); + if (tcptransp != NULL) { + if (!svc_reg(tcptransp, RPCPROG_MNT, RPCMNT_VER1, + mntsrv, tcpconf)) + syslog(LOG_WARNING, "can't register TCP RPCMNT_VER1 service"); + else + xcreated++; + if (!force_v2) { + if (!svc_reg(tcptransp, RPCPROG_MNT, RPCMNT_VER3, + mntsrv, tcpconf)) + syslog(LOG_WARNING, "can't register TCP RPCMNT_VER3 service"); + else + xcreated++; + } + } else + syslog(LOG_WARNING, "can't create TCP service"); + + } + if (udp6sock != -1 && udp6conf != NULL) { + bindresvport(udp6sock, NULL); + udp6transp = svc_dg_create(udp6sock, 0, 0); + if (udp6transp != NULL) { + if (!svc_reg(udp6transp, RPCPROG_MNT, RPCMNT_VER1, + mntsrv, udp6conf)) + syslog(LOG_WARNING, "can't register UDP6 RPCMNT_VER1 service"); + else + xcreated++; + if (!force_v2) { + if (!svc_reg(udp6transp, RPCPROG_MNT, RPCMNT_VER3, + mntsrv, udp6conf)) + syslog(LOG_WARNING, "can't register UDP6 RPCMNT_VER3 service"); + else + xcreated++; + } + } else + syslog(LOG_WARNING, "can't create UDP6 service"); + + } + if (tcp6sock != -1 && tcp6conf != NULL) { + bindresvport(tcp6sock, NULL); + listen(tcp6sock, SOMAXCONN); + tcp6transp = svc_vc_create(tcp6sock, 0, 0); + if (tcp6transp != NULL) { + if (!svc_reg(tcp6transp, RPCPROG_MNT, RPCMNT_VER1, + mntsrv, tcp6conf)) + syslog(LOG_WARNING, "can't register TCP6 RPCMNT_VER1 service"); + else + xcreated++; + if (!force_v2) { + if (!svc_reg(tcp6transp, RPCPROG_MNT, RPCMNT_VER3, + mntsrv, tcp6conf)) + syslog(LOG_WARNING, "can't register TCP6 RPCMNT_VER3 service"); + else + xcreated++; + } + } else + syslog(LOG_WARNING, "can't create TCP6 service"); + + } + if (xcreated == 0) { + syslog(LOG_ERR, "could not create any services"); exit(1); } svc_run(); @@ -361,20 +500,38 @@ mntsrv(rqstp, transp) struct fhreturn fhr; struct stat stb; struct statfs fsb; - struct hostent *hp; - struct in_addr saddrin; - u_int32_t saddr; + struct addrinfo *ai; + char host[NI_MAXHOST], numerichost[NI_MAXHOST]; + int lookup_failed = 1; + struct sockaddr *saddr; u_short sport; char rpcpath[RPCMNT_PATHLEN + 1], dirpath[MAXPATHLEN]; int bad = 0, defset, hostset; sigset_t sighup_mask; + struct sockaddr_in6 *sin6; + struct sockaddr_in *sin; sigemptyset(&sighup_mask); sigaddset(&sighup_mask, SIGHUP); - saddr = transp->xp_raddr.sin_addr.s_addr; - saddrin = transp->xp_raddr.sin_addr; - sport = ntohs(transp->xp_raddr.sin_port); - hp = (struct hostent *)NULL; + saddr = svc_getrpccaller(transp)->buf; + switch (saddr->sa_family) { + case AF_INET6: + sin6 = (struct sockaddr_in6 *)saddr; + sport = ntohs(sin6->sin6_port); + break; + case AF_INET: + sin = (struct sockaddr_in *)saddr; + sport = ntohs(sin->sin_port); + break; + default: + syslog(LOG_ERR, "request from unknown address family"); + return; + } + lookup_failed = getnameinfo(saddr, saddr->sa_len, host, sizeof host, + NULL, 0, 0); + getnameinfo(saddr, saddr->sa_len, numerichost, + sizeof numerichost, NULL, 0, NI_NUMERICHOST); + ai = NULL; switch (rqstp->rq_proc) { case NULLPROC: if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) @@ -384,13 +541,13 @@ mntsrv(rqstp, transp) if (sport >= IPPORT_RESERVED && resvport_only) { syslog(LOG_NOTICE, "mount request from %s from unprivileged port", - inet_ntoa(saddrin)); + numerichost); svcerr_weakauth(transp); return; } if (!svc_getargs(transp, xdr_dir, rpcpath)) { syslog(LOG_NOTICE, "undecodable mount request from %s", - inet_ntoa(saddrin)); + numerichost); svcerr_decode(transp); return; } @@ -403,12 +560,12 @@ mntsrv(rqstp, transp) if (realpath(rpcpath, dirpath) == NULL || stat(dirpath, &stb) < 0 || (!S_ISDIR(stb.st_mode) && - (dir_only || !S_ISREG(stb.st_mode))) || + (dir_only || !S_ISREG(stb.st_mode))) || statfs(dirpath, &fsb) < 0) { chdir("/"); /* Just in case realpath doesn't */ syslog(LOG_NOTICE, "mount request from %s for non existent path %s", - inet_ntoa(saddrin), dirpath); + numerichost, dirpath); if (debug) warnx("stat failed on %s", dirpath); bad = ENOENT; /* We will send error reply later */ @@ -420,9 +577,9 @@ mntsrv(rqstp, transp) hostset = defset = 0; if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) || ((dp = dirp_search(ep->ex_dirl, dirpath)) && - chk_host(dp, saddr, &defset, &hostset)) || - (defset && scan_tree(ep->ex_defdir, saddr) == 0 && - scan_tree(ep->ex_dirl, saddr) == 0))) { + chk_host(dp, saddr, &defset, &hostset)) || + (defset && scan_tree(ep->ex_defdir, saddr) == 0 && + scan_tree(ep->ex_dirl, saddr) == 0))) { if (bad) { if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) @@ -448,25 +605,21 @@ mntsrv(rqstp, transp) } if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&fhr)) syslog(LOG_ERR, "can't send reply"); - if (hp == NULL) - hp = gethostbyaddr((caddr_t)&saddr, - sizeof(saddr), AF_INET); - if (hp) - add_mlist(hp->h_name, dirpath); + if (!lookup_failed) + add_mlist(host, dirpath); else - add_mlist(inet_ntoa(saddrin), - dirpath); + add_mlist(numerichost, dirpath); if (debug) warnx("mount successful"); if (log) syslog(LOG_NOTICE, "mount request succeeded from %s for %s", - inet_ntoa(saddrin), dirpath); + numerichost, dirpath); } else { bad = EACCES; syslog(LOG_NOTICE, "mount request denied from %s for %s", - inet_ntoa(saddrin), dirpath); + numerichost, dirpath); } if (bad && !svc_sendreply(transp, xdr_long, (caddr_t)&bad)) @@ -479,56 +632,54 @@ mntsrv(rqstp, transp) else if (log) syslog(LOG_NOTICE, "dump request succeeded from %s", - inet_ntoa(saddrin)); + numerichost); return; case RPCMNT_UMOUNT: if (sport >= IPPORT_RESERVED && resvport_only) { syslog(LOG_NOTICE, "umount request from %s from unprivileged port", - inet_ntoa(saddrin)); + numerichost); svcerr_weakauth(transp); return; } if (!svc_getargs(transp, xdr_dir, rpcpath)) { syslog(LOG_NOTICE, "undecodable umount request from %s", - inet_ntoa(saddrin)); + numerichost); svcerr_decode(transp); return; } if (realpath(rpcpath, dirpath) == NULL) { syslog(LOG_NOTICE, "umount request from %s " "for non existent path %s", - inet_ntoa(saddrin), dirpath); + numerichost, dirpath); } if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) syslog(LOG_ERR, "can't send reply"); - hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); - if (hp) - del_mlist(hp->h_name, dirpath); - del_mlist(inet_ntoa(saddrin), dirpath); + if (!lookup_failed) + del_mlist(host, dirpath, saddr); + del_mlist(numerichost, dirpath, saddr); if (log) syslog(LOG_NOTICE, "umount request succeeded from %s for %s", - inet_ntoa(saddrin), dirpath); + numerichost, dirpath); return; case RPCMNT_UMNTALL: if (sport >= IPPORT_RESERVED && resvport_only) { syslog(LOG_NOTICE, "umountall request from %s from unprivileged port", - inet_ntoa(saddrin)); + numerichost); svcerr_weakauth(transp); return; } if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) syslog(LOG_ERR, "can't send reply"); - hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); - if (hp) - del_mlist(hp->h_name, (char *)NULL); - del_mlist(inet_ntoa(saddrin), (char *)NULL); + if (!lookup_failed) + del_mlist(host, NULL, saddr); + del_mlist(numerichost, NULL, saddr); if (log) syslog(LOG_NOTICE, "umountall request succeeded from %s", - inet_ntoa(saddrin)); + numerichost); return; case RPCMNT_EXPORT: if (!svc_sendreply(transp, xdr_explist, (caddr_t)NULL)) @@ -536,7 +687,7 @@ mntsrv(rqstp, transp) if (log) syslog(LOG_NOTICE, "export request succeeded from %s", - inet_ntoa(saddrin)); + numerichost); return; default: svcerr_noproc(transp); @@ -690,7 +841,7 @@ put_exlist(dp, xdrsp, adp, putdefp) if (grp->gr_type == GT_HOST) { if (!xdr_bool(xdrsp, &true)) return (1); - strp = grp->gr_ptr.gt_hostent->h_name; + strp = grp->gr_ptr.gt_addrinfo->ai_canonname; if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) return (1); @@ -732,7 +883,7 @@ get_exportlist() struct exportlist **epp; struct dirlist *dirhead; struct statfs fsb, *fsp; - struct hostent *hpe; + struct addrinfo *ai; struct xucred anon; char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp; @@ -786,7 +937,7 @@ get_exportlist() fsp->f_flags | MNT_UPDATE, (caddr_t)&targs) < 0) syslog(LOG_ERR, "can't delete exports for %s", - fsp->f_mntonname); + fsp->f_mntonname); } fsp++; } @@ -874,9 +1025,9 @@ get_exportlist() else out_of_mem(); if (debug) - warnx("making new ep fs=0x%x,0x%x", - fsb.f_fsid.val[0], - fsb.f_fsid.val[1]); + warnx("making new ep fs=0x%x,0x%x", + fsb.f_fsid.val[0], + fsb.f_fsid.val[1]); } else if (debug) warnx("found ep fs=0x%x,0x%x", fsb.f_fsid.val[0], @@ -944,14 +1095,17 @@ get_exportlist() if (debug) warnx("adding a default entry"); /* add a default group and make the grp list NULL */ - hpe = (struct hostent *)malloc(sizeof(struct hostent)); - if (hpe == (struct hostent *)NULL) - out_of_mem(); - hpe->h_name = strdup("Default"); - hpe->h_addrtype = AF_INET; - hpe->h_length = sizeof (u_int32_t); - hpe->h_addr_list = (char **)NULL; - grp->gr_ptr.gt_hostent = hpe; + ai = malloc(sizeof(struct addrinfo)); + ai->ai_flags = 0; + ai->ai_family = AF_INET; /* XXXX */ + ai->ai_socktype = SOCK_DGRAM; + /* setting the length to 0 will match anything */ + ai->ai_addrlen = 0; + ai->ai_flags = AI_CANONNAME; + ai->ai_canonname = strdup("Default"); + ai->ai_addr = NULL; + ai->ai_next = NULL; + grp->gr_ptr.gt_addrinfo = ai; /* * Don't allow a network export coincide with a list of @@ -961,13 +1115,13 @@ get_exportlist() getexp_err(ep, tgrp); goto nextline; - /* - * If an export list was specified on this line, make sure + /* + * If an export list was specified on this line, make sure * that we have at least one valid entry, otherwise skip it. */ } else { grp = tgrp; - while (grp && grp->gr_type == GT_IGNORE) + while (grp && grp->gr_type == GT_IGNORE) grp = grp->gr_next; if (! grp) { getexp_err(ep, tgrp); @@ -1219,19 +1373,27 @@ add_dlist(dpp, newdp, grp, flags) /* * Search for a dirpath on the export point. */ +void * +test() +{ +} + +/* + * Search for a dirpath on the export point. + */ struct dirlist * -dirp_search(dp, dirpath) +dirp_search(dp, dirp) struct dirlist *dp; - char *dirpath; + char *dirp; { int cmp; if (dp) { - cmp = strcmp(dp->dp_dirp, dirpath); + cmp = strcmp(dp->dp_dirp, dirp); if (cmp > 0) - return (dirp_search(dp->dp_left, dirpath)); + return (dirp_search(dp->dp_left, dirp)); else if (cmp < 0) - return (dirp_search(dp->dp_right, dirpath)); + return (dirp_search(dp->dp_right, dirp)); else return (dp); } @@ -1239,18 +1401,59 @@ dirp_search(dp, dirpath) } /* + * Some helper functions for netmasks. They all assume masks in network + * order (big endian). + */ +static int +bitcmp(void *dst, void *src, int bitlen) +{ + int i; + u_int8_t *p1 = dst, *p2 = src; + u_int8_t bitmask; + int bytelen, bitsleft; + + bytelen = bitlen / 8; + bitsleft = bitlen % 8; + + if (debug) { + printf("comparing:\n"); + for (i = 0; i < (bitsleft ? bytelen + 1 : bytelen); i++) + printf("%02x", p1[i]); + printf("\n"); + for (i = 0; i < (bitsleft ? bytelen + 1 : bytelen); i++) + printf("%02x", p2[i]); + printf("\n"); + } + + for (i = 0; i < bytelen; i++) { + if (*p1 != *p2) + return 1; + p1++; + p2++; + } + + for (i = 0; i < bitsleft; i++) { + bitmask = 1 << (7 - i); + if ((*p1 & bitmask) != (*p2 & bitmask)) + return 1; + } + + return 0; +} + +/* * Scan for a host match in a directory tree. */ int chk_host(dp, saddr, defsetp, hostsetp) struct dirlist *dp; - u_int32_t saddr; + struct sockaddr *saddr; int *defsetp; int *hostsetp; { struct hostlist *hp; struct grouplist *grp; - u_int32_t **addrp; + struct addrinfo *ai; if (dp) { if (dp->dp_flag & DP_DEFSET) @@ -1260,22 +1463,22 @@ chk_host(dp, saddr, defsetp, hostsetp) grp = hp->ht_grp; switch (grp->gr_type) { case GT_HOST: - addrp = (u_int32_t **) - grp->gr_ptr.gt_hostent->h_addr_list; - while (*addrp) { - if (**addrp == saddr) { - *hostsetp = (hp->ht_flag | DP_HOSTSET); - return (1); + ai = grp->gr_ptr.gt_addrinfo; + for (; ai; ai = ai->ai_next) { + if (!sacmp(ai->ai_addr, saddr)) { + *hostsetp = + (hp->ht_flag | DP_HOSTSET); + return (1); + } } - addrp++; - } break; case GT_NET: - if ((saddr & grp->gr_ptr.gt_net.nt_mask) == - grp->gr_ptr.gt_net.nt_net) { - *hostsetp = (hp->ht_flag | DP_HOSTSET); - return (1); - } + if (!netpartcmp(saddr, + (struct sockaddr *) &grp->gr_ptr.gt_net.nt_net, + grp->gr_ptr.gt_net.nt_mask)) { + *hostsetp = (hp->ht_flag | DP_HOSTSET); + return (1); + } break; }; hp = hp->ht_next; @@ -1290,7 +1493,7 @@ chk_host(dp, saddr, defsetp, hostsetp) int scan_tree(dp, saddr) struct dirlist *dp; - u_int32_t saddr; + struct sockaddr *saddr; { int defset, hostset; @@ -1392,6 +1595,11 @@ do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr) opt_flags |= OP_MASK; } else if (cpoptarg && (!strcmp(cpopt, "network") || !strcmp(cpopt, "n"))) { + if (strchr(cpoptarg, '/') != NULL) { + if (debug) + fprintf(stderr, "setting OP_MASKLEN\n"); + opt_flags |= OP_MASKLEN; + } if (grp->gr_type != GT_NULL) { syslog(LOG_ERR, "network/host conflict"); return (1); @@ -1442,84 +1650,40 @@ get_host(cp, grp, tgrp) struct grouplist *tgrp; { struct grouplist *checkgrp; - struct hostent *hp, *nhp; - char **addrp, **naddrp; - struct hostent t_host; + struct addrinfo *ai, hints; + int ecode; + char host[NI_MAXHOST]; int i; - u_int32_t saddr; char *aptr[2]; - if (grp->gr_type != GT_NULL) + if (grp->gr_type != GT_NULL) { + syslog(LOG_ERR, "Bad netgroup type for ip host %s", cp); return (1); - if ((hp = gethostbyname(cp)) == NULL) { - if (isdigit(*cp)) { - saddr = inet_addr(cp); - if (saddr == -1) { - syslog(LOG_ERR, "inet_addr failed for %s", cp); - return (1); - } - if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr), - AF_INET)) == NULL) { - hp = &t_host; - hp->h_name = cp; - hp->h_addrtype = AF_INET; - hp->h_length = sizeof (u_int32_t); - hp->h_addr_list = aptr; - aptr[0] = (char *)&saddr; - aptr[1] = (char *)NULL; - } - } else { - syslog(LOG_ERR, "gethostbyname failed for %s", cp); - return (1); - } } - /* - * Sanity check: make sure we don't already have an entry - * for this host in the grouplist. - */ - checkgrp = tgrp; - while (checkgrp != NULL) { - if (checkgrp->gr_type == GT_HOST && - checkgrp->gr_ptr.gt_hostent != NULL && - (!strcmp(checkgrp->gr_ptr.gt_hostent->h_name, hp->h_name) - || *(u_int32_t *)checkgrp->gr_ptr.gt_hostent->h_addr == - *(u_int32_t *)hp->h_addr)) { - grp->gr_type = GT_IGNORE; - return(0); - } - checkgrp = checkgrp->gr_next; - } - + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_CANONNAME; + hints.ai_protocol = IPPROTO_UDP; + ecode = getaddrinfo(cp, NULL, &hints, &ai); + if (ecode != 0) { + syslog(LOG_ERR,"can't get address info for " + "host %s", cp); + return 1; + } grp->gr_type = GT_HOST; - nhp = grp->gr_ptr.gt_hostent = (struct hostent *) - malloc(sizeof(struct hostent)); - if (nhp == (struct hostent *)NULL) - out_of_mem(); - memmove(nhp, hp, sizeof(struct hostent)); - i = strlen(hp->h_name)+1; - nhp->h_name = (char *)malloc(i); - if (nhp->h_name == (char *)NULL) - out_of_mem(); - memmove(nhp->h_name, hp->h_name, i); - addrp = hp->h_addr_list; - i = 1; - while (*addrp++) - i++; - naddrp = nhp->h_addr_list = (char **)malloc(i*sizeof(char *)); - if (naddrp == (char **)NULL) - out_of_mem(); - addrp = hp->h_addr_list; - while (*addrp) { - *naddrp = (char *)malloc(hp->h_length); - if (*naddrp == (char *)NULL) - out_of_mem(); - memmove(*naddrp, *addrp, hp->h_length); - addrp++; - naddrp++; + grp->gr_ptr.gt_addrinfo = ai; + while (ai != NULL) { + if (ai->ai_canonname == NULL) { + if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host, + sizeof host, NULL, 0, ninumeric) != 0) + strlcpy(host, "?", sizeof(host)); + ai->ai_canonname = strdup(host); + ai->ai_flags |= AI_CANONNAME; + } else + ai->ai_flags &= ~AI_CANONNAME; + if (debug) + (void)fprintf(stderr, "got host %s\n", ai->ai_canonname); + ai = ai->ai_next; } - *naddrp = (char *)NULL; - if (debug) - warnx("got host %s", hp->h_name); return (0); } @@ -1597,68 +1761,64 @@ do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb) int dirplen; struct statfs *fsb; { - char *cp = (char *)NULL; - u_int32_t **addrp; + struct sockaddr *addrp; + struct sockaddr_storage ss; + struct addrinfo *ai; + int addrlen; + char *cp = NULL; int done; char savedc = '\0'; - struct sockaddr_in sin, imask; union { struct ufs_args ua; struct iso_args ia; struct mfs_args ma; #ifdef __NetBSD__ struct msdosfs_args da; + struct adosfs_args aa; #endif struct ntfs_args na; } args; - u_int32_t net; args.ua.fspec = 0; args.ua.export.ex_flags = exflags; args.ua.export.ex_anon = *anoncrp; args.ua.export.ex_indexfile = ep->ex_indexfile; - memset(&sin, 0, sizeof(sin)); - memset(&imask, 0, sizeof(imask)); - sin.sin_family = AF_INET; - sin.sin_len = sizeof(sin); - imask.sin_family = AF_INET; - imask.sin_len = sizeof(sin); - if (grp->gr_type == GT_HOST) - addrp = (u_int32_t **)grp->gr_ptr.gt_hostent->h_addr_list; - else - addrp = (u_int32_t **)NULL; + if (grp->gr_type == GT_HOST) { + ai = grp->gr_ptr.gt_addrinfo; + addrp = ai->ai_addr; + addrlen = ai->ai_addrlen; + } else + addrp = NULL; done = FALSE; while (!done) { switch (grp->gr_type) { case GT_HOST: - if (addrp) { - sin.sin_addr.s_addr = **addrp; - args.ua.export.ex_addrlen = sizeof(sin); - } else - args.ua.export.ex_addrlen = 0; - args.ua.export.ex_addr = (struct sockaddr *)&sin; + if (addrp != NULL && addrp->sa_family == AF_INET6 && + have_v6 == 0) + goto skip; + args.ua.export.ex_addr = addrp; + args.ua.export.ex_addrlen = addrlen; args.ua.export.ex_masklen = 0; break; case GT_NET: - if (grp->gr_ptr.gt_net.nt_mask) - imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask; - else { - net = ntohl(grp->gr_ptr.gt_net.nt_net); - if (IN_CLASSA(net)) - imask.sin_addr.s_addr = inet_addr("255.0.0.0"); - else if (IN_CLASSB(net)) - imask.sin_addr.s_addr = - inet_addr("255.255.0.0"); - else - imask.sin_addr.s_addr = - inet_addr("255.255.255.0"); - grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr; + args.ua.export.ex_addr = (struct sockaddr *) + &grp->gr_ptr.gt_net.nt_net; + if (args.ua.export.ex_addr->sa_family == AF_INET6 && + have_v6 == 0) + goto skip; + args.ua.export.ex_addrlen = + args.ua.export.ex_addr->sa_len; + memset(&ss, 0, sizeof ss); + ss.ss_family = args.ua.export.ex_addr->sa_family; + ss.ss_len = args.ua.export.ex_addr->sa_len; + if (allones(&ss, grp->gr_ptr.gt_net.nt_mask) != 0) { + syslog(LOG_ERR, "Bad network flag"); + if (cp) + *cp = savedc; + return (1); } - sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net; - args.ua.export.ex_addr = (struct sockaddr *)&sin; - args.ua.export.ex_addrlen = sizeof (sin); - args.ua.export.ex_mask = (struct sockaddr *)&imask; - args.ua.export.ex_masklen = sizeof (imask); + args.ua.export.ex_mask = (struct sockaddr *)&ss; + args.ua.export.ex_masklen = ss.ss_len; break; case GT_IGNORE: return(0); @@ -1678,7 +1838,7 @@ do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb) * exportable file systems and not just "ufs". */ while (mount(fsb->f_fstypename, dirp, - fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) { + fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) { if (cp) *cp-- = savedc; else @@ -1707,10 +1867,15 @@ do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb) savedc = *cp; *cp = '\0'; } +skip: if (addrp) { - ++addrp; - if (*addrp == (u_int32_t *)NULL) + ai = ai->ai_next; + if (ai == NULL) done = TRUE; + else { + addrp = ai->ai_addr; + addrlen = ai->ai_addrlen; + } } else done = TRUE; } @@ -1729,47 +1894,105 @@ get_net(cp, net, maskflg) int maskflg; { struct netent *np; - long netaddr; - struct in_addr inetaddr, inetaddr2; - char *name; + char *name, *p, *prefp; + struct sockaddr_in sin, *sinp; + struct sockaddr *sa; + struct addrinfo hints, *ai = NULL; + char netname[NI_MAXHOST]; + long preflen; + int ecode; - if (isdigit(*cp) && ((netaddr = inet_network(cp)) != -1)) { - inetaddr = inet_makeaddr(netaddr, 0); - /* - * Due to arbitrary subnet masks, you don't know how many - * bits to shift the address to make it into a network, - * however you do know how to make a network address into - * a host with host == 0 and then compare them. - * (What a pest) - */ - if (!maskflg) { - setnetent(0); - while ((np = getnetent())) { - inetaddr2 = inet_makeaddr(np->n_net, 0); - if (inetaddr2.s_addr == inetaddr.s_addr) - break; - } - endnetent(); - } - } else if ((np = getnetbyname(cp)) != NULL) { - inetaddr = inet_makeaddr(np->n_net, 0); + if ((opt_flags & OP_MASKLEN) && !maskflg) { + p = strchr(cp, '/'); + *p = '\0'; + prefp = p + 1; + } + + if ((np = getnetbyname(cp)) != NULL) { + sin.sin_family = AF_INET; + sin.sin_len = sizeof sin; + sin.sin_addr = inet_makeaddr(np->n_net, 0); + sa = (struct sockaddr *)&sin; + } else if (isdigit(*cp)) { + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_flags = AI_NUMERICHOST; + if (getaddrinfo(cp, NULL, &hints, &ai) != 0) { + /* + * If getaddrinfo() failed, try the inet4 network + * notation with less than 3 dots. + */ + sin.sin_family = AF_INET; + sin.sin_len = sizeof sin; + sin.sin_addr = inet_makeaddr(inet_network(cp),0); + if (debug) + fprintf(stderr, "get_net: v4 addr %x\n", + sin.sin_addr.s_addr); + sa = (struct sockaddr *)&sin; + } else + sa = ai->ai_addr; + } else if (isxdigit(*cp) || *cp == ':') { + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_flags = AI_NUMERICHOST; + if (getaddrinfo(cp, NULL, &hints, &ai) == 0) + sa = ai->ai_addr; + else + goto fail; } else - return (1); + goto fail; + + ecode = getnameinfo(sa, sa->sa_len, netname, sizeof netname, + NULL, 0, ninumeric); + if (ecode != 0) + goto fail; if (maskflg) - net->nt_mask = inetaddr.s_addr; + net->nt_mask = countones(sa); else { + if (opt_flags & OP_MASKLEN) { + preflen = strtol(prefp, NULL, 10); + if (preflen == LONG_MIN && errno == ERANGE) + goto fail; + net->nt_mask = (int)preflen; + *p = '/'; + } + if (np) name = np->n_name; + else { + if (getnameinfo(sa, sa->sa_len, netname, sizeof netname, + NULL, 0, ninumeric) != 0) + strlcpy(netname, "?", sizeof(netname)); + name = netname; + } + net->nt_name = strdup(name); + memcpy(&net->nt_net, sa, sa->sa_len); + } + + if (!maskflg && sa->sa_family == AF_INET && + !(opt_flags & (OP_MASK|OP_MASKLEN))) { + sinp = (struct sockaddr_in *)sa; + if (IN_CLASSA(sinp->sin_addr.s_addr)) + net->nt_mask = 8; + else if (IN_CLASSB(sinp->sin_addr.s_addr)) + net->nt_mask = 16; + else if (IN_CLASSC(sinp->sin_addr.s_addr)) + net->nt_mask = 24; + else if (IN_CLASSD(sinp->sin_addr.s_addr)) + net->nt_mask = 28; else - name = inet_ntoa(inetaddr); - net->nt_name = (char *)malloc(strlen(name) + 1); - if (net->nt_name == (char *)NULL) - out_of_mem(); - strcpy(net->nt_name, name); - net->nt_net = inetaddr.s_addr; + net->nt_mask = 32; /* XXX */ } - return (0); + + if (ai) + freeaddrinfo(ai); + return 0; + +fail: + if (ai) + freeaddrinfo(ai); + return 1; } /* @@ -1958,15 +2181,28 @@ get_mountlist() fclose(mlfile); } -void -del_mlist(hostp, dirp) +int +del_mlist(hostp, dirp, saddr) char *hostp, *dirp; + struct sockaddr *saddr; { struct mountlist *mlp, **mlpp; struct mountlist *mlp2; + u_short sport; FILE *mlfile; int fnd = 0; + char host[NI_MAXHOST]; + switch (saddr->sa_family) { + case AF_INET6: + sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port); + break; + case AF_INET: + sport = ntohs(((struct sockaddr_in *)saddr)->sin_port); + break; + default: + return -1; + } mlpp = &mlhead; mlp = mlhead; while (mlp) { @@ -2034,17 +2270,11 @@ void free_grp(grp) struct grouplist *grp; { - char **addrp; + struct addrinfo *ai; if (grp->gr_type == GT_HOST) { - if (grp->gr_ptr.gt_hostent->h_name) { - addrp = grp->gr_ptr.gt_hostent->h_addr_list; - while (addrp && *addrp) - free(*addrp++); - free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list); - free(grp->gr_ptr.gt_hostent->h_name); - } - free((caddr_t)grp->gr_ptr.gt_hostent); + if (grp->gr_ptr.gt_addrinfo != NULL) + freeaddrinfo(grp->gr_ptr.gt_addrinfo); } else if (grp->gr_type == GT_NET) { if (grp->gr_ptr.gt_net.nt_name) free(grp->gr_ptr.gt_net.nt_name); @@ -2093,7 +2323,6 @@ check_options(dp) /* * Check an absolute directory path for any symbolic links. Return true - * if no symbolic links are found. */ int check_dirpath(dirp) @@ -2134,3 +2363,146 @@ get_num(cp) } return (res); } + +static int +netpartcmp(struct sockaddr *s1, struct sockaddr *s2, int bitlen) +{ + void *src, *dst; + + if (s1->sa_family != s2->sa_family) + return 1; + + switch (s1->sa_family) { + case AF_INET: + src = &((struct sockaddr_in *)s1)->sin_addr; + dst = &((struct sockaddr_in *)s2)->sin_addr; + if (bitlen > sizeof(((struct sockaddr_in *)s1)->sin_addr) * 8) + return 1; + break; + case AF_INET6: + src = &((struct sockaddr_in6 *)s1)->sin6_addr; + dst = &((struct sockaddr_in6 *)s2)->sin6_addr; + if (((struct sockaddr_in6 *)s1)->sin6_scope_id != + ((struct sockaddr_in6 *)s2)->sin6_scope_id) + return 1; + if (bitlen > sizeof(((struct sockaddr_in6 *)s1)->sin6_addr) * 8) + return 1; + break; + default: + return 1; + } + + return bitcmp(src, dst, bitlen); +} + +static int +allones(struct sockaddr_storage *ssp, int bitlen) +{ + u_int8_t *p; + int bytelen, bitsleft, i; + int zerolen; + + switch (ssp->ss_family) { + case AF_INET: + p = (u_int8_t *)&((struct sockaddr_in *)ssp)->sin_addr; + zerolen = sizeof (((struct sockaddr_in *)ssp)->sin_addr); + break; + case AF_INET6: + p = (u_int8_t *)&((struct sockaddr_in6 *)ssp)->sin6_addr; + zerolen = sizeof (((struct sockaddr_in6 *)ssp)->sin6_addr); + break; + default: + return -1; + } + + memset(p, 0, zerolen); + + bytelen = bitlen / 8; + bitsleft = bitlen % 8; + + if (bytelen > zerolen) + return -1; + + for (i = 0; i < bytelen; i++) + *p++ = 0xff; + + for (i = 0; i < bitsleft; i++) + *p |= 1 << (7 - i); + + return 0; +} + +static int +countones(struct sockaddr *sa) +{ + void *mask; + int i, bits = 0, bytelen; + u_int8_t *p; + + switch (sa->sa_family) { + case AF_INET: + mask = (u_int8_t *)&((struct sockaddr_in *)sa)->sin_addr; + bytelen = 4; + break; + case AF_INET6: + mask = (u_int8_t *)&((struct sockaddr_in6 *)sa)->sin6_addr; + bytelen = 16; + break; + default: + return 0; + } + + p = mask; + + for (i = 0; i < bytelen; i++, p++) { + if (*p != 0xff) { + for (bits = 0; bits < 8; bits++) { + if (!(*p & (1 << (7 - bits)))) + break; + } + break; + } + } + + return (i * 8 + bits); +} + +static int +sacmp(struct sockaddr *sa1, struct sockaddr *sa2) +{ + void *p1, *p2; + int len; + + if (sa1->sa_family != sa2->sa_family) + return 1; + + switch (sa1->sa_family) { + case AF_INET: + p1 = &((struct sockaddr_in *)sa1)->sin_addr; + p2 = &((struct sockaddr_in *)sa2)->sin_addr; + len = 4; + break; + case AF_INET6: + p1 = &((struct sockaddr_in6 *)sa1)->sin6_addr; + p2 = &((struct sockaddr_in6 *)sa2)->sin6_addr; + len = 16; + if (((struct sockaddr_in6 *)sa1)->sin6_scope_id != + ((struct sockaddr_in6 *)sa2)->sin6_scope_id) + return 1; + break; + default: + return 1; + } + + return memcmp(p1, p2, len); +} + +void terminate(sig) +int sig; +{ + close(mountdlockfd); + unlink(MOUNTDLOCK); + pmap_unset(RPCPROG_MNT, 1); + pmap_unset(RPCPROG_MNT, 3); + exit (0); +} diff --git a/usr.sbin/nfsd/nfsd.8 b/usr.sbin/nfsd/nfsd.8 index fb44149bb4d8..0031ea1b926e 100644 --- a/usr.sbin/nfsd/nfsd.8 +++ b/usr.sbin/nfsd/nfsd.8 @@ -42,7 +42,7 @@ server .Sh SYNOPSIS .Nm -.Op Fl arut +.Op Fl ardut .Op Fl n Ar num_servers .Op Fl h Ar bindip .Sh DESCRIPTION @@ -64,13 +64,19 @@ The following options are available: Register the .Tn NFS service with -.Xr portmap 8 +.Xr rpcbind 8 without creating any servers. This option can be used along with the .Fl u or .Fl t -options to re-register NFS if the portmap server is restarted. +options to re-register NFS if the rpcbind server is restarted. +.It Fl d +Unregister the +.Tn NFS +service with +.Xr rpcbind 8 +without creating any servers. .It Fl n Specifies how many servers to create. .It Fl h Ar bindip @@ -147,6 +153,16 @@ that the NFS sockets can only be accessed by the inside interface. would then be used to block nfs-related packets that come in on the outside interface. .Pp +.Nm +has to be terminated with SIGUSR1 and cannot be killed with SIGTERM oder SIGQUIT. +.Nm +needs to ignore these signals in order to stay alive as long +as possible during a shutdown, otherwise loopback mounts will +not be able to unmount. If you have to kill +.Nm +just do a +.Dq Li "kill -USR1 <PID of master nfsd>" +.Pp The .Nm utility exits 0 on success, and >0 if an error occurs. @@ -156,7 +172,7 @@ utility exits 0 on success, and >0 if an error occurs. .Xr kldload 8 , .Xr mountd 8 , .Xr nfsiod 8 , -.Xr portmap 8 , +.Xr rpcbind 8 , .Xr ipfw 8 .Sh HISTORY The diff --git a/usr.sbin/nfsd/nfsd.c b/usr.sbin/nfsd/nfsd.c index 2d923a42652b..959f0fb04d18 100644 --- a/usr.sbin/nfsd/nfsd.c +++ b/usr.sbin/nfsd/nfsd.c @@ -58,9 +58,6 @@ static const char rcsid[] = #include <netdb.h> #include <arpa/inet.h> -#ifdef ISO -#include <netiso/iso.h> -#endif #include <nfs/rpcv2.h> #include <nfs/nfsproto.h> #include <nfs/nfs.h> @@ -76,6 +73,7 @@ static const char rcsid[] = #include <stdlib.h> #include <strings.h> #include <unistd.h> +#include <netdb.h> /* Global defs */ #ifdef DEBUG @@ -103,15 +101,23 @@ struct timeval ktv; NFSKERBKEYSCHED_T kerb_keysched; #endif -void nonfs __P((int)); -void reapchild __P((int)); -void setbindhost __P((struct sockaddr_in *ia, const char *bindhost)); +#define MAXNFSDCNT 20 +#define DEFNFSDCNT 4 +pid_t children[MAXNFSDCNT]; /* PIDs of children */ +int nfsdcnt; /* number of children */ + +void cleanup(int); +void killchildren(void); +void nonfs (int); +void reapchild (int); +int setbindhost (struct addrinfo **ia, const char *bindhost, struct addrinfo hints); #ifdef OLD_SETPROCTITLE #ifdef __FreeBSD__ -void setproctitle __P((char *)); +void setproctitle (char *); #endif #endif -void usage __P((void)); +void unregistration (void); +void usage (void); /* * Nfs server daemon mostly just a user context for nfssvc() @@ -119,7 +125,7 @@ void usage __P((void)); * 1 - do file descriptor and signal cleanup * 2 - fork the nfsd(s) * 3 - create server socket(s) - * 4 - register socket with portmap + * 4 - register socket with rpcbind * * For connectionless protocols, just pass the socket into the kernel via. * nfssvc(). @@ -127,7 +133,8 @@ void usage __P((void)); * socket from accept, pass the msgsock into the kernel via. nfssvc(). * The arguments are: * -c - support iso cltp clients - * -r - reregister with portmapper + * -r - reregister with rpcbind + * -d - unregister with rpcbind * -t - support tcp nfs clients * -u - support udp nfs clients * followed by "n" which is the number of nfsds' to fork off @@ -138,20 +145,20 @@ main(argc, argv, envp) char *argv[], *envp[]; { struct nfsd_args nfsdargs; - struct sockaddr_in inetaddr, inetpeer; -#ifdef ISO - struct sockaddr_iso isoaddr, isopeer; - char *cp; -#endif + struct addrinfo *ai_udp, *ai_tcp, *ai_udp6, *ai_tcp6, hints; + struct netconfig *nconf_udp, *nconf_tcp, *nconf_udp6, *nconf_tcp6; + struct netbuf nb_udp, nb_tcp, nb_udp6, nb_tcp6; + struct sockaddr_in inetpeer; + struct sockaddr_in6 inet6peer; fd_set ready, sockbits; + fd_set v4bits, v6bits; int ch, cltpflag, connect_type_cnt, i, len, maxsock, msgsock; - int nfsdcnt, nfssvc_flag, on, reregister, sock, tcpflag, tcpsock; - int tp4cnt, tp4flag, tpipcnt, tpipflag, udpflag; - int bindhostc = 0, bindanyflag; + int nfssvc_flag, on = 1, unregister, reregister, sock; + int tcp6sock, ip6flag, tcpflag, tcpsock; + int udpflag, ecode, s; + int bindhostc = 0, bindanyflag, rpcbreg, rpcbregcnt; char **bindhost = NULL; -#ifdef notyet - int tp4sock, tpipsock; -#endif + pid_t pid; #ifdef NFSKERB struct group *grp; struct passwd *pwd; @@ -184,18 +191,11 @@ main(argc, argv, envp) LastArg = envp[-1] + strlen(envp[-1]); #endif -#define MAXNFSDCNT 20 -#define DEFNFSDCNT 4 nfsdcnt = DEFNFSDCNT; - cltpflag = reregister = tcpflag = tp4cnt = tp4flag = tpipcnt = 0; - bindanyflag = tpipflag = udpflag = 0; -#ifdef ISO -#define GETOPT "ach:n:rtu" -#define USAGE "[-acrtu] [-n num_servers] [-h bindip]" -#else -#define GETOPT "ah:n:rtu" -#define USAGE "[-artu] [-n num_servers] [-h bindip]" -#endif + cltpflag = unregister = reregister = tcpflag = 0; + bindanyflag = udpflag = ip6flag = 0; +#define GETOPT "ah:n:rdtu" +#define USAGE "[-ardtu] [-n num_servers] [-h bindip]" while ((ch = getopt(argc, argv, GETOPT)) != -1) switch (ch) { case 'a': @@ -221,25 +221,15 @@ main(argc, argv, envp) case 'r': reregister = 1; break; + case 'd': + unregister = 1; + break; case 't': tcpflag = 1; break; case 'u': udpflag = 1; break; -#ifdef ISO - case 'c': - cltpflag = 1; - break; -#ifdef notyet - case 'i': - tp4cnt = 1; - break; - case 'p': - tpipcnt = 1; - break; -#endif /* notyet */ -#endif /* ISO */ default: case '?': usage(); @@ -263,6 +253,13 @@ main(argc, argv, envp) nfsdcnt = DEFNFSDCNT; } } + ip6flag = 1; + s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (s < 0 && (errno == EPROTONOSUPPORT || + errno == EPFNOSUPPORT || errno == EAFNOSUPPORT)) + ip6flag = 0; + else + close(s); if (bindhostc == 0 || bindanyflag) { bindhostc++; @@ -278,33 +275,126 @@ main(argc, argv, envp) daemon(0, 0); (void)signal(SIGHUP, SIG_IGN); (void)signal(SIGINT, SIG_IGN); - (void)signal(SIGQUIT, SIG_IGN); (void)signal(SIGSYS, nonfs); + (void)signal(SIGUSR1, cleanup); + /* + * nfsd sits in the kernel most of the time. It needs + * to ignore SIGTERM/SIGQUIT in order to stay alive as long + * as possible during a shutdown, otherwise loopback + * mounts will not be able to unmount. + */ (void)signal(SIGTERM, SIG_IGN); + (void)signal(SIGQUIT, SIG_IGN); } (void)signal(SIGCHLD, reapchild); - + if (unregister) { + unregistration(); + exit (0); + } if (reregister) { - if (udpflag && - (!pmap_set(RPCPROG_NFS, 2, IPPROTO_UDP, NFS_PORT) || - !pmap_set(RPCPROG_NFS, 3, IPPROTO_UDP, NFS_PORT))) - err(1, "can't register with portmap for UDP"); - if (tcpflag && - (!pmap_set(RPCPROG_NFS, 2, IPPROTO_TCP, NFS_PORT) || - !pmap_set(RPCPROG_NFS, 3, IPPROTO_TCP, NFS_PORT))) - err(1, "can't register with portmap for TCP"); - exit(0); + if (udpflag) { + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp); + if (ecode != 0) { + syslog(LOG_ERR, "getaddrinfo udp: %s", + gai_strerror(ecode)); + exit(1); + } + nconf_udp = getnetconfigent("udp"); + if (nconf_udp == NULL) + err(1, "getnetconfigent udp failed"); + nb_udp.buf = ai_udp->ai_addr; + nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen; + if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp, &nb_udp)) || + (!rpcb_set(RPCPROG_NFS, 3, nconf_udp, &nb_udp))) + err(1, "rpcb_set udp failed"); + freeaddrinfo(ai_udp); + } + if (udpflag && ip6flag) { + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6); + if (ecode != 0) { + syslog(LOG_ERR, "getaddrinfo udp6: %s", + gai_strerror(ecode)); + exit(1); + } + nconf_udp6 = getnetconfigent("udp6"); + if (nconf_udp6 == NULL) + err(1, "getnetconfigent udp6 failed"); + nb_udp6.buf = ai_udp6->ai_addr; + nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen; + if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp6, &nb_udp6)) || + (!rpcb_set(RPCPROG_NFS, 3, nconf_udp6, &nb_udp6))) + err(1, "rpcb_set udp6 failed"); + freeaddrinfo(ai_udp6); + } + if (tcpflag) { + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp); + if (ecode != 0) { + syslog(LOG_ERR, "getaddrinfo tcp: %s", + gai_strerror(ecode)); + exit(1); + } + nconf_tcp = getnetconfigent("tcp"); + if (nconf_tcp == NULL) + err(1, "getnetconfigent tcp failed"); + nb_tcp.buf = ai_tcp->ai_addr; + nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen; + if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp, &nb_tcp)) || + (!rpcb_set(RPCPROG_NFS, 3, nconf_tcp, &nb_tcp))) + err(1, "rpcb_set tcp failed"); + freeaddrinfo(ai_tcp); + } + if (tcpflag && ip6flag) { + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6); + if (ecode != 0) { + syslog(LOG_ERR, "getaddrinfo tcp6: %s", + gai_strerror(ecode)); + exit(1); + } + nconf_tcp6 = getnetconfigent("tcp6"); + if (nconf_tcp6 == NULL) + err(1, "getnetconfigent tcp6 failed"); + nb_tcp6.buf = ai_tcp6->ai_addr; + nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen; + if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp6, &nb_tcp6)) || + (!rpcb_set(RPCPROG_NFS, 3, nconf_tcp6, &nb_tcp6))) + err(1, "rpcb_set tcp6 failed"); + freeaddrinfo(ai_tcp6); + } + exit (0); } + openlog("nfsd:", LOG_PID, LOG_DAEMON); for (i = 0; i < nfsdcnt; i++) { - switch (fork()) { + switch ((pid = fork())) { case -1: syslog(LOG_ERR, "fork: %m"); + killchildren(); exit (1); case 0: break; default: + children[i] = pid; continue; } @@ -399,182 +489,295 @@ main(argc, argv, envp) exit(0); } - /* If we are serving udp, set up the socket. */ - for (i = 0; udpflag && i < bindhostc; i++) { - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - syslog(LOG_ERR, "can't create udp socket"); - exit(1); - } - setbindhost(&inetaddr, bindhost[i]); - if (bind(sock, - (struct sockaddr *)&inetaddr, sizeof(inetaddr)) < 0) { - syslog(LOG_ERR, "can't bind udp addr %s: %m", bindhost[i]); - exit(1); - } - if (!pmap_set(RPCPROG_NFS, 2, IPPROTO_UDP, NFS_PORT) || - !pmap_set(RPCPROG_NFS, 3, IPPROTO_UDP, NFS_PORT)) { - syslog(LOG_ERR, "can't register with udp portmap"); - exit(1); + if (atexit(killchildren) == -1) { + syslog(LOG_ERR, "atexit: %s", strerror(errno)); + exit(1); + } + FD_ZERO(&v4bits); + FD_ZERO(&v6bits); + + rpcbregcnt = 0; + /* Set up the socket for udp and rpcb register it. */ + if (udpflag) { + rpcbreg = 0; + for (i = 0; i < bindhostc; i++) { + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + if (setbindhost(&ai_udp, bindhost[i], hints) == 0) { + rpcbreg = 1; + rpcbregcnt++; + if ((sock = socket(ai_udp->ai_family, + ai_udp->ai_socktype, + ai_udp->ai_protocol)) < 0) { + syslog(LOG_ERR, + "can't create udp socket"); + exit(1); + } + if (bind(sock, ai_udp->ai_addr, + ai_udp->ai_addrlen) < 0) { + syslog(LOG_ERR, + "can't bind udp addr %s: %m", + bindhost[i]); + exit(1); + } + freeaddrinfo(ai_udp); + nfsdargs.sock = sock; + nfsdargs.name = NULL; + nfsdargs.namelen = 0; + if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) { + syslog(LOG_ERR, "can't Add UDP socket"); + exit(1); + } + (void)close(sock); + } } - nfsdargs.sock = sock; - nfsdargs.name = NULL; - nfsdargs.namelen = 0; - if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) { - syslog(LOG_ERR, "can't Add UDP socket"); - exit(1); + if (rpcbreg == 1) { + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp); + if (ecode != 0) { + syslog(LOG_ERR, "getaddrinfo udp: %s", + gai_strerror(ecode)); + exit(1); + } + nconf_udp = getnetconfigent("udp"); + if (nconf_udp == NULL) + err(1, "getnetconfigent udp failed"); + nb_udp.buf = ai_udp->ai_addr; + nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen; + if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp, &nb_udp)) || + (!rpcb_set(RPCPROG_NFS, 3, nconf_udp, &nb_udp))) + err(1, "rpcb_set udp failed"); + freeaddrinfo(ai_udp); } - (void)close(sock); } -#ifdef ISO - /* If we are serving cltp, set up the socket. */ - if (cltpflag) { - if ((sock = socket(AF_ISO, SOCK_DGRAM, 0)) < 0) { - syslog(LOG_ERR, "can't create cltp socket"); - exit(1); - } - memset(&isoaddr, 0, sizeof(isoaddr)); - isoaddr.siso_family = AF_ISO; - isoaddr.siso_tlen = 2; - cp = TSEL(&isoaddr); - *cp++ = (NFS_PORT >> 8); - *cp = (NFS_PORT & 0xff); - isoaddr.siso_len = sizeof(isoaddr); - if (bind(sock, - (struct sockaddr *)&isoaddr, sizeof(isoaddr)) < 0) { - syslog(LOG_ERR, "can't bind cltp addr"); - exit(1); - } -#ifdef notyet - /* - * XXX - * Someday this should probably use "rpcbind", the son of - * portmap. - */ - if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, NFS_PORT)) { - syslog(LOG_ERR, "can't register with udp portmap"); - exit(1); + /* Set up the socket for udp6 and rpcb register it. */ + if (udpflag && ip6flag) { + rpcbreg = 0; + for (i = 0; i < bindhostc; i++) { + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + if (setbindhost(&ai_udp6, bindhost[i], hints) == 0) { + rpcbreg = 1; + rpcbregcnt++; + if ((sock = socket(ai_udp6->ai_family, + ai_udp6->ai_socktype, + ai_udp6->ai_protocol)) < 0) { + syslog(LOG_ERR, + "can't create udp6 socket"); + exit(1); + } + if (setsockopt(sock, IPPROTO_IPV6, + IPV6_BINDV6ONLY, + &on, sizeof on) < 0) { + syslog(LOG_ERR, + "can't set v6-only binding for " + "udp6 socket: %m"); + exit(1); + } + if (bind(sock, ai_udp6->ai_addr, + ai_udp6->ai_addrlen) < 0) { + syslog(LOG_ERR, + "can't bind udp6 addr %s: %m", + bindhost[i]); + exit(1); + } + freeaddrinfo(ai_udp6); + nfsdargs.sock = sock; + nfsdargs.name = NULL; + nfsdargs.namelen = 0; + if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) { + syslog(LOG_ERR, + "can't add UDP6 socket"); + exit(1); + } + (void)close(sock); + } } -#endif /* notyet */ - nfsdargs.sock = sock; - nfsdargs.name = NULL; - nfsdargs.namelen = 0; - if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) { - syslog(LOG_ERR, "can't add UDP socket"); - exit(1); + if (rpcbreg == 1) { + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6); + if (ecode != 0) { + syslog(LOG_ERR, "getaddrinfo udp6: %s", + gai_strerror(ecode)); + exit(1); + } + nconf_udp6 = getnetconfigent("udp6"); + if (nconf_udp6 == NULL) + err(1, "getnetconfigent udp6 failed"); + nb_udp6.buf = ai_udp6->ai_addr; + nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen; + if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp6, &nb_udp6)) || + (!rpcb_set(RPCPROG_NFS, 3, nconf_udp6, &nb_udp6))) + err(1, "rpcb_set udp6 failed"); + freeaddrinfo(ai_udp6); } - close(sock); } -#endif /* ISO */ - /* Now set up the master server socket waiting for tcp connections. */ - on = 1; - FD_ZERO(&sockbits); - connect_type_cnt = 0; - for (i = 0; tcpflag && i < bindhostc; i++) { - if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - syslog(LOG_ERR, "can't create tcp socket"); - exit(1); - } - if (setsockopt(tcpsock, - SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) - syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m"); - setbindhost(&inetaddr, bindhost[i]); - if (bind(tcpsock, - (struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0) { - syslog(LOG_ERR, "can't bind tcp addr %s: %m", bindhost[i]); - exit(1); - } - if (listen(tcpsock, 5) < 0) { - syslog(LOG_ERR, "listen failed"); - exit(1); + /* Set up the socket for tcp and rpcb register it. */ + if (tcpflag) { + rpcbreg = 0; + for (i = 0; i < bindhostc; i++) { + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + if (setbindhost(&ai_tcp, bindhost[i], hints) == 0) { + rpcbreg = 1; + rpcbregcnt++; + if ((tcpsock = socket(AF_INET, SOCK_STREAM, + 0)) < 0) { + syslog(LOG_ERR, + "can't create tpc socket"); + exit(1); + } + if (setsockopt(tcpsock, SOL_SOCKET, + SO_REUSEADDR, + (char *)&on, sizeof(on)) < 0) + syslog(LOG_ERR, + "setsockopt SO_REUSEADDR: %m"); + if (bind(tcpsock, ai_tcp->ai_addr, + ai_tcp->ai_addrlen) < 0) { + syslog(LOG_ERR, + "can't bind tcp addr %s: %m", + bindhost[i]); + exit(1); + } + if (listen(tcpsock, 5) < 0) { + syslog(LOG_ERR, "listen failed"); + exit(1); + } + freeaddrinfo(ai_tcp); + FD_SET(tcpsock, &sockbits); + FD_SET(tcpsock, &v4bits); + maxsock = tcpsock; + connect_type_cnt++; + } } - if (!pmap_set(RPCPROG_NFS, 2, IPPROTO_TCP, NFS_PORT) || - !pmap_set(RPCPROG_NFS, 3, IPPROTO_TCP, NFS_PORT)) { - syslog(LOG_ERR, "can't register tcp with portmap"); - exit(1); + if (rpcbreg == 1) { + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + ecode = getaddrinfo(NULL, "nfs", &hints, + &ai_tcp); + if (ecode != 0) { + syslog(LOG_ERR, "getaddrinfo tcp: %s", + gai_strerror(ecode)); + exit(1); + } + nconf_tcp = getnetconfigent("tcp"); + if (nconf_tcp == NULL) + err(1, "getnetconfigent tcp failed"); + nb_tcp.buf = ai_tcp->ai_addr; + nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen; + if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp, + &nb_tcp)) || (!rpcb_set(RPCPROG_NFS, 3, + nconf_tcp, &nb_tcp))) + err(1, "rpcb_set tcp failed"); + freeaddrinfo(ai_tcp); } - FD_SET(tcpsock, &sockbits); - maxsock = tcpsock; - connect_type_cnt++; } -#ifdef notyet - /* Now set up the master server socket waiting for tp4 connections. */ - if (tp4flag) { - if ((tp4sock = socket(AF_ISO, SOCK_SEQPACKET, 0)) < 0) { - syslog(LOG_ERR, "can't create tp4 socket"); - exit(1); - } - if (setsockopt(tp4sock, - SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) - syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m"); - memset(&isoaddr, 0, sizeof(isoaddr)); - isoaddr.siso_family = AF_ISO; - isoaddr.siso_tlen = 2; - cp = TSEL(&isoaddr); - *cp++ = (NFS_PORT >> 8); - *cp = (NFS_PORT & 0xff); - isoaddr.siso_len = sizeof(isoaddr); - if (bind(tp4sock, - (struct sockaddr *)&isoaddr, sizeof (isoaddr)) < 0) { - syslog(LOG_ERR, "can't bind tp4 addr"); - exit(1); - } - if (listen(tp4sock, 5) < 0) { - syslog(LOG_ERR, "listen failed"); - exit(1); + /* Set up the socket for tcp6 and rpcb register it. */ + if (tcpflag && ip6flag) { + rpcbreg = 0; + for (i = 0; i < bindhostc; i++) { + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + if (setbindhost(&ai_tcp6, bindhost[i], hints) == 0) { + rpcbreg = 1; + rpcbregcnt++; + if ((tcp6sock = socket(ai_tcp6->ai_family, + ai_tcp6->ai_socktype, + ai_tcp6->ai_protocol)) < 0) { + syslog(LOG_ERR, + "can't create tcp6 socket"); + exit(1); + } + if (setsockopt(tcp6sock, SOL_SOCKET, + SO_REUSEADDR, + (char *)&on, sizeof(on)) < 0) + syslog(LOG_ERR, + "setsockopt SO_REUSEADDR: %m"); + if (setsockopt(tcp6sock, IPPROTO_IPV6, + IPV6_BINDV6ONLY, &on, sizeof on) < 0) { + syslog(LOG_ERR, + "can't set v6-only binding for tcp6 " + "socket: %m"); + exit(1); + } + if (bind(tcp6sock, ai_tcp6->ai_addr, + ai_tcp6->ai_addrlen) < 0) { + syslog(LOG_ERR, + "can't bind tcp6 addr %s: %m", + bindhost[i]); + exit(1); + } + if (listen(tcp6sock, 5) < 0) { + syslog(LOG_ERR, "listen failed"); + exit(1); + } + freeaddrinfo(ai_tcp6); + FD_SET(tcp6sock, &sockbits); + FD_SET(tcp6sock, &v6bits); + if (maxsock < tcp6sock) + maxsock = tcp6sock; + connect_type_cnt++; + } } - /* - * XXX - * Someday this should probably use "rpcbind", the son of - * portmap. - */ - if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) { - syslog(LOG_ERR, "can't register tcp with portmap"); - exit(1); + if (rpcbreg == 1) { + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6); + if (ecode != 0) { + syslog(LOG_ERR, "getaddrinfo tcp6: %s", + gai_strerror(ecode)); + exit(1); + } + nconf_tcp6 = getnetconfigent("tcp6"); + if (nconf_tcp6 == NULL) + err(1, "getnetconfigent tcp6 failed"); + nb_tcp6.buf = ai_tcp6->ai_addr; + nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen; + if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp6, &nb_tcp6)) || + (!rpcb_set(RPCPROG_NFS, 3, nconf_tcp6, &nb_tcp6))) + err(1, "rpcb_set tcp6 failed"); + freeaddrinfo(ai_tcp6); } - FD_SET(tp4sock, &sockbits); - maxsock = tp4sock; - connect_type_cnt++; } - /* Now set up the master server socket waiting for tpip connections. */ - for (i = 0; tpipflag && i < bindhostc; i++) { - if ((tpipsock = socket(AF_INET, SOCK_SEQPACKET, 0)) < 0) { - syslog(LOG_ERR, "can't create tpip socket"); - exit(1); - } - if (setsockopt(tpipsock, - SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) - syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m"); - setbindhost(&inetaddr, bindhost[i]); - if (bind(tpipsock, - (struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0) { - syslog(LOG_ERR, "can't bind tcp addr %s: %m", bindhost[i]); - exit(1); - } - if (listen(tpipsock, 5) < 0) { - syslog(LOG_ERR, "listen failed"); - exit(1); - } - /* - * XXX - * Someday this should probably use "rpcbind", the son of - * portmap. - */ - if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) { - syslog(LOG_ERR, "can't register tcp with portmap"); - exit(1); - } - FD_SET(tpipsock, &sockbits); - maxsock = tpipsock; - connect_type_cnt++; + if (rpcbregcnt == 0) { + syslog(LOG_ERR, "rpcb_set() failed, nothing to do: %m"); + exit(1); } -#endif /* notyet */ - if (connect_type_cnt == 0) - exit(0); + if ((tcpflag) && (connect_type_cnt == 0)) { + syslog(LOG_ERR, "tcp connects == 0, nothing to do: %m"); + exit(1); + } setproctitle("master"); @@ -591,82 +794,94 @@ main(argc, argv, envp) exit(1); } } - if (tcpflag && FD_ISSET(tcpsock, &ready)) { - len = sizeof(inetpeer); - if ((msgsock = accept(tcpsock, - (struct sockaddr *)&inetpeer, &len)) < 0) { - syslog(LOG_ERR, "accept failed: %m"); - exit(1); - } - memset(inetpeer.sin_zero, 0, sizeof(inetpeer.sin_zero)); - if (setsockopt(msgsock, SOL_SOCKET, - SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0) - syslog(LOG_ERR, - "setsockopt SO_KEEPALIVE: %m"); - nfsdargs.sock = msgsock; - nfsdargs.name = (caddr_t)&inetpeer; - nfsdargs.namelen = sizeof(inetpeer); - nfssvc(NFSSVC_ADDSOCK, &nfsdargs); - (void)close(msgsock); - } -#ifdef notyet - if (tp4flag && FD_ISSET(tp4sock, &ready)) { - len = sizeof(isopeer); - if ((msgsock = accept(tp4sock, - (struct sockaddr *)&isopeer, &len)) < 0) { - syslog(LOG_ERR, "accept failed: %m"); - exit(1); - } - if (setsockopt(msgsock, SOL_SOCKET, - SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0) - syslog(LOG_ERR, - "setsockopt SO_KEEPALIVE: %m"); - nfsdargs.sock = msgsock; - nfsdargs.name = (caddr_t)&isopeer; - nfsdargs.namelen = len; - nfssvc(NFSSVC_ADDSOCK, &nfsdargs); - (void)close(msgsock); - } - if (tpipflag && FD_ISSET(tpipsock, &ready)) { - len = sizeof(inetpeer); - if ((msgsock = accept(tpipsock, - (struct sockaddr *)&inetpeer, &len)) < 0) { - syslog(LOG_ERR, "accept failed: %m"); - exit(1); + for (tcpsock = 0; tcpsock <= maxsock; tcpsock++) { + if (FD_ISSET(tcpsock, &ready)) { + if (FD_ISSET(tcpsock, &v4bits)) { + len = sizeof(inetpeer); + if ((msgsock = accept(tcpsock, + (struct sockaddr *)&inetpeer, &len)) < 0) { + syslog(LOG_ERR, "accept failed: %m"); + exit(1); + } + memset(inetpeer.sin_zero, 0, + sizeof(inetpeer.sin_zero)); + if (setsockopt(msgsock, SOL_SOCKET, + SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0) + syslog(LOG_ERR, + "setsockopt SO_KEEPALIVE: %m"); + nfsdargs.sock = msgsock; + nfsdargs.name = (caddr_t)&inetpeer; + nfsdargs.namelen = sizeof(inetpeer); + nfssvc(NFSSVC_ADDSOCK, &nfsdargs); + (void)close(msgsock); + } else if (FD_ISSET(tcpsock, &v6bits)) { + len = sizeof(inet6peer); + if ((msgsock = accept(tcpsock, + (struct sockaddr *)&inet6peer, + &len)) < 0) { + syslog(LOG_ERR, + "accept failed: %m"); + exit(1); + } + if (setsockopt(msgsock, SOL_SOCKET, + SO_KEEPALIVE, (char *)&on, + sizeof(on)) < 0) + syslog(LOG_ERR, "setsockopt " + "SO_KEEPALIVE: %m"); + nfsdargs.sock = msgsock; + nfsdargs.name = (caddr_t)&inet6peer; + nfsdargs.namelen = sizeof(inet6peer); + nfssvc(NFSSVC_ADDSOCK, &nfsdargs); + (void)close(msgsock); + } } - if (setsockopt(msgsock, SOL_SOCKET, - SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0) - syslog(LOG_ERR, "setsockopt SO_KEEPALIVE: %m"); - nfsdargs.sock = msgsock; - nfsdargs.name = (caddr_t)&inetpeer; - nfsdargs.namelen = len; - nfssvc(NFSSVC_ADDSOCK, &nfsdargs); - (void)close(msgsock); } -#endif /* notyet */ } } -void -setbindhost(struct sockaddr_in *ia, const char *bindhost) +int +setbindhost(struct addrinfo **ai, const char *bindhost, struct addrinfo hints) { - ia->sin_family = AF_INET; - ia->sin_port = htons(NFS_PORT); - ia->sin_len = sizeof(*ia); - if (bindhost == NULL || strcmp(bindhost,"*") == 0) { - ia->sin_addr.s_addr = INADDR_ANY; - } else { - if (inet_aton(bindhost, &ia->sin_addr) == 0) { - struct hostent *he; + int ecode; + u_int32_t host_addr[4]; /* IPv4 or IPv6 */ + const char *hostptr; - he = gethostbyname2(bindhost, ia->sin_family); - if (he == NULL) { - syslog(LOG_ERR, "gethostbyname of %s failed", bindhost); - exit(1); + if (bindhost == NULL || strcmp("*", bindhost) == 0) + hostptr = NULL; + else + hostptr = bindhost; + + if (hostptr != NULL) { + switch (hints.ai_family) { + case AF_INET: + if (inet_pton(AF_INET, hostptr, host_addr) == 1) { + hints.ai_flags = AI_NUMERICHOST; + } else { + if (inet_pton(AF_INET6, hostptr, + host_addr) == 1) + return (1); + } + break; + case AF_INET6: + if (inet_pton(AF_INET6, hostptr, host_addr) == 1) { + hints.ai_flags = AI_NUMERICHOST; + } else { + if (inet_pton(AF_INET, hostptr, + host_addr) == 1) + return (1); } - bcopy(he->h_addr, &ia->sin_addr, he->h_length); + break; + default: } } + + ecode = getaddrinfo(hostptr, "nfs", &hints, ai); + if (ecode != 0) { + syslog(LOG_ERR, "getaddrinfo %s: %s", bindhost, + gai_strerror(ecode)); + return (1); + } + return (0); } void @@ -691,6 +906,48 @@ reapchild(signo) while (wait3(NULL, WNOHANG, NULL) > 0); } +void +unregistration() +{ + if ((!rpcb_unset(RPCPROG_NFS, 2, NULL)) || + (!rpcb_unset(RPCPROG_NFS, 3, NULL))) + syslog(LOG_ERR, "rpcb_unset failed"); +} + +void +killchildren() +{ + int i; + sigset_t sigs; + + sigemptyset(&sigs); + /* + * Block SIGCHLD to avoid killing a reaped process (although it is + * unlikely, the pid might have been reused). + */ + sigaddset(&sigs, SIGCHLD); + if (sigprocmask(SIG_BLOCK, &sigs, NULL) == -1) { + syslog(LOG_ERR, "sigprocmask: %s", + strerror(errno)); + return; + } + for (i = 0; i < nfsdcnt; i++) { + if (children[i] > 0) + kill(children[i], SIGKILL); + } + if (sigprocmask(SIG_UNBLOCK, &sigs, NULL) == -1) { + syslog(LOG_ERR, "sigprocmask: %s", strerror(errno)); + } + unregistration(); +} + +void +cleanup(signo) +{ + killchildren(); + exit (0); +} + #ifdef OLD_SETPROCTITLE #ifdef __FreeBSD__ void diff --git a/usr.sbin/portmap/Makefile b/usr.sbin/portmap/Makefile deleted file mode 100644 index b87cf595a9e4..000000000000 --- a/usr.sbin/portmap/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# @(#)Makefile 8.1 (Berkeley) 6/6/93 -# $FreeBSD$ - -PROG= portmap -MAN8= portmap.8 -SRCS= portmap.c from_local.c pmap_check.c -SUBDIR= pmap_set pmap_dump - -CFLAGS+=-DCHECK_PORT -DHOSTS_ACCESS -DPADD= ${LIBWRAP} -LDADD= -lwrap - -.include <bsd.prog.mk> diff --git a/usr.sbin/portmap/from_local.c b/usr.sbin/portmap/from_local.c deleted file mode 100644 index 9886f1250b86..000000000000 --- a/usr.sbin/portmap/from_local.c +++ /dev/null @@ -1,233 +0,0 @@ - /* - * Check if an address belongs to the local system. Adapted from: - * - * @(#)pmap_svc.c 1.32 91/03/11 Copyright 1984,1990 Sun Microsystems, Inc. - * @(#)get_myaddress.c 2.1 88/07/29 4.0 RPCSRC. - */ - -/* - * Sun RPC is a product of Sun Microsystems, Inc. and is provided for - * unrestricted use provided that this legend is included on all tape - * media and as a part of the software program in whole or part. Users - * may copy or modify Sun RPC without charge, but are not authorized - * to license or distribute it to anyone else except as part of a product or - * program developed by the user or with the express written consent of - * Sun Microsystems, Inc. - * - * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE - * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR - * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. - * - * Sun RPC is provided with no support and without any obligation on the - * part of Sun Microsystems, Inc. to assist in its use, correction, - * modification or enhancement. - * - * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE - * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC - * OR ANY PART THEREOF. - * - * In no event will Sun Microsystems, Inc. be liable for any lost revenue - * or profits or other special, indirect and consequential damages, even if - * Sun has been advised of the possibility of such damages. - * - * Sun Microsystems, Inc. - * 2550 Garcia Avenue - * Mountain View, California 94043 - */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#) from_local.c 1.2 93/11/16 21:50:02"; -#endif -static const char rcsid[] = - "$FreeBSD$"; -#endif - -#ifdef TEST -#undef perror -#endif - -#include <sys/types.h> -#include <sys/ioctl.h> -#include <sys/socket.h> -#include <sys/sysctl.h> -#include <sys/time.h> - -#include <netdb.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <syslog.h> -#include <unistd.h> - -#include <net/if.h> -#include <net/if_dl.h> -#include <net/route.h> -#include <netinet/in.h> - -#include "pmap_check.h" - -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif - -#define ROUNDUP(x) ((x) ? (1 + (((x) - 1) | (sizeof(long) - 1))) : sizeof(long)) - -/* How many interfaces could there be on a computer? */ - -#define ESTIMATED_LOCAL 20 -static int num_local = -1; -static struct in_addr *addrs; - -static void -rtiparse(struct ifa_msghdr *ifam, struct rt_addrinfo *ai) -{ - char *wp; - int rtax; - - wp = (char *)(ifam + 1); - - ai->rti_addrs = ifam->ifam_addrs; - for (rtax = 0; rtax < sizeof ai->rti_info / sizeof *ai->rti_info; rtax++) - if (ifam->ifam_addrs & (1 << rtax)) { - ai->rti_info[rtax] = (struct sockaddr *)wp; - wp += ROUNDUP(ai->rti_info[rtax]->sa_len); - } else - ai->rti_info[rtax] = NULL; -} - -/* find_local - find all IP addresses for this host */ - -static int -find_local() -{ - int mib[6], n, s, alloced; - size_t needed; - char *buf, *end, *ptr; - struct if_msghdr *ifm; - struct ifa_msghdr *ifam; - struct rt_addrinfo ai; - struct ifreq ifr; - struct sockaddr_dl *dl; - - mib[0] = CTL_NET; - mib[1] = PF_ROUTE; - mib[4] = NET_RT_IFLIST; - mib[2] = mib[3] = mib[5] = 0; - - if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { - perror("socket"); - return (0); - } - if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { - close(s); - perror("sysctl(NET_RT_IFLIST)"); - return 0; - } - if ((buf = (char *)malloc(needed)) == NULL) { - close(s); - perror("malloc"); - return 0; - } - if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { - close(s); - free(buf); - perror("sysctl(NET_RT_IFLIST)(after malloc)"); - return 0; - } - - if (addrs) { - free(addrs); - addrs = NULL; - } - num_local = 0; - alloced = 0; - end = buf + needed; - - for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) { - ifm = (struct if_msghdr *)ptr; - dl = (struct sockaddr_dl *)(ifm + 1); - - if (ifm->ifm_index != dl->sdl_index || dl->sdl_nlen == 0) - /* Skip over remaining ifa_msghdrs */ - continue; - - n = dl->sdl_nlen > sizeof ifr.ifr_name ? - sizeof ifr.ifr_name : dl->sdl_nlen; - strncpy(ifr.ifr_name, dl->sdl_data, n); - if (n < sizeof ifr.ifr_name) - ifr.ifr_name[n] = '\0'; - - /* we only want the first address from each interface */ - if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) - fprintf(stderr, "%.*s: SIOCGIFFLAGS: %s\n", n, ifr.ifr_name, - strerror(errno)); - else if (ifr.ifr_flags & IFF_UP) { /* active interface */ - ifam = (struct ifa_msghdr *)(ptr + ifm->ifm_msglen); - while ((char *)ifam < end && ifam->ifam_type == RTM_NEWADDR) { - rtiparse(ifam, &ai); - - if (ai.rti_info[RTAX_IFA] != NULL && - ai.rti_info[RTAX_IFA]->sa_family == AF_INET) { - if (alloced < num_local + 1) { - alloced += ESTIMATED_LOCAL; - addrs = (struct in_addr *)realloc(addrs, alloced * sizeof addrs[0]); - if (addrs == NULL) { - perror("malloc/realloc"); - num_local = 0; - break; - } - } - addrs[num_local++] = ((struct sockaddr_in *) - ai.rti_info[RTAX_IFA])->sin_addr; - - } - ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen); - } - } - } - free(buf); - close(s); - - return num_local; -} - -/* from_local - determine whether request comes from the local system */ - -int -from_local(addr) - struct sockaddr_in *addr; -{ - int i; - - if (num_local == -1 && find_local() == 0) - syslog(LOG_ERR, "cannot find any active local network interfaces"); - - for (i = 0; i < num_local; i++) { - if (memcmp((char *) &(addr->sin_addr), (char *) &(addrs[i]), - sizeof(struct in_addr)) == 0) - return (TRUE); - } - return (FALSE); -} - -#ifdef TEST - -int -main(argc, argv) - int argc; - char **argv; -{ - char *inet_ntoa(); - int i; - - find_local(); - for (i = 0; i < num_local; i++) - printf("%s\n", inet_ntoa(addrs[i])); - - return 0; -} - -#endif diff --git a/usr.sbin/portmap/pmap_check.c b/usr.sbin/portmap/pmap_check.c deleted file mode 100644 index 7ad25c9a7743..000000000000 --- a/usr.sbin/portmap/pmap_check.c +++ /dev/null @@ -1,263 +0,0 @@ - /* - * pmap_check - additional portmap security. - * - * Always reject non-local requests to update the portmapper tables. - * - * Refuse to forward mount requests to the nfs mount daemon. Otherwise, the - * requests would appear to come from the local system, and nfs export - * restrictions could be bypassed. - * - * Refuse to forward requests to the nfsd process. - * - * Refuse to forward requests to NIS (YP) daemons; The only exception is the - * YPPROC_DOMAIN_NONACK broadcast rpc call that is used to establish initial - * contact with the NIS server. - * - * Always allocate an unprivileged port when forwarding a request. - * - * If compiled with -DCHECK_PORT, require that requests to register or - * unregister a privileged port come from a privileged port. This makes it - * more difficult to replace a critical service by a trojan. - * - * If compiled with -DHOSTS_ACCESS, reject requests from hosts that are not - * authorized by the /etc/hosts.{allow,deny} files. The local system is - * always treated as an authorized host. The access control tables are never - * consulted for requests from the local system, and are always consulted - * for requests from other hosts. Access control is based on IP addresses - * only; attempts to map an address to a host name might cause the - * portmapper to hang. - * - * Author: Wietse Venema (wietse@wzv.win.tue.nl), dept. of Mathematics and - * Computing Science, Eindhoven University of Technology, The Netherlands. - */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#) pmap_check.c 1.6 93/11/21 20:58:59"; -#endif -static const char rcsid[] = - "$FreeBSD$"; -#endif - -#include <stdio.h> -#include <unistd.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> - -#include <rpc/rpc.h> -#include <rpc/pmap_prot.h> -#include <syslog.h> -#include <netdb.h> -#include <sys/signal.h> - -#include "pmap_check.h" - -/* Explicit #defines in case the include files are not available. */ - -#define NFSPROG ((u_long) 100003) -#define MOUNTPROG ((u_long) 100005) -#define YPXPROG ((u_long) 100069) -#define YPPROG ((u_long) 100004) -#define YPPROC_DOMAIN_NONACK ((u_long) 2) -#define MOUNTPROC_MNT ((u_long) 1) - -static void logit __P((int, struct sockaddr_in *, u_long, u_long, const char *)); -static void toggle_verboselog __P((int)); - -int verboselog = 0; -int allow_severity = LOG_INFO; -int deny_severity = LOG_WARNING; - -/* A handful of macros for "readability". */ - -#define good_client(a) hosts_ctl("portmap", "", inet_ntoa(a->sin_addr), "") - -#define legal_port(a,p) \ - (ntohs((a)->sin_port) < IPPORT_RESERVED || (p) >= IPPORT_RESERVED) - -#define log_bad_port(addr, proc, prog) \ - logit(deny_severity, addr, proc, prog, ": request from unprivileged port") - -#define log_bad_host(addr, proc, prog) \ - logit(deny_severity, addr, proc, prog, ": request from unauthorized host") - -#define log_bad_owner(addr, proc, prog) \ - logit(deny_severity, addr, proc, prog, ": request from non-local host") - -#define log_no_forward(addr, proc, prog) \ - logit(deny_severity, addr, proc, prog, ": request not forwarded") - -#define log_client(addr, proc, prog) \ - logit(allow_severity, addr, proc, prog, "") - -/* check_startup - additional startup code */ - -void -check_startup() -{ - - /* - * Give up root privileges so that we can never allocate a privileged - * port when forwarding an rpc request. - */ - if (setuid(1) == -1) { - syslog(LOG_ERR, "setuid(1) failed: %m"); - exit(1); - } - (void) signal(SIGINT, toggle_verboselog); -} - -/* check_default - additional checks for NULL, DUMP, GETPORT and unknown */ - -int -check_default(addr, proc, prog) - struct sockaddr_in *addr; - u_long proc, prog; -{ -#ifdef HOSTS_ACCESS - if (!(from_local(addr) || good_client(addr))) { - log_bad_host(addr, proc, prog); - return (FALSE); - } -#endif - if (verboselog) - log_client(addr, proc, prog); - return (TRUE); -} - -/* check_privileged_port - additional checks for privileged-port updates */ - -int -check_privileged_port(addr, proc, prog, port) - struct sockaddr_in *addr; - u_long proc, prog, port; -{ -#ifdef CHECK_PORT - if (!legal_port(addr, port)) { - log_bad_port(addr, proc, prog); - return (FALSE); - } -#endif - return (TRUE); -} - -/* check_setunset - additional checks for update requests */ - -int -check_setunset(addr, proc, prog, port) - struct sockaddr_in *addr; - u_long proc, prog, port; -{ - if (!from_local(addr)) { -#ifdef HOSTS_ACCESS - (void) good_client(addr); /* because of side effects */ -#endif - log_bad_owner(addr, proc, prog); - return (FALSE); - } - if (port && !check_privileged_port(addr, proc, prog, port)) - return (FALSE); - if (verboselog) - log_client(addr, proc, prog); - return (TRUE); -} - -/* check_callit - additional checks for forwarded requests */ - -int -check_callit(addr, proc, prog, aproc) - struct sockaddr_in *addr; - u_long proc, prog, aproc; -{ -#ifdef HOSTS_ACCESS - if (!(from_local(addr) || good_client(addr))) { - log_bad_host(addr, proc, prog); - return (FALSE); - } -#endif - if (prog == PMAPPROG || prog == NFSPROG || prog == YPXPROG || - (prog == MOUNTPROG && aproc == MOUNTPROC_MNT) || - (prog == YPPROG && aproc != YPPROC_DOMAIN_NONACK)) { - log_no_forward(addr, proc, prog); - return (FALSE); - } - if (verboselog) - log_client(addr, proc, prog); - return (TRUE); -} - -/* toggle_verboselog - toggle verbose logging flag */ - -static void -toggle_verboselog(sig) - int sig; -{ - (void) signal(sig, toggle_verboselog); - verboselog = !verboselog; -} - -/* logit - report events of interest via the syslog daemon */ - -static void -logit(severity, addr, procnum, prognum, text) - int severity; - struct sockaddr_in *addr; - u_long procnum, prognum; - const char *text; -{ - const char *procname; - char procbuf[4 * sizeof(u_long)]; - const char *progname; - char progbuf[4 * sizeof(u_long)]; - struct rpcent *rpc; - struct proc_map { - u_long code; - const char *proc; - }; - struct proc_map *procp; - static struct proc_map procmap[] = { - {PMAPPROC_CALLIT, "callit"}, - {PMAPPROC_DUMP, "dump"}, - {PMAPPROC_GETPORT, "getport"}, - {PMAPPROC_NULL, "null"}, - {PMAPPROC_SET, "set"}, - {PMAPPROC_UNSET, "unset"}, - {0, 0}, - }; - - /* - * Fork off a process or the portmap daemon might hang while - * getrpcbynumber() or syslog() does its thing. - */ - - if (fork() == 0) { - - /* Try to map program number to name. */ - - if (prognum == 0) { - progname = ""; - } else if ((rpc = getrpcbynumber((int) prognum))) { - progname = rpc->r_name; - } else { - sprintf(progbuf, "%lu", prognum); - progname = progbuf; - } - - /* Try to map procedure number to name. */ - - for (procp = procmap; procp->proc && procp->code != procnum; procp++) - /* void */ ; - if ((procname = procp->proc) == 0) { - sprintf(procbuf, "%lu", (u_long) procnum); - procname = procbuf; - } - - /* Write syslog record. */ - - syslog(severity, "connect from %s to %s(%s)%s", - inet_ntoa(addr->sin_addr), procname, progname, text); - exit(0); - } -} diff --git a/usr.sbin/portmap/pmap_dump/Makefile b/usr.sbin/portmap/pmap_dump/Makefile deleted file mode 100644 index 0064f28630d1..000000000000 --- a/usr.sbin/portmap/pmap_dump/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# @(#)Makefile 8.1 (Berkeley) 6/6/93 - -PROG= pmap_dump -NOMAN= noman - -.include "${.CURDIR}/../../Makefile.inc" -.include <bsd.prog.mk> diff --git a/usr.sbin/portmap/pmap_dump/pmap_dump.c b/usr.sbin/portmap/pmap_dump/pmap_dump.c deleted file mode 100644 index 96fb5c2edb99..000000000000 --- a/usr.sbin/portmap/pmap_dump/pmap_dump.c +++ /dev/null @@ -1,69 +0,0 @@ - /* - * pmap_dump - dump portmapper table in format readable by pmap_set - * - * Author: Wietse Venema (wietse@wzv.win.tue.nl), dept. of Mathematics and - * Computing Science, Eindhoven University of Technology, The Netherlands. - */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#) pmap_dump.c 1.1 92/06/11 22:53:15"; -#endif -static const char rcsid[] = - "$FreeBSD$"; -#endif - -#include <stdio.h> -#include <sys/types.h> -#ifdef SYSV40 -#include <netinet/in.h> -#include <rpc/rpcent.h> -#else -#include <netdb.h> -#endif -#include <rpc/rpc.h> -#include <rpc/pmap_clnt.h> -#include <rpc/pmap_prot.h> - -static const char *protoname __P((u_long)); - -int -main(argc, argv) - int argc; - char **argv; -{ - struct sockaddr_in addr; - register struct pmaplist *list; - register struct rpcent *rpc; - - get_myaddress(&addr); - - for (list = pmap_getmaps(&addr); list; list = list->pml_next) { - rpc = getrpcbynumber((int) list->pml_map.pm_prog); - printf("%10lu %4lu %5s %6lu %s\n", - list->pml_map.pm_prog, - list->pml_map.pm_vers, - protoname(list->pml_map.pm_prot), - list->pml_map.pm_port, - rpc ? rpc->r_name : ""); - } -#undef perror - return (fclose(stdout) ? (perror(argv[0]), 1) : 0); -} - -static const char * -protoname(proto) - u_long proto; -{ - static char buf[BUFSIZ]; - - switch (proto) { - case IPPROTO_UDP: - return ("udp"); - case IPPROTO_TCP: - return ("tcp"); - default: - sprintf(buf, "%lu", proto); - return (buf); - } -} diff --git a/usr.sbin/portmap/pmap_set/Makefile b/usr.sbin/portmap/pmap_set/Makefile deleted file mode 100644 index 987e3209d303..000000000000 --- a/usr.sbin/portmap/pmap_set/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# @(#)Makefile 8.1 (Berkeley) 6/6/93 - -PROG= pmap_set -NOMAN= noman - -.include "${.CURDIR}/../../Makefile.inc" -.include <bsd.prog.mk> diff --git a/usr.sbin/portmap/pmap_set/pmap_set.c b/usr.sbin/portmap/pmap_set/pmap_set.c deleted file mode 100644 index 35a7fbe6e591..000000000000 --- a/usr.sbin/portmap/pmap_set/pmap_set.c +++ /dev/null @@ -1,78 +0,0 @@ - /* - * pmap_set - set portmapper table from data produced by pmap_dump - * - * Author: Wietse Venema (wietse@wzv.win.tue.nl), dept. of Mathematics and - * Computing Science, Eindhoven University of Technology, The Netherlands. - */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#) pmap_set.c 1.1 92/06/11 22:53:16"; -#endif -static const char rcsid[] = - "$FreeBSD$"; -#endif - -#include <err.h> -#include <stdio.h> -#include <sys/types.h> -#ifdef SYSV40 -#include <netinet/in.h> -#endif -#include <rpc/rpc.h> -#include <rpc/pmap_clnt.h> - -static int parse_line __P((char *, u_long *, u_long *, int *, unsigned *)); - -int -main(argc, argv) - int argc; - char **argv; -{ - struct sockaddr_in addr; - char buf[BUFSIZ]; - u_long prog; - u_long vers; - int prot; - unsigned port; - - get_myaddress(&addr); - - while (fgets(buf, sizeof(buf), stdin)) { - if (parse_line(buf, &prog, &vers, &prot, &port) == 0) { - warnx("malformed line: %s", buf); - return (1); - } - if (pmap_set(prog, vers, prot, (unsigned short) port) == 0) - warnx("not registered: %s", buf); - } - return (0); -} - -/* parse_line - convert line to numbers */ - -static int -parse_line(buf, prog, vers, prot, port) - char *buf; - u_long *prog, *vers; - int *prot; - unsigned *port; -{ - char proto_name[BUFSIZ]; - - if (sscanf(buf, "%lu %lu %s %u", prog, vers, proto_name, port) != 4) { - return (0); - } - if (strcmp(proto_name, "tcp") == 0) { - *prot = IPPROTO_TCP; - return (1); - } - if (strcmp(proto_name, "udp") == 0) { - *prot = IPPROTO_UDP; - return (1); - } - if (sscanf(proto_name, "%d", prot) == 1) { - return (1); - } - return (0); -} diff --git a/usr.sbin/portmap/portmap.8 b/usr.sbin/portmap/portmap.8 deleted file mode 100644 index 455ccbd80354..000000000000 --- a/usr.sbin/portmap/portmap.8 +++ /dev/null @@ -1,122 +0,0 @@ -.\" Copyright (c) 1987 Sun Microsystems -.\" Copyright (c) 1990, 1991, 1993 -.\" The Regents of the University of California. All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. -.\" 4. Neither the name of the University nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" @(#)portmap.8 8.1 (Berkeley) 6/6/93 -.\" $FreeBSD$ -.\" -.Dd June 6, 1993 -.Dt PORTMAP 8 -.Os BSD 4.3 -.Sh NAME -.Nm portmap -.Nd -.Tn RPC -program,version -to -.Tn DARPA -port mapper -.Sh SYNOPSIS -.Nm -.Op Fl d -.Op Fl v -.Sh DESCRIPTION -.Nm Portmap -is a server that converts -.Tn RPC -program numbers into -.Tn DARPA -protocol port numbers. -It must be running in order to make -.Tn RPC -calls. -.Pp -When an -.Tn RPC -server is started, it will tell -.Nm -what port number it is listening to, and what -.Tn RPC -program numbers it is prepared to serve. -When a client wishes to make an -.Tn RPC -call to a given program number, -it will first contact -.Nm -on the server machine to determine -the port number where -.Tn RPC -packets should be sent. -.Pp -.Nm Portmap -must be started before any -.Tn RPC -servers are invoked. -.Pp -.Nm Portmap -uses -.Xr hosts_access 5 -access control by default. -Access control patterns may only reference IP addresses. -.Pp -Normally -.Nm -forks and dissociates itself from the terminal -like any other daemon. -.Nm Portmap -then logs errors using -.Xr syslog 3 . -.Pp -The following options are available: -.Bl -tag -width indent -.It Fl d -Prevent -.Nm -from running as a daemon, -and causes errors and debugging information -to be printed to the standard error output. -.It Fl v -Enable verbose logging of access control checks. -.El -.Sh SEE ALSO -.Xr hosts_access 5 , -.Xr inetd.conf 5 , -.Xr inetd 8 , -.Xr rpcinfo 8 -.Sh BUGS -If -.Nm -crashes, all servers must be restarted. -.Sh HISTORY -The -.Nm -command appeared in -.Bx 4.3 diff --git a/usr.sbin/portmap/portmap.c b/usr.sbin/portmap/portmap.c deleted file mode 100644 index 658b53cbf872..000000000000 --- a/usr.sbin/portmap/portmap.c +++ /dev/null @@ -1,612 +0,0 @@ -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef lint -static const char copyright[] = -"@(#) Copyright (c) 1990, 1993\n\ - The Regents of the University of California. All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#)portmap.c 8.1 (Berkeley) 6/6/93"; -#endif -static const char rcsid[] = - "$FreeBSD$"; -#endif /* not lint */ - -/* -@(#)portmap.c 2.3 88/08/11 4.0 RPCSRC -static char sccsid[] = "@(#)portmap.c 1.32 87/08/06 Copyr 1984 Sun Micro"; -*/ - -/* - * portmap.c, Implements the program,version to port number mapping for - * rpc. - */ - -/* - * Sun RPC is a product of Sun Microsystems, Inc. and is provided for - * unrestricted use provided that this legend is included on all tape - * media and as a part of the software program in whole or part. Users - * may copy or modify Sun RPC without charge, but are not authorized - * to license or distribute it to anyone else except as part of a product or - * program developed by the user. - * - * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE - * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR - * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. - * - * Sun RPC is provided with no support and without any obligation on the - * part of Sun Microsystems, Inc. to assist in its use, correction, - * modification or enhancement. - * - * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE - * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC - * OR ANY PART THEREOF. - * - * In no event will Sun Microsystems, Inc. be liable for any lost revenue - * or profits or other special, indirect and consequential damages, even if - * Sun has been advised of the possibility of such damages. - * - * Sun Microsystems, Inc. - * 2550 Garcia Avenue - * Mountain View, California 94043 - */ - -#include <err.h> -#include <errno.h> -#include <netdb.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <syslog.h> -#include <unistd.h> -#include <rpc/rpc.h> -#include <rpc/pmap_prot.h> -#include <sys/socket.h> -#include <sys/ioctl.h> -#include <sys/wait.h> -#include <sys/signal.h> -#include <sys/resource.h> - -#include "pmap_check.h" - -static void reg_service __P((struct svc_req *, SVCXPRT *)); -static void reap __P((int)); -static void callit __P((struct svc_req *, SVCXPRT *)); -static void usage __P((void)); - -struct pmaplist *pmaplist; -int debugging = 0; - -int -main(argc, argv) - int argc; - char **argv; -{ - SVCXPRT *xprt; - int sock, c; - struct sockaddr_in addr; - int len = sizeof(struct sockaddr_in); - register struct pmaplist *pml; - - while ((c = getopt(argc, argv, "dv")) != -1) { - switch (c) { - - case 'd': - debugging = 1; - break; - - case 'v': - verboselog = 1; - break; - - default: - usage(); - } - } - - if (!debugging && daemon(0, 0)) - err(1, "fork"); - - openlog("portmap", debugging ? LOG_PID | LOG_PERROR : LOG_PID, - LOG_DAEMON); - - if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { - syslog(LOG_ERR, "cannot create udp socket: %m"); - exit(1); - } - - addr.sin_addr.s_addr = 0; - addr.sin_family = AF_INET; - addr.sin_port = htons(PMAPPORT); - if (bind(sock, (struct sockaddr *)&addr, len) != 0) { - syslog(LOG_ERR, "cannot bind udp: %m"); - exit(1); - } - - if ((xprt = svcudp_create(sock)) == (SVCXPRT *)NULL) { - syslog(LOG_ERR, "couldn't do udp_create"); - exit(1); - } - /* make an entry for ourself */ - pml = (struct pmaplist *)malloc((u_int)sizeof(struct pmaplist)); - pml->pml_next = 0; - pml->pml_map.pm_prog = PMAPPROG; - pml->pml_map.pm_vers = PMAPVERS; - pml->pml_map.pm_prot = IPPROTO_UDP; - pml->pml_map.pm_port = PMAPPORT; - pmaplist = pml; - - if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { - syslog(LOG_ERR, "cannot create tcp socket: %m"); - exit(1); - } - if (bind(sock, (struct sockaddr *)&addr, len) != 0) { - syslog(LOG_ERR, "cannot bind tcp: %m"); - exit(1); - } - if ((xprt = svctcp_create(sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE)) - == (SVCXPRT *)NULL) { - syslog(LOG_ERR, "couldn't do tcp_create"); - exit(1); - } - /* make an entry for ourself */ - pml = (struct pmaplist *)malloc((u_int)sizeof(struct pmaplist)); - pml->pml_map.pm_prog = PMAPPROG; - pml->pml_map.pm_vers = PMAPVERS; - pml->pml_map.pm_prot = IPPROTO_TCP; - pml->pml_map.pm_port = PMAPPORT; - pml->pml_next = pmaplist; - pmaplist = pml; - - (void)svc_register(xprt, PMAPPROG, PMAPVERS, reg_service, FALSE); - - /* additional initializations */ - check_startup(); - (void)signal(SIGCHLD, reap); - svc_run(); - syslog(LOG_ERR, "svc_run returned unexpectedly"); - abort(); -} - -static void -usage() -{ - fprintf(stderr, "usage: portmap [-dv]\n"); - exit(1); -} - -#ifndef lint -/* need to override perror calls in rpc library */ -void -perror(what) - const char *what; -{ - syslog(LOG_ERR, "%s: %m", what); -} -#endif - -static struct pmaplist * -find_service(prog, vers, prot) - u_long prog, vers, prot; -{ - register struct pmaplist *hit = NULL; - register struct pmaplist *pml; - - for (pml = pmaplist; pml != NULL; pml = pml->pml_next) { - if ((pml->pml_map.pm_prog != prog) || - (pml->pml_map.pm_prot != prot)) - continue; - hit = pml; - if (pml->pml_map.pm_vers == vers) - break; - } - return (hit); -} - -/* - * 1 OK, 0 not - */ -static void -reg_service(rqstp, xprt) - struct svc_req *rqstp; - SVCXPRT *xprt; -{ - struct pmap reg; - struct pmaplist *pml, *prevpml, *fnd; - int ans, port; - caddr_t t; - - /* - * Later wrappers change the logging severity on the fly. Reset to - * defaults before handling the next request. - */ - allow_severity = LOG_INFO; - deny_severity = LOG_WARNING; - - if (debugging) - (void) fprintf(stderr, "server: about to do a switch\n"); - switch (rqstp->rq_proc) { - - case PMAPPROC_NULL: - /* - * Null proc call - */ - /* remote host authorization check */ - check_default(svc_getcaller(xprt), rqstp->rq_proc, (u_long) 0); - if (!svc_sendreply(xprt, xdr_void, (caddr_t)0) && debugging) { - abort(); - } - break; - - case PMAPPROC_SET: - /* - * Set a program,version to port mapping - */ - if (!svc_getargs(xprt, xdr_pmap, (caddr_t)®)) - svcerr_decode(xprt); - else { - /* reject non-local requests, protect priv. ports */ - if (!check_setunset(svc_getcaller(xprt), - rqstp->rq_proc, reg.pm_prog, reg.pm_port)) { - ans = 0; - goto done; - } - /* - * check to see if already used - * find_service returns a hit even if - * the versions don't match, so check for it - */ - fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot); - if (fnd && fnd->pml_map.pm_vers == reg.pm_vers) { - if (fnd->pml_map.pm_port == reg.pm_port) { - ans = 1; - goto done; - } - else { - ans = 0; - goto done; - } - } else { - /* - * add to END of list - */ - pml = (struct pmaplist *) - malloc((u_int)sizeof(struct pmaplist)); - pml->pml_map = reg; - pml->pml_next = 0; - if (pmaplist == 0) { - pmaplist = pml; - } else { - for (fnd= pmaplist; fnd->pml_next != 0; - fnd = fnd->pml_next); - fnd->pml_next = pml; - } - ans = 1; - } - done: - if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) && - debugging) { - (void) fprintf(stderr, "svc_sendreply\n"); - abort(); - } - } - break; - - case PMAPPROC_UNSET: - /* - * Remove a program,version to port mapping. - */ - if (!svc_getargs(xprt, xdr_pmap, (caddr_t)®)) - svcerr_decode(xprt); - else { - ans = 0; - /* reject non-local requests */ - if (!check_setunset(svc_getcaller(xprt), - rqstp->rq_proc, reg.pm_prog, (u_long) 0)) - goto done; - for (prevpml = NULL, pml = pmaplist; pml != NULL; ) { - if ((pml->pml_map.pm_prog != reg.pm_prog) || - (pml->pml_map.pm_vers != reg.pm_vers)) { - /* both pml & prevpml move forwards */ - prevpml = pml; - pml = pml->pml_next; - continue; - } - /* found it; pml moves forward, prevpml stays */ - /* privileged port check */ - if (!check_privileged_port(svc_getcaller(xprt), - rqstp->rq_proc, - reg.pm_prog, - pml->pml_map.pm_port)) { - ans = 0; - break; - } - ans = 1; - t = (caddr_t)pml; - pml = pml->pml_next; - if (prevpml == NULL) - pmaplist = pml; - else - prevpml->pml_next = pml; - free(t); - } - if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) && - debugging) { - (void) fprintf(stderr, "svc_sendreply\n"); - abort(); - } - } - break; - - case PMAPPROC_GETPORT: - /* - * Lookup the mapping for a program,version and return its port - */ - if (!svc_getargs(xprt, xdr_pmap, (caddr_t)®)) - svcerr_decode(xprt); - else { - /* remote host authorization check */ - if (!check_default(svc_getcaller(xprt), - rqstp->rq_proc, - reg.pm_prog)) { - ans = 0; - goto done; - } - fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot); - if (fnd) - port = fnd->pml_map.pm_port; - else - port = 0; - if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&port)) && - debugging) { - (void) fprintf(stderr, "svc_sendreply\n"); - abort(); - } - } - break; - - case PMAPPROC_DUMP: - /* - * Return the current set of mapped program,version - */ - if (!svc_getargs(xprt, xdr_void, NULL)) - svcerr_decode(xprt); - else { - /* remote host authorization check */ - struct pmaplist *p; - if (!check_default(svc_getcaller(xprt), - rqstp->rq_proc, (u_long) 0)) { - p = 0; /* send empty list */ - } else { - p = pmaplist; - } - if ((!svc_sendreply(xprt, xdr_pmaplist, - (caddr_t)&p)) && debugging) { - (void) fprintf(stderr, "svc_sendreply\n"); - abort(); - } - } - break; - - case PMAPPROC_CALLIT: - /* - * Calls a procedure on the local machine. If the requested - * procedure is not registered this procedure does not return - * error information!! - * This procedure is only supported on rpc/udp and calls via - * rpc/udp. It passes null authentication parameters. - */ - callit(rqstp, xprt); - break; - - default: - /* remote host authorization check */ - check_default(svc_getcaller(xprt), rqstp->rq_proc, (u_long) 0); - svcerr_noproc(xprt); - break; - } -} - - -/* - * Stuff for the rmtcall service - */ -#define ARGSIZE 9000 - -struct encap_parms { - u_int arglen; - char *args; -}; - -static bool_t -xdr_encap_parms(xdrs, epp) - XDR *xdrs; - struct encap_parms *epp; -{ - - return (xdr_bytes(xdrs, &(epp->args), &(epp->arglen), ARGSIZE)); -} - -struct rmtcallargs { - u_long rmt_prog; - u_long rmt_vers; - u_long rmt_port; - u_long rmt_proc; - struct encap_parms rmt_args; -}; - -static bool_t -xdr_rmtcall_args(xdrs, cap) - XDR *xdrs; - struct rmtcallargs *cap; -{ - - /* does not get a port number */ - if (xdr_u_long(xdrs, &(cap->rmt_prog)) && - xdr_u_long(xdrs, &(cap->rmt_vers)) && - xdr_u_long(xdrs, &(cap->rmt_proc))) { - return (xdr_encap_parms(xdrs, &(cap->rmt_args))); - } - return (FALSE); -} - -static bool_t -xdr_rmtcall_result(xdrs, cap) - XDR *xdrs; - struct rmtcallargs *cap; -{ - if (xdr_u_long(xdrs, &(cap->rmt_port))) - return (xdr_encap_parms(xdrs, &(cap->rmt_args))); - return (FALSE); -} - -/* - * only worries about the struct encap_parms part of struct rmtcallargs. - * The arglen must already be set!! - */ -static bool_t -xdr_opaque_parms(xdrs, cap) - XDR *xdrs; - struct rmtcallargs *cap; -{ - return (xdr_opaque(xdrs, cap->rmt_args.args, cap->rmt_args.arglen)); -} - -/* - * This routine finds and sets the length of incoming opaque paraters - * and then calls xdr_opaque_parms. - */ -static bool_t -xdr_len_opaque_parms(xdrs, cap) - XDR *xdrs; - struct rmtcallargs *cap; -{ - register u_int beginpos, lowpos, highpos, currpos, pos; - - beginpos = lowpos = pos = xdr_getpos(xdrs); - highpos = lowpos + ARGSIZE; - while ((int)(highpos - lowpos) >= 0) { - currpos = (lowpos + highpos) / 2; - if (xdr_setpos(xdrs, currpos)) { - pos = currpos; - lowpos = currpos + 1; - } else { - highpos = currpos - 1; - } - } - xdr_setpos(xdrs, beginpos); - cap->rmt_args.arglen = pos - beginpos; - return (xdr_opaque_parms(xdrs, cap)); -} - -/* - * Call a remote procedure service - * This procedure is very quiet when things go wrong. - * The proc is written to support broadcast rpc. In the broadcast case, - * a machine should shut-up instead of complain, less the requestor be - * overrun with complaints at the expense of not hearing a valid reply ... - * - * This now forks so that the program & process that it calls can call - * back to the portmapper. - */ -static void -callit(rqstp, xprt) - struct svc_req *rqstp; - SVCXPRT *xprt; -{ - struct rmtcallargs a; - struct pmaplist *pml; - u_short port; - struct sockaddr_in me; - int pid, so = -1; - CLIENT *client; - struct authunix_parms *au = (struct authunix_parms *)rqstp->rq_clntcred; - struct timeval timeout; - char buf[ARGSIZE]; - - timeout.tv_sec = 5; - timeout.tv_usec = 0; - a.rmt_args.args = buf; - if (!svc_getargs(xprt, xdr_rmtcall_args, (caddr_t)&a)) - return; - /* host and service access control */ - if (!check_callit(svc_getcaller(xprt), - rqstp->rq_proc, a.rmt_prog, a.rmt_proc)) - return; - if ((pml = find_service(a.rmt_prog, a.rmt_vers, - (u_long)IPPROTO_UDP)) == NULL) - return; - /* - * fork a child to do the work. Parent immediately returns. - * Child exits upon completion. - */ - if ((pid = fork()) != 0) { - if (pid < 0) - syslog(LOG_ERR, "CALLIT (prog %lu): fork: %m", - a.rmt_prog); - return; - } - port = pml->pml_map.pm_port; - get_myaddress(&me); - me.sin_port = htons(port); - client = clntudp_create(&me, a.rmt_prog, a.rmt_vers, timeout, &so); - if (client != (CLIENT *)NULL) { - if (rqstp->rq_cred.oa_flavor == AUTH_UNIX) { - client->cl_auth = authunix_create(au->aup_machname, - au->aup_uid, au->aup_gid, au->aup_len, au->aup_gids); - } - a.rmt_port = (u_long)port; - if (clnt_call(client, a.rmt_proc, xdr_opaque_parms, &a, - xdr_len_opaque_parms, &a, timeout) == RPC_SUCCESS) { - svc_sendreply(xprt, xdr_rmtcall_result, (caddr_t)&a); - } - AUTH_DESTROY(client->cl_auth); - clnt_destroy(client); - } - (void)close(so); - exit(0); -} - -static void -reap(sig) - int sig; -{ - int save_errno; - - save_errno = errno; - while (wait3((int *)NULL, WNOHANG, (struct rusage *)NULL) > 0); - errno = save_errno; -} diff --git a/usr.sbin/rpc.lockd/Makefile b/usr.sbin/rpc.lockd/Makefile index 19a6565a4048..ba6b3c77dbc1 100644 --- a/usr.sbin/rpc.lockd/Makefile +++ b/usr.sbin/rpc.lockd/Makefile @@ -1,15 +1,17 @@ -# $FreeBSD$ +# $FreeBSD$ +# $NetBSD: Makefile,v 1.12 2000/08/07 16:23:31 thorpej Exp $ -PROG = rpc.lockd -SRCS = nlm_prot_svc.c nlm_prot.h lockd.c procs.c -MAN8 = rpc.lockd.8 +PROG= rpc.lockd +SRCS= nlm_prot_svc.c lockd.c lock_proc.c lockd_lock.c +MAN8= rpc.lockd.8 +MLINKS= rpc.lockd.8 lockd.8 -DPADD= ${LIBRPCSVC} -LDADD= -lrpcsvc +CFLAGS+= -I. -I${DESTDIR}/usr/include/rpcsvc -CFLAGS+= -I. +DPADD= ${LIBRPCSVC} ${LIBUTIL} +LDADD= -lrpcsvc -lutil -CLEANFILES= nlm_prot_svc.c nlm_prot.h +CLEANFILES= nlm_prot_svc.c nlm_prot.h test RPCSRC= ${DESTDIR}/usr/include/rpcsvc/nlm_prot.x RPCGEN= rpcgen -L -C @@ -20,7 +22,7 @@ nlm_prot_svc.c: ${RPCSRC} nlm_prot.h: ${RPCSRC} ${RPCGEN} -h -o ${.TARGET} ${RPCSRC} -test: test.c - cc -o test test.c -lrpcsvc +test: ${.CURDIR}/test.c + cc -o test ${.CURDIR}/test.c -lrpcsvc .include <bsd.prog.mk> diff --git a/usr.sbin/rpc.lockd/lock_proc.c b/usr.sbin/rpc.lockd/lock_proc.c new file mode 100644 index 000000000000..8b08fd0f49eb --- /dev/null +++ b/usr.sbin/rpc.lockd/lock_proc.c @@ -0,0 +1,1294 @@ +/* $NetBSD: lock_proc.c,v 1.7 2000/10/11 20:23:56 is Exp $ */ +/* $FreeBSD$ */ +/* + * Copyright (c) 1995 + * A.R. Gordon (andrew.gordon@net-tel.co.uk). 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 for the FreeBSD project + * 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 ANDREW GORDON 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/cdefs.h> +#ifndef lint +__RCSID("$NetBSD: lock_proc.c,v 1.7 2000/10/11 20:23:56 is Exp $"); +#endif + +#include <sys/param.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <netdb.h> +#include <stdio.h> +#include <string.h> +#include <syslog.h> +#include <netconfig.h> + +#include <rpc/rpc.h> +#include <rpcsvc/sm_inter.h> + +#include "lockd.h" +#include <rpcsvc/nlm_prot.h> +#include "lockd_lock.h" + + +#define CLIENT_CACHE_SIZE 64 /* No. of client sockets cached */ +#define CLIENT_CACHE_LIFETIME 120 /* In seconds */ + +static void log_from_addr __P((char *, struct svc_req *)); +static int addrcmp __P((struct sockaddr *, struct sockaddr *)); + +/* log_from_addr ----------------------------------------------------------- */ +/* + * Purpose: Log name of function called and source address + * Returns: Nothing + * Notes: Extracts the source address from the transport handle + * passed in as part of the called procedure specification + */ +static void +log_from_addr(fun_name, req) + char *fun_name; + struct svc_req *req; +{ + struct sockaddr *addr; + char hostname_buf[NI_MAXHOST]; + + addr = svc_getrpccaller(req->rq_xprt)->buf; + if (getnameinfo(addr , addr->sa_len, hostname_buf, sizeof hostname_buf, + NULL, 0, 0) != 0) + return; + + syslog(LOG_DEBUG, "%s from %s", fun_name, hostname_buf); +} + +/* get_client -------------------------------------------------------------- */ +/* + * Purpose: Get a CLIENT* for making RPC calls to lockd on given host + * Returns: CLIENT* pointer, from clnt_udp_create, or NULL if error + * Notes: Creating a CLIENT* is quite expensive, involving a + * conversation with the remote portmapper to get the + * port number. Since a given client is quite likely + * to make several locking requests in succession, it is + * desirable to cache the created CLIENT*. + * + * Since we are using UDP rather than TCP, there is no cost + * to the remote system in keeping these cached indefinitely. + * Unfortunately there is a snag: if the remote system + * reboots, the cached portmapper results will be invalid, + * and we will never detect this since all of the xxx_msg() + * calls return no result - we just fire off a udp packet + * and hope for the best. + * + * We solve this by discarding cached values after two + * minutes, regardless of whether they have been used + * in the meanwhile (since a bad one might have been used + * plenty of times, as the host keeps retrying the request + * and we keep sending the reply back to the wrong port). + * + * Given that the entries will always expire in the order + * that they were created, there is no point in a LRU + * algorithm for when the cache gets full - entries are + * always re-used in sequence. + */ +static CLIENT *clnt_cache_ptr[CLIENT_CACHE_SIZE]; +static long clnt_cache_time[CLIENT_CACHE_SIZE]; /* time entry created */ +static struct sockaddr_storage clnt_cache_addr[CLIENT_CACHE_SIZE]; +static int clnt_cache_next_to_use = 0; + +static int +addrcmp(sa1, sa2) + struct sockaddr *sa1; + struct sockaddr *sa2; +{ + int len; + void *p1, *p2; + + if (sa1->sa_family != sa2->sa_family) + return -1; + + switch (sa1->sa_family) { + case AF_INET: + p1 = &((struct sockaddr_in *)sa1)->sin_addr; + p2 = &((struct sockaddr_in *)sa2)->sin_addr; + len = 4; + break; + case AF_INET6: + p1 = &((struct sockaddr_in6 *)sa1)->sin6_addr; + p2 = &((struct sockaddr_in6 *)sa2)->sin6_addr; + len = 16; + break; + default: + return -1; + } + + return memcmp(p1, p2, len); +} + +CLIENT * +get_client(host_addr, vers) + struct sockaddr *host_addr; + rpcvers_t vers; +{ + CLIENT *client; + struct timeval retry_time, time_now; + int i; + char *netid; + struct netconfig *nconf; + char host[NI_MAXHOST]; + + gettimeofday(&time_now, NULL); + + /* + * Search for the given client in the cache, zapping any expired + * entries that we happen to notice in passing. + */ + for (i = 0; i < CLIENT_CACHE_SIZE; i++) { + client = clnt_cache_ptr[i]; + if (client && ((clnt_cache_time[i] + CLIENT_CACHE_LIFETIME) + < time_now.tv_sec)) { + /* Cache entry has expired. */ + if (debug_level > 3) + syslog(LOG_DEBUG, "Expired CLIENT* in cache"); + clnt_cache_time[i] = 0L; + clnt_destroy(client); + clnt_cache_ptr[i] = NULL; + client = NULL; + } + if (client && !addrcmp((struct sockaddr *)&clnt_cache_addr[i], + host_addr)) { + /* Found it! */ + if (debug_level > 3) + syslog(LOG_DEBUG, "Found CLIENT* in cache"); + return (client); + } + } + + /* Not found in cache. Free the next entry if it is in use. */ + if (clnt_cache_ptr[clnt_cache_next_to_use]) { + clnt_destroy(clnt_cache_ptr[clnt_cache_next_to_use]); + clnt_cache_ptr[clnt_cache_next_to_use] = NULL; + } + + /* + * Need a host string for clnt_tp_create. Use NI_NUMERICHOST + * to avoid DNS lookups. + */ + if (getnameinfo(host_addr, host_addr->sa_len, host, sizeof host, + NULL, 0, NI_NUMERICHOST) != 0) { + syslog(LOG_ERR, "unable to get name string for caller"); + return NULL; + } + +#if 1 + if (host_addr->sa_family == AF_INET6) + netid = "udp6"; + else + netid = "udp"; +#else + if (host_addr->sa_family == AF_INET6) + netid = "tcp6"; + else + netid = "tcp"; +#endif + nconf = getnetconfigent(netid); + if (nconf == NULL) { + syslog(LOG_ERR, "could not get netconfig info for '%s': " + "no /etc/netconfig file?", netid); + return NULL; + } + + client = clnt_tp_create(host, NLM_PROG, vers, nconf); + freenetconfigent(nconf); + + if (!client) { + syslog(LOG_ERR, "%s", clnt_spcreateerror("clntudp_create")); + syslog(LOG_ERR, "Unable to return result to %s", host); + return NULL; + } + + /* Success - update the cache entry */ + clnt_cache_ptr[clnt_cache_next_to_use] = client; + memcpy(&clnt_cache_addr[clnt_cache_next_to_use], host_addr, + host_addr->sa_len); + clnt_cache_time[clnt_cache_next_to_use] = time_now.tv_sec; + if (++clnt_cache_next_to_use > CLIENT_CACHE_SIZE) + clnt_cache_next_to_use = 0; + + /* + * Disable the default timeout, so we can specify our own in calls + * to clnt_call(). (Note that the timeout is a different concept + * from the retry period set in clnt_udp_create() above.) + */ + retry_time.tv_sec = -1; + retry_time.tv_usec = -1; + clnt_control(client, CLSET_TIMEOUT, (char *)&retry_time); + + if (debug_level > 3) + syslog(LOG_DEBUG, "Created CLIENT* for %s", host); + return client; +} + + +/* transmit_result --------------------------------------------------------- */ +/* + * Purpose: Transmit result for nlm_xxx_msg pseudo-RPCs + * Returns: Nothing - we have no idea if the datagram got there + * Notes: clnt_call() will always fail (with timeout) as we are + * calling it with timeout 0 as a hack to just issue a datagram + * without expecting a result + */ +void +transmit_result(opcode, result, addr) + int opcode; + nlm_res *result; + struct sockaddr *addr; +{ + static char dummy; + CLIENT *cli; + struct timeval timeo; + int success; + + if ((cli = get_client(addr, NLM_VERS)) != NULL) { + timeo.tv_sec = 0; /* No timeout - not expecting response */ + timeo.tv_usec = 0; + + success = clnt_call(cli, opcode, xdr_nlm_res, result, xdr_void, + &dummy, timeo); + + if (debug_level > 2) + syslog(LOG_DEBUG, "clnt_call returns %d(%s)", + success, clnt_sperrno(success)); + } +} +/* transmit4_result --------------------------------------------------------- */ +/* + * Purpose: Transmit result for nlm4_xxx_msg pseudo-RPCs + * Returns: Nothing - we have no idea if the datagram got there + * Notes: clnt_call() will always fail (with timeout) as we are + * calling it with timeout 0 as a hack to just issue a datagram + * without expecting a result + */ +void +transmit4_result(opcode, result, addr) + int opcode; + nlm4_res *result; + struct sockaddr *addr; +{ + static char dummy; + CLIENT *cli; + struct timeval timeo; + int success; + + if ((cli = get_client(addr, NLM_VERS4)) != NULL) { + timeo.tv_sec = 0; /* No timeout - not expecting response */ + timeo.tv_usec = 0; + + success = clnt_call(cli, opcode, xdr_nlm4_res, result, xdr_void, + &dummy, timeo); + + if (debug_level > 2) + syslog(LOG_DEBUG, "clnt_call returns %d(%s)", + success, clnt_sperrno(success)); + } +} + +/* + * converts a struct nlm_lock to struct nlm4_lock + */ +static void nlmtonlm4 __P((struct nlm_lock *, struct nlm4_lock *)); +static void +nlmtonlm4(arg, arg4) + struct nlm_lock *arg; + struct nlm4_lock *arg4; +{ + memcpy(arg4, arg, sizeof(nlm_lock)); + arg4->l_offset = arg->l_offset; + arg4->l_len = arg->l_len; +} +/* ------------------------------------------------------------------------- */ +/* + * Functions for Unix<->Unix locking (ie. monitored locking, with rpc.statd + * involved to ensure reclaim of locks after a crash of the "stateless" + * server. + * + * These all come in two flavours - nlm_xxx() and nlm_xxx_msg(). + * The first are standard RPCs with argument and result. + * The nlm_xxx_msg() calls implement exactly the same functions, but + * use two pseudo-RPCs (one in each direction). These calls are NOT + * standard use of the RPC protocol in that they do not return a result + * at all (NB. this is quite different from returning a void result). + * The effect of this is to make the nlm_xxx_msg() calls simple unacknowledged + * datagrams, requiring higher-level code to perform retries. + * + * Despite the disadvantages of the nlm_xxx_msg() approach (some of which + * are documented in the comments to get_client() above), this is the + * interface used by all current commercial NFS implementations + * [Solaris, SCO, AIX etc.]. This is presumed to be because these allow + * implementations to continue using the standard RPC libraries, while + * avoiding the block-until-result nature of the library interface. + * + * No client implementations have been identified so far that make use + * of the true RPC version (early SunOS releases would be a likely candidate + * for testing). + */ + +/* nlm_test ---------------------------------------------------------------- */ +/* + * Purpose: Test whether a specified lock would be granted if requested + * Returns: nlm_granted (or error code) + * Notes: + */ +nlm_testres * +nlm_test_1_svc(arg, rqstp) + nlm_testargs *arg; + struct svc_req *rqstp; +{ + static nlm_testres res; + struct nlm4_lock arg4; + struct nlm4_holder *holder; + nlmtonlm4(&arg->alock, &arg4); + + if (debug_level) + log_from_addr("nlm_test", rqstp); + + holder = testlock(&arg4, 0); + /* + * Copy the cookie from the argument into the result. Note that this + * is slightly hazardous, as the structure contains a pointer to a + * malloc()ed buffer that will get freed by the caller. However, the + * main function transmits the result before freeing the argument + * so it is in fact safe. + */ + res.cookie = arg->cookie; + if (holder == NULL) { + res.stat.stat = nlm_granted; + } else { + res.stat.stat = nlm_denied; + memcpy(&res.stat.nlm_testrply_u.holder, holder, + sizeof(struct nlm_holder)); + res.stat.nlm_testrply_u.holder.l_offset = holder->l_offset; + res.stat.nlm_testrply_u.holder.l_len = holder->l_len; + } + return (&res); +} + +void * +nlm_test_msg_1_svc(arg, rqstp) + nlm_testargs *arg; + struct svc_req *rqstp; +{ + nlm_testres res; + static char dummy; + struct sockaddr *addr; + CLIENT *cli; + int success; + struct timeval timeo; + struct nlm4_lock arg4; + struct nlm4_holder *holder; + + nlmtonlm4(&arg->alock, &arg4); + + if (debug_level) + log_from_addr("nlm_test_msg", rqstp); + + holder = testlock(&arg4, 0); + + res.cookie = arg->cookie; + if (holder == NULL) { + res.stat.stat = nlm_granted; + } else { + res.stat.stat = nlm_denied; + memcpy(&res.stat.nlm_testrply_u.holder, holder, + sizeof(struct nlm_holder)); + res.stat.nlm_testrply_u.holder.l_offset = holder->l_offset; + res.stat.nlm_testrply_u.holder.l_len = holder->l_len; + } + + /* + * nlm_test has different result type to the other operations, so + * can't use transmit_result() in this case + */ + addr = svc_getrpccaller(rqstp->rq_xprt)->buf; + if ((cli = get_client(addr, NLM_VERS)) != NULL) { + timeo.tv_sec = 0; /* No timeout - not expecting response */ + timeo.tv_usec = 0; + + success = clnt_call(cli, NLM_TEST_RES, xdr_nlm_testres, + &res, xdr_void, &dummy, timeo); + + if (debug_level > 2) + syslog(LOG_DEBUG, "clnt_call returns %d", success); + } + return (NULL); +} + +/* nlm_lock ---------------------------------------------------------------- */ +/* + * Purposes: Establish a lock + * Returns: granted, denied or blocked + * Notes: *** grace period support missing + */ +nlm_res * +nlm_lock_1_svc(arg, rqstp) + nlm_lockargs *arg; + struct svc_req *rqstp; +{ + static nlm_res res; + struct nlm4_lockargs arg4; + nlmtonlm4(&arg->alock, &arg4.alock); + arg4.cookie = arg->cookie; + arg4.block = arg->block; + arg4.exclusive = arg->exclusive; + arg4.reclaim = arg->reclaim; + arg4.state = arg->state; + + if (debug_level) + log_from_addr("nlm_lock", rqstp); + + /* copy cookie from arg to result. See comment in nlm_test_1() */ + res.cookie = arg->cookie; + + res.stat.stat = getlock(&arg4, rqstp, LOCK_MON); + return (&res); +} + +void * +nlm_lock_msg_1_svc(arg, rqstp) + nlm_lockargs *arg; + struct svc_req *rqstp; +{ + static nlm_res res; + struct nlm4_lockargs arg4; + + nlmtonlm4(&arg->alock, &arg4.alock); + arg4.cookie = arg->cookie; + arg4.block = arg->block; + arg4.exclusive = arg->exclusive; + arg4.reclaim = arg->reclaim; + arg4.state = arg->state; + + if (debug_level) + log_from_addr("nlm_lock_msg", rqstp); + + res.cookie = arg->cookie; + res.stat.stat = getlock(&arg4, rqstp, LOCK_ASYNC | LOCK_MON); + transmit_result(NLM_LOCK_RES, &res, + (struct sockaddr *)svc_getcaller(rqstp->rq_xprt)); + + return (NULL); +} + +/* nlm_cancel -------------------------------------------------------------- */ +/* + * Purpose: Cancel a blocked lock request + * Returns: granted or denied + * Notes: + */ +nlm_res * +nlm_cancel_1_svc(arg, rqstp) + nlm_cancargs *arg; + struct svc_req *rqstp; +{ + static nlm_res res; + struct nlm4_lock arg4; + + nlmtonlm4(&arg->alock, &arg4); + + if (debug_level) + log_from_addr("nlm_cancel", rqstp); + + /* copy cookie from arg to result. See comment in nlm_test_1() */ + res.cookie = arg->cookie; + + /* + * Since at present we never return 'nlm_blocked', there can never be + * a lock to cancel, so this call always fails. + */ + res.stat.stat = unlock(&arg4, LOCK_CANCEL); + return (&res); +} + +void * +nlm_cancel_msg_1_svc(arg, rqstp) + nlm_cancargs *arg; + struct svc_req *rqstp; +{ + static nlm_res res; + struct nlm4_lock arg4; + + nlmtonlm4(&arg->alock, &arg4); + + if (debug_level) + log_from_addr("nlm_cancel_msg", rqstp); + + res.cookie = arg->cookie; + /* + * Since at present we never return 'nlm_blocked', there can never be + * a lock to cancel, so this call always fails. + */ + res.stat.stat = unlock(&arg4, LOCK_CANCEL); + transmit_result(NLM_CANCEL_RES, &res, + (struct sockaddr *)svc_getcaller(rqstp->rq_xprt)); + return (NULL); +} + +/* nlm_unlock -------------------------------------------------------------- */ +/* + * Purpose: Release an existing lock + * Returns: Always granted, unless during grace period + * Notes: "no such lock" error condition is ignored, as the + * protocol uses unreliable UDP datagrams, and may well + * re-try an unlock that has already succeeded. + */ +nlm_res * +nlm_unlock_1_svc(arg, rqstp) + nlm_unlockargs *arg; + struct svc_req *rqstp; +{ + static nlm_res res; + struct nlm4_lock arg4; + + nlmtonlm4(&arg->alock, &arg4); + + if (debug_level) + log_from_addr("nlm_unlock", rqstp); + + res.stat.stat = unlock(&arg4, 0); + res.cookie = arg->cookie; + + return (&res); +} + +void * +nlm_unlock_msg_1_svc(arg, rqstp) + nlm_unlockargs *arg; + struct svc_req *rqstp; +{ + static nlm_res res; + struct nlm4_lock arg4; + + nlmtonlm4(&arg->alock, &arg4); + + if (debug_level) + log_from_addr("nlm_unlock_msg", rqstp); + + res.stat.stat = unlock(&arg4, 0); + res.cookie = arg->cookie; + + transmit_result(NLM_UNLOCK_RES, &res, + (struct sockaddr *)svc_getcaller(rqstp->rq_xprt)); + return (NULL); +} + +/* ------------------------------------------------------------------------- */ +/* + * Client-side pseudo-RPCs for results. Note that for the client there + * are only nlm_xxx_msg() versions of each call, since the 'real RPC' + * version returns the results in the RPC result, and so the client + * does not normally receive incoming RPCs. + * + * The exception to this is nlm_granted(), which is genuinely an RPC + * call from the server to the client - a 'call-back' in normal procedure + * call terms. + */ + +/* nlm_granted ------------------------------------------------------------- */ +/* + * Purpose: Receive notification that formerly blocked lock now granted + * Returns: always success ('granted') + * Notes: + */ +nlm_res * +nlm_granted_1_svc(arg, rqstp) + nlm_testargs *arg; + struct svc_req *rqstp; +{ + static nlm_res res; + + if (debug_level) + log_from_addr("nlm_granted", rqstp); + + /* copy cookie from arg to result. See comment in nlm_test_1() */ + res.cookie = arg->cookie; + + res.stat.stat = nlm_granted; + return (&res); +} + +void * +nlm_granted_msg_1_svc(arg, rqstp) + nlm_testargs *arg; + struct svc_req *rqstp; +{ + static nlm_res res; + + if (debug_level) + log_from_addr("nlm_granted_msg", rqstp); + + res.cookie = arg->cookie; + res.stat.stat = nlm_granted; + transmit_result(NLM_GRANTED_RES, &res, + (struct sockaddr *)svc_getcaller(rqstp->rq_xprt)); + return (NULL); +} + +/* nlm_test_res ------------------------------------------------------------ */ +/* + * Purpose: Accept result from earlier nlm_test_msg() call + * Returns: Nothing + */ +void * +nlm_test_res_1_svc(arg, rqstp) + nlm_testres *arg; + struct svc_req *rqstp; +{ + if (debug_level) + log_from_addr("nlm_test_res", rqstp); + return (NULL); +} + +/* nlm_lock_res ------------------------------------------------------------ */ +/* + * Purpose: Accept result from earlier nlm_lock_msg() call + * Returns: Nothing + */ +void * +nlm_lock_res_1_svc(arg, rqstp) + nlm_res *arg; + struct svc_req *rqstp; +{ + if (debug_level) + log_from_addr("nlm_lock_res", rqstp); + + return (NULL); +} + +/* nlm_cancel_res ---------------------------------------------------------- */ +/* + * Purpose: Accept result from earlier nlm_cancel_msg() call + * Returns: Nothing + */ +void * +nlm_cancel_res_1_svc(arg, rqstp) + nlm_res *arg; + struct svc_req *rqstp; +{ + if (debug_level) + log_from_addr("nlm_cancel_res", rqstp); + return (NULL); +} + +/* nlm_unlock_res ---------------------------------------------------------- */ +/* + * Purpose: Accept result from earlier nlm_unlock_msg() call + * Returns: Nothing + */ +void * +nlm_unlock_res_1_svc(arg, rqstp) + nlm_res *arg; + struct svc_req *rqstp; +{ + if (debug_level) + log_from_addr("nlm_unlock_res", rqstp); + return (NULL); +} + +/* nlm_granted_res --------------------------------------------------------- */ +/* + * Purpose: Accept result from earlier nlm_granted_msg() call + * Returns: Nothing + */ +void * +nlm_granted_res_1_svc(arg, rqstp) + nlm_res *arg; + struct svc_req *rqstp; +{ + if (debug_level) + log_from_addr("nlm_granted_res", rqstp); + return (NULL); +} + +/* ------------------------------------------------------------------------- */ +/* + * Calls for PCNFS locking (aka non-monitored locking, no involvement + * of rpc.statd). + * + * These are all genuine RPCs - no nlm_xxx_msg() nonsense here. + */ + +/* nlm_share --------------------------------------------------------------- */ +/* + * Purpose: Establish a DOS-style lock + * Returns: success or failure + * Notes: Blocking locks are not supported - client is expected + * to retry if required. + */ +nlm_shareres * +nlm_share_3_svc(arg, rqstp) + nlm_shareargs *arg; + struct svc_req *rqstp; +{ + static nlm_shareres res; + + if (debug_level) + log_from_addr("nlm_share", rqstp); + + res.cookie = arg->cookie; + res.stat = nlm_granted; + res.sequence = 1234356; /* X/Open says this field is ignored? */ + return (&res); +} + +/* nlm_unshare ------------------------------------------------------------ */ +/* + * Purpose: Release a DOS-style lock + * Returns: nlm_granted, unless in grace period + * Notes: + */ +nlm_shareres * +nlm_unshare_3_svc(arg, rqstp) + nlm_shareargs *arg; + struct svc_req *rqstp; +{ + static nlm_shareres res; + + if (debug_level) + log_from_addr("nlm_unshare", rqstp); + + res.cookie = arg->cookie; + res.stat = nlm_granted; + res.sequence = 1234356; /* X/Open says this field is ignored? */ + return (&res); +} + +/* nlm_nm_lock ------------------------------------------------------------ */ +/* + * Purpose: non-monitored version of nlm_lock() + * Returns: as for nlm_lock() + * Notes: These locks are in the same style as the standard nlm_lock, + * but the rpc.statd should not be called to establish a + * monitor for the client machine, since that machine is + * declared not to be running a rpc.statd, and so would not + * respond to the statd protocol. + */ +nlm_res * +nlm_nm_lock_3_svc(arg, rqstp) + nlm_lockargs *arg; + struct svc_req *rqstp; +{ + static nlm_res res; + + if (debug_level) + log_from_addr("nlm_nm_lock", rqstp); + + /* copy cookie from arg to result. See comment in nlm_test_1() */ + res.cookie = arg->cookie; + res.stat.stat = nlm_granted; + return (&res); +} + +/* nlm_free_all ------------------------------------------------------------ */ +/* + * Purpose: Release all locks held by a named client + * Returns: Nothing + * Notes: Potential denial of service security problem here - the + * locks to be released are specified by a host name, independent + * of the address from which the request has arrived. + * Should probably be rejected if the named host has been + * using monitored locks. + */ +void * +nlm_free_all_3_svc(arg, rqstp) + nlm_notify *arg; + struct svc_req *rqstp; +{ + static char dummy; + + if (debug_level) + log_from_addr("nlm_free_all", rqstp); + return (&dummy); +} + +/* calls for nlm version 4 (NFSv3) */ +/* nlm_test ---------------------------------------------------------------- */ +/* + * Purpose: Test whether a specified lock would be granted if requested + * Returns: nlm_granted (or error code) + * Notes: + */ +nlm4_testres * +nlm4_test_4_svc(arg, rqstp) + nlm4_testargs *arg; + struct svc_req *rqstp; +{ + static nlm4_testres res; + struct nlm4_holder *holder; + + if (debug_level) + log_from_addr("nlm4_test", rqstp); + + holder = testlock(&arg->alock, LOCK_V4); + + /* + * Copy the cookie from the argument into the result. Note that this + * is slightly hazardous, as the structure contains a pointer to a + * malloc()ed buffer that will get freed by the caller. However, the + * main function transmits the result before freeing the argument + * so it is in fact safe. + */ + res.cookie = arg->cookie; + if (holder == NULL) { + res.stat.stat = nlm4_granted; + } else { + res.stat.stat = nlm4_denied; + memcpy(&res.stat.nlm4_testrply_u.holder, holder, + sizeof(struct nlm4_holder)); + } + return (&res); +} + +void * +nlm4_test_msg_4_svc(arg, rqstp) + nlm4_testargs *arg; + struct svc_req *rqstp; +{ + nlm4_testres res; + static char dummy; + struct sockaddr *addr; + CLIENT *cli; + int success; + struct timeval timeo; + struct nlm4_holder *holder; + + if (debug_level) + log_from_addr("nlm4_test_msg", rqstp); + + holder = testlock(&arg->alock, LOCK_V4); + + res.cookie = arg->cookie; + if (holder == NULL) { + res.stat.stat = nlm4_granted; + } else { + res.stat.stat = nlm4_denied; + memcpy(&res.stat.nlm4_testrply_u.holder, holder, + sizeof(struct nlm4_holder)); + } + + /* + * nlm_test has different result type to the other operations, so + * can't use transmit4_result() in this case + */ + addr = svc_getrpccaller(rqstp->rq_xprt)->buf; + if ((cli = get_client(addr, NLM_VERS4)) != NULL) { + timeo.tv_sec = 0; /* No timeout - not expecting response */ + timeo.tv_usec = 0; + + success = clnt_call(cli, NLM4_TEST_RES, xdr_nlm4_testres, + &res, xdr_void, &dummy, timeo); + + if (debug_level > 2) + syslog(LOG_DEBUG, "clnt_call returns %d", success); + } + return (NULL); +} + +/* nlm_lock ---------------------------------------------------------------- */ +/* + * Purposes: Establish a lock + * Returns: granted, denied or blocked + * Notes: *** grace period support missing + */ +nlm4_res * +nlm4_lock_4_svc(arg, rqstp) + nlm4_lockargs *arg; + struct svc_req *rqstp; +{ + static nlm4_res res; + + if (debug_level) + log_from_addr("nlm4_lock", rqstp); + + /* copy cookie from arg to result. See comment in nlm_test_4() */ + res.cookie = arg->cookie; + + res.stat.stat = getlock(arg, rqstp, LOCK_MON | LOCK_V4); + return (&res); +} + +void * +nlm4_lock_msg_4_svc(arg, rqstp) + nlm4_lockargs *arg; + struct svc_req *rqstp; +{ + static nlm4_res res; + + if (debug_level) + log_from_addr("nlm4_lock_msg", rqstp); + + res.cookie = arg->cookie; + res.stat.stat = getlock(arg, rqstp, LOCK_MON | LOCK_ASYNC | LOCK_V4); + transmit4_result(NLM4_LOCK_RES, &res, + (struct sockaddr *)svc_getcaller(rqstp->rq_xprt)); + + return (NULL); +} + +/* nlm_cancel -------------------------------------------------------------- */ +/* + * Purpose: Cancel a blocked lock request + * Returns: granted or denied + * Notes: + */ +nlm4_res * +nlm4_cancel_4_svc(arg, rqstp) + nlm4_cancargs *arg; + struct svc_req *rqstp; +{ + static nlm4_res res; + + if (debug_level) + log_from_addr("nlm4_cancel", rqstp); + + /* copy cookie from arg to result. See comment in nlm_test_1() */ + res.cookie = arg->cookie; + + /* + * Since at present we never return 'nlm_blocked', there can never be + * a lock to cancel, so this call always fails. + */ + res.stat.stat = unlock(&arg->alock, LOCK_CANCEL); + return (&res); +} + +void * +nlm4_cancel_msg_4_svc(arg, rqstp) + nlm4_cancargs *arg; + struct svc_req *rqstp; +{ + static nlm4_res res; + + if (debug_level) + log_from_addr("nlm4_cancel_msg", rqstp); + + res.cookie = arg->cookie; + /* + * Since at present we never return 'nlm_blocked', there can never be + * a lock to cancel, so this call always fails. + */ + res.stat.stat = unlock(&arg->alock, LOCK_CANCEL | LOCK_V4); + transmit4_result(NLM4_CANCEL_RES, &res, + (struct sockaddr *)svc_getcaller(rqstp->rq_xprt)); + return (NULL); +} + +/* nlm_unlock -------------------------------------------------------------- */ +/* + * Purpose: Release an existing lock + * Returns: Always granted, unless during grace period + * Notes: "no such lock" error condition is ignored, as the + * protocol uses unreliable UDP datagrams, and may well + * re-try an unlock that has already succeeded. + */ +nlm4_res * +nlm4_unlock_4_svc(arg, rqstp) + nlm4_unlockargs *arg; + struct svc_req *rqstp; +{ + static nlm4_res res; + + if (debug_level) + log_from_addr("nlm4_unlock", rqstp); + + res.stat.stat = unlock(&arg->alock, LOCK_V4); + res.cookie = arg->cookie; + + return (&res); +} + +void * +nlm4_unlock_msg_4_svc(arg, rqstp) + nlm4_unlockargs *arg; + struct svc_req *rqstp; +{ + static nlm4_res res; + + if (debug_level) + log_from_addr("nlm4_unlock_msg", rqstp); + + res.stat.stat = unlock(&arg->alock, LOCK_V4); + res.cookie = arg->cookie; + + transmit4_result(NLM4_UNLOCK_RES, &res, + (struct sockaddr *)svc_getcaller(rqstp->rq_xprt)); + return (NULL); +} + +/* ------------------------------------------------------------------------- */ +/* + * Client-side pseudo-RPCs for results. Note that for the client there + * are only nlm_xxx_msg() versions of each call, since the 'real RPC' + * version returns the results in the RPC result, and so the client + * does not normally receive incoming RPCs. + * + * The exception to this is nlm_granted(), which is genuinely an RPC + * call from the server to the client - a 'call-back' in normal procedure + * call terms. + */ + +/* nlm_granted ------------------------------------------------------------- */ +/* + * Purpose: Receive notification that formerly blocked lock now granted + * Returns: always success ('granted') + * Notes: + */ +nlm4_res * +nlm4_granted_4_svc(arg, rqstp) + nlm4_testargs *arg; + struct svc_req *rqstp; +{ + static nlm4_res res; + + if (debug_level) + log_from_addr("nlm4_granted", rqstp); + + /* copy cookie from arg to result. See comment in nlm_test_1() */ + res.cookie = arg->cookie; + + res.stat.stat = nlm4_granted; + return (&res); +} + +void * +nlm4_granted_msg_4_svc(arg, rqstp) + nlm4_testargs *arg; + struct svc_req *rqstp; +{ + static nlm4_res res; + + if (debug_level) + log_from_addr("nlm4_granted_msg", rqstp); + + res.cookie = arg->cookie; + res.stat.stat = nlm4_granted; + transmit4_result(NLM4_GRANTED_RES, &res, + (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf); + return (NULL); +} + +/* nlm_test_res ------------------------------------------------------------ */ +/* + * Purpose: Accept result from earlier nlm_test_msg() call + * Returns: Nothing + */ +void * +nlm4_test_res_4_svc(arg, rqstp) + nlm4_testres *arg; + struct svc_req *rqstp; +{ + if (debug_level) + log_from_addr("nlm4_test_res", rqstp); + return (NULL); +} + +/* nlm_lock_res ------------------------------------------------------------ */ +/* + * Purpose: Accept result from earlier nlm_lock_msg() call + * Returns: Nothing + */ +void * +nlm4_lock_res_4_svc(arg, rqstp) + nlm4_res *arg; + struct svc_req *rqstp; +{ + if (debug_level) + log_from_addr("nlm4_lock_res", rqstp); + + return (NULL); +} + +/* nlm_cancel_res ---------------------------------------------------------- */ +/* + * Purpose: Accept result from earlier nlm_cancel_msg() call + * Returns: Nothing + */ +void * +nlm4_cancel_res_4_svc(arg, rqstp) + nlm4_res *arg; + struct svc_req *rqstp; +{ + if (debug_level) + log_from_addr("nlm4_cancel_res", rqstp); + return (NULL); +} + +/* nlm_unlock_res ---------------------------------------------------------- */ +/* + * Purpose: Accept result from earlier nlm_unlock_msg() call + * Returns: Nothing + */ +void * +nlm4_unlock_res_4_svc(arg, rqstp) + nlm4_res *arg; + struct svc_req *rqstp; +{ + if (debug_level) + log_from_addr("nlm4_unlock_res", rqstp); + return (NULL); +} + +/* nlm_granted_res --------------------------------------------------------- */ +/* + * Purpose: Accept result from earlier nlm_granted_msg() call + * Returns: Nothing + */ +void * +nlm4_granted_res_4_svc(arg, rqstp) + nlm4_res *arg; + struct svc_req *rqstp; +{ + if (debug_level) + log_from_addr("nlm4_granted_res", rqstp); + return (NULL); +} + +/* ------------------------------------------------------------------------- */ +/* + * Calls for PCNFS locking (aka non-monitored locking, no involvement + * of rpc.statd). + * + * These are all genuine RPCs - no nlm_xxx_msg() nonsense here. + */ + +/* nlm_share --------------------------------------------------------------- */ +/* + * Purpose: Establish a DOS-style lock + * Returns: success or failure + * Notes: Blocking locks are not supported - client is expected + * to retry if required. + */ +nlm4_shareres * +nlm4_share_4_svc(arg, rqstp) + nlm4_shareargs *arg; + struct svc_req *rqstp; +{ + static nlm4_shareres res; + + if (debug_level) + log_from_addr("nlm4_share", rqstp); + + res.cookie = arg->cookie; + res.stat = nlm4_granted; + res.sequence = 1234356; /* X/Open says this field is ignored? */ + return (&res); +} + +/* nlm4_unshare ------------------------------------------------------------ */ +/* + * Purpose: Release a DOS-style lock + * Returns: nlm_granted, unless in grace period + * Notes: + */ +nlm4_shareres * +nlm4_unshare_4_svc(arg, rqstp) + nlm4_shareargs *arg; + struct svc_req *rqstp; +{ + static nlm4_shareres res; + + if (debug_level) + log_from_addr("nlm_unshare", rqstp); + + res.cookie = arg->cookie; + res.stat = nlm4_granted; + res.sequence = 1234356; /* X/Open says this field is ignored? */ + return (&res); +} + +/* nlm4_nm_lock ------------------------------------------------------------ */ +/* + * Purpose: non-monitored version of nlm4_lock() + * Returns: as for nlm4_lock() + * Notes: These locks are in the same style as the standard nlm4_lock, + * but the rpc.statd should not be called to establish a + * monitor for the client machine, since that machine is + * declared not to be running a rpc.statd, and so would not + * respond to the statd protocol. + */ +nlm4_res * +nlm4_nm_lock_4_svc(arg, rqstp) + nlm4_lockargs *arg; + struct svc_req *rqstp; +{ + static nlm4_res res; + + if (debug_level) + log_from_addr("nlm4_nm_lock", rqstp); + + /* copy cookie from arg to result. See comment in nlm4_test_1() */ + res.cookie = arg->cookie; + res.stat.stat = nlm4_granted; + return (&res); +} + +/* nlm4_free_all ------------------------------------------------------------ */ +/* + * Purpose: Release all locks held by a named client + * Returns: Nothing + * Notes: Potential denial of service security problem here - the + * locks to be released are specified by a host name, independent + * of the address from which the request has arrived. + * Should probably be rejected if the named host has been + * using monitored locks. + */ +void * +nlm4_free_all_4_svc(arg, rqstp) + nlm_notify *arg; + struct svc_req *rqstp; +{ + static char dummy; + + if (debug_level) + log_from_addr("nlm4_free_all", rqstp); + return (&dummy); +} + +/* nlm_sm_notify --------------------------------------------------------- */ +/* + * Purpose: called by rpc.statd when a monitored host state changes. + * Returns: Nothing + */ +void * +nlm_sm_notify_0_svc(arg, rqstp) + struct nlm_sm_status *arg; + struct svc_req *rqstp; +{ + static char dummy; + notify(arg->mon_name, arg->state); + return (&dummy); +} diff --git a/usr.sbin/rpc.lockd/lockd.c b/usr.sbin/rpc.lockd/lockd.c index ac328569126e..e0ac5cf52994 100644 --- a/usr.sbin/rpc.lockd/lockd.c +++ b/usr.sbin/rpc.lockd/lockd.c @@ -1,3 +1,6 @@ +/* $NetBSD: lockd.c,v 1.7 2000/08/12 18:08:44 thorpej Exp $ */ +/* $FreeBSD$ */ + /* * Copyright (c) 1995 * A.R. Gordon (andrew.gordon@net-tel.co.uk). All rights reserved. @@ -31,77 +34,193 @@ * */ +#include <sys/cdefs.h> #ifndef lint -static const char rcsid[] = - "$FreeBSD$"; -#endif /* not lint */ +__RCSID("$NetBSD: lockd.c,v 1.7 2000/08/12 18:08:44 thorpej Exp $"); +#endif + +/* + * main() function for NFS lock daemon. Most of the code in this + * file was generated by running rpcgen /usr/include/rpcsvc/nlm_prot.x. + * + * The actual program logic is in the file lock_proc.c + */ -/* main() function for NFS lock daemon. Most of the code in this */ -/* file was generated by running rpcgen /usr/include/rpcsvc/nlm_prot.x */ -/* The actual program logic is in the file procs.c */ +#include <sys/types.h> +#include <sys/socket.h> #include <err.h> +#include <stdio.h> #include <stdlib.h> +#include <errno.h> +#include <syslog.h> +#include <signal.h> #include <string.h> +#include <unistd.h> +#include <libutil.h> +#include <netconfig.h> + #include <rpc/rpc.h> -#include <rpc/pmap_clnt.h> +#include <rpcsvc/sm_inter.h> + #include "lockd.h" +#include <rpcsvc/nlm_prot.h> + +int debug_level = 0; /* 0 = no debugging syslog() calls */ +int _rpcsvcdirty = 0; -void nlm_prog_1 __P((struct svc_req *, SVCXPRT *)); -void nlm_prog_3 __P((struct svc_req *, SVCXPRT *)); -static void usage __P((void)); +int grace_expired; -int debug_level = 0; /* Zero means no debugging syslog() calls */ +int main __P((int, char **)); +void nlm_prog_0 __P((struct svc_req *, SVCXPRT *)); +void nlm_prog_1 __P((struct svc_req *, SVCXPRT *)); +void nlm_prog_3 __P((struct svc_req *, SVCXPRT *)); +void nlm_prog_4 __P((struct svc_req *, SVCXPRT *)); +void usage __P((void)); + +void sigalarm_handler __P((int)); + +char *transports[] = { "udp", "tcp", "udp6", "tcp6" }; int -main(int argc, char **argv) +main(argc, argv) + int argc; + char **argv; { - SVCXPRT *transp; + SVCXPRT *transp; + int ch, i, maxindex, s; + struct sigaction sigchild, sigalarm; + int grace_period = 30; + struct netconfig *nconf; + + while ((ch = getopt(argc, argv, "d:g:")) != (-1)) { + switch (ch) { + case 'd': + debug_level = atoi(optarg); + if (!debug_level) { + usage(); + /* NOTREACHED */ + } + break; + case 'g': + grace_period = atoi(optarg); + if (!grace_period) { + usage(); + /* NOTREACHED */ + } + break; + default: + case '?': + usage(); + /* NOTREACHED */ + } + } + if (geteuid()) { /* This command allowed only to root */ + fprintf(stderr, "Sorry. You are not superuser\n"); + exit(1); + } + + (void)rpcb_unset(NLM_PROG, NLM_SM, NULL); + (void)rpcb_unset(NLM_PROG, NLM_VERS, NULL); + (void)rpcb_unset(NLM_PROG, NLM_VERSX, NULL); + (void)rpcb_unset(NLM_PROG, NLM_VERS4, NULL); - if (argc > 1) - { - if (strncmp(argv[1], "-d", 2)) - usage(); - if (argc > 2) debug_level = atoi(argv[2]); - else debug_level = atoi(argv[1] + 2); - /* Ensure at least some debug if -d with no specified level */ - if (!debug_level) debug_level = 1; - } + /* + * Check if IPv6 support is present. + */ + s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (s < 0) + maxindex = 2; + else { + close(s); + maxindex = 4; + } - (void)pmap_unset(NLM_PROG, NLM_VERS); - (void)pmap_unset(NLM_PROG, NLM_VERSX); + for (i = 0; i < maxindex; i++) { + nconf = getnetconfigent(transports[i]); + if (nconf == NULL) + errx(1, "cannot get udp netconf."); - transp = svcudp_create(RPC_ANYSOCK); - if (transp == NULL) - errx(1, "cannot create udp service"); - if (!svc_register(transp, NLM_PROG, NLM_VERS, nlm_prog_1, IPPROTO_UDP)) - errx(1, "unable to register (NLM_PROG, NLM_VERS, udp)"); - if (!svc_register(transp, NLM_PROG, NLM_VERSX, nlm_prog_3, IPPROTO_UDP)) - errx(1, "unable to register (NLM_PROG, NLM_VERSX, udp)"); + transp = svc_tli_create(RPC_ANYFD, nconf, NULL, 0, 0); + if (transp == NULL) { + errx(1, "cannot create %s service.", transports[i]); + /* NOTREACHED */ + } + if (!svc_reg(transp, NLM_PROG, NLM_SM, nlm_prog_0, nconf)) { + errx(1, "unable to register (NLM_PROG, NLM_SM, %s)", + transports[i]); + /* NOTREACHED */ + } + if (!svc_reg(transp, NLM_PROG, NLM_VERS, nlm_prog_1, nconf)) { + errx(1, "unable to register (NLM_PROG, NLM_VERS, %s)", + transports[i]); + /* NOTREACHED */ + } + if (!svc_reg(transp, NLM_PROG, NLM_VERSX, nlm_prog_3, nconf)) { + errx(1, "unable to register (NLM_PROG, NLM_VERSX, %s)", + transports[i]); + /* NOTREACHED */ + } + if (!svc_reg(transp, NLM_PROG, NLM_VERS4, nlm_prog_4, nconf)) { + errx(1, "unable to register (NLM_PROG, NLM_VERS4, %s)", + transports[i]); + /* NOTREACHED */ + } + freenetconfigent(nconf); + } - transp = svctcp_create(RPC_ANYSOCK, 0, 0); - if (transp == NULL) - errx(1, "cannot create tcp service"); - if (!svc_register(transp, NLM_PROG, NLM_VERS, nlm_prog_1, IPPROTO_TCP)) - errx(1, "unable to register (NLM_PROG, NLM_VERS, tcp)"); - if (!svc_register(transp, NLM_PROG, NLM_VERSX, nlm_prog_3, IPPROTO_TCP)) - errx(1, "unable to register (NLM_PROG, NLM_VERSX, tcp)"); + /* + * Note that it is NOT sensible to run this program from inetd - the + * protocol assumes that it will run immediately at boot time. + */ + if (daemon(0, 0)) { + err(1, "cannot fork"); + /* NOTREACHED */ + } - /* Note that it is NOT sensible to run this program from inetd - the */ - /* protocol assumes that it will run immediately at boot time. */ - if (daemon(0,0)) - err(1, "fork"); - openlog("rpc.lockd", 0, LOG_DAEMON); - if (debug_level) syslog(LOG_INFO, "Starting, debug level %d", debug_level); - else syslog(LOG_INFO, "Starting"); + openlog("rpc.lockd", 0, LOG_DAEMON); + if (debug_level) + syslog(LOG_INFO, "Starting, debug level %d", debug_level); + else + syslog(LOG_INFO, "Starting"); - svc_run(); /* Should never return */ - exit(1); + sigchild.sa_handler = sigchild_handler; + sigemptyset(&sigchild.sa_mask); + sigchild.sa_flags = SA_RESTART; + if (sigaction(SIGCHLD, &sigchild, NULL) != 0) { + syslog(LOG_WARNING, "sigaction(SIGCHLD) failed: %s", + strerror(errno)); + exit(1); + } + sigalarm.sa_handler = sigalarm_handler; + sigemptyset(&sigalarm.sa_mask); + sigalarm.sa_flags = SA_RESETHAND; /* should only happen once */ + sigalarm.sa_flags |= SA_RESTART; + if (sigaction(SIGALRM, &sigalarm, NULL) != 0) { + syslog(LOG_WARNING, "sigaction(SIGALRM) failed: %s", + strerror(errno)); + exit(1); + } + grace_expired = 0; + if (alarm(10) < 0) { + syslog(LOG_WARNING, "alarm failed: %s", + strerror(errno)); + exit(1); + } + + svc_run(); /* Should never return */ + exit(1); +} + +void +sigalarm_handler(s) + int s; +{ + grace_expired = 1; } -static void +void usage() { - fprintf(stderr, "usage: rpc.lockd [-d [debuglevel]]\n"); - exit(1); + errx(1, "usage: rpc.lockd [-d <debuglevel>] [-g <grace period>]"); } diff --git a/usr.sbin/rpc.lockd/lockd.h b/usr.sbin/rpc.lockd/lockd.h index 39586bfd77ae..42f14f1f2956 100644 --- a/usr.sbin/rpc.lockd/lockd.h +++ b/usr.sbin/rpc.lockd/lockd.h @@ -1,3 +1,6 @@ +/* $NetBSD: lockd.h,v 1.2 2000/06/07 14:34:40 bouyer Exp $ */ +/* $FreeBSD$ */ + /* * Copyright (c) 1995 * A.R. Gordon (andrew.gordon@net-tel.co.uk). All rights reserved. @@ -31,14 +34,6 @@ * */ - - -#include <stdio.h> -#include <rpc/rpc.h> -#include <syslog.h> -#include <rpcsvc/sm_inter.h> /* protocol to talk to rpc.statd */ -#include "nlm_prot.h" /* The protocol we are implementing */ - - -/* global variables ------------------------------------------------------- */ -extern int debug_level; +extern int debug_level; +extern int grace_expired; +void sigchild_handler __P((int)); diff --git a/usr.sbin/rpc.lockd/lockd_lock.c b/usr.sbin/rpc.lockd/lockd_lock.c new file mode 100644 index 000000000000..998a2009e82c --- /dev/null +++ b/usr.sbin/rpc.lockd/lockd_lock.c @@ -0,0 +1,759 @@ +/* $NetBSD: lockd_lock.c,v 1.5 2000/11/21 03:47:41 enami Exp $ */ +/* $FreeBSD$ */ + +/* + * Copyright (c) 2000 Manuel Bouyer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <syslog.h> +#include <errno.h> +#include <string.h> +#include <signal.h> +#include <rpc/rpc.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <sys/param.h> +#include <sys/mount.h> +#include <sys/wait.h> +#include <rpcsvc/sm_inter.h> +#include <rpcsvc/nlm_prot.h> +#include "lockd_lock.h" +#include "lockd.h" + +/* A set of utilities for managing file locking */ +LIST_HEAD(lcklst_head, file_lock); +struct lcklst_head lcklst_head = LIST_HEAD_INITIALIZER(lcklst_head); + +/* struct describing a lock */ +struct file_lock { + LIST_ENTRY(file_lock) lcklst; + fhandle_t filehandle; /* NFS filehandle */ + struct sockaddr *addr; + struct nlm4_holder client; /* lock holder */ + netobj client_cookie; /* cookie sent by the client */ + char client_name[128]; + int nsm_status; /* status from the remote lock manager */ + int status; /* lock status, see below */ + int flags; /* lock flags, see lockd_lock.h */ + pid_t locker; /* pid of the child process trying to get the lock */ + int fd; /* file descriptor for this lock */ +}; + +/* lock status */ +#define LKST_LOCKED 1 /* lock is locked */ +#define LKST_WAITING 2 /* file is already locked by another host */ +#define LKST_PROCESSING 3 /* child is trying to aquire the lock */ +#define LKST_DYING 4 /* must dies when we get news from the child */ + +void lfree __P((struct file_lock *)); +enum nlm_stats do_lock __P((struct file_lock *, int)); +enum nlm_stats do_unlock __P((struct file_lock *)); +void send_granted __P((struct file_lock *, int)); +void siglock __P((void)); +void sigunlock __P((void)); + +/* list of hosts we monitor */ +LIST_HEAD(hostlst_head, host); +struct hostlst_head hostlst_head = LIST_HEAD_INITIALIZER(hostlst_head); + +/* struct describing a lock */ +struct host { + LIST_ENTRY(host) hostlst; + char name[SM_MAXSTRLEN]; + int refcnt; +}; + +void do_mon __P((char *)); + +/* + * testlock(): inform the caller if the requested lock would be granted or not + * returns NULL if lock would granted, or pointer to the current nlm4_holder + * otherwise. + */ + +struct nlm4_holder * +testlock(lock, flags) + struct nlm4_lock *lock; + int flags; +{ + struct file_lock *fl; + fhandle_t filehandle; + + /* convert lock to a local filehandle */ + memcpy(&filehandle, lock->fh.n_bytes, sizeof(filehandle)); + + siglock(); + /* search through the list for lock holder */ + for (fl = LIST_FIRST(&lcklst_head); fl != NULL; + fl = LIST_NEXT(fl, lcklst)) { + if (fl->status != LKST_LOCKED) + continue; + if (memcmp(&fl->filehandle, &filehandle, sizeof(filehandle))) + continue; + /* got it ! */ + syslog(LOG_DEBUG, "test for %s: found lock held by %s", + lock->caller_name, fl->client_name); + sigunlock(); + return (&fl->client); + } + /* not found */ + sigunlock(); + syslog(LOG_DEBUG, "test for %s: no lock found", lock->caller_name); + return NULL; +} + +/* + * getlock: try to aquire the lock. + * If file is already locked and we can sleep, put the lock in the list with + * status LKST_WAITING; it'll be processed later. + * Otherwise try to lock. If we're allowed to block, fork a child which + * will do the blocking lock. + */ +enum nlm_stats +getlock(lckarg, rqstp, flags) + nlm4_lockargs * lckarg; + struct svc_req *rqstp; + int flags; +{ + struct file_lock *fl, *newfl; + enum nlm_stats retval; + + if (grace_expired == 0 && lckarg->reclaim == 0) + return (flags & LOCK_V4) ? + nlm4_denied_grace_period : nlm_denied_grace_period; + + /* allocate new file_lock for this request */ + newfl = malloc(sizeof(struct file_lock)); + if (newfl == NULL) { + syslog(LOG_NOTICE, "malloc failed: %s", strerror(errno)); + /* failed */ + return (flags & LOCK_V4) ? + nlm4_denied_nolock : nlm_denied_nolocks; + } + if (lckarg->alock.fh.n_len != sizeof(fhandle_t)) { + syslog(LOG_DEBUG, "recieved fhandle size %d, local size %d", + lckarg->alock.fh.n_len, (int)sizeof(fhandle_t)); + } + memcpy(&newfl->filehandle, lckarg->alock.fh.n_bytes, sizeof(fhandle_t)); + newfl->addr = (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf; + newfl->client.exclusive = lckarg->exclusive; + newfl->client.svid = lckarg->alock.svid; + newfl->client.oh.n_bytes = malloc(lckarg->alock.oh.n_len); + if (newfl->client.oh.n_bytes == NULL) { + syslog(LOG_NOTICE, "malloc failed: %s", strerror(errno)); + free(newfl); + return (flags & LOCK_V4) ? + nlm4_denied_nolock : nlm_denied_nolocks; + } + newfl->client.oh.n_len = lckarg->alock.oh.n_len; + memcpy(newfl->client.oh.n_bytes, lckarg->alock.oh.n_bytes, + lckarg->alock.oh.n_len); + newfl->client.l_offset = lckarg->alock.l_offset; + newfl->client.l_len = lckarg->alock.l_len; + newfl->client_cookie.n_len = lckarg->cookie.n_len; + newfl->client_cookie.n_bytes = malloc(lckarg->cookie.n_len); + if (newfl->client_cookie.n_bytes == NULL) { + syslog(LOG_NOTICE, "malloc failed: %s", strerror(errno)); + free(newfl->client.oh.n_bytes); + free(newfl); + return (flags & LOCK_V4) ? + nlm4_denied_nolock : nlm_denied_nolocks; + } + memcpy(newfl->client_cookie.n_bytes, lckarg->cookie.n_bytes, + lckarg->cookie.n_len); + strncpy(newfl->client_name, lckarg->alock.caller_name, 128); + newfl->nsm_status = lckarg->state; + newfl->status = 0; + newfl->flags = flags; + siglock(); + /* look for a lock rq from this host for this fh */ + for (fl = LIST_FIRST(&lcklst_head); fl != NULL; + fl = LIST_NEXT(fl, lcklst)) { + if (memcmp(&newfl->filehandle, &fl->filehandle, + sizeof(fhandle_t)) == 0) { + if (strcmp(newfl->client_name, fl->client_name) == 0 && + newfl->client.svid == fl->client.svid) { + /* already locked by this host ??? */ + sigunlock(); + syslog(LOG_NOTICE, "duplicate lock from %s", + newfl->client_name); + lfree(newfl); + switch(fl->status) { + case LKST_LOCKED: + return (flags & LOCK_V4) ? + nlm4_granted : nlm_granted; + case LKST_WAITING: + case LKST_PROCESSING: + return (flags & LOCK_V4) ? + nlm4_blocked : nlm_blocked; + case LKST_DYING: + return (flags & LOCK_V4) ? + nlm4_denied : nlm_denied; + default: + syslog(LOG_NOTICE, "bad status %d", + fl->status); + return (flags & LOCK_V4) ? + nlm4_failed : nlm_denied; + } + } + /* + * We already have a lock for this file. Put this one + * in waiting state if allowed to block + */ + if (lckarg->block) { + syslog(LOG_DEBUG, "lock from %s: already " + "locked, waiting", + lckarg->alock.caller_name); + newfl->status = LKST_WAITING; + LIST_INSERT_HEAD(&lcklst_head, newfl, lcklst); + do_mon(lckarg->alock.caller_name); + sigunlock(); + return (flags & LOCK_V4) ? + nlm4_blocked : nlm_blocked; + } else { + sigunlock(); + syslog(LOG_DEBUG, "lock from %s: already " + "locked, failed", + lckarg->alock.caller_name); + lfree(newfl); + return (flags & LOCK_V4) ? + nlm4_denied : nlm_denied; + } + } + } + /* no entry for this file yet; add to list */ + LIST_INSERT_HEAD(&lcklst_head, newfl, lcklst); + /* do the lock */ + retval = do_lock(newfl, lckarg->block); + switch (retval) { + case nlm4_granted: + /* case nlm_granted: is the same as nlm4_granted */ + case nlm4_blocked: + /* case nlm_blocked: is the same as nlm4_blocked */ + do_mon(lckarg->alock.caller_name); + break; + default: + lfree(newfl); + break; + } + sigunlock(); + return retval; +} + +/* unlock a filehandle */ +enum nlm_stats +unlock(lck, flags) + nlm4_lock *lck; + int flags; +{ + struct file_lock *fl; + fhandle_t filehandle; + int err = (flags & LOCK_V4) ? nlm4_granted : nlm_granted; + + memcpy(&filehandle, lck->fh.n_bytes, sizeof(fhandle_t)); + siglock(); + for (fl = LIST_FIRST(&lcklst_head); fl != NULL; + fl = LIST_NEXT(fl, lcklst)) { + if (strcmp(fl->client_name, lck->caller_name) || + memcmp(&filehandle, &fl->filehandle, sizeof(fhandle_t)) || + fl->client.oh.n_len != lck->oh.n_len || + memcmp(fl->client.oh.n_bytes, lck->oh.n_bytes, + fl->client.oh.n_len) != 0 || + fl->client.svid != lck->svid) + continue; + /* Got it, unlock and remove from the queue */ + syslog(LOG_DEBUG, "unlock from %s: found struct, status %d", + lck->caller_name, fl->status); + switch (fl->status) { + case LKST_LOCKED: + err = do_unlock(fl); + break; + case LKST_WAITING: + /* remove from the list */ + LIST_REMOVE(fl, lcklst); + lfree(fl); + break; + case LKST_PROCESSING: + /* + * being handled by a child; will clean up + * when the child exits + */ + fl->status = LKST_DYING; + break; + case LKST_DYING: + /* nothing to do */ + break; + default: + syslog(LOG_NOTICE, "unknow status %d for %s", + fl->status, fl->client_name); + } + sigunlock(); + return err; + } + sigunlock(); + /* didn't find a matching entry; log anyway */ + syslog(LOG_NOTICE, "no matching entry for %s", + lck->caller_name); + return (flags & LOCK_V4) ? nlm4_granted : nlm_granted; +} + +void +lfree(fl) + struct file_lock *fl; +{ + free(fl->client.oh.n_bytes); + free(fl->client_cookie.n_bytes); + free(fl); +} + +void +sigchild_handler(sig) + int sig; +{ + int status; + pid_t pid; + struct file_lock *fl; + + while (1) { + pid = wait4(-1, &status, WNOHANG, NULL); + if (pid == -1) { + if (errno != ECHILD) + syslog(LOG_NOTICE, "wait failed: %s", + strerror(errno)); + else + syslog(LOG_DEBUG, "wait failed: %s", + strerror(errno)); + return; + } + if (pid == 0) { + /* no more child to handle yet */ + return; + } + /* + * if we're here we have a child that exited + * Find the associated file_lock. + */ + for (fl = LIST_FIRST(&lcklst_head); fl != NULL; + fl = LIST_NEXT(fl, lcklst)) { + if (pid == fl->locker) + break; + } + if (pid != fl->locker) { + syslog(LOG_NOTICE, "unknow child %d", pid); + } else { + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + syslog(LOG_NOTICE, "child %d failed", pid); + /* + * can't do much here; we can't reply + * anything but OK for blocked locks + * Eventually the client will time out + * and retry. + */ + do_unlock(fl); + return; + } + + /* check lock status */ + syslog(LOG_DEBUG, "processing child %d, status %d", + pid, fl->status); + switch(fl->status) { + case LKST_PROCESSING: + fl->status = LKST_LOCKED; + send_granted(fl, (fl->flags & LOCK_V4) ? + nlm4_granted : nlm_granted); + break; + case LKST_DYING: + do_unlock(fl); + break; + default: + syslog(LOG_NOTICE, "bad lock status (%d) for" + " child %d", fl->status, pid); + } + } + } +} + +/* + * + * try to aquire the lock described by fl. Eventually fock a child to do a + * blocking lock if allowed and required. + */ + +enum nlm_stats +do_lock(fl, block) + struct file_lock *fl; + int block; +{ + int lflags, error; + struct stat st; + + fl->fd = fhopen(&fl->filehandle, O_RDWR); + if (fl->fd < 0) { + switch (errno) { + case ESTALE: + error = nlm4_stale_fh; + break; + case EROFS: + error = nlm4_rofs; + break; + default: + error = nlm4_failed; + } + if ((fl->flags & LOCK_V4) == 0) + error = nlm_denied; + syslog(LOG_NOTICE, "fhopen failed (from %s): %s", + fl->client_name, strerror(errno)); + LIST_REMOVE(fl, lcklst); + return error;; + } + if (fstat(fl->fd, &st) < 0) { + syslog(LOG_NOTICE, "fstat failed (from %s): %s", + fl->client_name, strerror(errno)); + } + syslog(LOG_DEBUG, "lock from %s for file%s%s: dev %d ino %d (uid %d), " + "flags %d", + fl->client_name, fl->client.exclusive ? " (exclusive)":"", + block ? " (block)":"", + st.st_dev, st.st_ino, st.st_uid, fl->flags); + lflags = LOCK_NB; + if (fl->client.exclusive == 0) + lflags |= LOCK_SH; + else + lflags |= LOCK_EX; + error = flock(fl->fd, lflags); + if (error != 0 && errno == EAGAIN && block) { + switch (fl->locker = fork()) { + case -1: /* fork failed */ + syslog(LOG_NOTICE, "fork failed: %s", strerror(errno)); + LIST_REMOVE(fl, lcklst); + close(fl->fd); + return (fl->flags & LOCK_V4) ? + nlm4_denied_nolock : nlm_denied_nolocks; + case 0: + /* + * Attempt a blocking lock. Will have to call + * NLM_GRANTED later. + */ + setproctitle("%s", fl->client_name); + lflags &= ~LOCK_NB; + if(flock(fl->fd, lflags) != 0) { + syslog(LOG_NOTICE, "flock failed: %s", + strerror(errno)); + exit(-1); + } + /* lock granted */ + exit(0); + default: + syslog(LOG_DEBUG, "lock request from %s: forked %d", + fl->client_name, fl->locker); + fl->status = LKST_PROCESSING; + return (fl->flags & LOCK_V4) ? + nlm4_blocked : nlm_blocked; + } + } + /* non block case */ + if (error != 0) { + switch (errno) { + case EAGAIN: + error = nlm4_denied; + break; + case ESTALE: + error = nlm4_stale_fh; + break; + case EROFS: + error = nlm4_rofs; + break; + default: + error = nlm4_failed; + } + if ((fl->flags & LOCK_V4) == 0) + error = nlm_denied; + if (errno != EAGAIN) + syslog(LOG_NOTICE, "flock for %s failed: %s", + fl->client_name, strerror(errno)); + else syslog(LOG_DEBUG, "flock for %s failed: %s", + fl->client_name, strerror(errno)); + LIST_REMOVE(fl, lcklst); + close(fl->fd); + return error; + } + fl->status = LKST_LOCKED; + return (fl->flags & LOCK_V4) ? nlm4_granted : nlm_granted; +} + +void +send_granted(fl, opcode) + struct file_lock *fl; + int opcode; +{ + CLIENT *cli; + static char dummy; + struct timeval timeo; + int success; + static struct nlm_res retval; + static struct nlm4_res retval4; + + cli = get_client(fl->addr, + (fl->flags & LOCK_V4) ? NLM_VERS4 : NLM_VERS); + if (cli == NULL) { + syslog(LOG_NOTICE, "failed to get CLIENT for %s", + fl->client_name); + /* + * We fail to notify remote that the lock has been granted. + * The client will timeout and retry, the lock will be + * granted at this time. + */ + return; + } + timeo.tv_sec = 0; + timeo.tv_usec = (fl->flags & LOCK_ASYNC) ? 0 : 500000; /* 0.5s */ + + if (fl->flags & LOCK_V4) { + static nlm4_testargs res; + res.cookie = fl->client_cookie; + res.exclusive = fl->client.exclusive; + res.alock.caller_name = fl->client_name; + res.alock.fh.n_len = sizeof(fhandle_t); + res.alock.fh.n_bytes = (char*)&fl->filehandle; + res.alock.oh = fl->client.oh; + res.alock.svid = fl->client.svid; + res.alock.l_offset = fl->client.l_offset; + res.alock.l_len = fl->client.l_len; + syslog(LOG_DEBUG, "sending v4 reply%s", + (fl->flags & LOCK_ASYNC) ? " (async)":""); + if (fl->flags & LOCK_ASYNC) { + success = clnt_call(cli, NLM4_GRANTED_MSG, + xdr_nlm4_testargs, &res, xdr_void, &dummy, timeo); + } else { + success = clnt_call(cli, NLM4_GRANTED, + xdr_nlm4_testargs, &res, xdr_nlm4_res, + &retval4, timeo); + } + } else { + static nlm_testargs res; + + res.cookie = fl->client_cookie; + res.exclusive = fl->client.exclusive; + res.alock.caller_name = fl->client_name; + res.alock.fh.n_len = sizeof(fhandle_t); + res.alock.fh.n_bytes = (char*)&fl->filehandle; + res.alock.oh = fl->client.oh; + res.alock.svid = fl->client.svid; + res.alock.l_offset = fl->client.l_offset; + res.alock.l_len = fl->client.l_len; + syslog(LOG_DEBUG, "sending v1 reply%s", + (fl->flags & LOCK_ASYNC) ? " (async)":""); + if (fl->flags & LOCK_ASYNC) { + success = clnt_call(cli, NLM_GRANTED_MSG, + xdr_nlm_testargs, &res, xdr_void, &dummy, timeo); + } else { + success = clnt_call(cli, NLM_GRANTED, + xdr_nlm_testargs, &res, xdr_nlm_res, + &retval, timeo); + } + } + if (debug_level > 2) + syslog(LOG_DEBUG, "clnt_call returns %d(%s) for granted", + success, clnt_sperrno(success)); + +} + +enum nlm_stats +do_unlock(rfl) + struct file_lock *rfl; +{ + struct file_lock *fl; + int error; + int lockst; + + /* unlock the file: closing is enouth ! */ + if (close(rfl->fd) < 0) { + if (errno == ESTALE) + error = nlm4_stale_fh; + else + error = nlm4_failed; + if ((fl->flags & LOCK_V4) == 0) + error = nlm_denied; + syslog(LOG_NOTICE, + "close failed (from %s): %s", + rfl->client_name, strerror(errno)); + } else { + error = (fl->flags & LOCK_V4) ? + nlm4_granted : nlm_granted; + } + LIST_REMOVE(rfl, lcklst); + + /* process the next LKST_WAITING lock request for this fh */ + for (fl = LIST_FIRST(&lcklst_head); fl != NULL; + fl = LIST_NEXT(fl, lcklst)) { + if (fl->status != LKST_WAITING || + memcmp(&rfl->filehandle, &fl->filehandle, + sizeof(fhandle_t)) != 0) + continue; + + lockst = do_lock(fl, 1); /* If it's LKST_WAITING we can block */ + switch (lockst) { + case nlm4_granted: + /* case nlm_granted: same as nlm4_granted */ + send_granted(fl, (fl->flags & LOCK_V4) ? + nlm4_granted : nlm_granted); + break; + case nlm4_blocked: + /* case nlm_blocked: same as nlm4_blocked */ + break; + default: + lfree(fl); + break; + } + break; + } + return error; +} + +void +siglock() +{ + sigset_t block; + + sigemptyset(&block); + sigaddset(&block, SIGCHLD); + + if (sigprocmask(SIG_BLOCK, &block, NULL) < 0) { + syslog(LOG_WARNING, "siglock failed: %s", strerror(errno)); + } +} + +void +sigunlock() +{ + sigset_t block; + + sigemptyset(&block); + sigaddset(&block, SIGCHLD); + + if (sigprocmask(SIG_UNBLOCK, &block, NULL) < 0) { + syslog(LOG_WARNING, "sigunlock failed: %s", strerror(errno)); + } +} + +/* monitor a host through rpc.statd, and keep a ref count */ +void +do_mon(hostname) + char *hostname; +{ + struct host *hp; + struct mon my_mon; + struct sm_stat_res res; + int retval; + + for (hp = LIST_FIRST(&hostlst_head); hp != NULL; + hp = LIST_NEXT(hp, hostlst)) { + if (strcmp(hostname, hp->name) == 0) { + /* already monitored, just bump refcnt */ + hp->refcnt++; + return; + } + } + /* not found, have to create an entry for it */ + hp = malloc(sizeof(struct host)); + strncpy(hp->name, hostname, SM_MAXSTRLEN); + hp->refcnt = 1; + syslog(LOG_DEBUG, "monitoring host %s", + hostname); + memset(&my_mon, 0, sizeof(my_mon)); + my_mon.mon_id.mon_name = hp->name; + my_mon.mon_id.my_id.my_name = "localhost"; + my_mon.mon_id.my_id.my_prog = NLM_PROG; + my_mon.mon_id.my_id.my_vers = NLM_SM; + my_mon.mon_id.my_id.my_proc = NLM_SM_NOTIFY; + if ((retval = + callrpc("localhost", SM_PROG, SM_VERS, SM_MON, xdr_mon, + (char*)&my_mon, xdr_sm_stat_res, (char*)&res)) != 0) { + syslog(LOG_WARNING, "rpc to statd failed: %s", + clnt_sperrno((enum clnt_stat)retval)); + free(hp); + return; + } + if (res.res_stat == stat_fail) { + syslog(LOG_WARNING, "statd failed"); + free(hp); + return; + } + LIST_INSERT_HEAD(&hostlst_head, hp, hostlst); +} + +void +notify(hostname, state) + char *hostname; + int state; +{ + struct file_lock *fl, *next_fl; + int err; + syslog(LOG_DEBUG, "notify from %s, new state %d", hostname, state); + /* search all lock for this host; if status changed, release the lock */ + siglock(); + for (fl = LIST_FIRST(&lcklst_head); fl != NULL; fl = next_fl) { + next_fl = LIST_NEXT(fl, lcklst); + if (strcmp(hostname, fl->client_name) == 0 && + fl->nsm_status != state) { + syslog(LOG_DEBUG, "state %d, nsm_state %d, unlocking", + fl->status, fl->nsm_status); + switch(fl->status) { + case LKST_LOCKED: + err = do_unlock(fl); + if (err != nlm_granted) + syslog(LOG_DEBUG, + "notify: unlock failed for %s (%d)", + hostname, err); + break; + case LKST_WAITING: + LIST_REMOVE(fl, lcklst); + lfree(fl); + break; + case LKST_PROCESSING: + fl->status = LKST_DYING; + break; + case LKST_DYING: + break; + default: + syslog(LOG_NOTICE, "unknow status %d for %s", + fl->status, fl->client_name); + } + } + } + sigunlock(); +} diff --git a/usr.sbin/rpc.lockd/lockd_lock.h b/usr.sbin/rpc.lockd/lockd_lock.h new file mode 100644 index 000000000000..5b0232f69d13 --- /dev/null +++ b/usr.sbin/rpc.lockd/lockd_lock.h @@ -0,0 +1,21 @@ +/* $NetBSD: lockd_lock.h,v 1.2 2000/06/09 14:00:54 fvdl Exp $ */ +/* $FreeBSD$ */ + +/* Headers and function declarations for file-locking utilities */ + +struct nlm4_holder * testlock __P((struct nlm4_lock *, int)); + +enum nlm_stats getlock __P((nlm4_lockargs *, struct svc_req *, int)); +enum nlm_stats unlock __P((nlm4_lock *, int)); +void notify __P((char *, int)); + +/* flags for testlock, getlock & unlock */ +#define LOCK_ASYNC 0x01 /* async version (getlock only) */ +#define LOCK_V4 0x02 /* v4 version */ +#define LOCK_MON 0x04 /* monitored lock (getlock only) */ +#define LOCK_CANCEL 0x08 /* cancel, not unlock request (unlock only) */ + +/* callbacks from lock_proc.c */ +void transmit_result __P((int, nlm_res *, struct sockaddr *)); +void transmit4_result __P((int, nlm4_res *, struct sockaddr *)); +CLIENT *get_client __P((struct sockaddr *, rpcvers_t)); diff --git a/usr.sbin/rpc.lockd/rpc.lockd.8 b/usr.sbin/rpc.lockd/rpc.lockd.8 index 2438aacf85d0..e87f5bb92c00 100644 --- a/usr.sbin/rpc.lockd/rpc.lockd.8 +++ b/usr.sbin/rpc.lockd/rpc.lockd.8 @@ -1,4 +1,5 @@ -.\" -*- nroff -*- +.\" $NetBSD: rpc.lockd.8,v 1.5 2000/06/09 18:51:47 cgd Exp $ +.\" $FreeBSD$ .\" .\" Copyright (c) 1995 A.R.Gordon, andrew.gordon@net-tel.co.uk .\" All rights reserved. @@ -31,7 +32,6 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $FreeBSD$ .\" .Dd September 24, 1995 .Dt RPC.LOCKD 8 @@ -41,34 +41,64 @@ .Nd NFS file locking daemon .Sh SYNOPSIS .Nm -.Op Fl d Op Ar debug_level +.Op Fl d Ar debug_level +.Op Fl g Ar grace period .Sh DESCRIPTION -.Nm Rpc.lockd -is a daemon which provides file- and record-locking services in an NFS -environment. +The +.Nm +daemon provides monitored and unmonitored file and record locking services +in an NFS environment. +To monitor the status of hosts requesting locks, +the locking daemon typically operates in conjunction +with +.Xr rpc.statd 8 . .Pp -The following option is available: +Options and operands available for +.Nm : .Bl -tag -width indent .It Fl d -Cause debugging information to be written to syslog, recording -all RPC transactions to the daemon. These messages are logged with level -LOG_DEBUG and facility LOG_DAEMON. If debug_level is not specified, -level 1 is assumed, giving one log line per protocol operation. Higher +The +.Fl d +option causes debugging information to be written to syslog, recording +all RPC transactions to the daemon. +These messages are logged with level +.Dv LOG_DEBUG +and facility +.Dv LOG_DAEMON . +Specifying a +.Ar debug_level +of 1 results +in the generation of one log line per protocol operation. +Higher debug levels can be specified, causing display of operation arguments and internal operations of the daemon. +.It Fl g +The +.Fl g +option allow to specify the +.Ar grace period , +in seconds. +During the grace period +.Nm +only accepts requests from hosts which are reinitialising locks which +existed before the server restart. +Default is 30 seconds. .El .Pp Error conditions are logged to syslog, irrespective of the debug level, -using log level LOG_ERR and facility LOG_DAEMON. +using log level +.Dv LOG_ERR +and facility +.Dv LOG_DAEMON . .Pp The .Nm daemon must NOT be invoked by .Xr inetd 8 because the protocol assumes that the daemon will run from system start time. -Instead, it should be run from -.Xr rc 8 -after the network has been started. +Instead, it should be configured in +.Xr rc.conf 5 +to run at system startup. .Sh FILES .Bl -tag -width /usr/include/rpcsvc/nlm_prot.x -compact .It Pa /usr/include/rpcsvc/nlm_prot.x @@ -76,21 +106,32 @@ RPC protocol specification for the network lock manager protocol. .El .Sh SEE ALSO .Xr syslog 3 , -.Xr rc 8 , +.Xr rc.conf 5 , .Xr rpc.statd 8 .Sh BUGS The current implementation provides only the server side of the protocol -(ie. clients running other OS types can establish locks on a +(i.e., clients running other OS types can establish locks on a .Fx +/ +.Nx fileserver, but there is currently no means for a .Fx +/ +.Nx client to establish locks). .Pp -Versions 1, 2 and 3 of the protocol are supported. However, only versions -2 (Unix systems) and 3 (PC-NFS clients) seem to be in common use - the version -1 support has not been tested due to the lack of version 1 clients against -which to test. +The current implementation serialises locks requests that could be shared. .Sh STANDARDS -The implementation is based on the specification in X/Open CAE Specification -C218, "Protocols for X/Open PC Interworking: XNFS, Issue 4", ISBN 1 872630 66 9 +The implementation is based on the specification in +.Rs +.%B "X/Open CAE Specification C218" +.%T "Protocols for X/Open PC Interworking: XNFS, Issue 4" +.%O ISBN 1 872630 66 9 +.Re +.Sh HISTORY +A version of +.Nm +appeared in +.Tn SunOS +4. diff --git a/usr.sbin/rpc.lockd/test.c b/usr.sbin/rpc.lockd/test.c index 0dd8eaefa09e..a751e5c6f4e4 100644 --- a/usr.sbin/rpc.lockd/test.c +++ b/usr.sbin/rpc.lockd/test.c @@ -1,14 +1,17 @@ +/* $NetBSD: test.c,v 1.2 1997/10/18 04:01:21 lukem Exp $ */ + +#include <sys/cdefs.h> +#include <rpc/rpc.h> +#include <rpcsvc/nlm_prot.h> #ifndef lint #if 0 static char sccsid[] = "from: @(#)nlm_prot.x 1.8 87/09/21 Copyr 1987 Sun Micro"; static char sccsid[] = "from: * @(#)nlm_prot.x 2.1 88/08/01 4.0 RPCSRC"; +#else +__RCSID("$NetBSD: test.c,v 1.2 1997/10/18 04:01:21 lukem Exp $"); +static const char rcsid[] = "$FreeBSD$"; #endif -static const char rcsid[] = - "$FreeBSD$"; -#endif /* not lint */ - -#include <rpc/rpc.h> -#include <rpcsvc/nlm_prot.h> +#endif /* not lint */ /* Default timeout can be changed using clnt_control() */ static struct timeval TIMEOUT = { 0, 0 }; @@ -304,63 +307,59 @@ nlm_free_all_3(argp, clnt) int main(int argc, char **argv) { - CLIENT *cli; - nlm_res res_block; - nlm_res *out; - nlm_lockargs arg; - struct timeval tim; - - printf("Creating client for host %s\n", argv[1]); - cli = clnt_create(argv[1], NLM_PROG, NLM_VERS, "udp"); - if (!cli) - { - printf("Failed to create client\n"); - exit(1); - } + CLIENT *cli; + nlm_res res_block; + nlm_res *out; + nlm_lockargs arg; + struct timeval tim; + printf("Creating client for host %s\n", argv[1]); + cli = clnt_create(argv[1], NLM_PROG, NLM_VERS, "udp"); + if (!cli) { + errx(1, "Failed to create client\n"); + /* NOTREACHED */ + } + clnt_control(cli, CLGET_TIMEOUT, &tim); + printf("Default timeout was %d.%d\n", tim.tv_sec, tim.tv_usec); + tim.tv_usec = -1; + tim.tv_sec = -1; + clnt_control(cli, CLSET_TIMEOUT, &tim); + clnt_control(cli, CLGET_TIMEOUT, &tim); + printf("timeout now %d.%d\n", tim.tv_sec, tim.tv_usec); - clnt_control(cli, CLGET_TIMEOUT, &tim); - printf("Default timeout was %d.%d\n", tim.tv_sec, tim.tv_usec); - tim.tv_usec = -1; - tim.tv_sec = -1; - clnt_control(cli, CLSET_TIMEOUT, &tim); - clnt_control(cli, CLGET_TIMEOUT, &tim); - printf("timeout now %d.%d\n", tim.tv_sec, tim.tv_usec); - - arg.cookie.n_len = 4; - arg.cookie.n_bytes = "hello"; - arg.block = 0; - arg.exclusive = 0; - arg.reclaim = 0; - arg.state = 0x1234; - arg.alock.caller_name = "localhost"; - arg.alock.fh.n_len = 32; - arg.alock.fh.n_bytes = "\x04\x04\x02\x00\x01\x00\x00\x00\x0c\x00\x00\x00\xff\xff\xff\xd0\x16\x00\x00\x5b\x7c\xff\xff\xff\xec\x2f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x19\x54\xef\xbf\xd7\x94"; - arg.alock.oh.n_len = 8; - arg.alock.oh.n_bytes = "\x00\x00\x02\xff\xff\xff\xd3"; - arg.alock.svid = 0x5678; - arg.alock.l_offset = 0; - arg.alock.l_len = 100; + arg.cookie.n_len = 4; + arg.cookie.n_bytes = "hello"; + arg.block = 0; + arg.exclusive = 0; + arg.reclaim = 0; + arg.state = 0x1234; + arg.alock.caller_name = "localhost"; + arg.alock.fh.n_len = 32; + arg.alock.fh.n_bytes = "\x04\x04\x02\x00\x01\x00\x00\x00\x0c\x00\x00\x00\xff\xff\xff\xd0\x16\x00\x00\x5b\x7c\xff\xff\xff\xec\x2f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x19\x54\xef\xbf\xd7\x94"; + arg.alock.oh.n_len = 8; + arg.alock.oh.n_bytes = "\x00\x00\x02\xff\xff\xff\xd3"; + arg.alock.svid = 0x5678; + arg.alock.l_offset = 0; + arg.alock.l_len = 100; - res_block.stat.stat = nlm_granted; - res_block.cookie.n_bytes = "hello"; - res_block.cookie.n_len = 5; + res_block.stat.stat = nlm_granted; + res_block.cookie.n_bytes = "hello"; + res_block.cookie.n_len = 5; #if 0 - if (nlm_lock_res_1(&res_block, cli)) printf("Success!\n"); - else printf("Fail\n"); + if (nlm_lock_res_1(&res_block, cli)) + printf("Success!\n"); + else + printf("Fail\n"); #else - if (out = nlm_lock_msg_1(&arg, cli)) - { - printf("Success!\n"); - printf("out->stat = %d", out->stat); - } - else - { - printf("Fail\n"); - } + if (out = nlm_lock_msg_1(&arg, cli)) { + printf("Success!\n"); + printf("out->stat = %d", out->stat); + } else { + printf("Fail\n"); + } #endif - return 0; + return 0; } diff --git a/usr.sbin/rpc.statd/statd.h b/usr.sbin/rpc.statd/statd.h index 7b4e6598adae..7bf7b1d0cc92 100644 --- a/usr.sbin/rpc.statd/statd.h +++ b/usr.sbin/rpc.statd/statd.h @@ -29,26 +29,13 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * + * $FreeBSD$ */ #include "sm_inter.h" -/* These pieces are missing from the distributed sm_inter.x, which */ -/* omits the SM_NOTIFY procedure used between cooperating rpc.statd's */ - -#define SM_NOTIFY ((u_long)6) -extern void *sm_notify_1(); - -struct stat_chge -{ - char *mon_name; - int state; -}; -typedef struct stat_chge stat_chge; -bool_t xdr_stat_chge(); - /* ------------------------------------------------------------------------- */ /* Data structures for recording monitored hosts diff --git a/usr.sbin/rpc.umntall/rpc.umntall.c b/usr.sbin/rpc.umntall/rpc.umntall.c index c59c77606ffd..5129ba9033d1 100644 --- a/usr.sbin/rpc.umntall/rpc.umntall.c +++ b/usr.sbin/rpc.umntall/rpc.umntall.c @@ -171,28 +171,23 @@ main(int argc, char **argv) { int do_umntall(char *hostname) { enum clnt_stat clnt_stat; - struct hostent *hp; - struct sockaddr_in saddr; - struct timeval pertry, try; - int so; + struct addrinfo *ai, hints; + struct timeval try; + int so, ecode; CLIENT *clp; - if ((hp = gethostbyname(hostname)) == NULL) { - warnx("gethostbyname(%s) failed", hostname); - return (0); + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_NUMERICHOST; + ecode = getaddrinfo(hostname, NULL, &hints, &ai); + if (ecode != 0) { + warnx("can't get net id for host/nfs: %s", + gai_strerror(ecode)); + return (1); } - memset(&saddr, 0, sizeof(saddr)); - saddr.sin_family = AF_INET; - saddr.sin_port = 0; - memmove(&saddr.sin_addr, hp->h_addr, MIN(hp->h_length, - sizeof(saddr.sin_addr))); - pertry.tv_sec = 3; - pertry.tv_usec = 0; - so = RPC_ANYSOCK; - if ((clp = clntudp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1, - pertry, &so)) == NULL) { - clnt_pcreateerror("Cannot send MNT PRC"); - return (0); + clp = clnt_create(hostname, RPCPROG_MNT, RPCMNT_VER1, "udp"); + if (clp == NULL) { + clnt_pcreateerror("Cannot MNT PRC"); + return (1); } clp->cl_auth = authunix_create_default(); try.tv_sec = 3; @@ -212,30 +207,25 @@ do_umntall(char *hostname) { int do_umount(char *hostname, char *dirp) { enum clnt_stat clnt_stat; - struct hostent *hp; - struct sockaddr_in saddr; - struct timeval pertry, try; + struct addrinfo *ai, hints; + struct timeval try; CLIENT *clp; - int so; + int so, ecode; - if ((hp = gethostbyname(hostname)) == NULL) { - warnx("gethostbyname(%s) failed", hostname); - return (0); + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_NUMERICHOST; + ecode = getaddrinfo(hostname, NULL, &hints, &ai); + if (ecode != 0) { + warnx("can't get net id for host/nfs: %s", + gai_strerror(ecode)); + return (1); } - memset(&saddr, 0, sizeof(saddr)); - saddr.sin_family = AF_INET; - saddr.sin_port = 0; - memmove(&saddr.sin_addr, hp->h_addr, MIN(hp->h_length, - sizeof(saddr.sin_addr))); - pertry.tv_sec = 3; - pertry.tv_usec = 0; - so = RPC_ANYSOCK; - if ((clp = clntudp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1, - pertry, &so)) == NULL) { - clnt_pcreateerror("Cannot send MNT PRC"); - return (0); + clp = clnt_create(hostname, RPCPROG_MNT, RPCMNT_VER1, "udp"); + if (clp == NULL) { + clnt_pcreateerror("Cannot MNT PRC"); + return (1); } - clp->cl_auth = authunix_create_default(); + clp->cl_auth = authsys_create_default(); try.tv_sec = 3; try.tv_usec = 0; clnt_stat = clnt_call(clp, RPCMNT_UMOUNT, xdr_dir, dirp, diff --git a/usr.sbin/rpc.yppasswdd/yppasswdd_main.c b/usr.sbin/rpc.yppasswdd/yppasswdd_main.c index 03b48250dbda..51f962180ff0 100644 --- a/usr.sbin/rpc.yppasswdd/yppasswdd_main.c +++ b/usr.sbin/rpc.yppasswdd/yppasswdd_main.c @@ -298,7 +298,18 @@ the %s domain -- aborting", yppasswd_domain); } unlink(sockname); - transp = svcunix_create(sock, 0, 0, sockname); + if (svc_create(yppasswdprog_1, YPPASSWDPROG, YPPASSWDVERS, + "netpath") == 0) { + (void) fprintf(stderr, + "%s: unable to create service\n", argv[0]); + exit(1); + } + if (svc_create(master_yppasswdprog_1, MASTER_YPPASSWDPROG, + MASTER_YPPASSWDVERS, "netpath") == 0) { + (void) fprintf(stderr, + "%s: unable to create service\n", argv[0]); + exit(1); + } if (transp == NULL) { yp_error("cannot create AF_LOCAL service."); exit(1); diff --git a/usr.sbin/rpc.ypupdated/ypupdated_extern.h b/usr.sbin/rpc.ypupdated/ypupdated_extern.h index 28ea7ac30411..17e9ee9cdc60 100644 --- a/usr.sbin/rpc.ypupdated/ypupdated_extern.h +++ b/usr.sbin/rpc.ypupdated/ypupdated_extern.h @@ -1,3 +1,4 @@ +/* $FreeBSD$ */ #include <db.h> #define YPOP_CHANGE 1 /* change, do not add */ diff --git a/usr.sbin/rpc.ypupdated/ypupdated_server.c b/usr.sbin/rpc.ypupdated/ypupdated_server.c index f0c5bff89af5..b306268485ac 100644 --- a/usr.sbin/rpc.ypupdated/ypupdated_server.c +++ b/usr.sbin/rpc.ypupdated/ypupdated_server.c @@ -43,7 +43,6 @@ static const char rcsid[] = #include <stdio.h> #include <rpc/rpc.h> -#include <rpc/auth_des.h> #include <rpc/key_prot.h> #include <sys/param.h> #include <sys/cdefs.h> diff --git a/usr.sbin/rpcbind/Makefile b/usr.sbin/rpcbind/Makefile new file mode 100644 index 000000000000..fb73b23a0f24 --- /dev/null +++ b/usr.sbin/rpcbind/Makefile @@ -0,0 +1,21 @@ +# $NetBSD: Makefile,v 1.3 2000/06/20 13:56:43 fvdl Exp $ +# $FreeBSD$ + +PROG= rpcbind +CFLAGS+= -I${LIBCRPCDIR} -I${LIBCINCLUDE} -DPORTMAP -DINET6 -DLIBWRAP +MAN8= rpcbind.8 +SRCS= check_bound.c rpcb_stat.c rpcb_svc_4.c rpcbind.c pmap_svc.c \ + rpcb_svc.c rpcb_svc_com.c security.c warmstart.c util.c \ + rpc_generic.c + +LIBCDIR= ${.CURDIR}/../../lib/libc +LIBCRPCDIR= ${LIBCDIR}/rpc +LIBCINCLUDE= ${LIBCDIR}/include + + +LDADD+= -lwrap -lutil +DPADD+= ${LIBWRAP} ${LIBUTIL} + +.PATH: ${LIBCRPCDIR} + +.include <bsd.prog.mk> diff --git a/usr.sbin/rpcbind/check_bound.c b/usr.sbin/rpcbind/check_bound.c new file mode 100644 index 000000000000..fe503d74ebd6 --- /dev/null +++ b/usr.sbin/rpcbind/check_bound.c @@ -0,0 +1,229 @@ +/* $NetBSD: check_bound.c,v 1.2 2000/06/22 08:09:26 fvdl Exp $ */ +/* $FreeBSD$ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* + * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. + */ + +/* #ident "@(#)check_bound.c 1.15 93/07/05 SMI" */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)check_bound.c 1.11 89/04/21 Copyr 1989 Sun Micro"; +#endif +#endif + +/* + * check_bound.c + * Checks to see whether the program is still bound to the + * claimed address and returns the univeral merged address + * + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <rpc/rpc.h> +#include <stdio.h> +#include <netconfig.h> +#include <syslog.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> + +#include "rpcbind.h" + +struct fdlist { + int fd; + struct netconfig *nconf; + struct fdlist *next; + int check_binding; +}; + +static struct fdlist *fdhead; /* Link list of the check fd's */ +static struct fdlist *fdtail; +static char *nullstring = ""; + +static bool_t check_bound __P((struct fdlist *, char *uaddr)); + +/* + * Returns 1 if the given address is bound for the given addr & transport + * For all error cases, we assume that the address is bound + * Returns 0 for success. + */ +static bool_t +check_bound(struct fdlist *fdl, char *uaddr) +{ + int fd; + struct netbuf *na; + int ans; + + if (fdl->check_binding == FALSE) + return (TRUE); + + na = uaddr2taddr(fdl->nconf, uaddr); + if (!na) + return (TRUE); /* punt, should never happen */ + + fd = __rpc_nconf2fd(fdl->nconf); + if (fd < 0) { + free(na); + return (TRUE); + } + + ans = bind(fd, (struct sockaddr *)na->buf, na->len); + + close(fd); + free(na); + + return (ans == 0 ? FALSE : TRUE); +} + +int +add_bndlist(struct netconfig *nconf, struct netbuf *baddr) +{ + struct fdlist *fdl; + struct netconfig *newnconf; + + newnconf = getnetconfigent(nconf->nc_netid); + if (newnconf == NULL) + return (-1); + fdl = (struct fdlist *)malloc((u_int)sizeof (struct fdlist)); + if (fdl == NULL) { + freenetconfigent(newnconf); + syslog(LOG_ERR, "no memory!"); + return (-1); + } + fdl->nconf = newnconf; + fdl->next = NULL; + if (fdhead == NULL) { + fdhead = fdl; + fdtail = fdl; + } else { + fdtail->next = fdl; + fdtail = fdl; + } + /* XXX no bound checking for now */ + fdl->check_binding = FALSE; + + return 0; +} + +bool_t +is_bound(char *netid, char *uaddr) +{ + struct fdlist *fdl; + + for (fdl = fdhead; fdl; fdl = fdl->next) + if (strcmp(fdl->nconf->nc_netid, netid) == 0) + break; + if (fdl == NULL) + return (TRUE); + return (check_bound(fdl, uaddr)); +} + +/* + * Returns NULL if there was some system error. + * Returns "" if the address was not bound, i.e the server crashed. + * Returns the merged address otherwise. + */ +char * +mergeaddr(SVCXPRT *xprt, char *netid, char *uaddr, char *saddr) +{ + struct fdlist *fdl; + char *c_uaddr, *s_uaddr, *m_uaddr, *allocated_uaddr = NULL; + + for (fdl = fdhead; fdl; fdl = fdl->next) + if (strcmp(fdl->nconf->nc_netid, netid) == 0) + break; + if (fdl == NULL) + return (NULL); + if (check_bound(fdl, uaddr) == FALSE) + /* that server died */ + return (nullstring); + /* + * If saddr is not NULL, the remote client may have included the + * address by which it contacted us. Use that for the "client" uaddr, + * otherwise use the info from the SVCXPRT. + */ + if (saddr != NULL) { + c_uaddr = saddr; + } else { + c_uaddr = taddr2uaddr(fdl->nconf, svc_getrpccaller(xprt)); + if (c_uaddr == NULL) { + syslog(LOG_ERR, "taddr2uaddr failed for %s", + fdl->nconf->nc_netid); + return (NULL); + } + allocated_uaddr = c_uaddr; + } + +#ifdef ND_DEBUG + if (debugging) { + if (saddr == NULL) { + fprintf(stderr, "mergeaddr: client uaddr = %s\n", + c_uaddr); + } else { + fprintf(stderr, "mergeaddr: contact uaddr = %s\n", + c_uaddr); + } + } +#endif + s_uaddr = uaddr; + /* + * This is all we should need for IP 4 and 6 + */ + m_uaddr = addrmerge(svc_getrpccaller(xprt), s_uaddr, c_uaddr, netid); +#ifdef ND_DEBUG + if (debugging) + fprintf(stderr, "mergeaddr: uaddr = %s, merged uaddr = %s\n", + uaddr, m_uaddr); +#endif + if (allocated_uaddr != NULL) + free(allocated_uaddr); + return (m_uaddr); +} + +/* + * Returns a netconf structure from its internal list. This + * structure should not be freed. + */ +struct netconfig * +rpcbind_get_conf(char *netid) +{ + struct fdlist *fdl; + + for (fdl = fdhead; fdl; fdl = fdl->next) + if (strcmp(fdl->nconf->nc_netid, netid) == 0) + break; + if (fdl == NULL) + return (NULL); + return (fdl->nconf); +} diff --git a/usr.sbin/rpcbind/pmap_svc.c b/usr.sbin/rpcbind/pmap_svc.c new file mode 100644 index 000000000000..b2cedd991aad --- /dev/null +++ b/usr.sbin/rpcbind/pmap_svc.c @@ -0,0 +1,368 @@ +/* $NetBSD: pmap_svc.c,v 1.2 2000/10/20 11:49:40 fvdl Exp $ */ +/* $FreeBSD$ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* + * Copyright (c) 1984 - 1991 by Sun Microsystems, Inc. + */ + +/* #ident "@(#)pmap_svc.c 1.14 93/07/05 SMI" */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)pmap_svc.c 1.23 89/04/05 Copyr 1984 Sun Micro"; +#endif +#endif + +/* + * pmap_svc.c + * The server procedure for the version 2 portmaper. + * All the portmapper related interface from the portmap side. + */ + +#ifdef PORTMAP +#include <sys/types.h> +#include <sys/socket.h> +#include <stdio.h> +#include <rpc/rpc.h> +#include <rpc/pmap_prot.h> +#include <rpc/rpcb_prot.h> +#ifdef RPCBIND_DEBUG +#include <stdlib.h> +#endif +#include "rpcbind.h" + +static struct pmaplist *find_service_pmap __P((rpcprog_t, rpcvers_t, + rpcprot_t)); +static bool_t pmapproc_change __P((struct svc_req *, SVCXPRT *, u_long)); +static bool_t pmapproc_getport __P((struct svc_req *, SVCXPRT *)); +static bool_t pmapproc_dump __P((struct svc_req *, SVCXPRT *)); + +/* + * Called for all the version 2 inquiries. + */ +void +pmap_service(struct svc_req *rqstp, SVCXPRT *xprt) +{ + rpcbs_procinfo(RPCBVERS_2_STAT, rqstp->rq_proc); + switch (rqstp->rq_proc) { + case PMAPPROC_NULL: + /* + * Null proc call + */ +#ifdef RPCBIND_DEBUG + if (debugging) + fprintf(stderr, "PMAPPROC_NULL\n"); +#endif + check_access(xprt, rqstp->rq_proc, NULL, PMAPVERS); + if ((!svc_sendreply(xprt, (xdrproc_t) xdr_void, NULL)) && + debugging) { + if (doabort) { + rpcbind_abort(); + } + } + break; + + case PMAPPROC_SET: + /* + * Set a program, version to port mapping + */ + pmapproc_change(rqstp, xprt, rqstp->rq_proc); + break; + + case PMAPPROC_UNSET: + /* + * Remove a program, version to port mapping. + */ + pmapproc_change(rqstp, xprt, rqstp->rq_proc); + break; + + case PMAPPROC_GETPORT: + /* + * Lookup the mapping for a program, version and return its + * port number. + */ + pmapproc_getport(rqstp, xprt); + break; + + case PMAPPROC_DUMP: + /* + * Return the current set of mapped program, version + */ +#ifdef RPCBIND_DEBUG + if (debugging) + fprintf(stderr, "PMAPPROC_DUMP\n"); +#endif + pmapproc_dump(rqstp, xprt); + break; + + case PMAPPROC_CALLIT: + /* + * Calls a procedure on the local machine. If the requested + * procedure is not registered this procedure does not return + * error information!! + * This procedure is only supported on rpc/udp and calls via + * rpc/udp. It passes null authentication parameters. + */ + rpcbproc_callit_com(rqstp, xprt, PMAPPROC_CALLIT, PMAPVERS); + break; + + default: + svcerr_noproc(xprt); + break; + } +} + +/* + * returns the item with the given program, version number. If that version + * number is not found, it returns the item with that program number, so that + * the port number is now returned to the caller. The caller when makes a + * call to this program, version number, the call will fail and it will + * return with PROGVERS_MISMATCH. The user can then determine the highest + * and the lowest version number for this program using clnt_geterr() and + * use those program version numbers. + */ +static struct pmaplist * +find_service_pmap(rpcprog_t prog, rpcvers_t vers, rpcprot_t prot) +{ + register struct pmaplist *hit = NULL; + register struct pmaplist *pml; + + for (pml = list_pml; pml != NULL; pml = pml->pml_next) { + if ((pml->pml_map.pm_prog != prog) || + (pml->pml_map.pm_prot != prot)) + continue; + hit = pml; + if (pml->pml_map.pm_vers == vers) + break; + } + return (hit); +} + +static bool_t +pmapproc_change(struct svc_req *rqstp, SVCXPRT *xprt, unsigned long op) +{ + struct pmap reg; + RPCB rpcbreg; + long ans; + struct sockaddr_in *who; + struct cmsgcred *cmcred; + char uidbuf[32]; + +#ifdef RPCBIND_DEBUG + if (debugging) + fprintf(stderr, "%s request for (%lu, %lu) : ", + op == PMAPPROC_SET ? "PMAP_SET" : "PMAP_UNSET", + reg.pm_prog, reg.pm_vers); +#endif + + if (!svc_getargs(xprt, (xdrproc_t) xdr_pmap, (char *)®)) { + svcerr_decode(xprt); + return (FALSE); + } + + if (!check_access(xprt, op, ®, PMAPVERS)) { + svcerr_weakauth(xprt); + return FALSE; + } + + who = svc_getcaller(xprt); + cmcred = __svc_getcallercreds(xprt); + + /* + * Can't use getpwnam here. We might end up calling ourselves + * and looping. + */ + if (cmcred == NULL) + rpcbreg.r_owner = "unknown"; + else if (cmcred->cmcred_uid == 0) + rpcbreg.r_owner = "superuser"; + else { + /* r_owner will be strdup-ed later */ + snprintf(uidbuf, sizeof uidbuf, "%d", cmcred->cmcred_uid); + rpcbreg.r_owner = uidbuf; + } + + rpcbreg.r_prog = reg.pm_prog; + rpcbreg.r_vers = reg.pm_vers; + + if (op == PMAPPROC_SET) { + char buf[32]; + + sprintf(buf, "0.0.0.0.%d.%d", (int)((reg.pm_port >> 8) & 0xff), + (int)(reg.pm_port & 0xff)); + rpcbreg.r_addr = buf; + if (reg.pm_prot == IPPROTO_UDP) { + rpcbreg.r_netid = udptrans; + } else if (reg.pm_prot == IPPROTO_TCP) { + rpcbreg.r_netid = tcptrans; + } else { + ans = FALSE; + goto done_change; + } + ans = map_set(&rpcbreg, rpcbreg.r_owner); + } else if (op == PMAPPROC_UNSET) { + bool_t ans1, ans2; + + rpcbreg.r_addr = NULL; + rpcbreg.r_netid = tcptrans; + ans1 = map_unset(&rpcbreg, rpcbreg.r_owner); + rpcbreg.r_netid = udptrans; + ans2 = map_unset(&rpcbreg, rpcbreg.r_owner); + ans = ans1 || ans2; + } else { + ans = FALSE; + } +done_change: + if ((!svc_sendreply(xprt, (xdrproc_t) xdr_long, (caddr_t) &ans)) && + debugging) { + fprintf(stderr, "portmap: svc_sendreply\n"); + if (doabort) { + rpcbind_abort(); + } + } +#ifdef RPCBIND_DEBUG + if (debugging) + fprintf(stderr, "%s\n", ans == TRUE ? "succeeded" : "failed"); +#endif + if (op == PMAPPROC_SET) + rpcbs_set(RPCBVERS_2_STAT, ans); + else + rpcbs_unset(RPCBVERS_2_STAT, ans); + return (TRUE); +} + +/* ARGSUSED */ +static bool_t +pmapproc_getport(struct svc_req *rqstp, SVCXPRT *xprt) +{ + struct pmap reg; + long lport; + int port = 0; + struct pmaplist *fnd; +#ifdef RPCBIND_DEBUG + char *uaddr; +#endif + + if (!svc_getargs(xprt, (xdrproc_t) xdr_pmap, (char *)®)) { + svcerr_decode(xprt); + return (FALSE); + } + + if (!check_access(xprt, PMAPPROC_GETPORT, ®, PMAPVERS)) { + svcerr_weakauth(xprt); + return FALSE; + } + +#ifdef RPCBIND_DEBUG + if (debugging) { + uaddr = taddr2uaddr(rpcbind_get_conf(xprt->xp_netid), + svc_getrpccaller(xprt)); + fprintf(stderr, "PMAP_GETPORT req for (%lu, %lu, %s) from %s :", + reg.pm_prog, reg.pm_vers, + reg.pm_prot == IPPROTO_UDP ? "udp" : "tcp", uaddr); + free(uaddr); + } +#endif + fnd = find_service_pmap(reg.pm_prog, reg.pm_vers, reg.pm_prot); + if (fnd) { + char serveuaddr[32], *ua; + int h1, h2, h3, h4, p1, p2; + char *netid; + + if (reg.pm_prot == IPPROTO_UDP) { + ua = udp_uaddr; + netid = udptrans; + } else { + ua = tcp_uaddr; /* To get the len */ + netid = tcptrans; + } + if (ua == NULL) { + goto sendreply; + } + if (sscanf(ua, "%d.%d.%d.%d.%d.%d", &h1, &h2, &h3, + &h4, &p1, &p2) == 6) { + p1 = (fnd->pml_map.pm_port >> 8) & 0xff; + p2 = (fnd->pml_map.pm_port) & 0xff; + sprintf(serveuaddr, "%d.%d.%d.%d.%d.%d", + h1, h2, h3, h4, p1, p2); + if (is_bound(netid, serveuaddr)) { + port = fnd->pml_map.pm_port; + } else { /* this service is dead; delete it */ + delete_prog(reg.pm_prog); + } + } + } +sendreply: + lport = port; + if ((!svc_sendreply(xprt, (xdrproc_t) xdr_long, (caddr_t)&lport)) && + debugging) { + (void) fprintf(stderr, "portmap: svc_sendreply\n"); + if (doabort) { + rpcbind_abort(); + } + } +#ifdef RPCBIND_DEBUG + if (debugging) + fprintf(stderr, "port = %d\n", port); +#endif + rpcbs_getaddr(RPCBVERS_2_STAT, reg.pm_prog, reg.pm_vers, + reg.pm_prot == IPPROTO_UDP ? udptrans : tcptrans, + port ? udptrans : ""); + + return (TRUE); +} + +/* ARGSUSED */ +static bool_t +pmapproc_dump(struct svc_req *rqstp, SVCXPRT *xprt) +{ + if (!svc_getargs(xprt, (xdrproc_t)xdr_void, NULL)) { + svcerr_decode(xprt); + return (FALSE); + } + + if (!check_access(xprt, PMAPPROC_DUMP, NULL, PMAPVERS)) { + svcerr_weakauth(xprt); + return FALSE; + } + + if ((!svc_sendreply(xprt, (xdrproc_t) xdr_pmaplist_ptr, + (caddr_t)&list_pml)) && debugging) { + if (debugging) + (void) fprintf(stderr, "portmap: svc_sendreply\n"); + if (doabort) { + rpcbind_abort(); + } + } + return (TRUE); +} + +#endif /* PORTMAP */ diff --git a/usr.sbin/rpcbind/rpcb_stat.c b/usr.sbin/rpcbind/rpcb_stat.c new file mode 100644 index 000000000000..05554932ebd0 --- /dev/null +++ b/usr.sbin/rpcbind/rpcb_stat.c @@ -0,0 +1,208 @@ +/* + * $NetBSD: rpcb_stat.c,v 1.2 2000/07/04 20:27:40 matt Exp $ + * $FreeBSD$ + */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* #pragma ident "@(#)rpcb_stat.c 1.7 94/04/25 SMI" */ + +/* + * rpcb_stat.c + * Allows for gathering of statistics + * + * Copyright (c) 1990 by Sun Microsystems, Inc. + */ + +#include <stdio.h> +#include <netconfig.h> +#include <rpc/rpc.h> +#include <rpc/rpcb_prot.h> +#include <sys/stat.h> +#ifdef PORTMAP +#include <rpc/pmap_prot.h> +#endif +#include <stdlib.h> +#include <string.h> +#include "rpcbind.h" + +static rpcb_stat_byvers inf; + +void +rpcbs_init() +{ + +} + +void +rpcbs_procinfo(rpcvers_t rtype, rpcproc_t proc) +{ + switch (rtype + 2) { +#ifdef PORTMAP + case PMAPVERS: /* version 2 */ + if (proc > rpcb_highproc_2) + return; + break; +#endif + case RPCBVERS: /* version 3 */ + if (proc > rpcb_highproc_3) + return; + break; + case RPCBVERS4: /* version 4 */ + if (proc > rpcb_highproc_4) + return; + break; + default: return; + } + inf[rtype].info[proc]++; + return; +} + +void +rpcbs_set(rpcvers_t rtype, bool_t success) +{ + if ((rtype >= RPCBVERS_STAT) || (success == FALSE)) + return; + inf[rtype].setinfo++; + return; +} + +void +rpcbs_unset(rpcvers_t rtype, bool_t success) +{ + if ((rtype >= RPCBVERS_STAT) || (success == FALSE)) + return; + inf[rtype].unsetinfo++; + return; +} + +void +rpcbs_getaddr(rpcvers_t rtype, rpcprog_t prog, rpcvers_t vers, char *netid, + char *uaddr) +{ + rpcbs_addrlist *al; + struct netconfig *nconf; + + if (rtype >= RPCBVERS_STAT) + return; + for (al = inf[rtype].addrinfo; al; al = al->next) { + + if(al->netid == NULL) + return; + if ((al->prog == prog) && (al->vers == vers) && + (strcmp(al->netid, netid) == 0)) { + if ((uaddr == NULL) || (uaddr[0] == NULL)) + al->failure++; + else + al->success++; + return; + } + } + nconf = rpcbind_get_conf(netid); + if (nconf == NULL) { + return; + } + al = (rpcbs_addrlist *) malloc(sizeof (rpcbs_addrlist)); + if (al == NULL) { + return; + } + al->prog = prog; + al->vers = vers; + al->netid = nconf->nc_netid; + if ((uaddr == NULL) || (uaddr[0] == NULL)) { + al->failure = 1; + al->success = 0; + } else { + al->failure = 0; + al->success = 1; + } + al->next = inf[rtype].addrinfo; + inf[rtype].addrinfo = al; +} + +void +rpcbs_rmtcall(rpcvers_t rtype, rpcproc_t rpcbproc, rpcprog_t prog, + rpcvers_t vers, rpcproc_t proc, char *netid, rpcblist_ptr rbl) +{ + rpcbs_rmtcalllist *rl; + struct netconfig *nconf; + + if (rtype > RPCBVERS_STAT) + return; + for (rl = inf[rtype].rmtinfo; rl; rl = rl->next) { + + if(rl->netid == NULL) + return; + + if ((rl->prog == prog) && (rl->vers == vers) && + (rl->proc == proc) && + (strcmp(rl->netid, netid) == 0)) { + if ((rbl == NULL) || + (rbl->rpcb_map.r_vers != vers)) + rl->failure++; + else + rl->success++; + if (rpcbproc == RPCBPROC_INDIRECT) + rl->indirect++; + return; + } + } + nconf = rpcbind_get_conf(netid); + if (nconf == NULL) { + return; + } + rl = (rpcbs_rmtcalllist *) malloc(sizeof (rpcbs_rmtcalllist)); + if (rl == NULL) { + return; + } + rl->prog = prog; + rl->vers = vers; + rl->proc = proc; + rl->netid = nconf->nc_netid; + if ((rbl == NULL) || + (rbl->rpcb_map.r_vers != vers)) { + rl->failure = 1; + rl->success = 0; + } else { + rl->failure = 0; + rl->success = 1; + } + rl->indirect = 1; + rl->next = inf[rtype].rmtinfo; + inf[rtype].rmtinfo = rl; + return; +} + +/* + */ +void * +rpcbproc_getstat(void *arg, struct svc_req *req, SVCXPRT *xprt, + rpcvers_t versnum) +{ + return (void *)&inf; +} diff --git a/usr.sbin/rpcbind/rpcb_svc.c b/usr.sbin/rpcbind/rpcb_svc.c new file mode 100644 index 000000000000..b01e9ac4be10 --- /dev/null +++ b/usr.sbin/rpcbind/rpcb_svc.c @@ -0,0 +1,233 @@ +/* $NetBSD: rpcb_svc.c,v 1.1 2000/06/02 23:15:41 fvdl Exp $ */ +/* $FreeBSD$ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* + * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. + */ + +/* #ident "@(#)rpcb_svc.c 1.16 93/07/05 SMI" */ + +/* + * rpcb_svc.c + * The server procedure for the version 3 rpcbind (TLI). + * + * It maintains a separate list of all the registered services with the + * version 3 of rpcbind. + */ +#include <sys/types.h> +#include <rpc/rpc.h> +#include <rpc/rpcb_prot.h> +#include <netconfig.h> +#include <syslog.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "rpcbind.h" + +static void *rpcbproc_getaddr_3_local __P((void *, struct svc_req *, SVCXPRT *, + rpcvers_t)); +static void *rpcbproc_dump_3_local __P((void *, struct svc_req *, SVCXPRT *, + rpcvers_t)); + +/* + * Called by svc_getreqset. There is a separate server handle for + * every transport that it waits on. + */ +void +rpcb_service_3(struct svc_req *rqstp, SVCXPRT *transp) +{ + union { + RPCB rpcbproc_set_3_arg; + RPCB rpcbproc_unset_3_arg; + RPCB rpcbproc_getaddr_3_local_arg; + struct rpcb_rmtcallargs rpcbproc_callit_3_arg; + char *rpcbproc_uaddr2taddr_3_arg; + struct netbuf rpcbproc_taddr2uaddr_3_arg; + } argument; + char *result; + xdrproc_t xdr_argument, xdr_result; + void *(*local) __P((void *, struct svc_req *, SVCXPRT *, rpcvers_t)); + + rpcbs_procinfo(RPCBVERS_3_STAT, rqstp->rq_proc); + + switch (rqstp->rq_proc) { + case NULLPROC: + /* + * Null proc call + */ +#ifdef RPCBIND_DEBUG + if (debugging) + fprintf(stderr, "RPCBPROC_NULL\n"); +#endif + /* This call just logs, no actual checks */ + check_access(transp, rqstp->rq_proc, NULL, RPCBVERS); + (void) svc_sendreply(transp, (xdrproc_t)xdr_void, (char *)NULL); + return; + + case RPCBPROC_SET: + xdr_argument = (xdrproc_t )xdr_rpcb; + xdr_result = (xdrproc_t )xdr_bool; + local = rpcbproc_set_com; + break; + + case RPCBPROC_UNSET: + xdr_argument = (xdrproc_t)xdr_rpcb; + xdr_result = (xdrproc_t)xdr_bool; + local = rpcbproc_unset_com; + break; + + case RPCBPROC_GETADDR: + xdr_argument = (xdrproc_t)xdr_rpcb; + xdr_result = (xdrproc_t)xdr_wrapstring; + local = rpcbproc_getaddr_3_local; + break; + + case RPCBPROC_DUMP: +#ifdef RPCBIND_DEBUG + if (debugging) + fprintf(stderr, "RPCBPROC_DUMP\n"); +#endif + xdr_argument = (xdrproc_t)xdr_void; + xdr_result = (xdrproc_t)xdr_rpcblist_ptr; + local = rpcbproc_dump_3_local; + break; + + case RPCBPROC_CALLIT: + rpcbproc_callit_com(rqstp, transp, rqstp->rq_proc, RPCBVERS); + return; + + case RPCBPROC_GETTIME: +#ifdef RPCBIND_DEBUG + if (debugging) + fprintf(stderr, "RPCBPROC_GETTIME\n"); +#endif + xdr_argument = (xdrproc_t)xdr_void; + xdr_result = (xdrproc_t)xdr_u_long; + local = rpcbproc_gettime_com; + break; + + case RPCBPROC_UADDR2TADDR: +#ifdef RPCBIND_DEBUG + if (debugging) + fprintf(stderr, "RPCBPROC_UADDR2TADDR\n"); +#endif + xdr_argument = (xdrproc_t)xdr_wrapstring; + xdr_result = (xdrproc_t)xdr_netbuf; + local = rpcbproc_uaddr2taddr_com; + break; + + case RPCBPROC_TADDR2UADDR: +#ifdef RPCBIND_DEBUG + if (debugging) + fprintf(stderr, "RPCBPROC_TADDR2UADDR\n"); +#endif + xdr_argument = (xdrproc_t)xdr_netbuf; + xdr_result = (xdrproc_t)xdr_wrapstring; + local = rpcbproc_taddr2uaddr_com; + break; + + default: + svcerr_noproc(transp); + return; + } + (void) memset((char *)&argument, 0, sizeof (argument)); + if (!svc_getargs(transp, (xdrproc_t) xdr_argument, + (char *) &argument)) { + svcerr_decode(transp); + if (debugging) + (void) fprintf(stderr, "rpcbind: could not decode\n"); + return; + } + if (!check_access(transp, rqstp->rq_proc, &argument, RPCBVERS)) { + svcerr_weakauth(transp); + goto done; + } + result = (*local)(&argument, rqstp, transp, RPCBVERS); + if (result != NULL && !svc_sendreply(transp, (xdrproc_t)xdr_result, + result)) { + svcerr_systemerr(transp); + if (debugging) { + (void) fprintf(stderr, "rpcbind: svc_sendreply\n"); + if (doabort) { + rpcbind_abort(); + } + } + } +done: + if (!svc_freeargs(transp, (xdrproc_t)xdr_argument, (char *) + &argument)) { + if (debugging) { + (void) fprintf(stderr, "unable to free arguments\n"); + if (doabort) { + rpcbind_abort(); + } + } + } +} + +/* + * Lookup the mapping for a program, version and return its + * address. Assuming that the caller wants the address of the + * server running on the transport on which the request came. + * + * We also try to resolve the universal address in terms of + * address of the caller. + */ +/* ARGSUSED */ +static void * +rpcbproc_getaddr_3_local(void *arg, struct svc_req *rqstp, SVCXPRT *transp, + rpcvers_t versnum) +{ + RPCB *regp = (RPCB *)arg; +#ifdef RPCBIND_DEBUG + if (debugging) { + char *uaddr; + + uaddr = taddr2uaddr(rpcbind_get_conf(transp->xp_netid), + svc_getrpccaller(transp)); + fprintf(stderr, "RPCB_GETADDR req for (%lu, %lu, %s) from %s: ", + (unsigned long)regp->r_prog, (unsigned long)regp->r_vers, + regp->r_netid, uaddr); + free(uaddr); + } +#endif + return (rpcbproc_getaddr_com(regp, rqstp, transp, RPCBVERS, + RPCB_ALLVERS)); +} + +/* ARGSUSED */ +static void * +rpcbproc_dump_3_local(void *arg, struct svc_req *rqstp, SVCXPRT *transp, + rpcvers_t versnum) +{ + return ((void *)&list_rbl); +} diff --git a/usr.sbin/rpcbind/rpcb_svc_4.c b/usr.sbin/rpcbind/rpcb_svc_4.c new file mode 100644 index 000000000000..5f14474a038e --- /dev/null +++ b/usr.sbin/rpcbind/rpcb_svc_4.c @@ -0,0 +1,454 @@ +/* + * $NetBSD: rpcb_svc_4.c,v 1.1 2000/06/02 23:15:41 fvdl Exp $ + * $FreeBSD$ + */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* + * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. + */ + +/* #ident "@(#)rpcb_svc_4.c 1.8 93/07/05 SMI" */ + +/* + * rpcb_svc_4.c + * The server procedure for the version 4 rpcbind. + * + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <rpc/rpc.h> +#include <stdio.h> +#include <unistd.h> +#include <netconfig.h> +#include <syslog.h> +#include <string.h> +#include <stdlib.h> +#include "rpcbind.h" + +static void *rpcbproc_getaddr_4_local __P((void *, struct svc_req *, SVCXPRT *, + rpcvers_t)); +static void *rpcbproc_getversaddr_4_local __P((void *, struct svc_req *, SVCXPRT *, rpcvers_t)); +static void *rpcbproc_getaddrlist_4_local + __P((void *, struct svc_req *, SVCXPRT *, rpcvers_t)); +static void free_rpcb_entry_list __P((rpcb_entry_list_ptr *)); +static void *rpcbproc_dump_4_local __P((void *, struct svc_req *, SVCXPRT *, rpcvers_t)); + +/* + * Called by svc_getreqset. There is a separate server handle for + * every transport that it waits on. + */ +void +rpcb_service_4(struct svc_req *rqstp, SVCXPRT *transp) +{ + union { + rpcb rpcbproc_set_4_arg; + rpcb rpcbproc_unset_4_arg; + rpcb rpcbproc_getaddr_4_local_arg; + char *rpcbproc_uaddr2taddr_4_arg; + struct netbuf rpcbproc_taddr2uaddr_4_arg; + } argument; + char *result; + xdrproc_t xdr_argument, xdr_result; + void *(*local) __P((void *, struct svc_req *, SVCXPRT *, rpcvers_t)); + + rpcbs_procinfo(RPCBVERS_4_STAT, rqstp->rq_proc); + + switch (rqstp->rq_proc) { + case NULLPROC: + /* + * Null proc call + */ +#ifdef RPCBIND_DEBUG + if (debugging) + fprintf(stderr, "RPCBPROC_NULL\n"); +#endif + check_access(transp, rqstp->rq_proc, NULL, RPCBVERS4); + (void) svc_sendreply(transp, (xdrproc_t) xdr_void, + (char *)NULL); + return; + + case RPCBPROC_SET: + /* + * Check to see whether the message came from + * loopback transports (for security reasons) + */ + xdr_argument = (xdrproc_t)xdr_rpcb; + xdr_result = (xdrproc_t)xdr_bool; + local = rpcbproc_set_com; + break; + + case RPCBPROC_UNSET: + /* + * Check to see whether the message came from + * loopback transports (for security reasons) + */ + xdr_argument = (xdrproc_t)xdr_rpcb; + xdr_result = (xdrproc_t)xdr_bool; + local = rpcbproc_unset_com; + break; + + case RPCBPROC_GETADDR: + xdr_argument = (xdrproc_t)xdr_rpcb; + xdr_result = (xdrproc_t)xdr_wrapstring; + local = rpcbproc_getaddr_4_local; + break; + + case RPCBPROC_GETVERSADDR: +#ifdef RPCBIND_DEBUG + if (debugging) + fprintf(stderr, "RPCBPROC_GETVERSADDR\n"); +#endif + xdr_argument = (xdrproc_t)xdr_rpcb; + xdr_result = (xdrproc_t)xdr_wrapstring; + local = rpcbproc_getversaddr_4_local; + break; + + case RPCBPROC_DUMP: +#ifdef RPCBIND_DEBUG + if (debugging) + fprintf(stderr, "RPCBPROC_DUMP\n"); +#endif + xdr_argument = (xdrproc_t)xdr_void; + xdr_result = (xdrproc_t)xdr_rpcblist_ptr; + local = rpcbproc_dump_4_local; + break; + + case RPCBPROC_INDIRECT: +#ifdef RPCBIND_DEBUG + if (debugging) + fprintf(stderr, "RPCBPROC_INDIRECT\n"); +#endif + rpcbproc_callit_com(rqstp, transp, rqstp->rq_proc, RPCBVERS4); + return; + +/* case RPCBPROC_CALLIT: */ + case RPCBPROC_BCAST: +#ifdef RPCBIND_DEBUG + if (debugging) + fprintf(stderr, "RPCBPROC_BCAST\n"); +#endif + rpcbproc_callit_com(rqstp, transp, rqstp->rq_proc, RPCBVERS4); + return; + + case RPCBPROC_GETTIME: +#ifdef RPCBIND_DEBUG + if (debugging) + fprintf(stderr, "RPCBPROC_GETTIME\n"); +#endif + xdr_argument = (xdrproc_t)xdr_void; + xdr_result = (xdrproc_t)xdr_u_long; + local = rpcbproc_gettime_com; + break; + + case RPCBPROC_UADDR2TADDR: +#ifdef RPCBIND_DEBUG + if (debugging) + fprintf(stderr, "RPCBPROC_UADDR2TADDR\n"); +#endif + xdr_argument = (xdrproc_t)xdr_wrapstring; + xdr_result = (xdrproc_t)xdr_netbuf; + local = rpcbproc_uaddr2taddr_com; + break; + + case RPCBPROC_TADDR2UADDR: +#ifdef RPCBIND_DEBUG + if (debugging) + fprintf(stderr, "RPCBPROC_TADDR2UADDR\n"); +#endif + xdr_argument = (xdrproc_t)xdr_netbuf; + xdr_result = (xdrproc_t)xdr_wrapstring; + local = rpcbproc_taddr2uaddr_com; + break; + + case RPCBPROC_GETADDRLIST: +#ifdef RPCBIND_DEBUG + if (debugging) + fprintf(stderr, "RPCBPROC_GETADDRLIST\n"); +#endif + xdr_argument = (xdrproc_t)xdr_rpcb; + xdr_result = (xdrproc_t)xdr_rpcb_entry_list_ptr; + local = rpcbproc_getaddrlist_4_local; + break; + + case RPCBPROC_GETSTAT: +#ifdef RPCBIND_DEBUG + if (debugging) + fprintf(stderr, "RPCBPROC_GETSTAT\n"); +#endif + xdr_argument = (xdrproc_t)xdr_void; + xdr_result = (xdrproc_t)xdr_rpcb_stat_byvers; + local = rpcbproc_getstat; + break; + + default: + svcerr_noproc(transp); + return; + } + memset((char *)&argument, 0, sizeof (argument)); + if (!svc_getargs(transp, (xdrproc_t) xdr_argument, + (char *)&argument)) { + svcerr_decode(transp); + if (debugging) + (void) fprintf(stderr, "rpcbind: could not decode\n"); + return; + } + if (!check_access(transp, rqstp->rq_proc, &argument, RPCBVERS4)) { + svcerr_weakauth(transp); + goto done; + } + result = (*local)(&argument, rqstp, transp, RPCBVERS4); + if (result != NULL && !svc_sendreply(transp, (xdrproc_t) xdr_result, + result)) { + svcerr_systemerr(transp); + if (debugging) { + (void) fprintf(stderr, "rpcbind: svc_sendreply\n"); + if (doabort) { + rpcbind_abort(); + } + } + } +done: + if (!svc_freeargs(transp, (xdrproc_t) xdr_argument, + (char *)&argument)) { + if (debugging) { + (void) fprintf(stderr, "unable to free arguments\n"); + if (doabort) { + rpcbind_abort(); + } + } + } + return; +} + +/* + * Lookup the mapping for a program, version and return its + * address. Assuming that the caller wants the address of the + * server running on the transport on which the request came. + * Even if a service with a different version number is available, + * it will return that address. The client should check with an + * clnt_call to verify whether the service is the one that is desired. + * We also try to resolve the universal address in terms of + * address of the caller. + */ +/* ARGSUSED */ +static void * +rpcbproc_getaddr_4_local(void *arg, struct svc_req *rqstp, SVCXPRT *transp, + rpcvers_t rpcbversnum) +{ + RPCB *regp = (RPCB *)arg; +#ifdef RPCBIND_DEBUG + if (debugging) { + char *uaddr; + + uaddr = taddr2uaddr(rpcbind_get_conf(transp->xp_netid), + svc_getrpccaller(transp)); + fprintf(stderr, "RPCB_GETADDR req for (%lu, %lu, %s) from %s: ", + (unsigned long)regp->r_prog, (unsigned long)regp->r_vers, + regp->r_netid, uaddr); + free(uaddr); + } +#endif + return (rpcbproc_getaddr_com(regp, rqstp, transp, RPCBVERS4, + RPCB_ALLVERS)); +} + +/* + * Lookup the mapping for a program, version and return its + * address. Assuming that the caller wants the address of the + * server running on the transport on which the request came. + * + * We also try to resolve the universal address in terms of + * address of the caller. + */ +/* ARGSUSED */ +static void * +rpcbproc_getversaddr_4_local(void *arg, struct svc_req *rqstp, SVCXPRT *transp, + rpcvers_t versnum) +{ + RPCB *regp = (RPCB *)arg; +#ifdef RPCBIND_DEBUG + if (debugging) { + char *uaddr; + + uaddr = taddr2uaddr(rpcbind_get_conf(transp->xp_netid), + svc_getrpccaller(transp)); + fprintf(stderr, "RPCB_GETVERSADDR rqst for (%lu, %lu, %s)" + " from %s : ", + (unsigned long)regp->r_prog, (unsigned long)regp->r_vers, + regp->r_netid, uaddr); + free(uaddr); + } +#endif + return (rpcbproc_getaddr_com(regp, rqstp, transp, RPCBVERS4, + RPCB_ONEVERS)); +} + +/* + * Lookup the mapping for a program, version and return the + * addresses for all transports in the current transport family. + * We return a merged address. + */ +/* ARGSUSED */ +static void * +rpcbproc_getaddrlist_4_local(void *arg, struct svc_req *rqstp, SVCXPRT *transp, + rpcvers_t versnum) +{ + RPCB *regp = (RPCB *)arg; + static rpcb_entry_list_ptr rlist; + register rpcblist_ptr rbl; + rpcb_entry_list_ptr rp, tail; + rpcprog_t prog; + rpcvers_t vers; + rpcb_entry *a; + struct netconfig *nconf; + struct netconfig *reg_nconf; + char *saddr, *maddr = NULL; + + free_rpcb_entry_list(&rlist); + prog = regp->r_prog; + vers = regp->r_vers; + reg_nconf = rpcbind_get_conf(transp->xp_netid); + if (reg_nconf == NULL) + return (NULL); + if (*(regp->r_addr) != '\0') { + saddr = regp->r_addr; + } else { + saddr = NULL; + } +#ifdef RPCBIND_DEBUG + if (debugging) { + fprintf(stderr, "r_addr: %s r_netid: %s nc_protofmly: %s\n", + regp->r_addr, regp->r_netid, reg_nconf->nc_protofmly); + } +#endif + for (rbl = list_rbl; rbl != NULL; rbl = rbl->rpcb_next) { + if ((rbl->rpcb_map.r_prog == prog) && + (rbl->rpcb_map.r_vers == vers)) { + nconf = rpcbind_get_conf(rbl->rpcb_map.r_netid); + if (nconf == NULL) + goto fail; + if (strcmp(nconf->nc_protofmly, reg_nconf->nc_protofmly) + != 0) { + continue; /* not same proto family */ + } +#ifdef RPCBIND_DEBUG + if (debugging) + fprintf(stderr, "\tmerge with: %s", rbl->rpcb_map.r_addr); +#endif + if ((maddr = mergeaddr(transp, rbl->rpcb_map.r_netid, + rbl->rpcb_map.r_addr, saddr)) == NULL) { +#ifdef RPCBIND_DEBUG + if (debugging) + fprintf(stderr, " FAILED\n"); +#endif + continue; + } else if (!maddr[0]) { +#ifdef RPCBIND_DEBUG + if (debugging) + fprintf(stderr, " SUCCEEDED, but port died - maddr: nullstring\n"); +#endif + /* The server died. Unset this combination */ + delete_prog(regp->r_prog); + continue; + } +#ifdef RPCBIND_DEBUG + if (debugging) + fprintf(stderr, " SUCCEEDED maddr: %s\n", maddr); +#endif + /* + * Add it to rlist. + */ + rp = (rpcb_entry_list_ptr) + malloc((u_int)sizeof (rpcb_entry_list)); + if (rp == NULL) + goto fail; + a = &rp->rpcb_entry_map; + a->r_maddr = maddr; + a->r_nc_netid = nconf->nc_netid; + a->r_nc_semantics = nconf->nc_semantics; + a->r_nc_protofmly = nconf->nc_protofmly; + a->r_nc_proto = nconf->nc_proto; + rp->rpcb_entry_next = NULL; + if (rlist == NULL) { + rlist = rp; + tail = rp; + } else { + tail->rpcb_entry_next = rp; + tail = rp; + } + rp = NULL; + } + } +#ifdef RPCBIND_DEBUG + if (debugging) { + for (rp = rlist; rp; rp = rp->rpcb_entry_next) { + fprintf(stderr, "\t%s %s\n", rp->rpcb_entry_map.r_maddr, + rp->rpcb_entry_map.r_nc_proto); + } + } +#endif + /* + * XXX: getaddrlist info is also being stuffed into getaddr. + * Perhaps wrong, but better than it not getting counted at all. + */ + rpcbs_getaddr(RPCBVERS4 - 2, prog, vers, transp->xp_netid, maddr); + return (void *)&rlist; + +fail: free_rpcb_entry_list(&rlist); + return (NULL); +} + +/* + * Free only the allocated structure, rest is all a pointer to some + * other data somewhere else. + */ +static void +free_rpcb_entry_list(rpcb_entry_list_ptr *rlistp) +{ + register rpcb_entry_list_ptr rbl, tmp; + + for (rbl = *rlistp; rbl != NULL; ) { + tmp = rbl; + rbl = rbl->rpcb_entry_next; + free((char *)tmp->rpcb_entry_map.r_maddr); + free((char *)tmp); + } + *rlistp = NULL; +} + +/* ARGSUSED */ +static void * +rpcbproc_dump_4_local(void *arg, struct svc_req *req, SVCXPRT *xprt, + rpcvers_t versnum) +{ + return ((void *)&list_rbl); +} diff --git a/usr.sbin/rpcbind/rpcb_svc_com.c b/usr.sbin/rpcbind/rpcb_svc_com.c new file mode 100644 index 000000000000..e0c74876afdd --- /dev/null +++ b/usr.sbin/rpcbind/rpcb_svc_com.c @@ -0,0 +1,1457 @@ +/* $NetBSD: rpcb_svc_com.c,v 1.6 2000/08/03 00:07:22 fvdl Exp $ */ +/* $FreeBSD$ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* + * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. + */ + +/* #ident "@(#)rpcb_svc_com.c 1.18 94/05/02 SMI" */ + +/* + * rpcb_svc_com.c + * The commom server procedure for the rpcbind. + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/param.h> +#include <sys/poll.h> +#include <sys/socket.h> +#include <rpc/rpc.h> +#include <rpc/rpcb_prot.h> +#include <rpc/svc_dg.h> +#include <netconfig.h> +#include <errno.h> +#include <syslog.h> +#include <unistd.h> +#include <stdio.h> +#ifdef PORTMAP +#include <netinet/in.h> +#include <rpc/pmap_prot.h> +#endif /* PORTMAP */ +#include <string.h> +#include <stdlib.h> + +#include "rpcbind.h" + +#define RPC_BUF_MAX 65536 /* can be raised if required */ + +static char *nullstring = ""; +static int rpcb_rmtcalls; + +struct rmtcallfd_list { + int fd; + SVCXPRT *xprt; + char *netid; + struct rmtcallfd_list *next; +}; + +#define NFORWARD 64 +#define MAXTIME_OFF 300 /* 5 minutes */ + +struct finfo { + int flag; +#define FINFO_ACTIVE 0x1 + u_int32_t caller_xid; + struct netbuf *caller_addr; + u_int32_t forward_xid; + int forward_fd; + char *uaddr; + rpcproc_t reply_type; + rpcvers_t versnum; + time_t time; +}; +static struct finfo FINFO[NFORWARD]; + + +static bool_t xdr_encap_parms __P((XDR *, struct encap_parms *)); +static bool_t xdr_rmtcall_args __P((XDR *, struct r_rmtcall_args *)); +static bool_t xdr_rmtcall_result __P((XDR *, struct r_rmtcall_args *)); +static bool_t xdr_opaque_parms __P((XDR *, struct r_rmtcall_args *)); +static int find_rmtcallfd_by_netid __P((char *)); +static SVCXPRT *find_rmtcallxprt_by_fd __P((int)); +static u_int32_t forward_register __P((u_int32_t, struct netbuf *, int, char *, + rpcproc_t, rpcvers_t)); +static struct finfo *forward_find __P((u_int32_t)); +static int free_slot_by_xid __P((u_int32_t)); +static int free_slot_by_index __P((int)); +static int netbufcmp __P((struct netbuf *, struct netbuf *)); +static struct netbuf *netbufdup __P((struct netbuf *)); +static void netbuffree __P((struct netbuf *)); +static int check_rmtcalls __P((struct pollfd *, int)); +static void xprt_set_caller __P((SVCXPRT *, struct finfo *)); +static void send_svcsyserr __P((SVCXPRT *, struct finfo *)); +static void handle_reply __P((int, SVCXPRT *)); +static void find_versions __P((rpcprog_t, char *, rpcvers_t *, rpcvers_t *)); +static rpcblist_ptr find_service __P((rpcprog_t, rpcvers_t, char *)); +static char *getowner __P((SVCXPRT *, char *, size_t)); +static int add_pmaplist __P((RPCB *)); +static int del_pmaplist __P((RPCB *)); + +/* + * Set a mapping of program, version, netid + */ +/* ARGSUSED */ +void * +rpcbproc_set_com(void *arg, struct svc_req *rqstp, SVCXPRT *transp, + rpcvers_t rpcbversnum) +{ + RPCB *regp = (RPCB *)arg; + static bool_t ans; + char owner[64]; + +#ifdef RPCBIND_DEBUG + if (debugging) + fprintf(stderr, "RPCB_SET request for (%lu, %lu, %s, %s) : ", + (unsigned long)regp->r_prog, (unsigned long)regp->r_vers, + regp->r_netid, regp->r_addr); +#endif + ans = map_set(regp, getowner(transp, owner, sizeof owner)); +#ifdef RPCBIND_DEBUG + if (debugging) + fprintf(stderr, "%s\n", ans == TRUE ? "succeeded" : "failed"); +#endif + /* XXX: should have used some defined constant here */ + rpcbs_set(rpcbversnum - 2, ans); + return (void *)&ans; +} + +bool_t +map_set(RPCB *regp, char *owner) +{ + RPCB reg, *a; + rpcblist_ptr rbl, fnd; + + reg = *regp; + /* + * check to see if already used + * find_service returns a hit even if + * the versions don't match, so check for it + */ + fnd = find_service(reg.r_prog, reg.r_vers, reg.r_netid); + if (fnd && (fnd->rpcb_map.r_vers == reg.r_vers)) { + if (!strcmp(fnd->rpcb_map.r_addr, reg.r_addr)) + /* + * if these match then it is already + * registered so just say "OK". + */ + return (TRUE); + else + return (FALSE); + } + /* + * add to the end of the list + */ + rbl = (rpcblist_ptr) malloc((u_int)sizeof (RPCBLIST)); + if (rbl == (rpcblist_ptr)NULL) { + return (FALSE); + } + a = &(rbl->rpcb_map); + a->r_prog = reg.r_prog; + a->r_vers = reg.r_vers; + a->r_netid = strdup(reg.r_netid); + a->r_addr = strdup(reg.r_addr); + a->r_owner = strdup(owner); + if (!a->r_addr || !a->r_netid || !a->r_owner) { + if (a->r_netid) + free((void *) a->r_netid); + if (a->r_addr) + free((void *) a->r_addr); + if (a->r_owner) + free((void *) a->r_owner); + free((void *)rbl); + return (FALSE); + } + rbl->rpcb_next = (rpcblist_ptr)NULL; + if (list_rbl == NULL) { + list_rbl = rbl; + } else { + for (fnd = list_rbl; fnd->rpcb_next; + fnd = fnd->rpcb_next) + ; + fnd->rpcb_next = rbl; + } +#ifdef PORTMAP + (void) add_pmaplist(regp); +#endif + return (TRUE); +} + +/* + * Unset a mapping of program, version, netid + */ +/* ARGSUSED */ +void * +rpcbproc_unset_com(void *arg, struct svc_req *rqstp, SVCXPRT *transp, + rpcvers_t rpcbversnum) +{ + RPCB *regp = (RPCB *)arg; + static bool_t ans; + char owner[64]; + +#ifdef RPCBIND_DEBUG + if (debugging) + fprintf(stderr, "RPCB_UNSET request for (%lu, %lu, %s) : ", + (unsigned long)regp->r_prog, (unsigned long)regp->r_vers, + regp->r_netid); +#endif + ans = map_unset(regp, getowner(transp, owner, sizeof owner)); +#ifdef RPCBIND_DEBUG + if (debugging) + fprintf(stderr, "%s\n", ans == TRUE ? "succeeded" : "failed"); +#endif + /* XXX: should have used some defined constant here */ + rpcbs_unset(rpcbversnum - 2, ans); + return (void *)&ans; +} + +bool_t +map_unset(RPCB *regp, char *owner) +{ + int ans = 0; + rpcblist_ptr rbl, prev, tmp; + + if (owner == NULL) + return (0); + + for (prev = NULL, rbl = list_rbl; rbl; /* cstyle */) { + if ((rbl->rpcb_map.r_prog != regp->r_prog) || + (rbl->rpcb_map.r_vers != regp->r_vers) || + (regp->r_netid[0] && strcasecmp(regp->r_netid, + rbl->rpcb_map.r_netid))) { + /* both rbl & prev move forwards */ + prev = rbl; + rbl = rbl->rpcb_next; + continue; + } + /* + * Check whether appropriate uid. Unset only + * if superuser or the owner itself. + */ + if (strcmp(owner, "superuser") && + strcmp(rbl->rpcb_map.r_owner, owner)) + return (0); + /* found it; rbl moves forward, prev stays */ + ans = 1; + tmp = rbl; + rbl = rbl->rpcb_next; + if (prev == NULL) + list_rbl = rbl; + else + prev->rpcb_next = rbl; + free((void *) tmp->rpcb_map.r_addr); + free((void *) tmp->rpcb_map.r_netid); + free((void *) tmp->rpcb_map.r_owner); + free((void *) tmp); + } +#ifdef PORTMAP + if (ans) + (void) del_pmaplist(regp); +#endif + /* + * We return 1 either when the entry was not there or it + * was able to unset it. It can come to this point only if + * atleast one of the conditions is true. + */ + return (1); +} + +void +delete_prog(int prog) +{ + RPCB reg; + register rpcblist_ptr rbl; + + for (rbl = list_rbl; rbl != NULL; rbl = rbl->rpcb_next) { + if ((rbl->rpcb_map.r_prog != prog)) + continue; + if (is_bound(rbl->rpcb_map.r_netid, rbl->rpcb_map.r_addr)) + continue; + reg.r_prog = rbl->rpcb_map.r_prog; + reg.r_vers = rbl->rpcb_map.r_vers; + reg.r_netid = strdup(rbl->rpcb_map.r_netid); + (void) map_unset(®, "superuser"); + free(reg.r_netid); + } +} + +void * +rpcbproc_getaddr_com(RPCB *regp, struct svc_req *rqstp, SVCXPRT *transp, + rpcvers_t rpcbversnum, rpcvers_t verstype) +{ + static char *uaddr; + char *saddr = NULL; + rpcblist_ptr fnd; + + if (uaddr && uaddr[0]) + free((void *) uaddr); + fnd = find_service(regp->r_prog, regp->r_vers, transp->xp_netid); + if (fnd && ((verstype == RPCB_ALLVERS) || + (regp->r_vers == fnd->rpcb_map.r_vers))) { + if (*(regp->r_addr) != '\0') { /* may contain a hint about */ + saddr = regp->r_addr; /* the interface that we */ + } /* should use */ + if (!(uaddr = mergeaddr(transp, transp->xp_netid, + fnd->rpcb_map.r_addr, saddr))) { + /* Try whatever we have */ + uaddr = strdup(fnd->rpcb_map.r_addr); + } else if (!uaddr[0]) { + /* + * The server died. Unset all versions of this prog. + */ + delete_prog(regp->r_prog); + uaddr = nullstring; + } + } else { + uaddr = nullstring; + } +#ifdef RPCBIND_DEBUG + if (debugging) + fprintf(stderr, "getaddr: %s\n", uaddr); +#endif + /* XXX: should have used some defined constant here */ + rpcbs_getaddr(rpcbversnum - 2, regp->r_prog, regp->r_vers, + transp->xp_netid, uaddr); + return (void *)&uaddr; +} + +/* ARGSUSED */ +void * +rpcbproc_gettime_com(void *arg, struct svc_req *rqstp, SVCXPRT *transp, + rpcvers_t rpcbversnum) +{ + static time_t curtime; + + (void) time(&curtime); + return (void *)&curtime; +} + +/* + * Convert uaddr to taddr. Should be used only by + * local servers/clients. (kernel level stuff only) + */ +/* ARGSUSED */ +void * +rpcbproc_uaddr2taddr_com(void *arg, struct svc_req *rqstp, SVCXPRT *transp, + rpcvers_t rpcbversnum) +{ + char **uaddrp = (char **)arg; + struct netconfig *nconf; + static struct netbuf nbuf; + static struct netbuf *taddr; + + if (taddr) { + free((void *) taddr->buf); + free((void *) taddr); + } + if (((nconf = rpcbind_get_conf(transp->xp_netid)) == NULL) || + ((taddr = uaddr2taddr(nconf, *uaddrp)) == NULL)) { + (void) memset((char *)&nbuf, 0, sizeof (struct netbuf)); + return (void *)&nbuf; + } + return (void *)taddr; +} + +/* + * Convert taddr to uaddr. Should be used only by + * local servers/clients. (kernel level stuff only) + */ +/* ARGSUSED */ +void * +rpcbproc_taddr2uaddr_com(void *arg, struct svc_req *rqstp, SVCXPRT *transp, + rpcvers_t rpcbversnum) +{ + struct netbuf *taddr = (struct netbuf *)arg; + static char *uaddr; + struct netconfig *nconf; + +#ifdef CHEW_FDS + int fd; + + if ((fd = open("/dev/null", O_RDONLY)) == -1) { + uaddr = (char *)strerror(errno); + return (&uaddr); + } +#endif /* CHEW_FDS */ + if (uaddr && !uaddr[0]) + free((void *) uaddr); + if (((nconf = rpcbind_get_conf(transp->xp_netid)) == NULL) || + ((uaddr = taddr2uaddr(nconf, taddr)) == NULL)) { + uaddr = nullstring; + } + return (void *)&uaddr; +} + + +static bool_t +xdr_encap_parms(XDR *xdrs, struct encap_parms *epp) +{ + return (xdr_bytes(xdrs, &(epp->args), (u_int *) &(epp->arglen), ~0)); +} + +/* + * XDR remote call arguments. It ignores the address part. + * written for XDR_DECODE direction only + */ +static bool_t +xdr_rmtcall_args(XDR *xdrs, struct r_rmtcall_args *cap) +{ + /* does not get the address or the arguments */ + if (xdr_u_int32_t(xdrs, &(cap->rmt_prog)) && + xdr_u_int32_t(xdrs, &(cap->rmt_vers)) && + xdr_u_int32_t(xdrs, &(cap->rmt_proc))) { + return (xdr_encap_parms(xdrs, &(cap->rmt_args))); + } + return (FALSE); +} + +/* + * XDR remote call results along with the address. Ignore + * program number, version number and proc number. + * Written for XDR_ENCODE direction only. + */ +static bool_t +xdr_rmtcall_result(XDR *xdrs, struct r_rmtcall_args *cap) +{ + bool_t result; + +#ifdef PORTMAP + if (cap->rmt_localvers == PMAPVERS) { + int h1, h2, h3, h4, p1, p2; + u_long port; + + /* interpret the universal address for TCP/IP */ + if (sscanf(cap->rmt_uaddr, "%d.%d.%d.%d.%d.%d", + &h1, &h2, &h3, &h4, &p1, &p2) != 6) + return (FALSE); + port = ((p1 & 0xff) << 8) + (p2 & 0xff); + result = xdr_u_long(xdrs, &port); + } else +#endif + if ((cap->rmt_localvers == RPCBVERS) || + (cap->rmt_localvers == RPCBVERS4)) { + result = xdr_wrapstring(xdrs, &(cap->rmt_uaddr)); + } else { + return (FALSE); + } + if (result == TRUE) + return (xdr_encap_parms(xdrs, &(cap->rmt_args))); + return (FALSE); +} + +/* + * only worries about the struct encap_parms part of struct r_rmtcall_args. + * The arglen must already be set!! + */ +static bool_t +xdr_opaque_parms(XDR *xdrs, struct r_rmtcall_args *cap) +{ + return (xdr_opaque(xdrs, cap->rmt_args.args, cap->rmt_args.arglen)); +} + +static struct rmtcallfd_list *rmthead; +static struct rmtcallfd_list *rmttail; + +int +create_rmtcall_fd(struct netconfig *nconf) +{ + int fd; + struct rmtcallfd_list *rmt; + SVCXPRT *xprt; + + if ((fd = __rpc_nconf2fd(nconf)) == -1) { + if (debugging) + fprintf(stderr, + "create_rmtcall_fd: couldn't open \"%s\" (errno %d)\n", + nconf->nc_device, errno); + return (-1); + } + xprt = svc_tli_create(fd, 0, (struct t_bind *) 0, 0, 0); + if (xprt == NULL) { + if (debugging) + fprintf(stderr, + "create_rmtcall_fd: svc_tli_create failed\n"); + return (-1); + } + rmt = (struct rmtcallfd_list *)malloc((u_int) + sizeof (struct rmtcallfd_list)); + if (rmt == NULL) { + syslog(LOG_ERR, "create_rmtcall_fd: no memory!"); + return (-1); + } + rmt->xprt = xprt; + rmt->netid = strdup(nconf->nc_netid); + xprt->xp_netid = rmt->netid; + rmt->fd = fd; + rmt->next = NULL; + if (rmthead == NULL) { + rmthead = rmt; + rmttail = rmt; + } else { + rmttail->next = rmt; + rmttail = rmt; + } + /* XXX not threadsafe */ + if (fd > svc_maxfd) + svc_maxfd = fd; + FD_SET(fd, &svc_fdset); + return (fd); +} + +static int +find_rmtcallfd_by_netid(char *netid) +{ + struct rmtcallfd_list *rmt; + + for (rmt = rmthead; rmt != NULL; rmt = rmt->next) { + if (strcmp(netid, rmt->netid) == 0) { + return (rmt->fd); + } + } + return (-1); +} + +static SVCXPRT * +find_rmtcallxprt_by_fd(int fd) +{ + struct rmtcallfd_list *rmt; + + for (rmt = rmthead; rmt != NULL; rmt = rmt->next) { + if (fd == rmt->fd) { + return (rmt->xprt); + } + } + return (NULL); +} + + +/* + * Call a remote procedure service. This procedure is very quiet when things + * go wrong. The proc is written to support broadcast rpc. In the broadcast + * case, a machine should shut-up instead of complain, lest the requestor be + * overrun with complaints at the expense of not hearing a valid reply. + * When receiving a request and verifying that the service exists, we + * + * receive the request + * + * open a new TLI endpoint on the same transport on which we received + * the original request + * + * remember the original request's XID (which requires knowing the format + * of the svc_dg_data structure) + * + * forward the request, with a new XID, to the requested service, + * remembering the XID used to send this request (for later use in + * reassociating the answer with the original request), the requestor's + * address, the file descriptor on which the forwarded request is + * made and the service's address. + * + * mark the file descriptor on which we anticipate receiving a reply from + * the service and one to select for in our private svc_run procedure + * + * At some time in the future, a reply will be received from the service to + * which we forwarded the request. At that time, we detect that the socket + * used was for forwarding (by looking through the finfo structures to see + * whether the fd corresponds to one of those) and call handle_reply() to + * + * receive the reply + * + * bundle the reply, along with the service's universal address + * + * create a SVCXPRT structure and use a version of svc_sendreply + * that allows us to specify the reply XID and destination, send the reply + * to the original requestor. + */ + +void +rpcbproc_callit_com(struct svc_req *rqstp, SVCXPRT *transp, + rpcproc_t reply_type, rpcvers_t versnum) +{ + register rpcblist_ptr rbl; + struct netconfig *nconf; + struct netbuf *caller; + struct r_rmtcall_args a; + char *buf_alloc = NULL, *outbufp; + char *outbuf_alloc = NULL; + char buf[RPC_BUF_MAX], outbuf[RPC_BUF_MAX]; + struct netbuf *na = (struct netbuf *) NULL; + struct rpc_msg call_msg; + int outlen; + u_int sendsz; + XDR outxdr; + AUTH *auth; + int fd = -1; + char *uaddr, *m_uaddr, *local_uaddr = NULL; + u_int32_t *xidp; + struct __rpc_sockinfo si; + struct sockaddr *localsa; + struct netbuf tbuf; + + if (!__rpc_fd2sockinfo(transp->xp_fd, &si)) { + if (reply_type == RPCBPROC_INDIRECT) + svcerr_systemerr(transp); + return; + } + if (si.si_socktype != SOCK_DGRAM) + return; /* Only datagram type accepted */ + sendsz = __rpc_get_t_size(si.si_af, si.si_proto, UDPMSGSIZE); + if (sendsz == 0) { /* data transfer not supported */ + if (reply_type == RPCBPROC_INDIRECT) + svcerr_systemerr(transp); + return; + } + /* + * Should be multiple of 4 for XDR. + */ + sendsz = ((sendsz + 3) / 4) * 4; + if (sendsz > RPC_BUF_MAX) { +#ifdef notyet + buf_alloc = alloca(sendsz); /* not in IDR2? */ +#else + buf_alloc = malloc(sendsz); +#endif /* notyet */ + if (buf_alloc == NULL) { + if (debugging) + fprintf(stderr, + "rpcbproc_callit_com: No Memory!\n"); + if (reply_type == RPCBPROC_INDIRECT) + svcerr_systemerr(transp); + return; + } + a.rmt_args.args = buf_alloc; + } else { + a.rmt_args.args = buf; + } + + call_msg.rm_xid = 0; /* For error checking purposes */ + if (!svc_getargs(transp, (xdrproc_t) xdr_rmtcall_args, (char *) &a)) { + if (reply_type == RPCBPROC_INDIRECT) + svcerr_decode(transp); + if (debugging) + fprintf(stderr, + "rpcbproc_callit_com: svc_getargs failed\n"); + goto error; + } + + if (!check_callit(transp, &a, versnum)) { + svcerr_weakauth(transp); + goto error; + } + + caller = svc_getrpccaller(transp); +#ifdef RPCBIND_DEBUG + if (debugging) { + uaddr = taddr2uaddr(rpcbind_get_conf(transp->xp_netid), caller); + fprintf(stderr, "%s %s req for (%lu, %lu, %lu, %s) from %s : ", + versnum == PMAPVERS ? "pmap_rmtcall" : + versnum == RPCBVERS ? "rpcb_rmtcall" : + versnum == RPCBVERS4 ? "rpcb_indirect" : "unknown", + reply_type == RPCBPROC_INDIRECT ? "indirect" : "callit", + (unsigned long)a.rmt_prog, (unsigned long)a.rmt_vers, + (unsigned long)a.rmt_proc, transp->xp_netid, + uaddr ? uaddr : "unknown"); + if (uaddr) + free((void *) uaddr); + } +#endif + + rbl = find_service(a.rmt_prog, a.rmt_vers, transp->xp_netid); + + rpcbs_rmtcall(versnum - 2, reply_type, a.rmt_prog, a.rmt_vers, + a.rmt_proc, transp->xp_netid, rbl); + + if (rbl == (rpcblist_ptr)NULL) { +#ifdef RPCBIND_DEBUG + if (debugging) + fprintf(stderr, "not found\n"); +#endif + if (reply_type == RPCBPROC_INDIRECT) + svcerr_noprog(transp); + goto error; + } + if (rbl->rpcb_map.r_vers != a.rmt_vers) { + if (reply_type == RPCBPROC_INDIRECT) { + rpcvers_t vers_low, vers_high; + + find_versions(a.rmt_prog, transp->xp_netid, + &vers_low, &vers_high); + svcerr_progvers(transp, vers_low, vers_high); + } + goto error; + } + +#ifdef RPCBIND_DEBUG + if (debugging) + fprintf(stderr, "found at uaddr %s\n", rbl->rpcb_map.r_addr); +#endif + /* + * Check whether this entry is valid and a server is present + * Mergeaddr() returns NULL if no such entry is present, and + * returns "" if the entry was present but the server is not + * present (i.e., it crashed). + */ + if (reply_type == RPCBPROC_INDIRECT) { + uaddr = mergeaddr(transp, transp->xp_netid, + rbl->rpcb_map.r_addr, NULL); + if ((uaddr == (char *) NULL) || uaddr[0] == '\0') { + svcerr_noprog(transp); + if (uaddr != NULL) { + free((void *) uaddr); + } + goto error; + } + if (uaddr != NULL) { + free((void *) uaddr); + } + } + nconf = rpcbind_get_conf(transp->xp_netid); + if (nconf == (struct netconfig *)NULL) { + if (reply_type == RPCBPROC_INDIRECT) + svcerr_systemerr(transp); + if (debugging) + fprintf(stderr, + "rpcbproc_callit_com: rpcbind_get_conf failed\n"); + goto error; + } + localsa = local_sa(((struct sockaddr *)caller->buf)->sa_family); + if (localsa == NULL) { + if (debugging) + fprintf(stderr, + "rpcbproc_callit_com: no local address\n"); + goto error; + } + tbuf.len = tbuf.maxlen = localsa->sa_len; + tbuf.buf = localsa; + local_uaddr = + addrmerge(&tbuf, rbl->rpcb_map.r_addr, NULL, nconf->nc_netid); + m_uaddr = addrmerge(caller, rbl->rpcb_map.r_addr, NULL, + nconf->nc_netid); +#ifdef RPCBIND_DEBUG + if (debugging) + fprintf(stderr, "merged uaddr %s\n", m_uaddr); +#endif + if ((fd = find_rmtcallfd_by_netid(nconf->nc_netid)) == -1) { + if (reply_type == RPCBPROC_INDIRECT) + svcerr_systemerr(transp); + free((void *) m_uaddr); + goto error; + } + xidp = __rpcb_get_dg_xidp(transp); + call_msg.rm_xid = forward_register(*xidp, + caller, fd, m_uaddr, reply_type, versnum); + if (call_msg.rm_xid == 0) { + /* + * A duplicate request for the slow server. Let's not + * beat on it any more. + */ + if (debugging) + fprintf(stderr, + "rpcbproc_callit_com: duplicate request\n"); + free((void *) m_uaddr); + goto error; + } else if (call_msg.rm_xid == -1) { + /* forward_register failed. Perhaps no memory. */ + if (debugging) + fprintf(stderr, + "rpcbproc_callit_com: forward_register failed\n"); + free((void *) m_uaddr); + goto error; + } + +#ifdef DEBUG_RMTCALL + if (debugging) + fprintf(stderr, + "rpcbproc_callit_com: original XID %x, new XID %x\n", + *xidp, call_msg.rm_xid); +#endif + call_msg.rm_direction = CALL; + call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; + call_msg.rm_call.cb_prog = a.rmt_prog; + call_msg.rm_call.cb_vers = a.rmt_vers; + if (sendsz > RPC_BUF_MAX) { +#ifdef notyet + outbuf_alloc = alloca(sendsz); /* not in IDR2? */ +#else + outbuf_alloc = malloc(sendsz); +#endif /* notyet */ + if (outbuf_alloc == NULL) { + if (reply_type == RPCBPROC_INDIRECT) + svcerr_systemerr(transp); + if (debugging) + fprintf(stderr, + "rpcbproc_callit_com: No memory!\n"); + goto error; + } + xdrmem_create(&outxdr, outbuf_alloc, sendsz, XDR_ENCODE); + } else { + xdrmem_create(&outxdr, outbuf, sendsz, XDR_ENCODE); + } + if (!xdr_callhdr(&outxdr, &call_msg)) { + if (reply_type == RPCBPROC_INDIRECT) + svcerr_systemerr(transp); + if (debugging) + fprintf(stderr, + "rpcbproc_callit_com: xdr_callhdr failed\n"); + goto error; + } + if (!xdr_u_int32_t(&outxdr, &(a.rmt_proc))) { + if (reply_type == RPCBPROC_INDIRECT) + svcerr_systemerr(transp); + if (debugging) + fprintf(stderr, + "rpcbproc_callit_com: xdr_u_long failed\n"); + goto error; + } + + if (rqstp->rq_cred.oa_flavor == AUTH_NULL) { + auth = authnone_create(); + } else if (rqstp->rq_cred.oa_flavor == AUTH_SYS) { + struct authunix_parms *au; + + au = (struct authunix_parms *)rqstp->rq_clntcred; + auth = authunix_create(au->aup_machname, + au->aup_uid, au->aup_gid, + au->aup_len, au->aup_gids); + if (auth == NULL) /* fall back */ + auth = authnone_create(); + } else { + /* we do not support any other authentication scheme */ + if (debugging) + fprintf(stderr, +"rpcbproc_callit_com: oa_flavor != AUTH_NONE and oa_flavor != AUTH_SYS\n"); + if (reply_type == RPCBPROC_INDIRECT) + svcerr_weakauth(transp); /* XXX too strong.. */ + goto error; + } + if (auth == NULL) { + if (reply_type == RPCBPROC_INDIRECT) + svcerr_systemerr(transp); + if (debugging) + fprintf(stderr, + "rpcbproc_callit_com: authwhatever_create returned NULL\n"); + goto error; + } + if (!AUTH_MARSHALL(auth, &outxdr)) { + if (reply_type == RPCBPROC_INDIRECT) + svcerr_systemerr(transp); + AUTH_DESTROY(auth); + if (debugging) + fprintf(stderr, + "rpcbproc_callit_com: AUTH_MARSHALL failed\n"); + goto error; + } + AUTH_DESTROY(auth); + if (!xdr_opaque_parms(&outxdr, &a)) { + if (reply_type == RPCBPROC_INDIRECT) + svcerr_systemerr(transp); + if (debugging) + fprintf(stderr, + "rpcbproc_callit_com: xdr_opaque_parms failed\n"); + goto error; + } + outlen = (int) XDR_GETPOS(&outxdr); + if (outbuf_alloc) + outbufp = outbuf_alloc; + else + outbufp = outbuf; + + na = uaddr2taddr(nconf, local_uaddr); + if (!na) { + if (reply_type == RPCBPROC_INDIRECT) + svcerr_systemerr(transp); + goto error; + } + + if (sendto(fd, outbufp, outlen, 0, (struct sockaddr *)na->buf, na->len) + != outlen) { + if (debugging) + fprintf(stderr, + "rpcbproc_callit_com: sendto failed: errno %d\n", errno); + if (reply_type == RPCBPROC_INDIRECT) + svcerr_systemerr(transp); + goto error; + } + goto out; + +error: + if (call_msg.rm_xid != 0) + (void) free_slot_by_xid(call_msg.rm_xid); +out: + if (local_uaddr) + free(local_uaddr); + if (buf_alloc) + free((void *) buf_alloc); + if (outbuf_alloc) + free((void *) outbuf_alloc); + if (na) { + free(na->buf); + free(na); + } +} + +/* + * Makes an entry into the FIFO for the given request. + * If duplicate request, returns a 0, else returns the xid of its call. + */ +static u_int32_t +forward_register(u_int32_t caller_xid, struct netbuf *caller_addr, + int forward_fd, char *uaddr, rpcproc_t reply_type, + rpcvers_t versnum) +{ + int i; + int j = 0; + time_t min_time, time_now; + static u_int32_t lastxid; + int entry = -1; + + min_time = FINFO[0].time; + time_now = time((time_t *)0); + /* initialization */ + if (lastxid == 0) + lastxid = time_now * NFORWARD; + + /* + * Check if it is an duplicate entry. Then, + * try to find an empty slot. If not available, then + * use the slot with the earliest time. + */ + for (i = 0; i < NFORWARD; i++) { + if (FINFO[i].flag & FINFO_ACTIVE) { + if ((FINFO[i].caller_xid == caller_xid) && + (FINFO[i].reply_type == reply_type) && + (FINFO[i].versnum == versnum) && + (!netbufcmp(FINFO[i].caller_addr, + caller_addr))) { + FINFO[i].time = time((time_t *)0); + return (0); /* Duplicate entry */ + } else { + /* Should we wait any longer */ + if ((time_now - FINFO[i].time) > MAXTIME_OFF) + (void) free_slot_by_index(i); + } + } + if (entry == -1) { + if ((FINFO[i].flag & FINFO_ACTIVE) == 0) { + entry = i; + } else if (FINFO[i].time < min_time) { + j = i; + min_time = FINFO[i].time; + } + } + } + if (entry != -1) { + /* use this empty slot */ + j = entry; + } else { + (void) free_slot_by_index(j); + } + if ((FINFO[j].caller_addr = netbufdup(caller_addr)) == NULL) { + return (-1); + } + rpcb_rmtcalls++; /* no of pending calls */ + FINFO[j].flag = FINFO_ACTIVE; + FINFO[j].reply_type = reply_type; + FINFO[j].versnum = versnum; + FINFO[j].time = time_now; + FINFO[j].caller_xid = caller_xid; + FINFO[j].forward_fd = forward_fd; + /* + * Though uaddr is not allocated here, it will still be freed + * from free_slot_*(). + */ + FINFO[j].uaddr = uaddr; + lastxid = lastxid + NFORWARD; + FINFO[j].forward_xid = lastxid + j; /* encode slot */ + return (FINFO[j].forward_xid); /* forward on this xid */ +} + +static struct finfo * +forward_find(u_int32_t reply_xid) +{ + int i; + + i = reply_xid % NFORWARD; + if (i < 0) + i += NFORWARD; + if ((FINFO[i].flag & FINFO_ACTIVE) && + (FINFO[i].forward_xid == reply_xid)) { + return (&FINFO[i]); + } + return (NULL); +} + +static int +free_slot_by_xid(u_int32_t xid) +{ + int entry; + + entry = xid % NFORWARD; + if (entry < 0) + entry += NFORWARD; + return (free_slot_by_index(entry)); +} + +static int +free_slot_by_index(int index) +{ + struct finfo *fi; + + fi = &FINFO[index]; + if (fi->flag & FINFO_ACTIVE) { + netbuffree(fi->caller_addr); + /* XXX may be too big, but can't access xprt array here */ + if (fi->forward_fd >= svc_maxfd) + svc_maxfd--; + free((void *) fi->uaddr); + fi->flag &= ~FINFO_ACTIVE; + rpcb_rmtcalls--; + return (1); + } + return (0); +} + +static int +netbufcmp(struct netbuf *n1, struct netbuf *n2) +{ + return ((n1->len != n2->len) || memcmp(n1->buf, n2->buf, n1->len)); +} + +static struct netbuf * +netbufdup(struct netbuf *ap) +{ + struct netbuf *np; + + np = (struct netbuf *) malloc(sizeof (struct netbuf) + ap->len); + if (np) { + np->maxlen = np->len = ap->len; + np->buf = ((char *) np) + sizeof (struct netbuf); + (void) memcpy(np->buf, ap->buf, ap->len); + } + return (np); +} + +static void +netbuffree(struct netbuf *ap) +{ + free((void *) ap); +} + + +#define MASKVAL (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND) + +void +my_svc_run() +{ + size_t nfds; + struct pollfd pollfds[FD_SETSIZE]; + int poll_ret, check_ret; + int n; +#ifdef SVC_RUN_DEBUG + int i; +#endif + register struct pollfd *p; + + for (;;) { + p = pollfds; + for (n = 0; n <= svc_maxfd; n++) { + if (FD_ISSET(n, &svc_fdset)) { + p->fd = n; + p->events = MASKVAL; + p++; + } + } + nfds = p - pollfds; + poll_ret = 0; +#ifdef SVC_RUN_DEBUG + if (debugging) { + fprintf(stderr, "polling for read on fd < "); + for (i = 0, p = pollfds; i < nfds; i++, p++) + if (p->events) + fprintf(stderr, "%d ", p->fd); + fprintf(stderr, ">\n"); + } +#endif + switch (poll_ret = poll(pollfds, nfds, INFTIM)) { + case -1: + /* + * We ignore all errors, continuing with the assumption + * that it was set by the signal handlers (or any + * other outside event) and not caused by poll(). + */ + case 0: + continue; + default: +#ifdef SVC_RUN_DEBUG + if (debugging) { + fprintf(stderr, "poll returned read fds < "); + for (i = 0, p = pollfds; i < nfds; i++, p++) + if (p->revents) + fprintf(stderr, "%d ", p->fd); + fprintf(stderr, ">\n"); + } +#endif + /* + * If we found as many replies on callback fds + * as the number of descriptors selectable which + * poll() returned, there can be no more so we + * don't call svc_getreq_poll. Otherwise, there + * must be another so we must call svc_getreq_poll. + */ + if ((check_ret = check_rmtcalls(pollfds, nfds)) == + poll_ret) + continue; + svc_getreq_poll(pollfds, poll_ret-check_ret); + } +#ifdef SVC_RUN_DEBUG + if (debugging) { + fprintf(stderr, "svc_maxfd now %u\n", svc_maxfd); + } +#endif + } +} + +static int +check_rmtcalls(struct pollfd *pfds, int nfds) +{ + int j, ncallbacks_found = 0, rmtcalls_pending; + SVCXPRT *xprt; + + if (rpcb_rmtcalls == 0) + return (0); + + rmtcalls_pending = rpcb_rmtcalls; + for (j = 0; j < nfds; j++) { + if ((xprt = find_rmtcallxprt_by_fd(pfds[j].fd)) != NULL) { + if (pfds[j].revents) { + ncallbacks_found++; +#ifdef DEBUG_RMTCALL + if (debugging) + fprintf(stderr, +"my_svc_run: polled on forwarding fd %d, netid %s - calling handle_reply\n", + pfds[j].fd, xprt->xp_netid); +#endif + handle_reply(pfds[j].fd, xprt); + pfds[j].revents = 0; + if (ncallbacks_found >= rmtcalls_pending) { + break; + } + } + } + } + return (ncallbacks_found); +} + +static void +xprt_set_caller(SVCXPRT *xprt, struct finfo *fi) +{ + u_int32_t *xidp; + + *(svc_getrpccaller(xprt)) = *(fi->caller_addr); + xidp = __rpcb_get_dg_xidp(xprt); + *xidp = fi->caller_xid; +} + +/* + * Call svcerr_systemerr() only if RPCBVERS4 + */ +static void +send_svcsyserr(SVCXPRT *xprt, struct finfo *fi) +{ + if (fi->reply_type == RPCBPROC_INDIRECT) { + xprt_set_caller(xprt, fi); + svcerr_systemerr(xprt); + } + return; +} + +static void +handle_reply(int fd, SVCXPRT *xprt) +{ + XDR reply_xdrs; + struct rpc_msg reply_msg; + struct rpc_err reply_error; + char *buffer; + struct finfo *fi; + int inlen, pos, len; + struct r_rmtcall_args a; + struct sockaddr_storage ss; + socklen_t fromlen; +#ifdef SVC_RUN_DEBUG + char *uaddr; +#endif + + buffer = malloc(RPC_BUF_MAX); + if (buffer == NULL) + goto done; + + do { + inlen = recvfrom(fd, buffer, RPC_BUF_MAX, 0, + (struct sockaddr *)&ss, &fromlen); + } while (inlen < 0 && errno == EINTR); + if (inlen < 0) { + if (debugging) + fprintf(stderr, + "handle_reply: recvfrom returned %d, errno %d\n", inlen, errno); + goto done; + } + + reply_msg.acpted_rply.ar_verf = _null_auth; + reply_msg.acpted_rply.ar_results.where = 0; + reply_msg.acpted_rply.ar_results.proc = (xdrproc_t) xdr_void; + + xdrmem_create(&reply_xdrs, buffer, (u_int)inlen, XDR_DECODE); + if (!xdr_replymsg(&reply_xdrs, &reply_msg)) { + if (debugging) + (void) fprintf(stderr, + "handle_reply: xdr_replymsg failed\n"); + goto done; + } + fi = forward_find(reply_msg.rm_xid); +#ifdef SVC_RUN_DEBUG + if (debugging) { + fprintf(stderr, "handle_reply: reply xid: %d fi addr: %p\n", + reply_msg.rm_xid, fi); + } +#endif + if (fi == NULL) { + goto done; + } + _seterr_reply(&reply_msg, &reply_error); + if (reply_error.re_status != RPC_SUCCESS) { + if (debugging) + (void) fprintf(stderr, "handle_reply: %s\n", + clnt_sperrno(reply_error.re_status)); + send_svcsyserr(xprt, fi); + goto done; + } + pos = XDR_GETPOS(&reply_xdrs); + len = inlen - pos; + a.rmt_args.args = &buffer[pos]; + a.rmt_args.arglen = len; + a.rmt_uaddr = fi->uaddr; + a.rmt_localvers = fi->versnum; + + xprt_set_caller(xprt, fi); +#ifdef SVC_RUN_DEBUG + uaddr = taddr2uaddr(rpcbind_get_conf("udp"), + svc_getrpccaller(xprt)); + if (debugging) { + fprintf(stderr, "handle_reply: forwarding address %s to %s\n", + a.rmt_uaddr, uaddr ? uaddr : "unknown"); + } + if (uaddr) + free((void *) uaddr); +#endif + svc_sendreply(xprt, (xdrproc_t) xdr_rmtcall_result, (char *) &a); +done: + if (buffer) + free(buffer); + + if (reply_msg.rm_xid == 0) { +#ifdef SVC_RUN_DEBUG + if (debugging) { + fprintf(stderr, "handle_reply: NULL xid on exit!\n"); + } +#endif + } else + (void) free_slot_by_xid(reply_msg.rm_xid); + return; +} + +static void +find_versions(rpcprog_t prog, char *netid, rpcvers_t *lowvp, rpcvers_t *highvp) +{ + register rpcblist_ptr rbl; + int lowv = 0; + int highv = 0; + + for (rbl = list_rbl; rbl != NULL; rbl = rbl->rpcb_next) { + if ((rbl->rpcb_map.r_prog != prog) || + ((rbl->rpcb_map.r_netid != NULL) && + (strcasecmp(rbl->rpcb_map.r_netid, netid) != 0))) + continue; + if (lowv == 0) { + highv = rbl->rpcb_map.r_vers; + lowv = highv; + } else if (rbl->rpcb_map.r_vers < lowv) { + lowv = rbl->rpcb_map.r_vers; + } else if (rbl->rpcb_map.r_vers > highv) { + highv = rbl->rpcb_map.r_vers; + } + } + *lowvp = lowv; + *highvp = highv; + return; +} + +/* + * returns the item with the given program, version number and netid. + * If that version number is not found, it returns the item with that + * program number, so that address is now returned to the caller. The + * caller when makes a call to this program, version number, the call + * will fail and it will return with PROGVERS_MISMATCH. The user can + * then determine the highest and the lowest version number for this + * program using clnt_geterr() and use those program version numbers. + * + * Returns the RPCBLIST for the given prog, vers and netid + */ +static rpcblist_ptr +find_service(rpcprog_t prog, rpcvers_t vers, char *netid) +{ + register rpcblist_ptr hit = NULL; + register rpcblist_ptr rbl; + + for (rbl = list_rbl; rbl != NULL; rbl = rbl->rpcb_next) { + if ((rbl->rpcb_map.r_prog != prog) || + ((rbl->rpcb_map.r_netid != NULL) && + (strcasecmp(rbl->rpcb_map.r_netid, netid) != 0))) + continue; + hit = rbl; + if (rbl->rpcb_map.r_vers == vers) + break; + } + return (hit); +} + +/* + * Copies the name associated with the uid of the caller and returns + * a pointer to it. Similar to getwd(). + */ +static char * +getowner(SVCXPRT *transp, char *owner, size_t ownersize) +{ + struct cmsgcred *cmcred; + + cmcred = __svc_getcallercreds(transp); + if (cmcred == NULL) + strlcpy(owner, "unknown", ownersize); + else if (cmcred->cmcred_uid == 0) + strlcpy(owner, "superuser", ownersize); + else + snprintf(owner, ownersize, "%d", cmcred->cmcred_uid); + + return owner; +} + +#ifdef PORTMAP +/* + * Add this to the pmap list only if it is UDP or TCP. + */ +static int +add_pmaplist(RPCB *arg) +{ + struct pmap pmap; + struct pmaplist *pml; + int h1, h2, h3, h4, p1, p2; + + if (strcmp(arg->r_netid, udptrans) == 0) { + /* It is UDP! */ + pmap.pm_prot = IPPROTO_UDP; + } else if (strcmp(arg->r_netid, tcptrans) == 0) { + /* It is TCP */ + pmap.pm_prot = IPPROTO_TCP; + } else + /* Not a IP protocol */ + return (0); + + /* interpret the universal address for TCP/IP */ + if (sscanf(arg->r_addr, "%d.%d.%d.%d.%d.%d", + &h1, &h2, &h3, &h4, &p1, &p2) != 6) + return (0); + pmap.pm_port = ((p1 & 0xff) << 8) + (p2 & 0xff); + pmap.pm_prog = arg->r_prog; + pmap.pm_vers = arg->r_vers; + /* + * add to END of list + */ + pml = (struct pmaplist *) malloc((u_int)sizeof (struct pmaplist)); + if (pml == NULL) { + (void) syslog(LOG_ERR, "rpcbind: no memory!\n"); + return (1); + } + pml->pml_map = pmap; + pml->pml_next = NULL; + if (list_pml == NULL) { + list_pml = pml; + } else { + struct pmaplist *fnd; + + /* Attach to the end of the list */ + for (fnd = list_pml; fnd->pml_next; fnd = fnd->pml_next) + ; + fnd->pml_next = pml; + } + return (0); +} + +/* + * Delete this from the pmap list only if it is UDP or TCP. + */ +static int +del_pmaplist(RPCB *arg) +{ + struct pmaplist *pml; + struct pmaplist *prevpml, *fnd; + long prot; + + if (strcmp(arg->r_netid, udptrans) == 0) { + /* It is UDP! */ + prot = IPPROTO_UDP; + } else if (strcmp(arg->r_netid, tcptrans) == 0) { + /* It is TCP */ + prot = IPPROTO_TCP; + } else if (arg->r_netid[0] == NULL) { + prot = 0; /* Remove all occurrences */ + } else { + /* Not a IP protocol */ + return (0); + } + for (prevpml = NULL, pml = list_pml; pml; /* cstyle */) { + if ((pml->pml_map.pm_prog != arg->r_prog) || + (pml->pml_map.pm_vers != arg->r_vers) || + (prot && (pml->pml_map.pm_prot != prot))) { + /* both pml & prevpml move forwards */ + prevpml = pml; + pml = pml->pml_next; + continue; + } + /* found it; pml moves forward, prevpml stays */ + fnd = pml; + pml = pml->pml_next; + if (prevpml == NULL) + list_pml = pml; + else + prevpml->pml_next = pml; + free((void *) fnd); + } + return (0); +} +#endif /* PORTMAP */ diff --git a/usr.sbin/rpcbind/rpcbind.8 b/usr.sbin/rpcbind/rpcbind.8 new file mode 100644 index 000000000000..34fea3df9f4f --- /dev/null +++ b/usr.sbin/rpcbind/rpcbind.8 @@ -0,0 +1,112 @@ +.\" @(#)rpcbind.1m 1.19 92/09/14 SMI; from SVr4 +.\" Copyright 1989 AT&T +.\" Copyright 1991 Sun Microsystems, Inc. +.\" $FreeBSD$ +.Dd September 14, 1992 +.Dt RPCBIND 8 +.Os +.Sh NAME +.Nm rpcbind +.Nd universal addresses to RPC program number mapper +.Sh SYNOPSIS +.Nm +.Op Fl dilLs +.Sh DESCRIPTION +.Nm +is a server that converts +.Tn RPC +program numbers into +universal addresses. +It must be running on the host to be able to make +.Tn RPC +calls +on a server on that machine. +.Pp +When an +.Tn RPC +service is started, +it tells +.Nm +the address at which it is listening, +and the +.Tn RPC +program numbers it is prepared to serve. +When a client wishes to make an +.Tn RPC +call to a given program number, +it first contacts +.Nm +on the server machine to determine +the address where +.Tn RPC +requests should be sent. +.Pp +.Nm +should be started before any other RPC service. +Normally, standard +.Tn RPC +servers are started by port monitors, so +.Nm +must be started before port monitors are invoked. +.Pp +When +.Nm +is started, it checks that certain name-to-address +translation-calls function correctly. +If they fail, the network configuration databases may be corrupt. +Since +.Tn RPC +services cannot function correctly in this situation, +.Nm +reports the condition and terminates. +.Pp +.Nm +can only be started by the super-user. +.Sh OPTIONS +.Bl -tag -width indent +.It Fl d +Run in debug mode. +In this mode, +.Nm +will not fork when it starts, will print additional information +during operation, and will abort on certain errors. +With this option, the name-to-address translation consistency +checks are shown in detail. +.It Fl i +.Dq insecure +mode. +Allows calls to SET and UNSET from any host. +Normally +.Nm +accepts these requests only from the loopback interface for security reasons. +This change is necessary for programs that were compiled with earlier +versions of the rpc library and do not make those requests using the +loopback interface. +.It Fl l +Turns on libwrap connection logging. +.It Fl s +causes +.Nm +to change to the user daemon as soon as possible. +This causes +.Nm +to use non-privileged ports for outgoing connections, preventing non-privileged +clients from using +.Nm +to connect to services from a privileged port. +.It Fl L +Allow old-style local connections over the loopback interface. +Without this flag, local connections are only allowed over a local socket, +.Pa /var/run/rpcbind.sock +.El +.Sh NOTES +All RPC servers must be restarted if +.Nm +is restarted. +.Sh SEE ALSO +.Xr rpcbind 3 , +.Xr rpcinfo 8 +.Sh FILES +.Bl -tag -width /var/run/rpcbind.sock -compact +.It Pa /var/run/rpcbind.sock +.El diff --git a/usr.sbin/rpcbind/rpcbind.c b/usr.sbin/rpcbind/rpcbind.c new file mode 100644 index 000000000000..2ddf2c084f8d --- /dev/null +++ b/usr.sbin/rpcbind/rpcbind.c @@ -0,0 +1,568 @@ +/* $NetBSD: rpcbind.c,v 1.1 2000/06/02 23:15:42 fvdl Exp $ */ +/* $FreeBSD$ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* + * Copyright (c) 1984 - 1991 by Sun Microsystems, Inc. + */ + +/* #ident "@(#)rpcbind.c 1.19 94/04/25 SMI" */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)rpcbind.c 1.35 89/04/21 Copyr 1984 Sun Micro"; +#endif +#endif + +/* + * rpcbind.c + * Implements the program, version to address mapping for rpc. + * + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/errno.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/wait.h> +#include <sys/signal.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <rpc/rpc.h> +#ifdef PORTMAP +#include <netinet/in.h> +#endif +#include <netdb.h> +#include <stdio.h> +#include <netconfig.h> +#include <stdlib.h> +#include <unistd.h> +#include <syslog.h> +#include <err.h> +#include <libutil.h> +#include <pwd.h> +#include <string.h> +#include <errno.h> +#include "rpcbind.h" + +/* Global variables */ +int debugging = 0; /* Tell me what's going on */ +int doabort = 0; /* When debugging, do an abort on errors */ +rpcblist_ptr list_rbl; /* A list of version 3/4 rpcbind services */ + +/* who to suid to if -s is given */ +#define RUN_AS "daemon" + +int runasdaemon = 0; +int insecure = 0; +int oldstyle_local = 0; +int verboselog = 0; + +#ifdef WARMSTART +/* Local Variable */ +static int warmstart = 0; /* Grab a old copy of registrations */ +#endif + +#ifdef PORTMAP +struct pmaplist *list_pml; /* A list of version 2 rpcbind services */ +char *udptrans; /* Name of UDP transport */ +char *tcptrans; /* Name of TCP transport */ +char *udp_uaddr; /* Universal UDP address */ +char *tcp_uaddr; /* Universal TCP address */ +#endif +static char servname[] = "rpcbind"; +static char superuser[] = "superuser"; + +int main __P((int, char *[])); + +static int init_transport __P((struct netconfig *)); +static void rbllist_add __P((rpcprog_t, rpcvers_t, struct netconfig *, + struct netbuf *)); +static void terminate __P((int)); +static void parseargs __P((int, char *[])); + +int +main(int argc, char *argv[]) +{ + struct netconfig *nconf; + void *nc_handle; /* Net config handle */ + struct rlimit rl; + + parseargs(argc, argv); + + getrlimit(RLIMIT_NOFILE, &rl); + if (rl.rlim_cur < 128) { + if (rl.rlim_max <= 128) + rl.rlim_cur = rl.rlim_max; + else + rl.rlim_cur = 128; + setrlimit(RLIMIT_NOFILE, &rl); + } + openlog("rpcbind", LOG_CONS, LOG_DAEMON); + if (geteuid()) { /* This command allowed only to root */ + fprintf(stderr, "Sorry. You are not superuser\n"); + exit(1); + } + nc_handle = setnetconfig(); /* open netconfig file */ + if (nc_handle == NULL) { + syslog(LOG_ERR, "could not read /etc/netconfig"); + exit(1); + } +#ifdef PORTMAP + udptrans = ""; + tcptrans = ""; +#endif + + nconf = getnetconfigent("unix"); + if (nconf == NULL) { + syslog(LOG_ERR, "%s: can't find local transport\n", argv[0]); + exit(1); + } + init_transport(nconf); + + while ((nconf = getnetconfig(nc_handle))) { + if (nconf->nc_flag & NC_VISIBLE) + init_transport(nconf); + } + endnetconfig(nc_handle); + + /* catch the usual termination signals for graceful exit */ + (void) signal(SIGCHLD, reap); + (void) signal(SIGINT, terminate); + (void) signal(SIGTERM, terminate); + (void) signal(SIGQUIT, terminate); + /* ignore others that could get sent */ + (void) signal(SIGPIPE, SIG_IGN); + (void) signal(SIGHUP, SIG_IGN); + (void) signal(SIGUSR1, SIG_IGN); + (void) signal(SIGUSR2, SIG_IGN); +#ifdef WARMSTART + if (warmstart) { + read_warmstart(); + } +#endif + if (debugging) { + printf("rpcbind debugging enabled."); + if (doabort) { + printf(" Will abort on errors!\n"); + } else { + printf("\n"); + } + } else { + if (daemon(0, 0)) + err(1, "fork failed"); + } + + if (runasdaemon) { + struct passwd *p; + + if((p = getpwnam(RUN_AS)) == NULL) { + syslog(LOG_ERR, "cannot get uid of daemon: %m"); + exit(1); + } + if (setuid(p->pw_uid) == -1) { + syslog(LOG_ERR, "setuid to daemon failed: %m"); + exit(1); + } + } + + network_init(); + + my_svc_run(); + syslog(LOG_ERR, "svc_run returned unexpectedly"); + rpcbind_abort(); + /* NOTREACHED */ + + return 0; +} + +/* + * Adds the entry into the rpcbind database. + * If PORTMAP, then for UDP and TCP, it adds the entries for version 2 also + * Returns 0 if succeeds, else fails + */ +static int +init_transport(struct netconfig *nconf) +{ + int fd; + struct t_bind taddr; + struct addrinfo hints, *res = NULL; + struct __rpc_sockinfo si; + SVCXPRT *my_xprt; + int status; /* bound checking ? */ + int aicode; + int addrlen; + struct sockaddr *sa; + struct sockaddr_un sun; + mode_t oldmask; + + if ((nconf->nc_semantics != NC_TPI_CLTS) && + (nconf->nc_semantics != NC_TPI_COTS) && + (nconf->nc_semantics != NC_TPI_COTS_ORD)) + return (1); /* not my type */ +#ifdef ND_DEBUG + if (debugging) { + int i; + char **s; + + (void) fprintf(stderr, "%s: %ld lookup routines :\n", + nconf->nc_netid, nconf->nc_nlookups); + for (i = 0, s = nconf->nc_lookups; i < nconf->nc_nlookups; + i++, s++) + fprintf(stderr, "[%d] - %s\n", i, *s); + } +#endif + + /* + * XXX - using RPC library internal functions. + */ + if ((fd = __rpc_nconf2fd(nconf)) < 0) { + syslog(LOG_ERR, "cannot create socket for %s", nconf->nc_netid); + return (1); + } + + if (!__rpc_nconf2sockinfo(nconf, &si)) { + syslog(LOG_ERR, "cannot get information for %s", + nconf->nc_netid); + return (1); + } + + if (!strcmp(nconf->nc_netid, "unix")) { + memset(&sun, 0, sizeof sun); + sun.sun_family = AF_LOCAL; + unlink(_PATH_RPCBINDSOCK); + strcpy(sun.sun_path, _PATH_RPCBINDSOCK); + sun.sun_len = SUN_LEN(&sun); + addrlen = sizeof (struct sockaddr_un); + sa = (struct sockaddr *)&sun; + } else { + /* Get rpcbind's address on this transport */ + + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = si.si_af; + hints.ai_socktype = si.si_socktype; + hints.ai_protocol = si.si_proto; + if ((aicode = getaddrinfo(NULL, servname, &hints, &res)) != 0) { + syslog(LOG_ERR, "cannot get local address for %s: %s", + nconf->nc_netid, gai_strerror(aicode)); + return 1; + } + addrlen = res->ai_addrlen; + sa = (struct sockaddr *)res->ai_addr; + } + oldmask = umask(S_IXUSR|S_IXGRP|S_IXOTH); + if (bind(fd, sa, addrlen) < 0) { + syslog(LOG_ERR, "cannot bind %s: %m", nconf->nc_netid); + if (res != NULL) + freeaddrinfo(res); + return 1; + } + (void) umask(oldmask); + + /* Copy the address */ + taddr.addr.len = taddr.addr.maxlen = addrlen; + taddr.addr.buf = malloc(addrlen); + if (taddr.addr.buf == NULL) { + syslog(LOG_ERR, "cannot allocate memory for %s address", + nconf->nc_netid); + if (res != NULL) + freeaddrinfo(res); + return 1; + } + memcpy(taddr.addr.buf, sa, addrlen); +#ifdef ND_DEBUG + if (debugging) { + /* for debugging print out our universal address */ + char *uaddr; + struct netbuf nb; + + nb.buf = sa; + nb.len = nb.maxlen = sa->sa_len; + uaddr = taddr2uaddr(nconf, &nb); + (void) fprintf(stderr, "rpcbind : my address is %s\n", uaddr); + (void) free(uaddr); + } +#endif + + if (res != NULL) + freeaddrinfo(res); + + if (nconf->nc_semantics != NC_TPI_CLTS) + listen(fd, SOMAXCONN); + + my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr, 0, 0); + if (my_xprt == (SVCXPRT *)NULL) { + syslog(LOG_ERR, "%s: could not create service", + nconf->nc_netid); + goto error; + } + +#ifdef PORTMAP + /* + * Register both the versions for tcp/ip, udp/ip and local. + */ + if ((strcmp(nconf->nc_protofmly, NC_INET) == 0 && + (strcmp(nconf->nc_proto, NC_TCP) == 0 || + strcmp(nconf->nc_proto, NC_UDP) == 0)) || + strcmp(nconf->nc_netid, "unix") == 0) { + struct pmaplist *pml; + + if (!svc_register(my_xprt, PMAPPROG, PMAPVERS, + pmap_service, NULL)) { + syslog(LOG_ERR, "could not register on %s", + nconf->nc_netid); + goto error; + } + pml = (struct pmaplist *)malloc((u_int)sizeof (struct pmaplist)); + if (pml == (struct pmaplist *)NULL) { + syslog(LOG_ERR, "no memory!"); + exit(1); + } + pml->pml_map.pm_prog = PMAPPROG; + pml->pml_map.pm_vers = PMAPVERS; + pml->pml_map.pm_port = PMAPPORT; + if (strcmp(nconf->nc_proto, NC_TCP) == 0) { + if (tcptrans[0]) { + syslog(LOG_ERR, + "cannot have more than one TCP transport"); + goto error; + } + tcptrans = strdup(nconf->nc_netid); + pml->pml_map.pm_prot = IPPROTO_TCP; + + /* Let's snarf the universal address */ + /* "h1.h2.h3.h4.p1.p2" */ + tcp_uaddr = taddr2uaddr(nconf, &taddr.addr); + } else if (strcmp(nconf->nc_proto, NC_UDP) == 0) { + if (udptrans[0]) { + syslog(LOG_ERR, + "cannot have more than one UDP transport"); + goto error; + } + udptrans = strdup(nconf->nc_netid); + pml->pml_map.pm_prot = IPPROTO_UDP; + + /* Let's snarf the universal address */ + /* "h1.h2.h3.h4.p1.p2" */ + udp_uaddr = taddr2uaddr(nconf, &taddr.addr); + } else if (strcmp(nconf->nc_netid, "unix") == 0) + pml->pml_map.pm_prot = IPPROTO_ST; + pml->pml_next = list_pml; + list_pml = pml; + + /* Add version 3 information */ + pml = (struct pmaplist *)malloc((u_int)sizeof (struct pmaplist)); + if (pml == (struct pmaplist *)NULL) { + syslog(LOG_ERR, "no memory!"); + exit(1); + } + pml->pml_map = list_pml->pml_map; + pml->pml_map.pm_vers = RPCBVERS; + pml->pml_next = list_pml; + list_pml = pml; + + /* Add version 4 information */ + pml = (struct pmaplist *)malloc((u_int)sizeof (struct pmaplist)); + if (pml == (struct pmaplist *)NULL) { + syslog(LOG_ERR, "no memory!"); + exit(1); + } + pml->pml_map = list_pml->pml_map; + pml->pml_map.pm_vers = RPCBVERS4; + pml->pml_next = list_pml; + list_pml = pml; + + /* Also add version 2 stuff to rpcbind list */ + rbllist_add(PMAPPROG, PMAPVERS, nconf, &taddr.addr); + } +#endif + + /* version 3 registration */ + if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS, rpcb_service_3, NULL)) { + syslog(LOG_ERR, "could not register %s version 3", + nconf->nc_netid); + goto error; + } + rbllist_add(RPCBPROG, RPCBVERS, nconf, &taddr.addr); + + /* version 4 registration */ + if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS4, rpcb_service_4, NULL)) { + syslog(LOG_ERR, "could not register %s version 4", + nconf->nc_netid); + goto error; + } + rbllist_add(RPCBPROG, RPCBVERS4, nconf, &taddr.addr); + + /* decide if bound checking works for this transport */ + status = add_bndlist(nconf, &taddr.addr); +#ifdef BIND_DEBUG + if (debugging) { + if (status < 0) { + fprintf(stderr, "Error in finding bind status for %s\n", + nconf->nc_netid); + } else if (status == 0) { + fprintf(stderr, "check binding for %s\n", + nconf->nc_netid); + } else if (status > 0) { + fprintf(stderr, "No check binding for %s\n", + nconf->nc_netid); + } + } +#endif + /* + * rmtcall only supported on CLTS transports for now. + */ + if (nconf->nc_semantics == NC_TPI_CLTS) { + status = create_rmtcall_fd(nconf); + +#ifdef BIND_DEBUG + if (debugging) { + if (status < 0) { + fprintf(stderr, + "Could not create rmtcall fd for %s\n", + nconf->nc_netid); + } else { + fprintf(stderr, "rmtcall fd for %s is %d\n", + nconf->nc_netid, status); + } + } +#endif + } + return (0); +error: + close(fd); + return (1); +} + +static void +rbllist_add(rpcprog_t prog, rpcvers_t vers, struct netconfig *nconf, + struct netbuf *addr) +{ + rpcblist_ptr rbl; + + rbl = (rpcblist_ptr)malloc((u_int)sizeof (rpcblist)); + if (rbl == (rpcblist_ptr)NULL) { + syslog(LOG_ERR, "no memory!"); + exit(1); + } + + rbl->rpcb_map.r_prog = prog; + rbl->rpcb_map.r_vers = vers; + rbl->rpcb_map.r_netid = strdup(nconf->nc_netid); + rbl->rpcb_map.r_addr = taddr2uaddr(nconf, addr); + rbl->rpcb_map.r_owner = strdup(superuser); + rbl->rpcb_next = list_rbl; /* Attach to global list */ + list_rbl = rbl; +} + +/* + * Catch the signal and die + */ +static void +terminate(int dummy) +{ +#ifdef WARMSTART + syslog(LOG_ERR, + "rpcbind terminating on signal. Restart with \"rpcbind -w\""); + write_warmstart(); /* Dump yourself */ +#endif + exit(2); +} + +void +rpcbind_abort() +{ +#ifdef WARMSTART + write_warmstart(); /* Dump yourself */ +#endif + abort(); +} + +/* get command line options */ +static void +parseargs(int argc, char *argv[]) +{ + int c; + + while ((c = getopt(argc, argv, "dwailLs")) != -1) { + switch (c) { + case 'a': + doabort = 1; /* when debugging, do an abort on */ + break; /* errors; for rpcbind developers */ + /* only! */ + case 'd': + debugging = 1; + break; + case 'i': + insecure = 1; + break; + case 'L': + oldstyle_local = 1; + break; + case 'l': + verboselog = 1; + break; + case 's': + runasdaemon = 1; + break; +#ifdef WARMSTART + case 'w': + warmstart = 1; + break; +#endif + default: /* error */ + fprintf(stderr, "usage: rpcbind [-Idwils]\n"); + exit (1); + } + } + if (doabort && !debugging) { + fprintf(stderr, + "-a (abort) specified without -d (debugging) -- ignored.\n"); + doabort = 0; + } +} + +void +reap(int dummy) +{ + int save_errno = errno; + + while (wait3(NULL, WNOHANG, NULL) > 0) + ; + errno = save_errno; +} + +void +toggle_verboselog(int dummy) +{ + verboselog = !verboselog; +} diff --git a/usr.sbin/rpcbind/rpcbind.h b/usr.sbin/rpcbind/rpcbind.h new file mode 100644 index 000000000000..63cf2d4200f5 --- /dev/null +++ b/usr.sbin/rpcbind/rpcbind.h @@ -0,0 +1,144 @@ +/* $NetBSD: rpcbind.h,v 1.1 2000/06/03 00:47:21 fvdl Exp $ */ +/* $FreeBSD$ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* + * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. + */ + +/* #ident "@(#)rpcbind.h 1.4 90/04/12 SMI" */ + +/* + * rpcbind.h + * The common header declarations + */ + +#ifndef rpcbind_h +#define rpcbind_h + +#ifdef PORTMAP +#include <rpc/pmap_prot.h> +#endif +#include <rpc/rpcb_prot.h> + +/* + * Stuff for the rmtcall service + */ +struct encap_parms { + u_int32_t arglen; + char *args; +}; + +struct r_rmtcall_args { + u_int32_t rmt_prog; + u_int32_t rmt_vers; + u_int32_t rmt_proc; + int rmt_localvers; /* whether to send port # or uaddr */ + char *rmt_uaddr; + struct encap_parms rmt_args; +}; + +extern int debugging; +extern int doabort; +extern int verboselog; +extern int insecure; +extern int oldstyle_local; +extern rpcblist_ptr list_rbl; /* A list of version 3 & 4 rpcbind services */ + +#ifdef PORTMAP +extern struct pmaplist *list_pml; /* A list of version 2 rpcbind services */ +extern char *udptrans; /* Name of UDP transport */ +extern char *tcptrans; /* Name of TCP transport */ +extern char *udp_uaddr; /* Universal UDP address */ +extern char *tcp_uaddr; /* Universal TCP address */ +#endif + +int add_bndlist __P((struct netconfig *, struct netbuf *)); +bool_t is_bound __P((char *, char *)); +char *mergeaddr __P((SVCXPRT *, char *, char *, char *)); +struct netconfig *rpcbind_get_conf __P((char *)); + +void rpcbs_init __P((void)); +void rpcbs_procinfo __P((rpcvers_t, rpcproc_t)); +void rpcbs_set __P((rpcvers_t, bool_t)); +void rpcbs_unset __P((rpcvers_t, bool_t)); +void rpcbs_getaddr __P((rpcvers_t, rpcprog_t, rpcvers_t, char *, char *)); +void rpcbs_rmtcall __P((rpcvers_t, rpcproc_t, rpcprog_t, rpcvers_t, rpcproc_t, + char *, rpcblist_ptr)); +void *rpcbproc_getstat __P((void *, struct svc_req *, SVCXPRT *, rpcvers_t)); + +void rpcb_service_3 __P((struct svc_req *, SVCXPRT *)); +void rpcb_service_4 __P((struct svc_req *, SVCXPRT *)); + +/* Common functions shared between versions */ +void *rpcbproc_set_com __P((void *, struct svc_req *, SVCXPRT *, rpcvers_t)); +void *rpcbproc_unset_com __P((void *, struct svc_req *, SVCXPRT *, rpcvers_t)); +bool_t map_set __P((RPCB *, char *)); +bool_t map_unset __P((RPCB *, char *)); +void delete_prog __P((int)); +void *rpcbproc_getaddr_com __P((RPCB *, struct svc_req *, SVCXPRT *, rpcvers_t, + rpcvers_t)); +void *rpcbproc_gettime_com __P((void *, struct svc_req *, SVCXPRT *, + rpcvers_t)); +void *rpcbproc_uaddr2taddr_com __P((void *, struct svc_req *, + SVCXPRT *, rpcvers_t)); +void *rpcbproc_taddr2uaddr_com __P((void *, struct svc_req *, SVCXPRT *, + rpcvers_t)); +int create_rmtcall_fd __P((struct netconfig *)); +void rpcbproc_callit_com __P((struct svc_req *, SVCXPRT *, rpcvers_t, + rpcvers_t)); +void my_svc_run __P((void)); + +void rpcbind_abort __P((void)); +void reap __P((int)); +void toggle_verboselog __P((int)); + +int check_access __P((SVCXPRT *, rpcproc_t, void *, int)); +int check_callit __P((SVCXPRT *, struct r_rmtcall_args *, int)); +void logit __P((int, struct sockaddr *, rpcproc_t, rpcprog_t, const char *)); +int is_loopback __P((struct netbuf *)); + +#ifdef PORTMAP +extern void pmap_service __P((struct svc_req *, SVCXPRT *)); +#endif + +void write_warmstart __P((void)); +void read_warmstart __P((void)); + +char *addrmerge __P((struct netbuf *caller, char *serv_uaddr, char *clnt_uaddr, + char *netid)); +void network_init __P((void)); +struct sockaddr *local_sa __P((int)); + +/* For different getaddr semantics */ +#define RPCB_ALLVERS 0 +#define RPCB_ONEVERS 1 + +#endif /* rpcbind_h */ diff --git a/usr.sbin/rpcbind/security.c b/usr.sbin/rpcbind/security.c new file mode 100644 index 000000000000..8d784d6c6686 --- /dev/null +++ b/usr.sbin/rpcbind/security.c @@ -0,0 +1,283 @@ +/* $NetBSD: security.c,v 1.5 2000/06/08 09:01:05 fvdl Exp $ */ +/* $FreeBSD$ */ + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <rpc/rpc.h> +#include <rpc/rpcb_prot.h> +#include <rpc/pmap_prot.h> +#include <err.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <libutil.h> +#include <syslog.h> +#include <netdb.h> + +/* + * XXX for special case checks in check_callit. + */ +#include <rpcsvc/mount.h> +#include <rpcsvc/rquota.h> +#include <rpcsvc/nfs_prot.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> +#include <rpcsvc/yppasswd.h> + +#include "rpcbind.h" + +#ifdef LIBWRAP +# include <tcpd.h> +#ifndef LIBWRAP_ALLOW_FACILITY +# define LIBWRAP_ALLOW_FACILITY LOG_AUTH +#endif +#ifndef LIBWRAP_ALLOW_SEVERITY +# define LIBWRAP_ALLOW_SEVERITY LOG_INFO +#endif +#ifndef LIBWRAP_DENY_FACILITY +# define LIBWRAP_DENY_FACILITY LOG_AUTH +#endif +#ifndef LIBWRAP_DENY_SEVERITY +# define LIBWRAP_DENY_SEVERITY LOG_WARNING +#endif +int allow_severity = LIBWRAP_ALLOW_FACILITY|LIBWRAP_ALLOW_SEVERITY; +int deny_severity = LIBWRAP_DENY_FACILITY|LIBWRAP_DENY_SEVERITY; +#endif + +#ifndef PORTMAP_LOG_FACILITY +# define PORTMAP_LOG_FACILITY LOG_AUTH +#endif +#ifndef PORTMAP_LOG_SEVERITY +# define PORTMAP_LOG_SEVERITY LOG_INFO +#endif +int log_severity = PORTMAP_LOG_FACILITY|PORTMAP_LOG_SEVERITY; + +extern int verboselog; + +int +check_access(SVCXPRT *xprt, rpcproc_t proc, void *args, int rpcbvers) +{ + struct netbuf *caller = svc_getrpccaller(xprt); + struct sockaddr *addr = (struct sockaddr *)caller->buf; +#ifdef LIBWRAP + struct request_info req; +#endif + rpcprog_t prog = 0; + rpcb *rpcbp; + struct pmap *pmap; + + /* + * The older PMAP_* equivalents have the same numbers, so + * they are accounted for here as well. + */ + switch (proc) { + case RPCBPROC_GETADDR: + case RPCBPROC_SET: + case RPCBPROC_UNSET: + if (rpcbvers > PMAPVERS) { + rpcbp = (rpcb *)args; + prog = rpcbp->r_prog; + } else { + pmap = (struct pmap *)args; + prog = pmap->pm_prog; + } + if (proc == RPCBPROC_GETADDR) + break; + if (!insecure && !is_loopback(caller)) { + if (verboselog) + logit(log_severity, addr, proc, prog, + " declined (non-loopback sender)"); + return 0; + } + break; + case RPCBPROC_CALLIT: + case RPCBPROC_INDIRECT: + case RPCBPROC_DUMP: + case RPCBPROC_GETTIME: + case RPCBPROC_UADDR2TADDR: + case RPCBPROC_TADDR2UADDR: + case RPCBPROC_GETVERSADDR: + case RPCBPROC_GETADDRLIST: + case RPCBPROC_GETSTAT: + default: + } + +#ifdef LIBWRAP + if (addr->sa_family == AF_LOCAL) + return 1; + request_init(&req, RQ_DAEMON, "rpcbind", RQ_CLIENT_SIN, addr, 0); + sock_methods(&req); + if(!hosts_access(&req)) { + logit(deny_severity, addr, proc, prog, ": request from unauthorized host"); + return 0; + } +#endif + if (verboselog) + logit(log_severity, addr, proc, prog, ""); + return 1; +} + +int +is_loopback(struct netbuf *nbuf) +{ + struct sockaddr *addr = (struct sockaddr *)nbuf->buf; + struct sockaddr_in *sin; +#ifdef INET6 + struct sockaddr_in6 *sin6; +#endif + + switch (addr->sa_family) { + case AF_INET: + if (!oldstyle_local) + return 0; + sin = (struct sockaddr_in *)addr; + return ((sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) && + (ntohs(sin->sin_port) < IPPORT_RESERVED)); +#ifdef INET6 + case AF_INET6: + if (!oldstyle_local) + return 0; + sin6 = (struct sockaddr_in6 *)addr; + return (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr) && + (ntohs(sin6->sin6_port) < IPV6PORT_RESERVED)); +#endif + case AF_LOCAL: + return 1; + default: + } + + return 0; +} + + +/* logit - report events of interest via the syslog daemon */ +void +logit(int severity, struct sockaddr *addr, rpcproc_t procnum, rpcprog_t prognum, + const char *text) +{ + const char *procname; + char procbuf[32]; + char *progname; + char progbuf[32]; + char fromname[NI_MAXHOST]; + struct rpcent *rpc; + static const char *procmap[] = { + /* RPCBPROC_NULL */ "null", + /* RPCBPROC_SET */ "set", + /* RPCBPROC_UNSET */ "unset", + /* RPCBPROC_GETADDR */ "getport/addr", + /* RPCBPROC_DUMP */ "dump", + /* RPCBPROC_CALLIT */ "callit", + /* RPCBPROC_GETTIME */ "gettime", + /* RPCBPROC_UADDR2TADDR */ "uaddr2taddr", + /* RPCBPROC_TADDR2UADDR */ "taddr2uaddr", + /* RPCBPROC_GETVERSADDR */ "getversaddr", + /* RPCBPROC_INDIRECT */ "indirect", + /* RPCBPROC_GETADDRLIST */ "getaddrlist", + /* RPCBPROC_GETSTAT */ "getstat" + }; + + /* + * Fork off a process or the portmap daemon might hang while + * getrpcbynumber() or syslog() does its thing. + */ + + if (fork() == 0) { + setproctitle("logit"); + + /* Try to map program number to name. */ + + if (prognum == 0) { + progname = ""; + } else if ((rpc = getrpcbynumber((int) prognum))) { + progname = rpc->r_name; + } else { + snprintf(progname = progbuf, sizeof(progbuf), "%u", + (unsigned)prognum); + } + + /* Try to map procedure number to name. */ + + if (procnum > (sizeof procmap / sizeof (char *))) { + snprintf(procbuf, sizeof procbuf, "%u", + (unsigned)procnum); + procname = procbuf; + } else + procname = procmap[procnum]; + + /* Write syslog record. */ + + if (addr->sa_family == AF_LOCAL) + strcpy(fromname, "unix"); + else + getnameinfo(addr, addr->sa_len, fromname, + sizeof fromname, NULL, 0, NI_NUMERICHOST); + + syslog(severity, "connect from %s to %s(%s)%s", + fromname, procname, progname, text); + _exit(0); + } +} + +int +check_callit(SVCXPRT *xprt, struct r_rmtcall_args *args, int versnum) +{ + struct sockaddr *sa = (struct sockaddr *)svc_getrpccaller(xprt)->buf; + + /* + * Always allow calling NULLPROC + */ + if (args->rmt_proc == 0) + return 1; + + /* + * XXX - this special casing sucks. + */ + switch (args->rmt_prog) { + case RPCBPROG: + /* + * Allow indirect calls to ourselves in insecure mode. + * The is_loopback checks aren't useful then anyway. + */ + if (!insecure) + goto deny; + break; + case MOUNTPROG: + if (args->rmt_proc != MOUNTPROC_MNT && + args->rmt_proc != MOUNTPROC_UMNT) + break; + goto deny; + case YPBINDPROG: + if (args->rmt_proc != YPBINDPROC_SETDOM) + break; + /* FALLTHROUGH */ + case YPPASSWDPROG: + case NFS_PROGRAM: + case RQUOTAPROG: + goto deny; + case YPPROG: + switch (args->rmt_proc) { + case YPPROC_ALL: + case YPPROC_MATCH: + case YPPROC_FIRST: + case YPPROC_NEXT: + goto deny; + default: + } + default: + } + + return 1; +deny: +#ifdef LIBWRAP + logit(deny_severity, sa, args->rmt_proc, args->rmt_prog, + ": indirect call not allowed"); +#else + logit(0, sa, args->rmt_proc, args->rmt_prog, + ": indirect call not allowed"); +#endif + return 0; +} diff --git a/usr.sbin/rpcbind/util.c b/usr.sbin/rpcbind/util.c new file mode 100644 index 000000000000..bf2001945e43 --- /dev/null +++ b/usr.sbin/rpcbind/util.c @@ -0,0 +1,381 @@ +/* + * $NetBSD: util.c,v 1.4 2000/08/03 00:04:30 fvdl Exp $ + * $FreeBSD$ + */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Frank van der Linden. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/queue.h> +#include <net/if.h> +#include <netinet/in.h> +#include <ifaddrs.h> +#include <sys/poll.h> +#include <rpc/rpc.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <netdb.h> +#include <netconfig.h> +#include <stdio.h> +#include <arpa/inet.h> + +#include "rpcbind.h" + +static struct sockaddr_in *local_in4; +#ifdef INET6 +static struct sockaddr_in6 *local_in6; +#endif + +static int bitmaskcmp __P((void *, void *, void *, int)); +#ifdef INET6 +static void in6_fillscopeid __P((struct sockaddr_in6 *)); +#endif + +/* + * For all bits set in "mask", compare the corresponding bits in + * "dst" and "src", and see if they match. + */ +static int +bitmaskcmp(void *dst, void *src, void *mask, int bytelen) +{ + int i, j; + u_int8_t *p1 = dst, *p2 = src, *netmask = mask; + u_int8_t bitmask; + + for (i = 0; i < bytelen; i++) { + for (j = 0; j < 8; j++) { + bitmask = 1 << j; + if (!(netmask[i] & bitmask)) + continue; + if ((p1[i] & bitmask) != (p2[i] & bitmask)) + return 1; + } + } + + return 0; +} + +/* + * Taken from ifconfig.c + */ +#ifdef INET6 +static void +in6_fillscopeid(struct sockaddr_in6 *sin6) +{ + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { + sin6->sin6_scope_id = + ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]); + sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0; + } +} +#endif + +char * +addrmerge(struct netbuf *caller, char *serv_uaddr, char *clnt_uaddr, + char *netid) +{ + struct ifaddrs *ifap, *ifp, *bestif; +#ifdef INET6 + struct sockaddr_in6 *servsin6, *sin6mask, *clntsin6, *ifsin6, *realsin6; + struct sockaddr_in6 *newsin6; +#endif + struct sockaddr_in *servsin, *sinmask, *clntsin, *newsin, *ifsin; + struct netbuf *serv_nbp, *clnt_nbp = NULL, tbuf; + struct sockaddr *serv_sa; + struct sockaddr *clnt_sa; + struct sockaddr_storage ss; + struct netconfig *nconf; + struct sockaddr *clnt = caller->buf; + char *ret = NULL; + +#ifdef ND_DEBUG + if (debugging) + fprintf(stderr, "addrmerge(caller, %s, %s, %s\n", serv_uaddr, + clnt_uaddr, netid); +#endif + nconf = getnetconfigent(netid); + if (nconf == NULL) + return NULL; + + /* + * Local merge, just return a duplicate. + */ + if (clnt_uaddr != NULL && strncmp(clnt_uaddr, "0.0.0.0.", 8) == 0) + return strdup(clnt_uaddr); + + serv_nbp = uaddr2taddr(nconf, serv_uaddr); + if (serv_nbp == NULL) + return NULL; + + serv_sa = (struct sockaddr *)serv_nbp->buf; + if (clnt_uaddr != NULL) { + clnt_nbp = uaddr2taddr(nconf, clnt_uaddr); + clnt_sa = (struct sockaddr *)clnt_nbp->buf; + } else { + clnt_sa = (struct sockaddr *) + malloc(sizeof (struct sockaddr_storage)); + memcpy(clnt_sa, clnt, clnt->sa_len); + } + + if (getifaddrs(&ifp) < 0) + return 0; + + /* + * Loop through all interfaces. For each interface, see if the + * network portion of its address is equal to that of the client. + * If so, we have found the interface that we want to use. + */ + for (ifap = ifp; ifap != NULL; ifap = ifap->ifa_next) { + if (ifap->ifa_addr->sa_family != clnt->sa_family || + !(ifap->ifa_flags & IFF_UP)) + continue; + + switch (clnt->sa_family) { + case AF_INET: + /* + * realsin: address that recvfrom gave us. + * ifsin: address of interface being examined. + * clntsin: address that client want us to contact + * it on + * servsin: local address of RPC service. + * sinmask: netmask of this interface + * newsin: initially a copy of clntsin, eventually + * the merged address + */ + servsin = (struct sockaddr_in *)serv_sa; + clntsin = (struct sockaddr_in *)clnt_sa; + sinmask = (struct sockaddr_in *)ifap->ifa_netmask; + newsin = (struct sockaddr_in *)&ss; + ifsin = (struct sockaddr_in *)ifap->ifa_addr; + if (!bitmaskcmp(&ifsin->sin_addr, &clntsin->sin_addr, + &sinmask->sin_addr, sizeof (struct in_addr))) { + /* + * Found it. + */ + memcpy(newsin, ifap->ifa_addr, + clnt_sa->sa_len); + newsin->sin_port = servsin->sin_port; + tbuf.len = clnt_sa->sa_len; + tbuf.maxlen = sizeof (struct sockaddr_storage); + tbuf.buf = newsin; + goto found; + } + break; +#ifdef INET6 + case AF_INET6: + /* + * realsin6: address that recvfrom gave us. + * ifsin6: address of interface being examined. + * clntsin6: address that client want us to contact + * it on + * servsin6: local address of RPC service. + * sin6mask: netmask of this interface + * newsin6: initially a copy of clntsin, eventually + * the merged address + * + * For v6 link local addresses, if the client contacted + * us via a link-local address, and wants us to reply + * to one, use the scope id to see which one. + */ + realsin6 = (struct sockaddr_in6 *)clnt; + ifsin6 = (struct sockaddr_in6 *)ifap->ifa_addr; + in6_fillscopeid(ifsin6); + clntsin6 = (struct sockaddr_in6 *)clnt_sa; + servsin6 = (struct sockaddr_in6 *)serv_sa; + sin6mask = (struct sockaddr_in6 *)ifap->ifa_netmask; + newsin6 = (struct sockaddr_in6 *)&ss; + if (IN6_IS_ADDR_LINKLOCAL(&ifsin6->sin6_addr) && + IN6_IS_ADDR_LINKLOCAL(&realsin6->sin6_addr) && + IN6_IS_ADDR_LINKLOCAL(&clntsin6->sin6_addr)) { + if (ifsin6->sin6_scope_id != + realsin6->sin6_scope_id) + continue; +match: + memcpy(newsin6, ifsin6, clnt_sa->sa_len); + newsin6->sin6_port = servsin6->sin6_port; + tbuf.maxlen = sizeof (struct sockaddr_storage); + tbuf.len = clnt_sa->sa_len; + tbuf.buf = newsin6; + goto found; + } + if (!bitmaskcmp(&ifsin6->sin6_addr, + &clntsin6->sin6_addr, &sin6mask->sin6_addr, + sizeof (struct in6_addr))) + goto match; + break; +#endif + default: + goto freeit; + } + } + /* + * Didn't find anything. Get the first possibly useful interface, + * preferring "normal" interfaces to point-to-point and loopback + * ones. + */ + bestif = NULL; + for (ifap = ifp; ifap != NULL; ifap = ifap->ifa_next) { + if (ifap->ifa_addr->sa_family != clnt->sa_family || + !(ifap->ifa_flags & IFF_UP)) + continue; + if (!(ifap->ifa_flags & IFF_LOOPBACK) && + !(ifap->ifa_flags & IFF_POINTOPOINT)) { + bestif = ifap; + break; + } + if (bestif == NULL) + bestif = ifap; + else if ((bestif->ifa_flags & IFF_LOOPBACK) && + !(ifap->ifa_flags & IFF_LOOPBACK)) + bestif = ifap; + } + ifap = bestif; +found: + if (ifap != NULL) + ret = taddr2uaddr(nconf, &tbuf); +freeit: + freenetconfigent(nconf); + free(serv_sa); + free(serv_nbp); + if (clnt_sa != NULL) + free(clnt_sa); + if (clnt_nbp != NULL) + free(clnt_nbp); + freeifaddrs(ifp); + +#ifdef ND_DEBUG + if (debugging) + fprintf(stderr, "addrmerge: returning %s\n", ret); +#endif + return ret; +} + +void +network_init() +{ +#ifdef INET6 + struct ifaddrs *ifap, *ifp; + struct ipv6_mreq mreq6; + int ifindex, s; +#endif + int ecode; + struct addrinfo hints, *res; + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_INET; + if ((ecode = getaddrinfo(NULL, "sunrpc", &hints, &res))) { + if (debugging) + fprintf(stderr, "can't get local ip4 address: %s\n", + gai_strerror(ecode)); + } else { + local_in4 = (struct sockaddr_in *)malloc(sizeof *local_in4); + if (local_in4 == NULL) { + if (debugging) + fprintf(stderr, "can't alloc local ip4 addr\n"); + } + memcpy(local_in4, res->ai_addr, sizeof *local_in4); + } + +#ifdef INET6 + hints.ai_family = AF_INET6; + if ((ecode = getaddrinfo(NULL, "sunrpc", &hints, &res))) { + if (debugging) + fprintf(stderr, "can't get local ip6 address: %s\n", + gai_strerror(ecode)); + } else { + local_in6 = (struct sockaddr_in6 *)malloc(sizeof *local_in6); + if (local_in6 == NULL) { + if (debugging) + fprintf(stderr, "can't alloc local ip6 addr\n"); + } + memcpy(local_in6, res->ai_addr, sizeof *local_in6); + } + + /* + * Now join the RPC ipv6 multicast group on all interfaces. + */ + if (getifaddrs(&ifp) < 0) + return; + + mreq6.ipv6mr_interface = 0; + inet_pton(AF_INET6, RPCB_MULTICAST_ADDR, &mreq6.ipv6mr_multiaddr); + + s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + + /* + * Loop through all interfaces. For each interface, see if the + * network portion of its address is equal to that of the client. + * If so, we have found the interface that we want to use. + */ + for (ifap = ifp; ifap != NULL; ifap = ifap->ifa_next) { + if (ifap->ifa_addr->sa_family != AF_INET6 || + !(ifap->ifa_flags & IFF_MULTICAST)) + continue; + ifindex = if_nametoindex(ifap->ifa_name); + if (ifindex == mreq6.ipv6mr_interface) + /* + * Already did this one. + */ + continue; + mreq6.ipv6mr_interface = ifindex; + if (setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6, + sizeof mreq6) < 0) + if (debugging) + perror("setsockopt v6 multicast"); + } +#endif + + /* close(s); */ +} + +struct sockaddr * +local_sa(int af) +{ + switch (af) { + case AF_INET: + return (struct sockaddr *)local_in4; +#ifdef INET6 + case AF_INET6: + return (struct sockaddr *)local_in6; +#endif + default: + return NULL; + } +} diff --git a/usr.sbin/rpcbind/warmstart.c b/usr.sbin/rpcbind/warmstart.c new file mode 100644 index 000000000000..fea278952f26 --- /dev/null +++ b/usr.sbin/rpcbind/warmstart.c @@ -0,0 +1,179 @@ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* + * warmstart.c + * Allows for gathering of registrations from a earlier dumped file. + * + * Copyright (c) 1990 by Sun Microsystems, Inc. + */ + +/* + * #ident "@(#)warmstart.c 1.7 93/07/05 SMI" + * $FreeBSD$/ + */ +#include <sys/types.h> +#include <sys/stat.h> +#include <stdio.h> +#include <rpc/rpc.h> +#include <rpc/rpcb_prot.h> +#include <rpc/xdr.h> +#ifdef PORTMAP +#include <netinet/in.h> +#include <rpc/pmap_prot.h> +#endif +#include <syslog.h> +#include <unistd.h> + +#include "rpcbind.h" + +/* + * XXX this code is unsafe and is not used. It should be made safe. + */ + + +/* These files keep the pmap_list and rpcb_list in XDR format */ +#define RPCBFILE "/tmp/rpcbind.file" +#ifdef PORTMAP +#define PMAPFILE "/tmp/portmap.file" +#endif + +static bool_t write_struct __P((char *, xdrproc_t, void *)); +static bool_t read_struct __P((char *, xdrproc_t, void *)); + +static bool_t +write_struct(char *filename, xdrproc_t structproc, void *list) +{ + FILE *fp; + XDR xdrs; + mode_t omask; + + omask = umask(077); + fp = fopen(filename, "w"); + if (fp == NULL) { + int i; + + for (i = 0; i < 10; i++) + close(i); + fp = fopen(filename, "w"); + if (fp == NULL) { + syslog(LOG_ERR, + "cannot open file = %s for writing", filename); + syslog(LOG_ERR, "cannot save any registration"); + return (FALSE); + } + } + (void) umask(omask); + xdrstdio_create(&xdrs, fp, XDR_ENCODE); + + if (structproc(&xdrs, list) == FALSE) { + syslog(LOG_ERR, "rpcbind: xdr_%s: failed", filename); + fclose(fp); + return (FALSE); + } + XDR_DESTROY(&xdrs); + fclose(fp); + return (TRUE); +} + +static bool_t +read_struct(char *filename, xdrproc_t structproc, void *list) +{ + FILE *fp; + XDR xdrs; + struct stat sbuf; + + if (stat(filename, &sbuf) != 0) { + fprintf(stderr, + "rpcbind: cannot stat file = %s for reading\n", filename); + goto error; + } + if ((sbuf.st_uid != 0) || (sbuf.st_mode & S_IRWXG) || + (sbuf.st_mode & S_IRWXO)) { + fprintf(stderr, + "rpcbind: invalid permissions on file = %s for reading\n", + filename); + goto error; + } + fp = fopen(filename, "r"); + if (fp == NULL) { + fprintf(stderr, + "rpcbind: cannot open file = %s for reading\n", filename); + goto error; + } + xdrstdio_create(&xdrs, fp, XDR_DECODE); + + if (structproc(&xdrs, list) == FALSE) { + fprintf(stderr, "rpcbind: xdr_%s: failed\n", filename); + fclose(fp); + goto error; + } + XDR_DESTROY(&xdrs); + fclose(fp); + return (TRUE); + +error: fprintf(stderr, "rpcbind: will start from scratch\n"); + return (FALSE); +} + +void +write_warmstart() +{ + (void) write_struct(RPCBFILE, xdr_rpcblist_ptr, &list_rbl); +#ifdef PORTMAP + (void) write_struct(PMAPFILE, xdr_pmaplist_ptr, &list_pml); +#endif + +} + +void +read_warmstart() +{ + rpcblist_ptr tmp_rpcbl = NULL; +#ifdef PORTMAP + struct pmaplist *tmp_pmapl = NULL; +#endif + int ok1, ok2 = TRUE; + + ok1 = read_struct(RPCBFILE, xdr_rpcblist_ptr, &tmp_rpcbl); + if (ok1 == FALSE) + return; +#ifdef PORTMAP + ok2 = read_struct(PMAPFILE, xdr_pmaplist_ptr, &tmp_pmapl); +#endif + if (ok2 == FALSE) { + xdr_free((xdrproc_t) xdr_rpcblist_ptr, (char *)&tmp_rpcbl); + return; + } + xdr_free((xdrproc_t) xdr_rpcblist_ptr, (char *)&list_rbl); + list_rbl = tmp_rpcbl; +#ifdef PORTMAP + xdr_free((xdrproc_t) xdr_pmaplist_ptr, (char *)&list_pml); + list_pml = tmp_pmapl; +#endif +} diff --git a/usr.sbin/ypbind/yp_ping.c b/usr.sbin/ypbind/yp_ping.c index 558843f0c7fc..744eda07d795 100644 --- a/usr.sbin/ypbind/yp_ping.c +++ b/usr.sbin/ypbind/yp_ping.c @@ -310,7 +310,7 @@ get_reply: } /* end successful completion */ else { /* maybe our credentials need to be refreshed ... */ - if (nrefreshes > 0 && AUTH_REFRESH(cl->cl_auth)) { + if (nrefreshes > 0 && AUTH_REFRESH(cl->cl_auth, &reply_msg)) { nrefreshes--; goto call_again; } @@ -502,7 +502,7 @@ int __yp_ping(restricted_addrs, cnt, dom, port) clnt->cl_auth = authunix_create_default(); cu = (struct cu_data *)clnt->cl_private; tv.tv_sec = 0; - clnt_control(clnt, CLSET_TIMEOUT, &tv); + clnt_control(clnt, CLSET_TIMEOUT, (char *)&tv); ioctl(sock, FIONBIO, &dontblock); oldfunc = clnt->cl_ops->cl_call; clnt->cl_ops->cl_call = clntudp_a_call; diff --git a/usr.sbin/ypbind/ypbind.c b/usr.sbin/ypbind/ypbind.c index d6e5e2be1c3a..5304422116c9 100644 --- a/usr.sbin/ypbind/ypbind.c +++ b/usr.sbin/ypbind/ypbind.c @@ -743,7 +743,7 @@ struct _dom_binding *ypdb; ptr = (char *)&ypdb->dom_domain; stat = clnt_broadcast(YPPROG, YPVERS, YPPROC_DOMAIN_NONACK, xdr_domainname, (char *)&ptr, xdr_bool, (char *)&out, - broadcast_result); + (resultproc_t)broadcast_result); } if (stat != RPC_SUCCESS) { diff --git a/usr.sbin/yppush/yppush_main.c b/usr.sbin/yppush/yppush_main.c index 39b5bdf43d76..ba25dda2a8db 100644 --- a/usr.sbin/yppush/yppush_main.c +++ b/usr.sbin/yppush/yppush_main.c @@ -415,7 +415,7 @@ int yp_push(server, map, tid) job->stat = 0; job->tid = tid; job->port = xprt->xp_port; - job->sock = xprt->xp_sock; /*XXX: Evil!! EEEEEEEVIL!!! */ + job->sock = xprt->xp_fd; /*XXX: Evil!! EEEEEEEVIL!!! */ job->server = strdup(server); job->map = strdup(map); job->prognum = prognum; @@ -437,8 +437,8 @@ int yp_push(server, map, tid) * 2) Even in this day and age, there are still some *NIXes * that don't support async socket I/O. */ - if (fcntl(xprt->xp_sock, F_SETOWN, getpid()) == -1 || - fcntl(xprt->xp_sock, F_SETFL, O_ASYNC) == -1) { + if (fcntl(xprt->xp_fd, F_SETOWN, getpid()) == -1 || + fcntl(xprt->xp_fd, F_SETFL, O_ASYNC) == -1) { yp_error("failed to set async I/O mode: %s", strerror(errno)); yppush_exit(1); diff --git a/usr.sbin/ypserv/yp_dnslookup.c b/usr.sbin/ypserv/yp_dnslookup.c index 5aa03e79c6b3..fdbac25c272a 100644 --- a/usr.sbin/ypserv/yp_dnslookup.c +++ b/usr.sbin/ypserv/yp_dnslookup.c @@ -434,7 +434,7 @@ ypstat yp_async_lookup_name(rqstp, name) /* Check for SOCK_DGRAM or SOCK_STREAM -- we need to know later */ type = -1; len = sizeof(type); - if (getsockopt(rqstp->rq_xprt->xp_sock, SOL_SOCKET, + if (getsockopt(rqstp->rq_xprt->xp_fd, SOL_SOCKET, SO_TYPE, &type, &len) == -1) { yp_error("getsockopt failed: %s", strerror(errno)); return(YP_YPERR); @@ -490,7 +490,7 @@ ypstat yp_async_lookup_addr(rqstp, addr) /* Check for SOCK_DGRAM or SOCK_STREAM -- we need to know later */ type = -1; len = sizeof(type); - if (getsockopt(rqstp->rq_xprt->xp_sock, SOL_SOCKET, + if (getsockopt(rqstp->rq_xprt->xp_fd, SOL_SOCKET, SO_TYPE, &type, &len) == -1) { yp_error("getsockopt failed: %s", strerror(errno)); return(YP_YPERR); |
