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 /lib | |
| parent | 1ac2b9fe972a0c73729565f8310fa6eba55718c4 (diff) | |
Notes
Diffstat (limited to 'lib')
101 files changed, 17066 insertions, 7222 deletions
diff --git a/lib/libc/gen/_pthread_stubs.c b/lib/libc/gen/_pthread_stubs.c index be6dab74635cb..4783359022975 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 ddffa82e4025c..cc15a692d9875 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 0000000000000..e6ceb5ba14138 --- /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 1a66d5f4c9cdc..9a3a99161ae8c 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 f9471598931ed..1247c808a6574 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 ad9d70f990564..c915fad283c6e 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 51cfb1f62bb3d..e154cd2fe3156 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 9649df3ab51bb..403e00d571f40 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 114d59d4428cf..f352c6d5eda90 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 dced8f2104b39..37d0ce9f09831 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 14679c00a9ccb..f60e79f9fa6b0 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 54f23fc9fefd2..11bb74f8eb7fc 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 b71339822dc4e..bfb011e0316af 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 2aed9ddc48c88..43b2a4f3d8bc4 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 0000000000000..f6f8641142a78 --- /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 0000000000000..f9f56127eb4a2 --- /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 d885f1820d17a..696ea541a2edc 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 331f52b04496d..6ddf39d98347d 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 6f228fe99d69f..01dfc7997d0ae 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 46d959b22011e..09b65fc0b0d05 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 9e8e3948d26bb..0000000000000 --- 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 bc103ed095031..0000000000000 --- 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 d55859ca1fdb7..0000000000000 --- 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 0000000000000..bce8fbe31ae1e --- /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 ab01971657e75..a62cad2227f21 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 70c3ac00fb99f..0000000000000 --- 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 0000000000000..fb1151eebd4c0 --- /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 0000000000000..c7278b1cf91bc --- /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 0000000000000..913a4cb1e8b2f --- /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 0000000000000..132a5102a83b4 --- /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 49227b41b5f4d..6c8fe5e21534b 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 208e5d0ea104f..6a02ca152c7f9 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 4290235e686dd..d200103c22811 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 b4fa8124d43e3..3b6768532b6f6 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 24c6257fd8866..193ef26e1afc7 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 c6c3e78f1558b..8adb29de18615 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 8cd6b6b0678eb..298a451d2f77b 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 0000000000000..5abf831fd7504 --- /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 0000000000000..25738bcc2efe6 --- /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 cec14df72ab53..f598f78d3ee06 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 2fa0a3c1bd57c..36fa3dcd629c3 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 41bb78d582db6..676444e1e5d4c 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 b51ac696b0f32..4c8397f412d41 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 bef94fdf45eb2..ff75c9ff1d62f 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 f424842994770..62b572562d57a 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 9c5230ddaeba5..e30f977cb3096 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 298c95613e4ec..51e6d3a0c3e04 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 e2c73cf88de51..fdd28512fd4eb 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 8a45a9979a9d3..6cf79f06bd2ca 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 dca3a1880d938..827fd3eb7cafc 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 0000000000000..b3d720b0fae22 --- /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 0000000000000..cd368dd351a34 --- /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 0000000000000..e13ac5b864273 --- /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 0000000000000..8a1269393aff2 --- /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 043c082850564..ba5839e6df3fa 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 44b3279660390..16e0a2b00305a 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 0000000000000..790bbc59683f7 --- /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 940a29d13704e..4dbfe19839e33 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 0000000000000..a915e5743b86a --- /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 0000000000000..07783d67089c0 --- /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 0000000000000..06ff75516ec4f --- /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 0000000000000..b9788b2e3a70f --- /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 0000000000000..3a6e0c9fd4f13 --- /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 0000000000000..2ab6f00e9bca2 --- /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 0000000000000..e021a330f8f70 --- /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 0000000000000..2fdc74ff391c0 --- /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 0000000000000..aa46510876944 --- /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 0000000000000..c094e9974e626 --- /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 0000000000000..3092696486073 --- /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 f28b4fda9b8a3..03d1b8542c540 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 94d6057e6004b..6e57245a4dd51 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 fa1dca7ce7ec6..48d65b0a839b9 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 f3af780f16831..0d363c132bac8 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 4e800e5e2aa3f..ba6e483012b5f 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 0000000000000..03ace97f964c7 --- /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 0000000000000..773118d62e36f --- /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 4726152534280..5ab10f8a77dc2 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 bc5b48a7d0ddd..78862fe0410d5 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 1bfaf1c8cd453..fec87b7fcf29f 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 d7e425bf247de..0000000000000 --- 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 0abd48696bdba..0000000000000 --- 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 5e77c19287cc2..0000000000000 --- 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 0000000000000..add21ee8097e1 --- /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 1837ef889a384..62ab805b4c187 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 49266e5026c3a..35554a7478ba3 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 50b68fb14755d..113ac3cd0a68b 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 b7d36fea5ca39..8e0a302441a03 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 3966320b72980..024888f834a17 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 3193e64939dd8..b54fc59c0a43b 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 7136463df5454..616dbf6188712 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 b0cdbce930082..60e7020413efb 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 5a4c1a78dc080..f90cc344798d9 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 708573ccdf58d..c4328ec181a8a 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 fe19b0e081d36..cf9e154df50da 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/lib/libc_r/uthread/uthread_main_np.c b/lib/libc_r/uthread/uthread_main_np.c new file mode 100644 index 0000000000000..1ce336998f59a --- /dev/null +++ b/lib/libc_r/uthread/uthread_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/libkse/thread/Makefile.inc b/lib/libkse/thread/Makefile.inc index fe19b0e081d36..cf9e154df50da 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 0000000000000..1ce336998f59a --- /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 fe19b0e081d36..cf9e154df50da 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 0000000000000..1ce336998f59a --- /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 077a33eadc69b..d6f319de9169d 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 f3d42b7154d85..26104fb2e7521 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) |
