diff options
Diffstat (limited to 'src/lib/rpc')
73 files changed, 14611 insertions, 0 deletions
diff --git a/src/lib/rpc/ChangeLog b/src/lib/rpc/ChangeLog new file mode 100644 index 000000000..a78d05c37 --- /dev/null +++ b/src/lib/rpc/ChangeLog @@ -0,0 +1,20 @@ +Fri Jul 12 15:33:50 1996 Marc Horowitz <marc@mit.edu> + + * rpc_dtablesize.c (_rpc_dtablesize): put in a few checks to make + sure that the return value is never larger than FD_SETSIZE, since + this function's purpose is to be used as the first arg to + select(). + +Tue Jul 9 17:56:54 1996 Marc Horowitz <marc@mit.edu> + + * rpc.h, netdb.h, getrpcent.c: Our build can (and will) require + that the rpc header files shipped with kerberos be used if the + library shipped with kerberos is used. Thus, some simplifying + assumptions can be made, mostly having to do with the declaration + of struct rpcent and the related functions. + * clnt_perror.c: made usage of sys_errlist conditional on + NEED_SYS_ERRLIST + * configure.in (DECLARE_SYS_ERRLIST): added + * Makefile.in (DONE): added a few rules and variable so shared + library creation would work + diff --git a/src/lib/rpc/Makefile.in b/src/lib/rpc/Makefile.in new file mode 100644 index 000000000..9426bb94c --- /dev/null +++ b/src/lib/rpc/Makefile.in @@ -0,0 +1,148 @@ +CFLAGS = $(CCOPTS) $(DEFS) -DDEBUG_GSSAPI -I$(srcdir)/.. + +##DOSBUILDTOP = ..\.. +##DOSLIBNAME=libgssrpc.lib + +.c.o: + $(CC) $(CFLAGS) -c $(srcdir)/$*.c +@SHARED_RULE@ + +SRCS = $(srcdir)/auth_none.c \ + $(srcdir)/auth_unix.c \ + $(srcdir)/auth_any.c \ + $(srcdir)/authunix_prot.c \ + $(srcdir)/auth_gssapi.c \ + $(srcdir)/auth_gssapi_misc.c \ + $(srcdir)/bindresvport.c \ + $(srcdir)/clnt_generic.c \ + $(srcdir)/clnt_perror.c \ + $(srcdir)/clnt_raw.c \ + $(srcdir)/clnt_simple.c \ + $(srcdir)/clnt_tcp.c \ + $(srcdir)/clnt_udp.c \ + $(srcdir)/rpc_dtablesize.c \ + $(srcdir)/get_myaddress.c \ + $(srcdir)/getrpcent.c \ + $(srcdir)/getrpcport.c \ + $(srcdir)/pmap_clnt.c \ + $(srcdir)/pmap_getmaps.c \ + $(srcdir)/pmap_getport.c \ + $(srcdir)/pmap_prot.c \ + $(srcdir)/pmap_prot2.c \ + $(srcdir)/pmap_rmt.c \ + $(srcdir)/rpc_prot.c \ + $(srcdir)/rpc_commondata.c \ + $(srcdir)/rpc_callmsg.c \ + $(srcdir)/svc.c \ + $(srcdir)/svc_auth.c \ + $(srcdir)/svc_auth_unix.c \ + $(srcdir)/svc_auth_any.c \ + $(srcdir)/svc_auth_gssapi.c \ + $(srcdir)/svc_raw.c \ + $(srcdir)/svc_run.c \ + $(srcdir)/svc_simple.c \ + $(srcdir)/svc_tcp.c \ + $(srcdir)/svc_udp.c \ + $(srcdir)/xdr.c \ + $(srcdir)/xdr_array.c \ + $(srcdir)/xdr_float.c \ + $(srcdir)/xdr_mem.c \ + $(srcdir)/xdr_rec.c \ + $(srcdir)/xdr_reference.c \ + $(srcdir)/xdr_stdio.c \ + $(srcdir)/xdr_alloc.c + +OBJS = auth_none.$(OBJEXT) \ + auth_unix.$(OBJEXT) \ + auth_any.$(OBJEXT) \ + authunix_prot.$(OBJEXT) \ + auth_gssapi.$(OBJEXT) \ + auth_gssapi_misc.$(OBJEXT) \ + bindresvport.$(OBJEXT) \ + clnt_generic.$(OBJEXT) \ + clnt_perror.$(OBJEXT) \ + clnt_raw.$(OBJEXT) \ + clnt_simple.$(OBJEXT) \ + clnt_tcp.$(OBJEXT) \ + clnt_udp.$(OBJEXT) \ + rpc_dtablesize.$(OBJEXT) \ + get_myaddress.$(OBJEXT) \ + getrpcent.$(OBJEXT) \ + getrpcport.$(OBJEXT) \ + pmap_clnt.$(OBJEXT) \ + pmap_getmaps.$(OBJEXT) \ + pmap_getport.$(OBJEXT) \ + pmap_prot.$(OBJEXT) \ + pmap_prot2.$(OBJEXT) \ + pmap_rmt.$(OBJEXT) \ + rpc_prot.$(OBJEXT) \ + rpc_commondata.$(OBJEXT) \ + rpc_callmsg.$(OBJEXT) \ + svc.$(OBJEXT) \ + svc_auth.$(OBJEXT) \ + svc_auth_unix.$(OBJEXT) \ + svc_auth_any.$(OBJEXT) \ + svc_auth_gssapi.$(OBJEXT) \ + svc_raw.$(OBJEXT) \ + svc_run.$(OBJEXT) \ + svc_simple.$(OBJEXT) \ + svc_tcp.$(OBJEXT) \ + svc_udp.$(OBJEXT) \ + xdr.$(OBJEXT) \ + xdr_array.$(OBJEXT) \ + xdr_float.$(OBJEXT) \ + xdr_mem.$(OBJEXT) \ + xdr_rec.$(OBJEXT) \ + xdr_reference.$(OBJEXT) \ + xdr_stdio.$(OBJEXT) \ + xdr_alloc.$(OBJEXT) + +LIB_SUBDIRS= . +LIBDONE= DONE +# +# Depends on libgssapi_krb5, libkrb5, libcrypto, libcom_err +# +GSSAPI_KRB5_VER=@GSSAPI_KRB5_SH_VERS@ +KRB5_VER=@KRB5_SH_VERS@ +CRYPTO_VER=@CRYPTO_SH_VERS@ +COMERR_VER=@COMERR_SH_VERS@ +DEPLIBS=$(TOPLIBD)/libgssapi_krb5.$(SHEXT).$(COMERR_VER) \ + $(TOPLIBD)/libkrb5.$(SHEXT).$(KRB5_VER) \ + $(TOPLIBD)/libcrypto.$(SHEXT).$(CRYPTO_VER) \ + $(TOPLIBD)/libcom_err.$(SHEXT).$(COMERR_VER) + +SHLIB_LIBS=-lkrb5 -lcrypto -lcom_err -ldyn +SHLIB_LDFLAGS= $(LDFLAGS) @SHLIB_RPATH_DIRS@ +SHLIB_LIBDIRS= @SHLIB_LIBDIRS@ + +all-unix:: shared includes $(OBJS) +all-mac:: $(OBJS) +all-windows:: $(OBJS) + +shared: + mkdir shared + +check-windows:: + +clean-unix:: + $(RM) shared/* + +clean-mac:: +clean-windows:: + +DONE: $(OBJS) + $(RM) DONE + echo $(OBJS) > DONE + +libgssrpc.$(STEXT): $(OBJS) + $(RM) $@ + $(ARADD) $@ $(OBJS) + $(RANLIB) $@ + +install:: libgssrpc.a + $(INSTALL_DATA) libgssrpc.a $(DESTDIR)$(KRB5_LIBDIR)/libgssrpc.a + $(RANLIB) $(DESTDIR)$(KRB5_LIBDIR)/libgssrpc.a + +clean:: + $(RM) libgssrpc.$(LIBEXT) libgssrpc.bak DONE + diff --git a/src/lib/rpc/Makefile.ov b/src/lib/rpc/Makefile.ov new file mode 100644 index 000000000..d64c77e22 --- /dev/null +++ b/src/lib/rpc/Makefile.ov @@ -0,0 +1,52 @@ +# +# Makefile for librpclib.a. +# +# $Id$ +# $Source$ +# +TOP = .. +include $(TOP)/config.mk/template + +SUBDIRS = unit-test + +SRCS = auth_none.c auth_unix.c auth_any.c authunix_prot.c \ + auth_gssapi.c auth_gssapi_misc.c bindresvport.c \ + clnt_generic.c clnt_perror.c clnt_raw.c clnt_simple.c clnt_tcp.c \ + clnt_udp.c rpc_dtablesize.c get_myaddress.c getrpcent.c getrpcport.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 \ + svc.c svc_auth.c svc_auth_unix.c svc_auth_any.c svc_auth_gssapi.c \ + svc_raw.c svc_run.c svc_simple.c \ + svc_tcp.c svc_udp.c xdr.c xdr_array.c xdr_float.c xdr_mem.c \ + xdr_rec.c xdr_reference.c xdr_stdio.c xdr_alloc.c + +OBJS = auth_none.o auth_unix.o auth_any.o authunix_prot.o \ + auth_gssapi.o auth_gssapi_misc.o bindresvport.o \ + clnt_generic.o clnt_perror.o clnt_raw.o clnt_simple.o clnt_tcp.o \ + clnt_udp.o rpc_dtablesize.o get_myaddress.o getrpcent.o getrpcport.o \ + pmap_clnt.o pmap_getmaps.o pmap_getport.o pmap_prot.o \ + pmap_prot2.o pmap_rmt.o rpc_prot.o rpc_commondata.o rpc_callmsg.o \ + svc.o svc_auth.o svc_auth_unix.o svc_auth_any.o svc_auth_gssapi.o \ + svc_raw.o svc_run.o svc_simple.o \ + svc_tcp.o svc_udp.o xdr.o xdr_array.o xdr_float.o xdr_mem.o \ + xdr_rec.o xdr_reference.o xdr_stdio.o xdr_alloc.o + +HDRS = auth.h auth_unix.h auth_gssapi.h clnt.h pmap_clnt.h \ + pmap_prot.h pmap_rmt.h rpc.h rpc_msg.h svc.h svc_auth.h types.h xdr.h + +HDRS_DIR = rpc + +LIB = librpclib.a + +CFLAGS := -I.. $(CFLAGS) -DDEBUG_GSSAPI=0 $(D_NEEDS_RPCENT) + +expand StageLibrary + +expand StageIncludes + +expand Depend + +expand SubdirTarget + +expand Saber + diff --git a/src/lib/rpc/auth.h b/src/lib/rpc/auth.h new file mode 100644 index 000000000..4b0a40ccc --- /dev/null +++ b/src/lib/rpc/auth.h @@ -0,0 +1,197 @@ +/* @(#)auth.h 2.3 88/08/07 4.0 RPCSRC; from 1.17 88/02/08 SMI */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * auth.h, Authentication interface. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * The data structures are completely opaque to the client. The client + * is required to pass a AUTH * to routines that create rpc + * "sessions". + */ + + +#define MAX_AUTH_BYTES 400 +#define MAXNETNAMELEN 255 /* maximum length of network user's name */ + +/* + * Status returned from authentication check + */ +enum auth_stat { + AUTH_OK=0, + /* + * failed at remote end + */ + AUTH_BADCRED=1, /* bogus credentials (seal broken) */ + AUTH_REJECTEDCRED=2, /* client should begin new session */ + AUTH_BADVERF=3, /* bogus verifier (seal broken) */ + AUTH_REJECTEDVERF=4, /* verifier expired or was replayed */ + AUTH_TOOWEAK=5, /* rejected due to security reasons */ + /* + * failed locally + */ + AUTH_INVALIDRESP=6, /* bogus response verifier */ + AUTH_FAILED=7 /* some unknown reason */ +}; + +union des_block { +#if 0 /* XXX nothing uses this, anyway */ + struct { + rpc_u_int32 high; + rpc_u_int32 low; + } key; +#endif + char c[8]; +}; +typedef union des_block des_block; +extern bool_t xdr_des_block(); + +/* + * Authentication info. Opaque to client. + */ +struct opaque_auth { + enum_t oa_flavor; /* flavor of auth */ + caddr_t oa_base; /* address of more auth stuff */ + unsigned 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; + union des_block ah_key; + struct auth_ops { + void (*ah_nextverf)(); + int (*ah_marshal)(); /* nextverf & serialize */ + int (*ah_validate)(); /* validate varifier */ + int (*ah_refresh)(); /* refresh credentials */ + void (*ah_destroy)(); /* destroy this structure */ + int (*ah_wrap)(); /* encode data for wire */ + int (*ah_unwrap)(); /* decode data from wire */ + } *ah_ops; + caddr_t ah_private; +} AUTH; + + +/* + * Authentication ops. + * The ops and the auth handle provide the interface to the authenticators. + * + * AUTH *auth; + * XDR *xdrs; + * struct opaque_auth verf; + */ +#define AUTH_NEXTVERF(auth) \ + ((*((auth)->ah_ops->ah_nextverf))(auth)) +#define auth_nextverf(auth) \ + ((*((auth)->ah_ops->ah_nextverf))(auth)) + +#define AUTH_MARSHALL(auth, xdrs) \ + ((*((auth)->ah_ops->ah_marshal))(auth, xdrs)) +#define auth_marshall(auth, xdrs) \ + ((*((auth)->ah_ops->ah_marshal))(auth, xdrs)) + +#define AUTH_VALIDATE(auth, verfp) \ + ((*((auth)->ah_ops->ah_validate))((auth), verfp)) +#define auth_validate(auth, verfp) \ + ((*((auth)->ah_ops->ah_validate))((auth), verfp)) + +#define AUTH_REFRESH(auth, msg) \ + ((*((auth)->ah_ops->ah_refresh))(auth, msg)) +#define auth_refresh(auth, msg) \ + ((*((auth)->ah_ops->ah_refresh))(auth, msg)) + +#define AUTH_WRAP(auth, xdrs, xfunc, xwhere) \ + ((*((auth)->ah_ops->ah_wrap))(auth, xdrs, \ + xfunc, xwhere)) +#define AUTH_WRAP(auth, xdrs, xfunc, xwhere) \ + ((*((auth)->ah_ops->ah_wrap))(auth, xdrs, \ + xfunc, xwhere)) +#define AUTH_UNWRAP(auth, xdrs, xfunc, xwhere) \ + ((*((auth)->ah_ops->ah_unwrap))(auth, xdrs, \ + xfunc, xwhere)) +#define AUTH_UNWRAP(auth, xdrs, xfunc, xwhere) \ + ((*((auth)->ah_ops->ah_unwrap))(auth, xdrs, \ + xfunc, xwhere)) + +#define AUTH_DESTROY(auth) \ + ((*((auth)->ah_ops->ah_destroy))(auth)) +#define auth_destroy(auth) \ + ((*((auth)->ah_ops->ah_destroy))(auth)) + + +extern struct opaque_auth _null_auth; + + +/* + * These are the various implementations of client side authenticators. + */ + +/* + * Any style authentication. These routines can be used by any + * authentication style that does not use the wrap/unwrap functions. + */ +int authany_wrap(), authany_unwrap(); + +/* + * Unix style authentication + * AUTH *authunix_create(machname, uid, gid, len, aup_gids) + * char *machname; + * int uid; + * int gid; + * int len; + * int *aup_gids; + */ +extern AUTH *authunix_create(); +extern AUTH *authunix_create_default(); /* takes no parameters */ +extern AUTH *authnone_create(); /* takes no parameters */ +extern AUTH *authdes_create(); + +/* + * GSS-API style authentication: + * see <rpc/auth_gssapi.h> + */ + +#define AUTH_NONE 0 /* no authentication */ +#define AUTH_NULL 0 /* backward compatibility */ +#define AUTH_UNIX 1 /* unix style (uid, gids) */ +#define AUTH_SHORT 2 /* short hand unix style */ +#define AUTH_DES 3 /* des style (encrypted timestamps) */ +#define AUTH_GSSAPI 300001 /* GSS-API style */ + +/* + * BACKWARDS COMPATIBILIY! OpenV*Secure 1.0 had AUTH_GSSAPI == 4. We + * need to accept this value until 1.0 is dead. + */ +#define AUTH_GSSAPI_COMPAT 4 diff --git a/src/lib/rpc/auth_any.c b/src/lib/rpc/auth_any.c new file mode 100644 index 000000000..5e2a8633a --- /dev/null +++ b/src/lib/rpc/auth_any.c @@ -0,0 +1,19 @@ +/* + * auth_any.c + * Provides default functions for authentication flavors that do not + * use all the fields in structauth_ops. + */ + +#include <stdio.h> +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <rpc/auth.h> + +int authany_wrap(auth, xdrs, xfunc, xwhere) + AUTH *auth; + XDR *xdrs; + xdrproc_t xfunc; + caddr_t xwhere; +{ + return (*xfunc)(xdrs, xwhere); +} diff --git a/src/lib/rpc/auth_gssapi.c b/src/lib/rpc/auth_gssapi.c new file mode 100644 index 000000000..0ffe96d18 --- /dev/null +++ b/src/lib/rpc/auth_gssapi.c @@ -0,0 +1,901 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. + * + * $Header$ + * + * $Log$ + * Revision 1.23 1996/07/22 20:39:39 marc + * this commit includes all the changes on the OV_9510_INTEGRATION and + * OV_MERGE branches. This includes, but is not limited to, the new openvision + * admin system, and major changes to gssapi to add functionality, and bring + * the implementation in line with rfc1964. before committing, the + * code was built and tested for netbsd and solaris. + * + * Revision 1.22.4.1 1996/07/18 04:18:29 marc + * merged in changes from OV_9510_BP to OV_9510_FINAL1 + * + * Revision 1.22.2.1 1996/06/20 23:35:31 marc + * File added to the repository on a branch + * + * Revision 1.22 1996/06/05 20:56:16 bjaspan + * memset bindings to zero before use + * + * Revision 1.21 1996/05/12 06:11:38 marc + * renamed lots of types: u_foo to unsigned foo, and foo32 to rpc_foo32. This is to make autoconfiscation less painful. + * + * Revision 1.20 1995/12/13 14:02:45 grier + * Longs to ints for Alpha + * + * Revision 1.19 1995/10/31 16:36:00 bjaspan + * GS reported this bug. When talking to a 1.1 server, the server will + * not fail indicating the version is wrong because it never checks the + * version; it just responds with call_res.version 1. So we have to + * deal. Oops. + * + * It's amazing what can fall through the cracks when most of the + * development team is fired.. + * + * Revision 1.18 1995/10/31 16:07:06 bjaspan + * fix from grier + * + * Revision 1.17 1995/08/24 21:06:26 bjaspan + * set acceptor channel bindings + * + * Revision 1.16 1995/08/23 20:27:37 bjaspan + * [secure-rpc/3392] add channel bindinds to the rpc + * + * Revision 1.15 1995/05/08 22:32:01 marc + * change call_arg.version from 1 to 2 to indicate the new client is in use. + * + * Revision 1.14 1995/03/22 22:05:20 jik + * Reorder the auth_ops structure, to agree with the order of the version of + * this library in the GK source tree. I chose to reorder this one rather + * than reorder the GK tree because Barry says that the order in the GK tree + * makes more sense. + * + * Revision 1.13 1994/10/27 12:39:02 jik + * [secure-rpc/2808: add credential versioning] + * + * Sandbox: + * + * [secure-rpc/2808] add version field to client creds + * + * change to use GSS_ERROR &c macros; I don't think this is correct + * ============================================================================= + * + * Revision 1.14 1994/10/26 20:03:46 bjaspan + * [secure-rpc/2808] add version field to client creds + * + * Revision 1.13 1994/04/07 16:12:06 jik + * The second argument to xdr_opaque_auth is struct auth *, not struct + * auth. + * + * Revision 1.12 1993/12/08 21:42:43 bjaspan + * use AUTH_GSSAPI_DISPLAY_STATUS macro, reindent + * + * Revision 1.11 1993/12/06 21:21:03 bjaspan + * debugging levels + * + * Revision 1.10 1993/11/18 23:13:07 bjaspan + * add some function comments + * + * Revision 1.9 1993/11/15 19:50:03 bjaspan + * redefine AUTH_REFRESH to take the error message as an argument, and + * change auth_gssapi_refresh to increment the seq_num on REJECTEDVERF + * + * Revision 1.8 1993/11/12 02:31:59 bjaspan + * set rpc_createerr as appropriate + * + * Revision 1.7 1993/11/03 21:21:02 bjaspan + * fix seq_num handling in cases of errors and retransmission + * + * Revision 1.6 1993/11/01 19:55:20 bjaspan + * display gss_major and gss_minor, and unstatic auth_gssapi_debug + * + * Revision 1.5 1993/10/28 22:07:33 bjaspan + * create_default takes char *, use seq_num in args/results + * + * Revision 1.4 1993/10/26 21:11:53 bjaspan + * working + * + * Revision 1.3 1993/10/21 19:01:09 bjaspan + * added auth_gssapi_destroy, cleaned up a few things + * + * Revision 1.2 1993/10/19 03:10:58 bjaspan + * snapshot: GSS-API working in hacked up state, not seal/unseal + * + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +#include <stdio.h> +#include <string.h> +#include <sys/errno.h> + +#include <gssapi/gssapi.h> +#include <gssapi/gssapi_generic.h> + +#include <rpc/rpc.h> +#include <rpc/auth_gssapi.h> + +#ifdef __CODECENTER__ +#define DEBUG_GSSAPI 1 +#endif + +#ifdef DEBUG_GSSAPI +int auth_debug_gssapi = DEBUG_GSSAPI; +#define L_PRINTF(l,args) if (auth_debug_gssapi >= l) printf args +#define PRINTF(args) L_PRINTF(99, args) +#define AUTH_GSSAPI_DISPLAY_STATUS(args) \ + if (auth_debug_gssapi) auth_gssapi_display_status args +#else +#define PRINTF(args) +#define L_PRINTF(l, args) +#define AUTH_GSSAPI_DISPLAY_STATUS(args) +#endif + +static void auth_gssapi_nextverf(); +static bool_t auth_gssapi_marshall(); +static bool_t auth_gssapi_validate(); +static bool_t auth_gssapi_refresh(); +static bool_t auth_gssapi_wrap(); +static bool_t auth_gssapi_unwrap(); +static void auth_gssapi_destroy(); + +static bool_t marshall_new_creds(); + +static struct auth_ops auth_gssapi_ops = { + auth_gssapi_nextverf, + auth_gssapi_marshall, + auth_gssapi_validate, + auth_gssapi_refresh, + auth_gssapi_destroy, + auth_gssapi_wrap, + auth_gssapi_unwrap, +}; + +/* + * the ah_private data structure for an auth_handle + */ +struct auth_gssapi_data { + bool_t established; + CLIENT *clnt; + gss_ctx_id_t context; + gss_buffer_desc client_handle; + rpc_u_int32 seq_num; + int def_cred; + + /* pre-serialized ah_cred */ + unsigned char cred_buf[MAX_AUTH_BYTES]; + rpc_u_int32 cred_len; +}; +#define AUTH_PRIVATE(auth) ((struct auth_gssapi_data *)auth->ah_private) + +extern struct rpc_createerr rpc_createerr; + +/* + * Function: auth_gssapi_create_default + * + * Purpose: Create a GSS-API style authenticator, with default + * options, and return the handle. + * + * Effects: See design document, section XXX. + */ +AUTH *auth_gssapi_create_default(CLIENT *clnt, char *service_name) +{ + AUTH *auth; + OM_uint32 gssstat, minor_stat; + gss_buffer_desc input_name; + gss_name_t target_name; + + input_name.value = service_name; + input_name.length = strlen(service_name) + 1; + + gssstat = gss_import_name(&minor_stat, &input_name, + gss_nt_service_name, &target_name); + if (gssstat != GSS_S_COMPLETE) { + AUTH_GSSAPI_DISPLAY_STATUS(("parsing name", gssstat, + minor_stat)); + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = ENOMEM; + return NULL; + } + + auth = auth_gssapi_create(clnt, + &gssstat, + &minor_stat, + GSS_C_NO_CREDENTIAL, + target_name, + GSS_C_NULL_OID, + GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG, + 0, + NULL, + NULL, + NULL); + + gss_release_name(&minor_stat, &target_name); + return auth; +} + +/* + * Function: auth_gssapi_create + * + * Purpose: Create a GSS-API style authenticator, with all the + * options, and return the handle. + * + * Effects: See design document, section XXX. + */ +AUTH *auth_gssapi_create(CLIENT *clnt, + OM_uint32 *gssstat, + OM_uint32 *minor_stat, + gss_cred_id_t claimant_cred_handle, + gss_name_t target_name, + gss_OID mech_type, + int req_flags, + OM_uint32 time_req, + gss_OID *actual_mech_type, + int *ret_flags, + OM_uint32 *time_rec) +{ + AUTH *auth, *save_auth; + struct auth_gssapi_data *pdata; + struct gss_channel_bindings_struct bindings, *bindp; + struct sockaddr_in laddr, raddr; + enum clnt_stat callstat; + struct timeval timeout; + int init_func; + + auth_gssapi_init_arg call_arg; + auth_gssapi_init_res call_res; + gss_buffer_desc *input_token, isn_buf; + + memset(&rpc_createerr, 0, sizeof(rpc_createerr)); + + /* this timeout is only used if clnt_control(clnt, CLSET_TIMEOUT) */ + /* has not already been called.. therefore, we can just pick */ + /* something reasonable-sounding.. */ + timeout.tv_sec = 30; + timeout.tv_usec = 0; + + auth = NULL; + pdata = NULL; + + auth = (AUTH *) malloc(sizeof(*auth)); + pdata = (struct auth_gssapi_data *) malloc(sizeof(*pdata)); + if (auth == NULL || pdata == NULL) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = ENOMEM; + goto cleanup; + } + memset((char *) auth, 0, sizeof(*auth)); + memset((char *) pdata, 0, sizeof(*pdata)); + + auth->ah_ops = &auth_gssapi_ops; + auth->ah_private = (caddr_t) pdata; + + /* initial creds are auth_msg TRUE and no handle */ + marshall_new_creds(auth, TRUE, NULL); + + /* initial verifier is empty */ + auth->ah_verf.oa_flavor = AUTH_GSSAPI; + auth->ah_verf.oa_base = NULL; + auth->ah_verf.oa_length = 0; + + AUTH_PRIVATE(auth)->established = FALSE; + AUTH_PRIVATE(auth)->clnt = clnt; + AUTH_PRIVATE(auth)->def_cred = (claimant_cred_handle == + GSS_C_NO_CREDENTIAL); + + /* don't assume the caller will want to change clnt->cl_auth */ + save_auth = clnt->cl_auth; + clnt->cl_auth = auth; + + /* start by trying latest version */ + call_arg.version = 3; + +try_new_version: + /* set state for initial call to init_sec_context */ + input_token = GSS_C_NO_BUFFER; + AUTH_PRIVATE(auth)->context = GSS_C_NO_CONTEXT; + init_func = AUTH_GSSAPI_INIT; + + if (call_arg.version == 3) { + if (clnt_control(clnt, CLGET_LOCAL_ADDR, &laddr) == FALSE) { + PRINTF(("gssapi_create: CLGET_LOCAL_ADDR failed")); + goto cleanup; + } + if (clnt_control(clnt, CLGET_SERVER_ADDR, &raddr) == FALSE) { + PRINTF(("gssapi_create: CLGET_SERVER_ADDR failed")); + goto cleanup; + } + + memset(&bindings, 0, sizeof(bindings)); + bindings.application_data.length = 0; + bindings.initiator_addrtype = GSS_C_AF_INET; + bindings.initiator_address.length = 4; + bindings.initiator_address.value = &laddr.sin_addr.s_addr; + + bindings.acceptor_addrtype = GSS_C_AF_INET; + bindings.acceptor_address.length = 4; + bindings.acceptor_address.value = &raddr.sin_addr.s_addr; + bindp = &bindings; + } else { + bindp = NULL; + } + + memset((char *) &call_res, 0, sizeof(call_res)); + +next_token: + *gssstat = gss_init_sec_context(minor_stat, + claimant_cred_handle, + &AUTH_PRIVATE(auth)->context, + target_name, + mech_type, + req_flags, + time_req, + bindp, + input_token, + actual_mech_type, + &call_arg.token, + ret_flags, + time_rec); + + if (*gssstat != GSS_S_COMPLETE && *gssstat != GSS_S_CONTINUE_NEEDED) { + AUTH_GSSAPI_DISPLAY_STATUS(("initializing context", *gssstat, + *minor_stat)); + goto cleanup; + } + + /* if we got a token, pass it on */ + if (call_arg.token.length != 0) { + + /* + * sanity check: if we received a signed isn in the last + * response then there *cannot* be another token to send + */ + if (call_res.signed_isn.length != 0) { + PRINTF(("gssapi_create: unexpected token from init_sec\n")); + goto cleanup; + } + + PRINTF(("gssapi_create: calling GSSAPI_INIT (%d)\n", init_func)); + + memset((char *) &call_res, 0, sizeof(call_res)); + callstat = clnt_call(clnt, init_func, + xdr_authgssapi_init_arg, &call_arg, + xdr_authgssapi_init_res, &call_res, + timeout); + gss_release_buffer(minor_stat, &call_arg.token); + + if (callstat != RPC_SUCCESS) { + struct rpc_err err; + + clnt_geterr(clnt, &err); + if (callstat == RPC_AUTHERROR && + (err.re_why == AUTH_BADCRED || err.re_why == AUTH_FAILED) + && call_arg.version >= 1) { + L_PRINTF(1, ("call_arg protocol " + "version %d rejected, trying %d.\n", + call_arg.version, call_arg.version-1)); + call_arg.version--; + goto try_new_version; + } else { + PRINTF(("gssapi_create: GSSAPI_INIT (%d) failed, stat %d\n", + init_func, callstat)); + } + + goto cleanup; + } else if (call_res.version != call_arg.version && + !(call_arg.version == 2 && call_res.version == 1)) { + /* + * The Secure 1.1 servers always respond with version + * 1. Thus, if we just tried a version >=3, fall all + * the way back to version 1 since that is all they + * understand + */ + if (call_arg.version > 2 && call_res.version == 1) { + L_PRINTF(1, ("Talking to Secure 1.1 server, " + "using version 1.\n")); + call_arg.version = 1; + goto try_new_version; + } + + PRINTF(("gssapi_create: invalid call_res vers %d\n", + call_res.version)); + goto cleanup; + } else if (call_res.gss_major != GSS_S_COMPLETE) { + AUTH_GSSAPI_DISPLAY_STATUS(("in response from server", + call_res.gss_major, + call_res.gss_minor)); + goto cleanup; + } + + PRINTF(("gssapi_create: GSSAPI_INIT (%d) succeeded\n", init_func)); + init_func = AUTH_GSSAPI_CONTINUE_INIT; + + /* check for client_handle */ + if (AUTH_PRIVATE(auth)->client_handle.length == 0) { + if (call_res.client_handle.length == 0) { + PRINTF(("gssapi_create: expected client_handle\n")); + goto cleanup; + } else { + PRINTF(("gssapi_create: got client_handle %d\n", + *((rpc_u_int32 *)call_res.client_handle.value))); + + GSS_DUP_BUFFER(AUTH_PRIVATE(auth)->client_handle, + call_res.client_handle); + + /* auth_msg is TRUE; there may be more tokens */ + marshall_new_creds(auth, TRUE, + &AUTH_PRIVATE(auth)->client_handle); + } + } else if (!GSS_BUFFERS_EQUAL(AUTH_PRIVATE(auth)->client_handle, + call_res.client_handle)) { + PRINTF(("gssapi_create: got different client_handle\n")); + goto cleanup; + } + + /* check for token */ + if (call_res.token.length==0 && *gssstat==GSS_S_CONTINUE_NEEDED) { + PRINTF(("gssapi_create: expected token\n")); + goto cleanup; + } else if (call_res.token.length != 0) { + if (*gssstat == GSS_S_COMPLETE) { + PRINTF(("gssapi_create: got unexpected token\n")); + goto cleanup; + } else { + /* assumes call_res is safe until init_sec_context */ + input_token = &call_res.token; + PRINTF(("gssapi_create: got new token\n")); + } + } + } + + /* check for isn */ + if (*gssstat == GSS_S_COMPLETE) { + if (call_res.signed_isn.length == 0) { + PRINTF(("gssapi_created: expected signed isn\n")); + goto cleanup; + } else { + PRINTF(("gssapi_create: processing signed isn\n")); + + /* don't check conf (integ only) or qop (accpet default) */ + *gssstat = gss_unseal(minor_stat, + AUTH_PRIVATE(auth)->context, + &call_res.signed_isn, + &isn_buf, NULL, NULL); + + if (*gssstat != GSS_S_COMPLETE) { + AUTH_GSSAPI_DISPLAY_STATUS(("unsealing isn", + *gssstat, *minor_stat)); + goto cleanup; + } else if (isn_buf.length != sizeof(rpc_u_int32)) { + PRINTF(("gssapi_create: gss_unseal gave %d bytes\n", + isn_buf.length)); + goto cleanup; + } + + AUTH_PRIVATE(auth)->seq_num = (rpc_u_int32) + ntohl(*((rpc_u_int32*)isn_buf.value)); + *gssstat = gss_release_buffer(minor_stat, &isn_buf); + if (*gssstat != GSS_S_COMPLETE) { + AUTH_GSSAPI_DISPLAY_STATUS(("releasing unsealed isn", + *gssstat, *minor_stat)); + goto cleanup; + } + + PRINTF(("gssapi_create: isn is %d\n", + AUTH_PRIVATE(auth)->seq_num)); + + /* we no longer need these results.. */ + xdr_free(xdr_authgssapi_init_res, &call_res); + } + } else if (call_res.signed_isn.length != 0) { + PRINTF(("gssapi_create: got signed isn, can't check yet\n")); + } + + /* results were okay.. continue if necessary */ + if (*gssstat == GSS_S_CONTINUE_NEEDED) { + PRINTF(("gssapi_create: not done, continuing\n")); + goto next_token; + } + + /* + * Done! Context is established, we have client_handle and isn. + */ + AUTH_PRIVATE(auth)->established = TRUE; + + marshall_new_creds(auth, FALSE, + &AUTH_PRIVATE(auth)->client_handle); + + PRINTF(("gssapi_create: done. client_handle %#x, isn %d\n\n", + *((rpc_u_int32 *)AUTH_PRIVATE(auth)->client_handle.value), + AUTH_PRIVATE(auth)->seq_num)); + + /* don't assume the caller will want to change clnt->cl_auth */ + clnt->cl_auth = save_auth; + + return auth; + + /******************************************************************/ + +cleanup: + PRINTF(("gssapi_create: bailing\n\n")); + + if (AUTH_PRIVATE(auth)) + auth_gssapi_destroy(auth); + else if (auth) + free(auth); + auth = NULL; + + /* don't assume the caller will want to change clnt->cl_auth */ + clnt->cl_auth = save_auth; + + if (rpc_createerr.cf_stat == 0) + rpc_createerr.cf_stat = RPC_AUTHERROR; + + return auth; +} + +/* + * Function: marshall_new_creds + * + * Purpose: (pre-)serialize auth_msg and client_handle fields of + * auth_gssapi_creds into auth->cred_buf + * + * Arguments: + * + * auth (r/w) the AUTH structure to modify + * auth_msg (r) the auth_msg field to serialize + * client_handle (r) the client_handle field to serialize, or + * NULL + * + * Returns: TRUE if successful, FALSE if not + * + * Requires: auth must point to a valid GSS-API auth structure, auth_msg + * must be TRUE or FALSE, client_handle must be a gss_buffer_t with a valid + * value and length field or NULL. + * + * Effects: auth->ah_cred is set to the serialized auth_gssapi_creds + * version 2 structure (stored in the cred_buf field of private data) + * containing version, auth_msg and client_handle. + * auth->ah_cred.oa_flavor is set to AUTH_GSSAPI. If cliend_handle is + * NULL, it is treated as if it had a length of 0 and a value of NULL. + * + * Modifies: auth + */ +static bool_t marshall_new_creds(auth, auth_msg, client_handle) + AUTH *auth; + bool_t auth_msg; + gss_buffer_t client_handle; +{ + auth_gssapi_creds creds; + XDR xdrs; + + PRINTF(("marshall_new_creds: starting\n")); + + creds.version = 2; + + creds.auth_msg = auth_msg; + if (client_handle) + GSS_COPY_BUFFER(creds.client_handle, *client_handle) + else { + creds.client_handle.length = 0; + creds.client_handle.value = NULL; + } + + xdrmem_create(&xdrs, AUTH_PRIVATE(auth)->cred_buf, + MAX_AUTH_BYTES, XDR_ENCODE); + if (! xdr_authgssapi_creds(&xdrs, &creds)) { + PRINTF(("marshall_new_creds: failed encoding auth_gssapi_creds\n")); + XDR_DESTROY(&xdrs); + return FALSE; + } + AUTH_PRIVATE(auth)->cred_len = xdr_getpos(&xdrs); + XDR_DESTROY(&xdrs); + + PRINTF(("marshall_new_creds: auth_gssapi_creds is %d bytes\n", + AUTH_PRIVATE(auth)->cred_len)); + + auth->ah_cred.oa_flavor = AUTH_GSSAPI; + auth->ah_cred.oa_base = (char *) AUTH_PRIVATE(auth)->cred_buf; + auth->ah_cred.oa_length = AUTH_PRIVATE(auth)->cred_len; + + PRINTF(("marshall_new_creds: succeeding\n")); + + return TRUE; +} + + +/* + * Function: auth_gssapi_nextverf + * + * Purpose: None. + * + * Effects: None. Never called. + */ +static void auth_gssapi_nextverf(/*auth*/) + /*AUTH *auth;*/ +{ +} + +/* + * Function: auth_gssapi_marhsall + * + * Purpose: Marshall RPC credentials and verifier onto xdr stream. + * + * Arguments: + * + * auth (r/w) AUTH structure for client + * xdrs (r/w) XDR stream to marshall to + * + * Returns: boolean indicating success/failure + * + * Effects: + * + * The pre-serialized credentials in cred_buf are serialized. If the + * context is established, the sealed sequence number is serialized as + * the verifier. If the context is not established, an empty verifier + * is serialized. The sequence number is *not* incremented, because + * this function is called multiple times if retransmission is required. + * + * If this took all the header fields as arguments, it could sign + * them. + */ +static bool_t auth_gssapi_marshall(auth, xdrs) + AUTH *auth; + XDR *xdrs; +{ + OM_uint32 minor_stat; + gss_buffer_desc out_buf; + rpc_u_int32 seq_num; + + if (AUTH_PRIVATE(auth)->established == TRUE) { + PRINTF(("gssapi_marshall: starting\n")); + + seq_num = AUTH_PRIVATE(auth)->seq_num + 1; + + PRINTF(("gssapi_marshall: sending seq_num %d\n", seq_num)); + + if (auth_gssapi_seal_seq(AUTH_PRIVATE(auth)->context, seq_num, + &out_buf) == FALSE) { + PRINTF(("gssapi_marhshall: seal failed\n")); + } + + auth->ah_verf.oa_base = out_buf.value; + auth->ah_verf.oa_length = out_buf.length; + + if (! xdr_opaque_auth(xdrs, &auth->ah_cred) || + ! xdr_opaque_auth(xdrs, &auth->ah_verf)) { + (void) gss_release_buffer(&minor_stat, &out_buf); + return FALSE; + } + (void) gss_release_buffer(&minor_stat, &out_buf); + } else { + PRINTF(("gssapi_marshall: not established, sending null verf\n")); + + auth->ah_verf.oa_base = NULL; + auth->ah_verf.oa_length = 0; + + if (! xdr_opaque_auth(xdrs, &auth->ah_cred) || + ! xdr_opaque_auth(xdrs, &auth->ah_verf)) { + return FALSE; + } + } + + return TRUE; +} + +/* + * Function: auth_gssapi_validate + * + * Purpose: Validate RPC response verifier from server. + * + * Effects: See design document, section XXX. + */ +static bool_t auth_gssapi_validate(auth, verf) + AUTH *auth; + struct opaque_auth *verf; +{ + gss_buffer_desc in_buf; + rpc_u_int32 seq_num; + + if (AUTH_PRIVATE(auth)->established == FALSE) { + PRINTF(("gssapi_validate: not established, noop\n")); + return TRUE; + } + + PRINTF(("gssapi_validate: starting\n")); + + in_buf.length = verf->oa_length; + in_buf.value = verf->oa_base; + if (auth_gssapi_unseal_seq(AUTH_PRIVATE(auth)->context, &in_buf, + &seq_num) == FALSE) { + PRINTF(("gssapi_validate: failed unsealing verifier\n")); + return FALSE; + } + + /* we sent seq_num+1, so we should get back seq_num+2 */ + if (AUTH_PRIVATE(auth)->seq_num+2 != seq_num) { + PRINTF(("gssapi_validate: expecting seq_num %d, got %d (%#x)\n", + AUTH_PRIVATE(auth)->seq_num + 2, seq_num, seq_num)); + return FALSE; + } + PRINTF(("gssapi_validate: seq_num %d okay\n", seq_num)); + + /* +1 for successful transmission, +1 for successful validation */ + AUTH_PRIVATE(auth)->seq_num += 2; + + PRINTF(("gssapi_validate: succeeding\n")); + + return TRUE; +} + +/* + * Function: auth_gssapi_refresh + * + * Purpose: Attempts to resyncrhonize the sequence number. + * + * Effects: + * + * When the server receives a properly authenticated RPC call, it + * increments the sequence number it is expecting from the client. + * But if the server's response is lost for any reason, the client + * can't know whether the server ever received it, assumes it didn't, + * and does *not* increment its sequence number. Thus, the client's + * next call will fail with AUTH_REJECTEDCRED because the server will + * think it is a replay attack. + * + * When an AUTH_REJECTEDCRED error arrives, this function attempts to + * resyncrhonize by incrementing the client's sequence number and + * returning TRUE. If any other error arrives, it returns FALSE. + */ +static bool_t auth_gssapi_refresh(auth, msg) + AUTH *auth; + struct rpc_msg *msg; +{ + if (msg->rm_reply.rp_rjct.rj_stat == AUTH_ERROR && + msg->rm_reply.rp_rjct.rj_why == AUTH_REJECTEDVERF) { + PRINTF(("gssapi_refresh: rejected verifier, incrementing\n")); + AUTH_PRIVATE(auth)->seq_num++; + return TRUE; + } else { + PRINTF(("gssapi_refresh: failing\n")); + return FALSE; + } +} + +/* + * Function: auth_gssapi_destroy + * + * Purpose: Destroy a GSS-API authentication structure. + * + * Effects: This function destroys the GSS-API authentication + * context, and sends a message to the server instructing it to + * invokte gss_process_token() and thereby destroy its corresponding + * context. Since the client doesn't really care whether the server + * gets this message, no failures are reported. + */ +static void auth_gssapi_destroy(auth) + AUTH *auth; +{ + struct timeval timeout; + OM_uint32 gssstat, minor_stat; + gss_cred_id_t cred; + int callstat; + + if (AUTH_PRIVATE(auth)->client_handle.length == 0) { + PRINTF(("gssapi_destroy: no client_handle, not calling destroy\n")); + goto skip_call; + } + + PRINTF(("gssapi_destroy: marshalling new creds\n")); + if (!marshall_new_creds(auth, TRUE, &AUTH_PRIVATE(auth)->client_handle)) { + PRINTF(("gssapi_destroy: marshall_new_creds failed\n")); + goto skip_call; + } + + PRINTF(("gssapi_destroy: calling GSSAPI_DESTROY\n")); + timeout.tv_sec = 1; + timeout.tv_usec = 0; + callstat = clnt_call(AUTH_PRIVATE(auth)->clnt, AUTH_GSSAPI_DESTROY, + xdr_void, NULL, xdr_void, NULL, timeout); + if (callstat != RPC_SUCCESS) + clnt_sperror(AUTH_PRIVATE(auth)->clnt, + "gssapi_destroy: GSSAPI_DESTROY failed"); + +skip_call: + PRINTF(("gssapi_destroy: deleting context\n")); + gssstat = gss_delete_sec_context(&minor_stat, + &AUTH_PRIVATE(auth)->context, + NULL); + if (gssstat != GSS_S_COMPLETE) + AUTH_GSSAPI_DISPLAY_STATUS(("deleting context", gssstat, + minor_stat)); + if (AUTH_PRIVATE(auth)->def_cred) { + cred = GSS_C_NO_CREDENTIAL; + gssstat = gss_release_cred(&minor_stat, &cred); + if (gssstat != GSS_S_COMPLETE) + AUTH_GSSAPI_DISPLAY_STATUS(("deleting default credential", + gssstat, minor_stat)); + } + + if (AUTH_PRIVATE(auth)->client_handle.length != 0) + gss_release_buffer(&minor_stat, + &AUTH_PRIVATE(auth)->client_handle); + +#if 0 + PRINTF(("gssapi_destroy: calling GSSAPI_EXIT\n")); + AUTH_PRIVATE(auth)->established = FALSE; + callstat = clnt_call(AUTH_PRIVATE(auth)->clnt, AUTH_GSSAPI_EXIT, + xdr_void, NULL, xdr_void, NULL, timeout); +#endif + + free(auth->ah_private); + free(auth); + PRINTF(("gssapi_destroy: done\n")); +} + +/* + * Function: auth_gssapi_wrap + * + * Purpose: encrypt the serialized arguments from xdr_func applied to + * xdr_ptr and write the result to xdrs. + * + * Effects: See design doc, section XXX. + */ +static bool_t auth_gssapi_wrap(auth, out_xdrs, xdr_func, xdr_ptr) + AUTH *auth; + XDR *out_xdrs; + bool_t (*xdr_func)(); + caddr_t xdr_ptr; +{ + OM_uint32 gssstat, minor_stat; + + if (! AUTH_PRIVATE(auth)->established) { + PRINTF(("gssapi_wrap: context not established, noop\n")); + return (*xdr_func)(out_xdrs, xdr_ptr); + } else if (! auth_gssapi_wrap_data(&gssstat, &minor_stat, + AUTH_PRIVATE(auth)->context, + AUTH_PRIVATE(auth)->seq_num+1, + out_xdrs, xdr_func, xdr_ptr)) { + if (gssstat != GSS_S_COMPLETE) + AUTH_GSSAPI_DISPLAY_STATUS(("encrypting function arguments", + gssstat, minor_stat)); + return FALSE; + } else + return TRUE; +} + +/* + * Function: auth_gssapi_unwrap + * + * Purpose: read encrypted arguments from xdrs, decrypt, and + * deserialize with xdr_func into xdr_ptr. + * + * Effects: See design doc, section XXX. + */ +static bool_t auth_gssapi_unwrap(auth, in_xdrs, xdr_func, xdr_ptr) + AUTH *auth; + XDR *in_xdrs; + bool_t (*xdr_func)(); + caddr_t xdr_ptr; +{ + OM_uint32 gssstat, minor_stat; + + if (! AUTH_PRIVATE(auth)->established) { + PRINTF(("gssapi_unwrap: context not established, noop\n")); + return (*xdr_func)(in_xdrs, xdr_ptr); + } else if (! auth_gssapi_unwrap_data(&gssstat, &minor_stat, + AUTH_PRIVATE(auth)->context, + AUTH_PRIVATE(auth)->seq_num, + in_xdrs, xdr_func, xdr_ptr)) { + if (gssstat != GSS_S_COMPLETE) + AUTH_GSSAPI_DISPLAY_STATUS(("decrypting function arguments", + gssstat, minor_stat)); + return FALSE; + } else + return TRUE; +} diff --git a/src/lib/rpc/auth_gssapi.h b/src/lib/rpc/auth_gssapi.h new file mode 100644 index 000000000..9092149a5 --- /dev/null +++ b/src/lib/rpc/auth_gssapi.h @@ -0,0 +1,161 @@ +/* + * auth_gssapi.h, Protocol for GSS-API style authentication parameters for RPC + * + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. + * + * $Id$ + * $Source$ + * + * $Log$ + * Revision 1.18 1996/07/22 20:39:41 marc + * this commit includes all the changes on the OV_9510_INTEGRATION and + * OV_MERGE branches. This includes, but is not limited to, the new openvision + * admin system, and major changes to gssapi to add functionality, and bring + * the implementation in line with rfc1964. before committing, the + * code was built and tested for netbsd and solaris. + * + * Revision 1.17.4.1 1996/07/18 04:18:31 marc + * merged in changes from OV_9510_BP to OV_9510_FINAL1 + * + * Revision 1.17.2.1 1996/06/20 23:35:44 marc + * File added to the repository on a branch + * + * Revision 1.17 1996/05/12 06:11:38 marc + * renamed lots of types: u_foo to unsigned foo, and foo32 to rpc_foo32. This is to make autoconfiscation less painful. + * + * Revision 1.16 1996/01/31 19:16:16 grier + * [secure/3570] + * Remove (void *) casts to memcpy() args + * + * Revision 1.15 1995/12/28 17:54:34 jik + * Don't define DEBUG_GSSAPI here. + * + * Revision 1.14 1995/12/13 14:03:01 grier + * Longs to ints for Alpha + * + * Revision 1.13 1995/11/07 23:15:26 grier + * memcpy() casts + * + * Revision 1.12 1995/05/25 18:35:59 bjaspan + * [secure-rpc/3103] log misc errors from RPC + * + * Revision 1.11 1994/10/27 12:39:14 jik + * [secure-rpc/2808: add credential versioning] + * + * Sandbox: + * + * [secure-rpc/2808] add version field to client creds + * + * Revision 1.11 1994/10/26 20:04:00 bjaspan + * [secure-rpc/2808] add version field to client creds + * + * Revision 1.10 1993/11/12 02:32:50 bjaspan + * add badauth, don't use const_gss_OID + * + * Revision 1.9 1993/11/03 23:46:15 bjaspan + * new log_badverf format + * + * Revision 1.8 1993/11/03 21:21:38 bjaspan + * added log_badverf + * + * Revision 1.7 1993/11/03 01:29:56 bjaspan + * add const to gss_nt_* + * + */ + +#define AUTH_GSSAPI_EXIT 0 +#define AUTH_GSSAPI_INIT 1 +#define AUTH_GSSAPI_CONTINUE_INIT 2 +#define AUTH_GSSAPI_MSG 3 +#define AUTH_GSSAPI_DESTROY 4 + +typedef struct _auth_gssapi_name { + char *name; + gss_OID type; +} auth_gssapi_name; + +typedef struct _auth_gssapi_creds { + rpc_u_int32 version; + bool_t auth_msg; + gss_buffer_desc client_handle; +} auth_gssapi_creds; + +typedef struct _auth_gssapi_init_arg { + rpc_u_int32 version; + gss_buffer_desc token; +} auth_gssapi_init_arg; + +typedef struct _auth_gssapi_init_res { + rpc_u_int32 version; + gss_buffer_desc client_handle; + OM_uint32 gss_major, gss_minor; + gss_buffer_desc token; + gss_buffer_desc signed_isn; +} auth_gssapi_init_res; + +typedef void (*auth_gssapi_log_badauth_func)(OM_uint32 major, + OM_uint32 minor, + struct sockaddr_in *raddr, + caddr_t data); + +typedef void (*auth_gssapi_log_badverf_func)(gss_name_t client, + gss_name_t server, + struct svc_req *rqst, + struct rpc_msg *msg, + caddr_t data); + +typedef void (*auth_gssapi_log_miscerr_func)(struct svc_req *rqst, + struct rpc_msg *msg, + char *error, + caddr_t data); + +bool_t xdr_authgssapi_creds(); +bool_t xdr_authgssapi_init_arg(); +bool_t xdr_authgssapi_init_res(); + +bool_t auth_gssapi_wrap_data(OM_uint32 *major, OM_uint32 *minor, + gss_ctx_id_t context, rpc_u_int32 seq_num, XDR + *out_xdrs, bool_t (*xdr_func)(), caddr_t + xdr_ptr); +bool_t auth_gssapi_unwrap_data(OM_uint32 *major, OM_uint32 *minor, + gss_ctx_id_t context, rpc_u_int32 seq_num, XDR + *in_xdrs, bool_t (*xdr_func)(), caddr_t + xdr_ptr); + +AUTH *auth_gssapi_create(CLIENT *clnt, + OM_uint32 *major_status, + OM_uint32 *minor_status, + gss_cred_id_t claimant_cred_handle, + gss_name_t target_name, + gss_OID mech_type, + int req_flags, + OM_uint32 time_req, + gss_OID *actual_mech_type, + int *ret_flags, + OM_uint32 *time_rec); + +AUTH *auth_gssapi_create_default(CLIENT *clnt, char *service_name); + +void auth_gssapi_display_status(char *msg, OM_uint32 major, + OM_uint32 minor); +bool_t _svcauth_gssapi_set_name(char *name, gss_OID name_type); + +void _svcauth_set_log_badauth_func(auth_gssapi_log_badauth_func func, + caddr_t data); +void _svcauth_set_log_badverf_func(auth_gssapi_log_badverf_func func, + caddr_t data); +void _svcauth_set_log_miscerr_func(auth_gssapi_log_miscerr_func func, + caddr_t data); + +#define GSS_COPY_BUFFER(dest, src) { \ + (dest).length = (src).length; \ + (dest).value = (src).value; } + +#define GSS_DUP_BUFFER(dest, src) { \ + (dest).length = (src).length; \ + (dest).value = (void *) malloc((dest).length); \ + memcpy((dest).value, (src).value, (dest).length); } + +#define GSS_BUFFERS_EQUAL(b1, b2) (((b1).length == (b2).length) && \ + !memcmp((b1).value,(b2).value,(b1.length))) + diff --git a/src/lib/rpc/auth_gssapi_misc.c b/src/lib/rpc/auth_gssapi_misc.c new file mode 100644 index 000000000..bd7b6e5a3 --- /dev/null +++ b/src/lib/rpc/auth_gssapi_misc.c @@ -0,0 +1,390 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. + * + * $Header$ + * + * $Log$ + * Revision 1.14 1996/07/22 20:39:44 marc + * this commit includes all the changes on the OV_9510_INTEGRATION and + * OV_MERGE branches. This includes, but is not limited to, the new openvision + * admin system, and major changes to gssapi to add functionality, and bring + * the implementation in line with rfc1964. before committing, the + * code was built and tested for netbsd and solaris. + * + * Revision 1.13.4.1 1996/07/18 04:18:32 marc + * merged in changes from OV_9510_BP to OV_9510_FINAL1 + * + * Revision 1.13.2.1 1996/06/20 23:35:49 marc + * File added to the repository on a branch + * + * Revision 1.13 1996/05/12 06:11:38 marc + * renamed lots of types: u_foo to unsigned foo, and foo32 to rpc_foo32. This is to make autoconfiscation less painful. + * + * Revision 1.12 1996/02/25 15:53:57 grier + * [secure/3570] + * OSF1 long changes + * + * Revision 1.11 1995/12/13 14:03:30 grier + * Longs to ints for Alpha + * + * Revision 1.10 1994/10/27 12:39:23 jik + * [secure-rpc/2808: add credential versioning] + * + * Sandbox: + * + * [secure-rpc/2808] back out the backwards compat hack (I only put it + * there in case we ever decide we want it, which we won't) and just + * handle the version field as if it were always there + * + * [secure-rpc/2808] add a backwards-compatible version field encoder + * + * change to use GSS_ERROR &c macros; I don't think this is correct + * ============================================================================= + * + * Revision 1.12 1994/10/26 19:48:45 bjaspan + * [secure-rpc/2808] back out the backwards compat hack (I only put it + * there in case we ever decide we want it, which we won't) and just + * handle the version field as if it were always there + * + * Revision 1.11 1994/10/26 19:47:42 bjaspan + * [secure-rpc/2808] add a backwards-compatible version field encoder + * + * Revision 1.10 1993/12/19 22:19:40 bjaspan + * [secure-rpc/1077] use free instead of xdr_free(xdr_bytes,...) because + * xdr_bytes takes non-standard arguments + * + * Revision 1.9 1993/12/08 21:43:37 bjaspan + * use AUTH_GSSAPI_DISPLAY_STATUS macro, reindent + * + * Revision 1.8 1993/12/06 21:21:21 bjaspan + * debugging levels + * + * Revision 1.7 1993/11/03 23:46:34 bjaspan + * add debugging printfs showing amount of data wrapped/unwrapped + * + * Revision 1.6 1993/11/03 21:21:53 bjaspan + * unstatic misc_debug_gssapi + * + * Revision 1.5 1993/11/01 19:55:54 bjaspan + * improve display_status messages, and include gss_{major,minor} + * + * Revision 1.4 1993/10/28 22:08:21 bjaspan + * wrap/unwrap_data include sequence number in arg/result block + * + * Revision 1.3 1993/10/27 18:26:16 bjaspan + * use xdr_free instead of free(in_buf.value); doesn't actually make a + * difference, though + * + * Revision 1.2 1993/10/26 21:12:38 bjaspan + * cleaning + * + * Revision 1.1 1993/10/19 03:12:28 bjaspan + * Initial revision + * + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +#include <rpc/rpc.h> +#include <stdio.h> + +#include <gssapi/gssapi.h> +#include <rpc/auth_gssapi.h> + +#ifdef __CODECENTER__ +#define DEBUG_GSSAPI 1 +#endif + +#ifdef DEBUG_GSSAPI +int misc_debug_gssapi = DEBUG_GSSAPI; +#define L_PRINTF(l,args) if (misc_debug_gssapi >= l) printf args +#define PRINTF(args) L_PRINTF(99, args) +#define AUTH_GSSAPI_DISPLAY_STATUS(args) \ + if (misc_debug_gssapi) auth_gssapi_display_status args +#else +#define PRINTF(args) +#define L_PRINTF(l, args) +#define AUTH_GSSAPI_DISPLAY_STATUS(args) +#endif + +static void auth_gssapi_display_status_1(char *, OM_uint32, int, int); + +bool_t xdr_gss_buf(xdrs, buf) + XDR *xdrs; + gss_buffer_t buf; +{ + /* + * On decode, xdr_bytes will only allocate buf->value if the + * length read in is < maxsize (last arg). This is dumb, because + * the whole point of allocating memory is so that I don't *have* + * to know the maximum length. -1 effectively disables this + * braindamage. + */ + return xdr_bytes(xdrs, (char **) &buf->value, (unsigned int *) &buf->length, + (xdrs->x_op == XDR_DECODE && buf->value == NULL) + ? (unsigned int) -1 : (unsigned int) buf->length); +} + +bool_t xdr_authgssapi_creds(xdrs, creds) + XDR *xdrs; + auth_gssapi_creds *creds; +{ + if (! xdr_u_int32(xdrs, &creds->version) || + ! xdr_bool(xdrs, &creds->auth_msg) || + ! xdr_gss_buf(xdrs, &creds->client_handle)) + return FALSE; + return TRUE; +} + +bool_t xdr_authgssapi_init_arg(xdrs, init_arg) + XDR *xdrs; + auth_gssapi_init_arg *init_arg; +{ + if (! xdr_u_int32(xdrs, &init_arg->version) || + ! xdr_gss_buf(xdrs, &init_arg->token)) + return FALSE; + return TRUE; +} + +bool_t xdr_authgssapi_init_res(xdrs, init_res) + XDR *xdrs; + auth_gssapi_init_res *init_res; +{ + if (! xdr_u_int32(xdrs, &init_res->version) || + ! xdr_gss_buf(xdrs, &init_res->client_handle) || + ! xdr_u_int32(xdrs, &init_res->gss_major) || + ! xdr_u_int32(xdrs, &init_res->gss_minor) || + ! xdr_gss_buf(xdrs, &init_res->token) || + ! xdr_gss_buf(xdrs, &init_res->signed_isn)) + return FALSE; + return TRUE; +} + +bool_t auth_gssapi_seal_seq(context, seq_num, out_buf) + gss_ctx_id_t context; + rpc_u_int32 seq_num; + gss_buffer_t out_buf; +{ + gss_buffer_desc in_buf; + OM_uint32 gssstat, minor_stat; + rpc_u_int32 nl_seq_num; + + nl_seq_num = htonl(seq_num); + + in_buf.length = sizeof(rpc_u_int32); + in_buf.value = (char *) &nl_seq_num; + gssstat = gss_seal(&minor_stat, context, 0, GSS_C_QOP_DEFAULT, + &in_buf, NULL, out_buf); + if (gssstat != GSS_S_COMPLETE) { + PRINTF(("gssapi_seal_seq: failed\n")); + AUTH_GSSAPI_DISPLAY_STATUS(("sealing sequence number", + gssstat, minor_stat)); + return FALSE; + } + return TRUE; +} + +bool_t auth_gssapi_unseal_seq(context, in_buf, seq_num) + gss_ctx_id_t context; + gss_buffer_t in_buf; + rpc_u_int32 *seq_num; +{ + gss_buffer_desc out_buf; + OM_uint32 gssstat, minor_stat; + rpc_u_int32 nl_seq_num; + + gssstat = gss_unseal(&minor_stat, context, in_buf, &out_buf, + NULL, NULL); + if (gssstat != GSS_S_COMPLETE) { + PRINTF(("gssapi_unseal_seq: failed\n")); + AUTH_GSSAPI_DISPLAY_STATUS(("unsealing sequence number", + gssstat, minor_stat)); + return FALSE; + } else if (out_buf.length != sizeof(rpc_u_int32)) { + PRINTF(("gssapi_unseal_seq: unseal gave %d bytes\n", + out_buf.length)); + gss_release_buffer(&minor_stat, &out_buf); + return FALSE; + } + + nl_seq_num = *((rpc_u_int32 *) out_buf.value); + *seq_num = (rpc_u_int32) ntohl(nl_seq_num); + gss_release_buffer(&minor_stat, &out_buf); + + return TRUE; +} + +void auth_gssapi_display_status(char *msg, OM_uint32 major, OM_uint32 minor) +{ + auth_gssapi_display_status_1(msg, major, GSS_C_GSS_CODE, 0); + auth_gssapi_display_status_1(msg, minor, GSS_C_MECH_CODE, 0); +} + +static void auth_gssapi_display_status_1(char *m, OM_uint32 code, int type, + int rec) +{ + OM_uint32 gssstat, minor_stat; + gss_buffer_desc msg; + int msg_ctx; + + msg_ctx = 0; + while (1) { + gssstat = gss_display_status(&minor_stat, code, + type, GSS_C_NULL_OID, + &msg_ctx, &msg); + if (gssstat != GSS_S_COMPLETE) { + if (!rec) { + auth_gssapi_display_status_1(m,gssstat,GSS_C_GSS_CODE,1); + auth_gssapi_display_status_1(m, minor_stat, + GSS_C_MECH_CODE, 1); + } else + fprintf(stderr,"GSS-API authentication error %s: " + "recursive failure!\n", msg); + return; + } + + fprintf(stderr, "GSS-API authentication error %s: %s\n", m, + (char *)msg.value); + (void) gss_release_buffer(&minor_stat, &msg); + + if (!msg_ctx) + break; + } +} + +bool_t auth_gssapi_wrap_data(major, minor, context, seq_num, out_xdrs, + xdr_func, xdr_ptr) + OM_uint32 *major, *minor; + gss_ctx_id_t context; + rpc_u_int32 seq_num; + XDR *out_xdrs; + bool_t (*xdr_func)(); + caddr_t xdr_ptr; +{ + gss_buffer_desc in_buf, out_buf; + XDR temp_xdrs; + int conf_state; + + PRINTF(("gssapi_wrap_data: starting\n")); + + *major = GSS_S_COMPLETE; + *minor = 0; /* assumption */ + + xdralloc_create(&temp_xdrs, XDR_ENCODE); + + /* serialize the sequence number into local memory */ + PRINTF(("gssapi_wrap_data: encoding seq_num %d\n", seq_num)); + if (! xdr_u_int32(&temp_xdrs, &seq_num)) { + PRINTF(("gssapi_wrap_data: serializing seq_num failed\n")); + XDR_DESTROY(&temp_xdrs); + return FALSE; + } + + /* serialize the arguments into local memory */ + if (!(*xdr_func)(&temp_xdrs, xdr_ptr)) { + PRINTF(("gssapi_wrap_data: serializing arguments failed\n")); + XDR_DESTROY(&temp_xdrs); + return FALSE; + } + + in_buf.length = xdr_getpos(&temp_xdrs); + in_buf.value = xdralloc_getdata(&temp_xdrs); + + *major = gss_seal(minor, context, 1, + GSS_C_QOP_DEFAULT, &in_buf, &conf_state, + &out_buf); + if (*major != GSS_S_COMPLETE) { + XDR_DESTROY(&temp_xdrs); + return FALSE; + } + + PRINTF(("gssapi_wrap_data: %d bytes data, %d bytes sealed\n", + in_buf.length, out_buf.length)); + + /* write the token */ + if (! xdr_bytes(out_xdrs, (char **) &out_buf.value, + (unsigned int *) &out_buf.length, + out_buf.length)) { + PRINTF(("gssapi_wrap_data: serializing encrypted data failed\n")); + XDR_DESTROY(&temp_xdrs); + return FALSE; + } + + *major = gss_release_buffer(minor, &out_buf); + + PRINTF(("gssapi_wrap_data: succeeding\n\n")); + XDR_DESTROY(&temp_xdrs); + return TRUE; +} + +bool_t auth_gssapi_unwrap_data(major, minor, context, seq_num, + in_xdrs, xdr_func, xdr_ptr) + OM_uint32 *major, *minor; + gss_ctx_id_t context; + rpc_u_int32 seq_num; + XDR *in_xdrs; + bool_t (*xdr_func)(); + caddr_t xdr_ptr; +{ + gss_buffer_desc in_buf, out_buf; + XDR temp_xdrs; + rpc_u_int32 verf_seq_num; + int conf, qop; + + PRINTF(("gssapi_unwrap_data: starting\n")); + + *major = GSS_S_COMPLETE; + *minor = 0; /* assumption */ + + in_buf.value = NULL; + out_buf.value = NULL; + + if (! xdr_bytes(in_xdrs, (char **) &in_buf.value, + (unsigned int *) &in_buf.length, (unsigned int) -1)) { + PRINTF(("gssapi_unwrap_data: deserializing encrypted data failed\n")); + return FALSE; + } + + *major = gss_unseal(minor, context, &in_buf, &out_buf, &conf, + &qop); + free(in_buf.value); + if (*major != GSS_S_COMPLETE) + return FALSE; + + PRINTF(("gssapi_unwrap_data: %d bytes data, %d bytes sealed\n", + out_buf.length, in_buf.length)); + + xdrmem_create(&temp_xdrs, out_buf.value, out_buf.length, XDR_DECODE); + + /* deserialize the sequence number */ + if (! xdr_u_int32(&temp_xdrs, &verf_seq_num)) { + PRINTF(("gssapi_unwrap_data: deserializing verf_seq_num failed\n")); + gss_release_buffer(minor, &out_buf); + XDR_DESTROY(&temp_xdrs); + return FALSE; + } + if (verf_seq_num != seq_num) { + PRINTF(("gssapi_unwrap_data: seq %d specified, read %d\n", + seq_num, verf_seq_num)); + gss_release_buffer(minor, &out_buf); + XDR_DESTROY(&temp_xdrs); + return FALSE; + } + PRINTF(("gssapi_unwrap_data: unwrap seq_num %d okay\n", verf_seq_num)); + + /* deserialize the arguments into xdr_ptr */ + if (! (*xdr_func)(&temp_xdrs, xdr_ptr)) { + PRINTF(("gssapi_unwrap_data: deserializing arguments failed\n")); + gss_release_buffer(minor, &out_buf); + XDR_DESTROY(&temp_xdrs); + return FALSE; + } + + PRINTF(("gssapi_unwrap_data: succeeding\n\n")); + + gss_release_buffer(minor, &out_buf); + XDR_DESTROY(&temp_xdrs); + return TRUE; +} diff --git a/src/lib/rpc/auth_none.c b/src/lib/rpc/auth_none.c new file mode 100644 index 000000000..90f3bb8be --- /dev/null +++ b/src/lib/rpc/auth_none.c @@ -0,0 +1,136 @@ +/* @(#)auth_none.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)auth_none.c 1.19 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * auth_none.c + * Creates a client authentication handle for passing "null" + * credentials and verifiers to remote systems. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <rpc/auth.h> +#include <stdlib.h> +#define MAX_MARSHEL_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, + authany_wrap, + authany_wrap, +}; + +static struct authnone_private { + AUTH no_client; + char marshalled_client[MAX_MARSHEL_SIZE]; + unsigned int mcnt; +} *authnone_private; + +AUTH * +authnone_create() +{ + register struct authnone_private *ap = authnone_private; + XDR xdr_stream; + register XDR *xdrs; + + if (ap == 0) { + ap = (struct authnone_private *)calloc(1, sizeof (*ap)); + if (ap == 0) + 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; + xdrs = &xdr_stream; + xdrmem_create(xdrs, ap->marshalled_client, (unsigned int)MAX_MARSHEL_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); + } + return (&ap->no_client); +} + +/*ARGSUSED*/ +static bool_t +authnone_marshal(client, xdrs) + AUTH *client; + XDR *xdrs; +{ + register struct authnone_private *ap = authnone_private; + + if (ap == 0) + return (0); + return ((*xdrs->x_ops->x_putbytes)(xdrs, + ap->marshalled_client, ap->mcnt)); +} + +static void +authnone_verf() +{ +} + +static bool_t +authnone_validate() +{ + + return (TRUE); +} + +static bool_t +authnone_refresh() +{ + + return (FALSE); +} + +static void +authnone_destroy() +{ +} diff --git a/src/lib/rpc/auth_unix.c b/src/lib/rpc/auth_unix.c new file mode 100644 index 000000000..b41e442fc --- /dev/null +++ b/src/lib/rpc/auth_unix.c @@ -0,0 +1,322 @@ +/* @(#)auth_unix.c 2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)auth_unix.c 1.19 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * auth_unix.c, Implements UNIX style authentication parameters. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * The system is very weak. The client uses no encryption for it's + * credentials and only sends null verifiers. The server sends backs + * null verifiers or optionally a verifier that suggests a new short hand + * for the credentials. + * + */ + +#include <stdio.h> + +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <rpc/auth.h> +#include <rpc/auth_unix.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, + authany_wrap, + authany_wrap, +}; + +/* + * This struct is pointed to by the ah_private field of an auth_handle. + */ +struct audata { + struct opaque_auth au_origcred; /* original credentials */ + struct opaque_auth au_shcred; /* short hand cred */ + rpc_u_int32 au_shfaults; /* short hand cache faults */ + char au_marshed[MAX_AUTH_BYTES]; + unsigned int au_mpos; /* xdr pos at end of marshed */ +}; +#define AUTH_PRIVATE(auth) ((struct audata *)auth->ah_private) + +static bool_t marshal_new_auth(); + + +/* + * Create a unix style authenticator. + * Returns an auth handle with the given stuff in it. + */ +AUTH * +authunix_create(machname, uid, gid, len, aup_gids) + char *machname; + int uid; + int gid; + register 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; + + /* + * Allocate and set up auth handle + */ + auth = (AUTH *)mem_alloc(sizeof(*auth)); +#ifndef KERNEL + if (auth == NULL) { + (void)fprintf(stderr, "authunix_create: out of memory\n"); + return (NULL); + } +#endif + au = (struct audata *)mem_alloc(sizeof(*au)); +#ifndef KERNEL + if (au == NULL) { + (void)fprintf(stderr, "authunix_create: out of memory\n"); + return (NULL); + } +#endif + auth->ah_ops = &auth_unix_ops; + auth->ah_private = (caddr_t)au; + auth->ah_verf = au->au_shcred = _null_auth; + au->au_shfaults = 0; + + /* + * fill in param struct from the given params + */ + (void)gettimeofday(&now, (struct timezone *)0); + aup.aup_time = now.tv_sec; + aup.aup_machname = machname; + aup.aup_uid = uid; + aup.aup_gid = gid; + aup.aup_len = (unsigned int)len; + aup.aup_gids = aup_gids; + + /* + * Serialize the parameters into origcred + */ + xdrmem_create(&xdrs, mymem, MAX_AUTH_BYTES, XDR_ENCODE); + if (! xdr_authunix_parms(&xdrs, &aup)) + abort(); + au->au_origcred.oa_length = len = XDR_GETPOS(&xdrs); + au->au_origcred.oa_flavor = AUTH_UNIX; +#ifdef KERNEL + au->au_origcred.oa_base = mem_alloc((unsigned int) len); +#else + if ((au->au_origcred.oa_base = mem_alloc((unsigned int) len)) == NULL) { + (void)fprintf(stderr, "authunix_create: out of memory\n"); + return (NULL); + } +#endif + memmove(au->au_origcred.oa_base, mymem, (unsigned int)len); + + /* + * set auth handle to reflect new cred. + */ + auth->ah_cred = au->au_origcred; + marshal_new_auth(auth); + return (auth); +} + +/* + * Returns an auth handle with parameters determined by doing lots of + * syscalls. + */ +AUTH * +authunix_create_default() +{ + register int len; + char machname[MAX_MACHINE_NAME + 1]; + register int uid; + register int gid; + int gids[NGRPS]; + + if (gethostname(machname, MAX_MACHINE_NAME) == -1) + abort(); + machname[MAX_MACHINE_NAME] = 0; + uid = geteuid(); + gid = getegid(); + if ((len = getgroups(NGRPS, gids)) < 0) + abort(); + return (authunix_create(machname, uid, gid, len, gids)); +} + +/* + * authunix operations + */ + +static void +authunix_nextverf(auth) + AUTH *auth; +{ + /* no action necessary */ +} + +static bool_t +authunix_marshal(auth, xdrs) + AUTH *auth; + XDR *xdrs; +{ + register struct audata *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; +{ + register struct audata *au; + XDR xdrs; + + if (verf.oa_flavor == AUTH_SHORT) { + au = AUTH_PRIVATE(auth); + xdrmem_create(&xdrs, verf.oa_base, verf.oa_length, XDR_DECODE); + + if (au->au_shcred.oa_base != NULL) { + mem_free(au->au_shcred.oa_base, + au->au_shcred.oa_length); + au->au_shcred.oa_base = NULL; + } + if (xdr_opaque_auth(&xdrs, &au->au_shcred)) { + auth->ah_cred = au->au_shcred; + } else { + xdrs.x_op = XDR_FREE; + (void)xdr_opaque_auth(&xdrs, &au->au_shcred); + au->au_shcred.oa_base = NULL; + auth->ah_cred = au->au_origcred; + } + marshal_new_auth(auth); + } + return (TRUE); +} + +static bool_t +authunix_refresh(auth) + register AUTH *auth; +{ + register struct audata *au = AUTH_PRIVATE(auth); + struct authunix_parms aup; + struct timeval now; + XDR xdrs; + register int stat; + + if (auth->ah_cred.oa_base == au->au_origcred.oa_base) { + /* there is no hope. Punt */ + return (FALSE); + } + au->au_shfaults ++; + + /* first deserialize the creds back into a struct authunix_parms */ + aup.aup_machname = NULL; + aup.aup_gids = (int *)NULL; + xdrmem_create(&xdrs, au->au_origcred.oa_base, + au->au_origcred.oa_length, XDR_DECODE); + stat = xdr_authunix_parms(&xdrs, &aup); + if (! stat) + goto done; + + /* update the time and serialize in place */ + (void)gettimeofday(&now, (struct timezone *)0); + aup.aup_time = now.tv_sec; + xdrs.x_op = XDR_ENCODE; + XDR_SETPOS(&xdrs, 0); + stat = xdr_authunix_parms(&xdrs, &aup); + if (! stat) + goto done; + auth->ah_cred = au->au_origcred; + marshal_new_auth(auth); +done: + /* free the struct authunix_parms created by deserializing */ + xdrs.x_op = XDR_FREE; + (void)xdr_authunix_parms(&xdrs, &aup); + XDR_DESTROY(&xdrs); + return (stat); +} + +static void +authunix_destroy(auth) + register AUTH *auth; +{ + register struct audata *au = AUTH_PRIVATE(auth); + + mem_free(au->au_origcred.oa_base, au->au_origcred.oa_length); + + if (au->au_shcred.oa_base != NULL) + mem_free(au->au_shcred.oa_base, au->au_shcred.oa_length); + + mem_free(auth->ah_private, sizeof(struct audata)); + + if (auth->ah_verf.oa_base != NULL) + mem_free(auth->ah_verf.oa_base, auth->ah_verf.oa_length); + + mem_free((caddr_t)auth, sizeof(*auth)); +} + +/* + * Marshals (pre-serializes) an auth struct. + * sets private data, au_marshed and au_mpos + */ +static bool_t +marshal_new_auth(auth) + register AUTH *auth; +{ + XDR xdr_stream; + register XDR *xdrs = &xdr_stream; + register struct audata *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 { + au->au_mpos = XDR_GETPOS(xdrs); + } + XDR_DESTROY(xdrs); +} diff --git a/src/lib/rpc/auth_unix.h b/src/lib/rpc/auth_unix.h new file mode 100644 index 000000000..4b54f1db6 --- /dev/null +++ b/src/lib/rpc/auth_unix.h @@ -0,0 +1,72 @@ +/* @(#)auth_unix.h 2.2 88/07/29 4.0 RPCSRC; from 1.8 88/02/08 SMI */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* @(#)auth_unix.h 1.5 86/07/16 SMI */ + +/* + * auth_unix.h, Protocol for UNIX style authentication parameters for RPC + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +/* + * The system is very weak. The client uses no encryption for it + * credentials and only sends null verifiers. The server sends backs + * null verifiers or optionally a verifier that suggests a new short hand + * for the credentials. + */ + +/* The machine name is part of a credential; it may not exceed 255 bytes */ +#define MAX_MACHINE_NAME 255 + +/* gids compose part of a credential; there may not be more than 16 of them */ +#define NGRPS 16 + +/* + * Unix style credentials. + */ +struct authunix_parms { + rpc_u_int32 aup_time; + char *aup_machname; + int aup_uid; + int aup_gid; + unsigned int aup_len; + int *aup_gids; +}; + +extern bool_t xdr_authunix_parms(); + +/* + * If a response verifier has flavor AUTH_SHORT, + * then the body of the response verifier encapsulates the following structure; + * again it is serialized in the obvious fashion. + */ +struct short_hand_verf { + struct opaque_auth new_cred; +}; diff --git a/src/lib/rpc/authunix_prot.c b/src/lib/rpc/authunix_prot.c new file mode 100644 index 000000000..36770f298 --- /dev/null +++ b/src/lib/rpc/authunix_prot.c @@ -0,0 +1,66 @@ +/* @(#)authunix_prot.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)authunix_prot.c 1.15 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * authunix_prot.c + * XDR for UNIX style authentication parameters for RPC + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + + +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <rpc/auth.h> +#include <rpc/auth_unix.h> + +/* + * XDR for unix authentication parameters. + */ +bool_t +xdr_authunix_parms(xdrs, p) + register XDR *xdrs; + register struct authunix_parms *p; +{ + + if (xdr_u_int32(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) ) { + return (TRUE); + } + return (FALSE); +} + diff --git a/src/lib/rpc/bindresvport.c b/src/lib/rpc/bindresvport.c new file mode 100644 index 000000000..875aeefb6 --- /dev/null +++ b/src/lib/rpc/bindresvport.c @@ -0,0 +1,79 @@ +static char sccsid[] = "@(#)bindresvport.c 2.2 88/07/29 4.0 RPCSRC 1.8 88/02/08 SMI"; +/* + * 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) 1987 by Sun Microsystems, Inc. + */ + +#include <sys/types.h> +#include <sys/errno.h> +#include <sys/socket.h> +#include <netinet/in.h> + +/* + * Bind a socket to a privileged IP port + */ +bindresvport(sd, sin) + int sd; + struct sockaddr_in *sin; +{ + int res; + static short port; + struct sockaddr_in myaddr; + extern int errno; + int i; + +#define STARTPORT 600 +#define ENDPORT (IPPORT_RESERVED - 1) +#define NPORTS (ENDPORT - STARTPORT + 1) + + if (sin == (struct sockaddr_in *)0) { + sin = &myaddr; + memset(sin, 0, sizeof (*sin)); + sin->sin_family = AF_INET; + } else if (sin->sin_family != AF_INET) { + errno = EPFNOSUPPORT; + return (-1); + } + if (port == 0) { + port = (getpid() % NPORTS) + STARTPORT; + } + res = -1; + errno = EADDRINUSE; + for (i = 0; i < NPORTS && res < 0 && errno == EADDRINUSE; i++) { + sin->sin_port = htons(port++); + if (port > ENDPORT) { + port = STARTPORT; + } + res = bind(sd, (struct sockaddr *) sin, + sizeof(struct sockaddr_in)); + } + return (res); +} diff --git a/src/lib/rpc/clnt.h b/src/lib/rpc/clnt.h new file mode 100644 index 000000000..442a96d44 --- /dev/null +++ b/src/lib/rpc/clnt.h @@ -0,0 +1,335 @@ +/* @(#)clnt.h 2.1 88/07/29 4.0 RPCSRC; from 1.31 88/02/08 SMI*/ +/* + * 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 + */ + +/* + * clnt.h - Client side remote procedure call interface. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#ifndef _CLNT_ +#define _CLNT_ + +/* + * Rpc calls return an enum clnt_stat. This should be looked at more, + * since each implementation is required to live with this (implementation + * independent) list of errors. + */ +enum clnt_stat { + RPC_SUCCESS=0, /* call succeeded */ + /* + * local errors + */ + RPC_CANTENCODEARGS=1, /* can't encode arguments */ + RPC_CANTDECODERES=2, /* can't decode results */ + RPC_CANTSEND=3, /* failure in sending call */ + RPC_CANTRECV=4, /* failure in receiving result */ + RPC_TIMEDOUT=5, /* call timed out */ + /* + * remote errors + */ + RPC_VERSMISMATCH=6, /* rpc versions not compatible */ + RPC_AUTHERROR=7, /* authentication error */ + RPC_PROGUNAVAIL=8, /* program not available */ + RPC_PROGVERSMISMATCH=9, /* program version mismatched */ + RPC_PROCUNAVAIL=10, /* procedure unavailable */ + RPC_CANTDECODEARGS=11, /* decode arguments error */ + RPC_SYSTEMERROR=12, /* generic "other problem" */ + + /* + * callrpc & clnt_create errors + */ + RPC_UNKNOWNHOST=13, /* unknown host name */ + RPC_UNKNOWNPROTO=17, /* unkown protocol */ + + /* + * _ create errors + */ + RPC_PMAPFAILURE=14, /* the pmapper failed in its call */ + RPC_PROGNOTREGISTERED=15, /* remote program is not registered */ + /* + * unspecified error + */ + RPC_FAILED=16 +}; + + +/* + * Error info. + */ +struct rpc_err { + enum clnt_stat re_status; + union { + int RE_errno; /* realated system error */ + enum auth_stat RE_why; /* why the auth error occurred */ + struct { + rpc_u_int32 low; /* lowest verion supported */ + rpc_u_int32 high; /* highest verion supported */ + } RE_vers; + struct { /* maybe meaningful if RPC_FAILED */ + rpc_int32 s1; + rpc_int32 s2; + } RE_lb; /* life boot & debugging only */ + } ru; +#define re_errno ru.RE_errno +#define re_why ru.RE_why +#define re_vers ru.RE_vers +#define re_lb ru.RE_lb +}; + + +/* + * Client rpc handle. + * Created by individual implementations, see e.g. rpc_udp.c. + * Client is responsible for initializing auth, see e.g. auth_none.c. + */ +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 */ +} CLIENT; + + +/* + * client side rpc interface ops + * + * Parameter types are: + * + */ + +/* + * enum clnt_stat + * CLNT_CALL(rh, proc, xargs, argsp, xres, resp, timeout) + * CLIENT *rh; + * rpc_u_int32 proc; + * xdrproc_t xargs; + * caddr_t argsp; + * xdrproc_t xres; + * caddr_t resp; + * struct timeval timeout; + */ +#define CLNT_CALL(rh, proc, xargs, argsp, xres, resp, secs) \ + ((*(rh)->cl_ops->cl_call)(rh, proc, xargs, argsp, xres, resp, secs)) +#define clnt_call(rh, proc, xargs, argsp, xres, resp, secs) \ + ((*(rh)->cl_ops->cl_call)(rh, proc, xargs, argsp, xres, resp, secs)) + +/* + * void + * CLNT_ABORT(rh); + * CLIENT *rh; + */ +#define CLNT_ABORT(rh) ((*(rh)->cl_ops->cl_abort)(rh)) +#define clnt_abort(rh) ((*(rh)->cl_ops->cl_abort)(rh)) + +/* + * struct rpc_err + * CLNT_GETERR(rh); + * CLIENT *rh; + */ +#define CLNT_GETERR(rh,errp) ((*(rh)->cl_ops->cl_geterr)(rh, errp)) +#define clnt_geterr(rh,errp) ((*(rh)->cl_ops->cl_geterr)(rh, errp)) + + +/* + * bool_t + * CLNT_FREERES(rh, xres, resp); + * CLIENT *rh; + * xdrproc_t xres; + * caddr_t resp; + */ +#define CLNT_FREERES(rh,xres,resp) ((*(rh)->cl_ops->cl_freeres)(rh,xres,resp)) +#define clnt_freeres(rh,xres,resp) ((*(rh)->cl_ops->cl_freeres)(rh,xres,resp)) + +/* + * bool_t + * CLNT_CONTROL(cl, request, info) + * CLIENT *cl; + * unsigned int request; + * char *info; + */ +#define CLNT_CONTROL(cl,rq,in) ((*(cl)->cl_ops->cl_control)(cl,rq,in)) +#define clnt_control(cl,rq,in) ((*(cl)->cl_ops->cl_control)(cl,rq,in)) + +/* + * control operations that apply to both udp and tcp transports + */ +#define CLSET_TIMEOUT 1 /* set timeout (timeval) */ +#define CLGET_TIMEOUT 2 /* get timeout (timeval) */ +#define CLGET_SERVER_ADDR 3 /* get server's address (sockaddr) */ +/* + * udp only control operations + */ +#define CLSET_RETRY_TIMEOUT 4 /* set retry timeout (timeval) */ +#define CLGET_RETRY_TIMEOUT 5 /* get retry timeout (timeval) */ +/* + * new control operations + */ +#define CLGET_LOCAL_ADDR 6 /* get local address (sockaddr, getsockname)*/ + +/* + * void + * CLNT_DESTROY(rh); + * CLIENT *rh; + */ +#define CLNT_DESTROY(rh) ((*(rh)->cl_ops->cl_destroy)(rh)) +#define clnt_destroy(rh) ((*(rh)->cl_ops->cl_destroy)(rh)) + + +/* + * RPCTEST is a test program which is accessable on every rpc + * transport/port. It is used for testing, performance evaluation, + * and network administration. + */ + +#define RPCTEST_PROGRAM ((rpc_u_int32)1) +#define RPCTEST_VERSION ((rpc_u_int32)1) +#define RPCTEST_NULL_PROC ((rpc_u_int32)2) +#define RPCTEST_NULL_BATCH_PROC ((rpc_u_int32)3) + +/* + * By convention, procedure 0 takes null arguments and returns them + */ + +#define NULLPROC ((rpc_u_int32)0) + +/* + * Below are the client handle creation routines for the various + * implementations of client side rpc. They can return NULL if a + * creation failure occurs. + */ + +/* + * Memory based rpc (for speed check and testing) + * CLIENT * + * clntraw_create(prog, vers) + * rpc_u_int32 prog; + * rpc_u_int32 vers; + */ +extern CLIENT *clntraw_create(); + + +/* + * Generic client creation routine. Supported protocols are "udp" and "tcp" + */ +extern CLIENT * +clnt_create(/*host, prog, vers, prot*/); /* + char *host; -- hostname + rpc_u_int32 prog; -- program number + rpc_u_int32 vers; -- version number + char *prot; -- protocol +*/ + + + + +/* + * TCP based rpc + * CLIENT * + * clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz) + * struct sockaddr_in *raddr; + * rpc_u_int32 prog; + * rpc_u_int32 version; + * register int *sockp; + * unsigned int sendsz; + * unsigned int recvsz; + */ +extern CLIENT *clnttcp_create(); + +/* + * UDP based rpc. + * CLIENT * + * clntudp_create(raddr, program, version, wait, sockp) + * struct sockaddr_in *raddr; + * rpc_u_int32 program; + * rpc_u_int32 version; + * struct timeval wait; + * int *sockp; + * + * Same as above, but you specify max packet sizes. + * CLIENT * + * clntudp_bufcreate(raddr, program, version, wait, sockp, sendsz, recvsz) + * struct sockaddr_in *raddr; + * rpc_u_int32 program; + * rpc_u_int32 version; + * struct timeval wait; + * int *sockp; + * unsigned int sendsz; + * unsigned int recvsz; + */ +extern CLIENT *clntudp_create(); +extern CLIENT *clntudp_bufcreate(); + +/* + * Print why creation failed + */ +void clnt_pcreateerror(/* char *msg */); /* stderr */ +char *clnt_spcreateerror(/* char *msg */); /* string */ + +/* + * Like clnt_perror(), but is more verbose in its output + */ +void clnt_perrno(/* enum clnt_stat num */); /* stderr */ + +/* + * Print an English error message, given the client error code + */ +void clnt_perror(/* CLIENT *clnt, char *msg */); /* stderr */ +char *clnt_sperror(/* CLIENT *clnt, char *msg */); /* string */ + +/* + * If a creation fails, the following allows the user to figure out why. + */ +struct rpc_createerr { + enum clnt_stat cf_stat; + struct rpc_err cf_error; /* useful when cf_stat == RPC_PMAPFAILURE */ +}; + +extern struct rpc_createerr rpc_createerr; + + + +/* + * Copy error message to buffer. + */ +char *clnt_sperrno(/* enum clnt_stat num */); /* string */ + + + +#define UDPMSGSIZE 8800 /* rpc imposed limit on udp msg size */ +#define RPCSMALLMSGSIZE 400 /* a more reasonable packet size */ + +#endif /*!_CLNT_*/ diff --git a/src/lib/rpc/clnt_generic.c b/src/lib/rpc/clnt_generic.c new file mode 100644 index 000000000..f111c2e14 --- /dev/null +++ b/src/lib/rpc/clnt_generic.c @@ -0,0 +1,110 @@ +/* @(#)clnt_generic.c 2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)clnt_generic.c 1.4 87/08/11 (C) 1987 SMI"; +#endif +/* + * Copyright (C) 1987, Sun Microsystems, Inc. + */ +#include <rpc/rpc.h> +#include <sys/socket.h> +#include <sys/errno.h> +#include <netdb.h> + +/* + * Generic client creation: takes (hostname, program-number, protocol) and + * returns client handle. Default options are set, which the user can + * change using the rpc equivalent of ioctl()'s. + */ +CLIENT * +clnt_create(hostname, prog, vers, proto) + char *hostname; + unsigned prog; + unsigned vers; + char *proto; +{ + struct hostent *h; + struct protoent *p; + struct sockaddr_in sin; + int sock; + struct timeval tv; + CLIENT *client; + + h = gethostbyname(hostname); + if (h == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNHOST; + 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); + } + sin.sin_family = h->h_addrtype; + sin.sin_port = 0; + memset(sin.sin_zero, 0, sizeof(sin.sin_zero)); + memmove((char*)&sin.sin_addr, h->h_addr, h->h_length); + p = getprotobyname(proto); + if (p == 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); + } + tv.tv_sec = 25; + clnt_control(client, CLSET_TIMEOUT, &tv); + break; + case IPPROTO_TCP: + client = clnttcp_create(&sin, prog, vers, &sock, 0, 0); + if (client == NULL) { + return (NULL); + } + tv.tv_sec = 25; + tv.tv_usec = 0; + clnt_control(client, CLSET_TIMEOUT, &tv); + break; + default: + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = EPFNOSUPPORT; + return (NULL); + } + return (client); +} diff --git a/src/lib/rpc/clnt_perror.c b/src/lib/rpc/clnt_perror.c new file mode 100644 index 000000000..63eef49f0 --- /dev/null +++ b/src/lib/rpc/clnt_perror.c @@ -0,0 +1,306 @@ +/* @(#)clnt_perror.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)clnt_perror.c 1.15 87/10/07 Copyr 1984 Sun Micro"; +#endif + +/* + * clnt_perror.c + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + */ +#include <stdio.h> +#include <string.h> + +#include <rpc/types.h> +#include <rpc/auth.h> +#include <rpc/clnt.h> + +#ifdef NEED_SYS_ERRLIST +extern char *sys_errlist[]; +#endif +static char *auth_errmsg(); + +extern char *strcpy(); + +static char *buf; + +static char * +_buf() +{ + + if (buf == 0) + buf = (char *)malloc(256); + return (buf); +} + +/* + * Print reply error info + */ +char * +clnt_sperror(rpch, s) + CLIENT *rpch; + char *s; +{ + struct rpc_err e; + void clnt_perrno(); + char *err; + char *str = _buf(); + char *strstart = str; + + if (str == 0) + return (0); + CLNT_GETERR(rpch, &e); + + (void) sprintf(str, "%s: ", s); + str += strlen(str); + + (void) strcpy(str, clnt_sperrno(e.re_status)); + str += strlen(str); + + switch (e.re_status) { + case RPC_SUCCESS: + case RPC_CANTENCODEARGS: + case RPC_CANTDECODERES: + case RPC_TIMEDOUT: + case RPC_PROGUNAVAIL: + case RPC_PROCUNAVAIL: + case RPC_CANTDECODEARGS: + case RPC_SYSTEMERROR: + case RPC_UNKNOWNHOST: + case RPC_UNKNOWNPROTO: + case RPC_PMAPFAILURE: + case RPC_PROGNOTREGISTERED: + case RPC_FAILED: + break; + + case RPC_CANTSEND: + case RPC_CANTRECV: + (void) sprintf(str, "; errno = %s", + sys_errlist[e.re_errno]); + str += strlen(str); + break; + + case RPC_VERSMISMATCH: + (void) sprintf(str, + "; low version = %lu, high version = %lu", + e.re_vers.low, e.re_vers.high); + str += strlen(str); + break; + + case RPC_AUTHERROR: + err = auth_errmsg(e.re_why); + (void) sprintf(str,"; why = "); + str += strlen(str); + if (err != NULL) { + (void) sprintf(str, "%s",err); + } else { + (void) sprintf(str, + "(unknown authentication error - %d)", + (int) e.re_why); + } + str += strlen(str); + break; + + case RPC_PROGVERSMISMATCH: + (void) sprintf(str, + "; low version = %lu, high version = %lu", + e.re_vers.low, e.re_vers.high); + str += strlen(str); + break; + + default: /* unknown */ + (void) sprintf(str, + "; s1 = %lu, s2 = %lu", + e.re_lb.s1, e.re_lb.s2); + str += strlen(str); + break; + } + (void) sprintf(str, "\n"); + return(strstart) ; +} + +void +clnt_perror(rpch, s) + CLIENT *rpch; + char *s; +{ + (void) fprintf(stderr,"%s",clnt_sperror(rpch,s)); +} + + +struct rpc_errtab { + enum clnt_stat status; + char *message; +}; + +static struct rpc_errtab rpc_errlist[] = { + { RPC_SUCCESS, + "RPC: Success" }, + { RPC_CANTENCODEARGS, + "RPC: Can't encode arguments" }, + { RPC_CANTDECODERES, + "RPC: Can't decode result" }, + { RPC_CANTSEND, + "RPC: Unable to send" }, + { RPC_CANTRECV, + "RPC: Unable to receive" }, + { RPC_TIMEDOUT, + "RPC: Timed out" }, + { RPC_VERSMISMATCH, + "RPC: Incompatible versions of RPC" }, + { RPC_AUTHERROR, + "RPC: Authentication error" }, + { RPC_PROGUNAVAIL, + "RPC: Program unavailable" }, + { RPC_PROGVERSMISMATCH, + "RPC: Program/version mismatch" }, + { RPC_PROCUNAVAIL, + "RPC: Procedure unavailable" }, + { RPC_CANTDECODEARGS, + "RPC: Server can't decode arguments" }, + { RPC_SYSTEMERROR, + "RPC: Remote system error" }, + { RPC_UNKNOWNHOST, + "RPC: Unknown host" }, + { RPC_UNKNOWNPROTO, + "RPC: Unknown protocol" }, + { RPC_PMAPFAILURE, + "RPC: Port mapper failure" }, + { RPC_PROGNOTREGISTERED, + "RPC: Program not registered"}, + { RPC_FAILED, + "RPC: Failed (unspecified error)"} +}; + + +/* + * This interface for use by clntrpc + */ +char * +clnt_sperrno(stat) + enum clnt_stat stat; +{ + int i; + + for (i = 0; i < sizeof(rpc_errlist)/sizeof(struct rpc_errtab); i++) { + if (rpc_errlist[i].status == stat) { + return (rpc_errlist[i].message); + } + } + return ("RPC: (unknown error code)"); +} + +void +clnt_perrno(num) + enum clnt_stat num; +{ + (void) fprintf(stderr,"%s",clnt_sperrno(num)); +} + + +char * +clnt_spcreateerror(s) + char *s; +{ + extern int sys_nerr; + char *str = _buf(); + + if (str == 0) + return(0); + (void) sprintf(str, "%s: ", s); + (void) strcat(str, clnt_sperrno(rpc_createerr.cf_stat)); + switch (rpc_createerr.cf_stat) { + case RPC_PMAPFAILURE: + (void) strcat(str, " - "); + (void) strcat(str, + clnt_sperrno(rpc_createerr.cf_error.re_status)); + break; + + case RPC_SYSTEMERROR: + (void) strcat(str, " - "); + if (rpc_createerr.cf_error.re_errno > 0 + && rpc_createerr.cf_error.re_errno < sys_nerr) + (void) strcat(str, + sys_errlist[rpc_createerr.cf_error.re_errno]); + else + (void) sprintf(&str[strlen(str)], "Error %d", + rpc_createerr.cf_error.re_errno); + break; + } + (void) strcat(str, "\n"); + return (str); +} + +void +clnt_pcreateerror(s) + char *s; +{ + (void) fprintf(stderr,"%s",clnt_spcreateerror(s)); +} + +struct auth_errtab { + enum auth_stat status; + char *message; +}; + +static struct auth_errtab auth_errlist[] = { + { AUTH_OK, + "Authentication OK" }, + { AUTH_BADCRED, + "Invalid client credential" }, + { AUTH_REJECTEDCRED, + "Server rejected credential" }, + { AUTH_BADVERF, + "Invalid client verifier" }, + { AUTH_REJECTEDVERF, + "Server rejected verifier" }, + { AUTH_TOOWEAK, + "Client credential too weak" }, + { AUTH_INVALIDRESP, + "Invalid server verifier" }, + { AUTH_FAILED, + "Failed (unspecified error)" }, +}; + +static char * +auth_errmsg(stat) + enum auth_stat stat; +{ + int i; + + for (i = 0; i < sizeof(auth_errlist)/sizeof(struct auth_errtab); i++) { + if (auth_errlist[i].status == stat) { + return(auth_errlist[i].message); + } + } + return(NULL); +} diff --git a/src/lib/rpc/clnt_raw.c b/src/lib/rpc/clnt_raw.c new file mode 100644 index 000000000..d05dbaa7e --- /dev/null +++ b/src/lib/rpc/clnt_raw.c @@ -0,0 +1,239 @@ +/* @(#)clnt_raw.c 2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)clnt_raw.c 1.22 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * clnt_raw.c + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * Memory based rpc for simple testing and timing. + * Interface to create an rpc client and server in the same process. + * This lets us similate rpc and get round trip overhead, without + * any interference from the kernal. + */ + +#include <rpc/rpc.h> + +#define MCALL_MSG_SIZE 24 + +/* + * This is the "network" we will be moving stuff over. + */ +static struct clntraw_private { + CLIENT client_object; + XDR xdr_stream; + char _raw_buf[UDPMSGSIZE]; + char mashl_callmsg[MCALL_MSG_SIZE]; + unsigned 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(); + +/* + * Create a client handle for memory based rpc. + */ +CLIENT * +clntraw_create(prog, vers) + rpc_u_int32 prog; + rpc_u_int32 vers; +{ + register struct clntraw_private *clp = clntraw_private; + struct rpc_msg call_msg; + XDR *xdrs = &clp->xdr_stream; + CLIENT *client = &clp->client_object; + + if (clp == 0) { + clp = (struct clntraw_private *)calloc(1, sizeof (*clp)); + if (clp == 0) + return (0); + clntraw_private = clp; + } + /* + * pre-serialize the staic part of the call msg and stash it away + */ + 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."); + } + clp->mcnt = XDR_GETPOS(xdrs); + XDR_DESTROY(xdrs); + + /* + * Set xdrmem for client/server shared buffer + */ + xdrmem_create(xdrs, clp->_raw_buf, UDPMSGSIZE, XDR_FREE); + + /* + * create client handle + */ + client->cl_ops = &client_ops; + client->cl_auth = authnone_create(); + return (client); +} + +static enum clnt_stat +clntraw_call(h, proc, xargs, argsp, xresults, resultsp, timeout) + CLIENT *h; + rpc_u_int32 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 rpc_msg msg; + enum clnt_stat status; + struct rpc_err error; + long procl = proc; + + if (clp == 0) + return (RPC_FAILED); +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, &procl)) || + (! AUTH_MARSHALL(h->cl_auth, xdrs)) || + (! (*xargs)(xdrs, argsp))) { + return (RPC_CANTENCODEARGS); + } + (void)XDR_GETPOS(xdrs); /* called just to cause overhead */ + + /* + * We have to call server input routine here because this is + * all going on in one process. Yuk. + */ + svc_getreq(1); + + /* + * get results + */ + xdrs->x_op = XDR_DECODE; + XDR_SETPOS(xdrs, 0); + msg.acpted_rply.ar_verf = _null_auth; + msg.acpted_rply.ar_results.where = resultsp; + msg.acpted_rply.ar_results.proc = xresults; + if (! xdr_replymsg(xdrs, &msg)) + return (RPC_CANTDECODERES); + sunrpc_seterr_reply(&msg, &error); + status = error.re_status; + + if (status == RPC_SUCCESS) { + if (! AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf)) { + status = RPC_AUTHERROR; + } + } /* end successful completion */ + else { + if (AUTH_REFRESH(h->cl_auth, &msg)) + goto call_again; + } /* end of unsuccessful completion */ + + if (status == RPC_SUCCESS) { + if (! AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf)) { + status = RPC_AUTHERROR; + } + if (msg.acpted_rply.ar_verf.oa_base != NULL) { + xdrs->x_op = XDR_FREE; + (void)xdr_opaque_auth(xdrs, &(msg.acpted_rply.ar_verf)); + } + } + + return (status); +} + +static void +clntraw_geterr() +{ +} + + +static bool_t +clntraw_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; + bool_t rval; + + if (clp == 0) + { + rval = (bool_t) RPC_FAILED; + return (rval); + } + xdrs->x_op = XDR_FREE; + return ((*xdr_res)(xdrs, res_ptr)); +} + +static void +clntraw_abort() +{ +} + +static bool_t +clntraw_control() +{ + return (FALSE); +} + +static void +clntraw_destroy() +{ +} diff --git a/src/lib/rpc/clnt_simple.c b/src/lib/rpc/clnt_simple.c new file mode 100644 index 000000000..0d8f7a4df --- /dev/null +++ b/src/lib/rpc/clnt_simple.c @@ -0,0 +1,112 @@ +/* @(#)clnt_simple.c 2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)clnt_simple.c 1.35 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * clnt_simple.c + * Simplified front end to rpc. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <stdio.h> +#include <rpc/rpc.h> +#include <sys/socket.h> +#include <netdb.h> +#include <string.h> + +static struct callrpc_private { + CLIENT *client; + int socket; + int oldprognum, oldversnum, valid; + char *oldhost; +} *callrpc_private; + +callrpc(host, prognum, versnum, procnum, inproc, in, outproc, out) + char *host; + xdrproc_t inproc, outproc; + char *in, *out; +{ + register struct callrpc_private *crp = callrpc_private; + struct sockaddr_in server_addr; + enum clnt_stat clnt_stat; + struct hostent *hp; + struct timeval timeout, tottimeout; + + if (crp == 0) { + crp = (struct callrpc_private *)calloc(1, sizeof (*crp)); + if (crp == 0) + return (0); + callrpc_private = crp; + } + if (crp->oldhost == NULL) { + crp->oldhost = mem_alloc(256); + crp->oldhost[0] = 0; + crp->socket = RPC_ANYSOCK; + } + if (crp->valid && crp->oldprognum == prognum && crp->oldversnum == versnum + && strcmp(crp->oldhost, host) == 0) { + /* reuse old client */ + } else { + crp->valid = 0; + (void)close(crp->socket); + crp->socket = RPC_ANYSOCK; + if (crp->client) { + clnt_destroy(crp->client); + crp->client = NULL; + } + if ((hp = gethostbyname(host)) == NULL) + return ((int) RPC_UNKNOWNHOST); + timeout.tv_usec = 0; + timeout.tv_sec = 5; + memmove((char *)&server_addr.sin_addr, hp->h_addr, hp->h_length); + server_addr.sin_family = AF_INET; + server_addr.sin_port = 0; + if ((crp->client = clntudp_create(&server_addr, (rpc_u_int32)prognum, + (rpc_u_int32)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); + } + tottimeout.tv_sec = 25; + tottimeout.tv_usec = 0; + clnt_stat = clnt_call(crp->client, procnum, inproc, in, + outproc, out, tottimeout); + /* + * if call failed, empty cache + */ + if (clnt_stat != RPC_SUCCESS) + crp->valid = 0; + return ((int) clnt_stat); +} diff --git a/src/lib/rpc/clnt_tcp.c b/src/lib/rpc/clnt_tcp.c new file mode 100644 index 000000000..c573897f7 --- /dev/null +++ b/src/lib/rpc/clnt_tcp.c @@ -0,0 +1,476 @@ +/* @(#)clnt_tcp.c 2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 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 <stdio.h> +#include <rpc/rpc.h> +#include <sys/socket.h> +#include <netdb.h> +#include <errno.h> +#include <rpc/pmap_clnt.h> + +#define MCALL_MSG_SIZE 24 + +extern int errno; + +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 */ + unsigned 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; + rpc_u_int32 prog; + rpc_u_int32 vers; + register int *sockp; + unsigned int sendsz; + unsigned int recvsz; +{ + CLIENT *h; + register struct ct_data *ct; + struct timeval now; + struct rpc_msg call_msg; + + 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) { + unsigned 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; + (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 = 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 staic 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 + */ + mem_free((caddr_t)ct, sizeof(struct ct_data)); + 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; + rpc_u_int32 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; + rpc_u_int32 x_id; + rpc_u_int32 *msg_x_id = (rpc_u_int32 *)(ct->ct_mcall); /* yuk */ + register bool_t shipnow; + int refreshes = 2; + long procl = proc; + + 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, &procl)) || + (! AUTH_MARSHALL(h->cl_auth, xdrs)) || + (! AUTH_WRAP(h->cl_auth, xdrs, xdr_args, args_ptr))) { + if (ct->ct_error.re_status == RPC_SUCCESS) + ct->ct_error.re_status = RPC_CANTENCODEARGS; + (void)xdrrec_endofrecord(xdrs, TRUE); + 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 + */ + sunrpc_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 (! AUTH_UNWRAP(h->cl_auth, xdrs, + xdr_results, results_ptr)) { + if (ct->ct_error.re_status == RPC_SUCCESS) + ct->ct_error.re_status = RPC_CANTDECODERES; + } + } /* end successful completion */ + else { + /* maybe our credentials need to be refreshed ... */ + if (refreshes-- && AUTH_REFRESH(h->cl_auth, &reply_msg)) + goto call_again; + } /* end of unsuccessful completion */ + /* free verifier ... */ + if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) && + (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)); + } + 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; + int len; + + switch (request) { + case CLSET_TIMEOUT: + ct->ct_wait = *(struct timeval *)info; + ct->ct_waitset = TRUE; + break; + case CLGET_TIMEOUT: + *(struct timeval *)info = ct->ct_wait; + break; + case CLGET_SERVER_ADDR: + *(struct sockaddr_in *)info = ct->ct_addr; + break; + case CLGET_LOCAL_ADDR: + len = sizeof(struct sockaddr); + if (getsockname(ct->ct_sock, (struct sockaddr*)info, &len) < 0) + return FALSE; + else + return TRUE; + 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; +{ +#ifdef FD_SETSIZE + fd_set mask; + fd_set readfds; + + if (len == 0) + return (0); + FD_ZERO(&mask); + FD_SET(ct->ct_sock, &mask); +#else + register int mask = 1 << (ct->ct_sock); + int readfds; + + if (len == 0) + return (0); + +#endif /* def FD_SETSIZE */ + while (TRUE) { + readfds = mask; + switch (select(_rpc_dtablesize(), &readfds, (fd_set*)NULL, (fd_set*)NULL, + &(ct->ct_wait))) { + 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; + } + 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/src/lib/rpc/clnt_udp.c b/src/lib/rpc/clnt_udp.c new file mode 100644 index 000000000..000b9683d --- /dev/null +++ b/src/lib/rpc/clnt_udp.c @@ -0,0 +1,460 @@ +/* @(#)clnt_udp.c 2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)clnt_udp.c 1.39 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * clnt_udp.c, Implements a UDP/IP based, client side RPC. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <stdio.h> +#include <rpc/rpc.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#if defined(sparc) +#include <sys/filio.h> +#endif +#include <netdb.h> +#include <errno.h> +#include <rpc/pmap_clnt.h> + +extern int errno; + +/* + * 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; + unsigned int cu_xdrpos; + unsigned int cu_sendsz; + char *cu_outbuf; + unsigned 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; + rpc_u_int32 program; + rpc_u_int32 version; + struct timeval wait; + register int *sockp; + unsigned int sendsz; + unsigned int recvsz; +{ + CLIENT *cl; + register struct cu_data *cu; + struct timeval now; + struct rpc_msg call_msg; + + 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) { + unsigned 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 = 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 prov 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; + rpc_u_int32 program; + rpc_u_int32 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 */ + rpc_u_int32 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; +#ifdef FD_SETSIZE + fd_set readfds; + fd_set mask; +#else + int readfds; + register int mask; +#endif /* def FD_SETSIZE */ + struct sockaddr_in from; + 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; + long procl = proc; + + 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; +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 + */ + (*(unsigned short *)(cu->cu_outbuf))++; + if ((! XDR_PUTLONG(xdrs, &procl)) || + (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || + (! AUTH_WRAP(cl->cl_auth, xdrs, xargs, argsp))) + 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; + return (cu->cu_error.re_status = RPC_CANTSEND); + } + + /* + * Hack to provide rpc-based message passing + */ + if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { + 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 = NULL; + reply_msg.acpted_rply.ar_results.proc = xdr_void; +#ifdef FD_SETSIZE + FD_ZERO(&mask); + FD_SET(cu->cu_sock, &mask); +#else + mask = 1 << cu->cu_sock; +#endif /* def FD_SETSIZE */ + for (;;) { + readfds = mask; + switch (select(_rpc_dtablesize(), &readfds, (fd_set *)NULL, + (fd_set *)NULL, &(cu->cu_wait))) { + + case 0: + time_waited.tv_sec += cu->cu_wait.tv_sec; + time_waited.tv_usec += cu->cu_wait.tv_usec; + while (time_waited.tv_usec >= 1000000) { + time_waited.tv_sec++; + time_waited.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; + return (cu->cu_error.re_status = RPC_TIMEDOUT); + + /* + * buggy in other cases because time_waited is not being + * updated. + */ + case -1: + if (errno == EINTR) + continue; + cu->cu_error.re_errno = errno; + 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; + return (cu->cu_error.re_status = RPC_CANTRECV); + } + if (inlen < sizeof(rpc_u_int32)) + continue; + /* see if reply transaction id matches sent id */ + if (*((rpc_u_int32 *)(cu->cu_inbuf)) != *((rpc_u_int32 *)(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, (unsigned int)inlen, XDR_DECODE); + ok = xdr_replymsg(&reply_xdrs, &reply_msg); + /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */ + if (ok) { + sunrpc_seterr_reply(&reply_msg, &(cu->cu_error)); + if (cu->cu_error.re_status == RPC_SUCCESS) { + if (! AUTH_VALIDATE(cl->cl_auth, + &reply_msg.acpted_rply.ar_verf)) { + cu->cu_error.re_status = RPC_AUTHERROR; + cu->cu_error.re_why = AUTH_INVALIDRESP; + } else if (! AUTH_UNWRAP(cl->cl_auth, &reply_xdrs, + xresults, resultsp)) { + if (cu->cu_error.re_status == RPC_SUCCESS) + cu->cu_error.re_status = RPC_CANTDECODERES; + } + } /* end successful completion */ + else { + /* 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 */ + /* free verifier */ + if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) && + (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 of valid reply message */ + else { + cu->cu_error.re_status = RPC_CANTDECODERES; + } + 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; + int len; + + switch (request) { + case CLSET_TIMEOUT: + cu->cu_total = *(struct timeval *)info; + break; + case CLGET_TIMEOUT: + *(struct timeval *)info = cu->cu_total; + break; + case CLSET_RETRY_TIMEOUT: + cu->cu_wait = *(struct timeval *)info; + break; + case CLGET_RETRY_TIMEOUT: + *(struct timeval *)info = cu->cu_wait; + break; + case CLGET_SERVER_ADDR: + *(struct sockaddr_in *)info = cu->cu_raddr; + break; + case CLGET_LOCAL_ADDR: + len = sizeof(struct sockaddr); + if (getsockname(cu->cu_sock, (struct sockaddr*)info, &len) < 0) + return FALSE; + else + return TRUE; + 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/src/lib/rpc/configure.in b/src/lib/rpc/configure.in new file mode 100644 index 000000000..6084638d3 --- /dev/null +++ b/src/lib/rpc/configure.in @@ -0,0 +1,41 @@ +AC_INIT(auth_gssapi.c) +CONFIG_RULES +AC_PROG_ARCHIVE +AC_PROG_ARCHIVE_ADD +AC_PROG_RANLIB +AC_PROG_INSTALL + +AC_CHECK_SIZEOF(int) +SIZEOF_INT=$ac_cv_sizeof_int +AC_SUBST(SIZEOF_INT) +AC_CHECK_SIZEOF(long) +SIZEOF_LONG=$ac_cv_sizeof_long +AC_SUBST(SIZEOF_LONG) + +DECLARE_SYS_ERRLIST + +V5_SHARED_LIB_OBJS +V5_MAKE_SHARED_LIB(libgssrpc,1.0,.., ./rpc) +GSSAPI_KRB5_SH_VERS=$krb5_cv_shlib_version_libgssapi_krb5 +AC_SUBST(GSSAPI_KRB5_SH_VERS) +KRB5_SH_VERS=$krb5_cv_shlib_version_libkrb5 +AC_SUBST(KRB5_SH_VERS) +CRYPTO_SH_VERS=$krb5_cv_shlib_version_libcrypto +AC_SUBST(CRYPTO_SH_VERS) +COMERR_SH_VERS=$krb5_cv_shlib_version_libcom_err +AC_SUBST(COMERR_SH_VERS) +CopySrcHeader(auth.h,[$](BUILDTOP)/include/rpc) +CopySrcHeader(auth_gssapi.h,[$](BUILDTOP)/include/rpc) +CopySrcHeader(auth_unix.h,[$](BUILDTOP)/include/rpc) +CopySrcHeader(clnt.h,[$](BUILDTOP)/include/rpc) +CopySrcHeader(netdb.h,[$](BUILDTOP)/include/rpc) +CopySrcHeader(pmap_clnt.h,[$](BUILDTOP)/include/rpc) +CopySrcHeader(pmap_prot.h,[$](BUILDTOP)/include/rpc) +CopySrcHeader(pmap_rmt.h,[$](BUILDTOP)/include/rpc) +CopySrcHeader(rpc.h,[$](BUILDTOP)/include/rpc) +CopySrcHeader(rpc_msg.h,[$](BUILDTOP)/include/rpc) +CopySrcHeader(svc.h,[$](BUILDTOP)/include/rpc) +CopySrcHeader(svc_auth.h,[$](BUILDTOP)/include/rpc) +CopyHeader(types.h,[$](BUILDTOP)/include/rpc) +CopySrcHeader(xdr.h,[$](BUILDTOP)/include/rpc) +V5_AC_OUTPUT_MAKEFILE( ,types.h:types.hin) diff --git a/src/lib/rpc/get_myaddress.c b/src/lib/rpc/get_myaddress.c new file mode 100644 index 000000000..fa4c54e78 --- /dev/null +++ b/src/lib/rpc/get_myaddress.c @@ -0,0 +1,95 @@ +/* @(#)get_myaddress.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)get_myaddress.c 1.4 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * get_myaddress.c + * + * Get client's IP address via ioctl. This avoids using the yellowpages. + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <rpc/types.h> +#include <rpc/pmap_prot.h> +#include <sys/socket.h> +#if defined(sun) +#include <sys/sockio.h> +#endif +#include <stdio.h> +#ifdef OSF1 +#include <net/route.h> +#include <sys/mbuf.h> +#endif +#include <net/if.h> +#include <sys/ioctl.h> +#include <arpa/inet.h> +#include <netinet/in.h> + +/* + * don't use gethostbyname, which would invoke yellow pages + */ +get_myaddress(addr) + struct sockaddr_in *addr; +{ + int s; + char buf[BUFSIZ]; + struct ifconf ifc; + struct ifreq ifreq, *ifr; + int len; + + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + perror("get_myaddress: socket"); + exit(1); + } + ifc.ifc_len = sizeof (buf); + ifc.ifc_buf = buf; + if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) { + perror("get_myaddress: ioctl (get interface configuration)"); + exit(1); + } + ifr = ifc.ifc_req; + for (len = ifc.ifc_len; len; len -= sizeof ifreq) { + ifreq = *ifr; + if (ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) { + perror("get_myaddress: ioctl"); + exit(1); + } + if ((ifreq.ifr_flags & IFF_UP) && + ifr->ifr_addr.sa_family == AF_INET) { + *addr = *((struct sockaddr_in *)&ifr->ifr_addr); + addr->sin_port = htons(PMAPPORT); + break; + } + ifr++; + } + (void) close(s); +} diff --git a/src/lib/rpc/getrpcent.c b/src/lib/rpc/getrpcent.c new file mode 100644 index 000000000..e48d5b1e9 --- /dev/null +++ b/src/lib/rpc/getrpcent.c @@ -0,0 +1,256 @@ +/* @(#)getrpcent.c 2.2 88/07/29 4.0 RPCSRC */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)getrpcent.c 1.9 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * 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) 1985 by Sun Microsystems, Inc. + */ + +#include <stdio.h> +#include <sys/types.h> +#include <rpc/rpc.h> +#include <rpc/netdb.h> +#include <netdb.h> +#include <string.h> +#include <sys/socket.h> + +/* setrpcent is declared as int-returning in netdb.h on hpux */ +/* setrpcent is declared as int-returning in rpc/rpcent.h on Solaris */ +#if !defined(hpux) && !(defined(sun) && defined(__svr4__)) +#define SETRPCENT_TYPE void +#else +#define SETRPCENT_TYPE int +#endif + +/* endrpcent is declared as int-returning in netdb.h on hpux */ +#ifndef hpux +#define ENDRPCENT_TYPE void +#else +#define ENDRPCENT_TYPE int +#endif + +SETRPCENT_TYPE setrpcent(int); +ENDRPCENT_TYPE endrpcent(void); + +/* + * Internet version. + */ +struct rpcdata { + FILE *rpcf; + char *current; + int currentlen; + int stayopen; +#define MAXALIASES 35 + char *rpc_aliases[MAXALIASES]; + struct rpcent rpc; + char line[BUFSIZ+1]; + char *domain; +} *rpcdata; +static struct rpcdata *_rpcdata(); + +static struct rpcent *interpret(); +struct hostent *gethostent(); +char *inet_ntoa(); + +static char RPCDB[] = "/etc/rpc"; + +static struct rpcdata * +_rpcdata() +{ + register struct rpcdata *d = rpcdata; + + if (d == 0) { + d = (struct rpcdata *)calloc(1, sizeof (struct rpcdata)); + rpcdata = d; + } + return (d); +} + +struct rpcent * +getrpcbynumber(number) + register int number; +{ + register struct rpcdata *d = _rpcdata(); + register struct rpcent *p; + int reason; + char adrstr[16], *val = NULL; + int vallen; + + if (d == 0) + return (0); + setrpcent(0); + while (p = getrpcent()) { + if (p->r_number == number) + break; + } + endrpcent(); + return (p); +} + +struct rpcent * +getrpcbyname(name) + const char *name; +{ + struct rpcent *rpc; + char **rp; + + setrpcent(0); + while(rpc = getrpcent()) { + if (strcmp(rpc->r_name, name) == 0) + return (rpc); + for (rp = rpc->r_aliases; *rp != NULL; rp++) { + if (strcmp(*rp, name) == 0) + return (rpc); + } + } + endrpcent(); + return (NULL); +} + +SETRPCENT_TYPE setrpcent(f) + int f; +{ + register struct rpcdata *d = _rpcdata(); + + if (d == 0) + return; + if (d->rpcf == NULL) + d->rpcf = fopen(RPCDB, "r"); + else + rewind(d->rpcf); + if (d->current) + free(d->current); + d->current = NULL; + d->stayopen |= f; +} + +ENDRPCENT_TYPE endrpcent() +{ + register struct rpcdata *d = _rpcdata(); + + if (d == 0) + return; + if (d->current && !d->stayopen) { + free(d->current); + d->current = NULL; + } + if (d->rpcf && !d->stayopen) { + fclose(d->rpcf); + d->rpcf = NULL; + } +} + +struct rpcent * +getrpcent() +{ + struct rpcent *hp; + int reason; + char *key = NULL, *val = NULL; + int keylen, vallen; + register struct rpcdata *d = _rpcdata(); + + if (d == 0) + return(NULL); + if (d->rpcf == NULL && (d->rpcf = fopen(RPCDB, "r")) == NULL) + return (NULL); + if (fgets(d->line, BUFSIZ, d->rpcf) == NULL) + return (NULL); + return interpret(d->line, strlen(d->line)); +} + +static struct rpcent * +interpret(val, len) +char *val; +{ + register struct rpcdata *d = _rpcdata(); + char *p; + register char *cp, **q; + + if (d == 0) + return; + strncpy(d->line, val, len); + p = d->line; + d->line[len] = '\n'; + if (*p == '#') + return (getrpcent()); + cp = strchr(p, '#'); + if (cp == NULL) + { + cp = strchr(p, '\n'); + if (cp == NULL) + return (getrpcent()); + } + *cp = '\0'; + cp = strchr(p, ' '); + if (cp == NULL) + { + cp = strchr(p, '\t'); + if (cp == NULL) + return (getrpcent()); + } + *cp++ = '\0'; + /* THIS STUFF IS INTERNET SPECIFIC */ + d->rpc.r_name = d->line; + while (*cp == ' ' || *cp == '\t') + cp++; + d->rpc.r_number = atoi(cp); + q = d->rpc.r_aliases = d->rpc_aliases; + cp = strchr(p, ' '); + if (cp != NULL) + *cp++ = '\0'; + else + { + cp = strchr(p, '\t'); + if (cp != NULL) + *cp++ = '\0'; + } + while (cp && *cp) { + if (*cp == ' ' || *cp == '\t') { + cp++; + continue; + } + if (q < &(d->rpc_aliases[MAXALIASES - 1])) + *q++ = cp; + cp = strchr(p, ' '); + if (cp != NULL) + *cp++ = '\0'; + else + { + cp = strchr(p, '\t'); + if (cp != NULL) + *cp++ = '\0'; + } + } + *q = NULL; + return (&d->rpc); +} diff --git a/src/lib/rpc/getrpcport.c b/src/lib/rpc/getrpcport.c new file mode 100644 index 000000000..d209a1527 --- /dev/null +++ b/src/lib/rpc/getrpcport.c @@ -0,0 +1,55 @@ +/* @(#)getrpcport.c 2.1 88/07/29 4.0 RPCSRC */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)getrpcport.c 1.3 87/08/11 SMI"; +#endif +/* + * 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) 1985 by Sun Microsystems, Inc. + */ + +#include <stdio.h> +#include <rpc/rpc.h> +#include <netdb.h> +#include <sys/socket.h> + +getrpcport(host, prognum, versnum, proto) + char *host; +{ + struct sockaddr_in addr; + struct hostent *hp; + + if ((hp = gethostbyname(host)) == NULL) + return (0); + memmove((char *) &addr.sin_addr, hp->h_addr, hp->h_length); + addr.sin_family = AF_INET; + addr.sin_port = 0; + return (pmap_getport(&addr, prognum, versnum, proto)); +} diff --git a/src/lib/rpc/netdb.h b/src/lib/rpc/netdb.h new file mode 100644 index 000000000..f6b6374b5 --- /dev/null +++ b/src/lib/rpc/netdb.h @@ -0,0 +1,50 @@ +#ifndef RPC_NETDB_H +#define RPC_NETDB_H + +/* @(#)netdb.h 2.1 88/07/29 3.9 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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 + */ +/* @(#)rpc.h 1.8 87/07/24 SMI */ + +/* since the gssrpc library requires that any application using it be +built with these header files, I am making the decision that any app +which uses the rpcent routines must use this header file, or something +compatible (which most <netdb.h> are) --marc */ + +/* Really belongs in <netdb.h> */ + +struct rpcent { + char *r_name; /* name of server for this rpc program */ + char **r_aliases; /* alias list */ + int r_number; /* rpc program number */ +}; + +struct rpcent *getrpcbyname(), *getrpcbynumber(), *getrpcent(); + +#endif diff --git a/src/lib/rpc/pmap_clnt.c b/src/lib/rpc/pmap_clnt.c new file mode 100644 index 000000000..7218777cc --- /dev/null +++ b/src/lib/rpc/pmap_clnt.c @@ -0,0 +1,115 @@ +/* @(#)pmap_clnt.c 2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)pmap_clnt.c 1.37 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * pmap_clnt.c + * Client interface to pmap rpc service. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <rpc/rpc.h> +#include <rpc/pmap_prot.h> +#include <rpc/pmap_clnt.h> + +static struct timeval timeout = { 5, 0 }; +static struct timeval tottimeout = { 60, 0 }; + +void clnt_perror(); + + +/* + * 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) + rpc_u_int32 program; + rpc_u_int32 version; + int protocol; + unsigned short port; +{ + struct sockaddr_in myaddress; + int socket = -1; + register CLIENT *client; + struct pmap parms; + bool_t rslt; + + get_myaddress(&myaddress); + 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_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"); + return (FALSE); + } + CLNT_DESTROY(client); + (void)close(socket); + return (rslt); +} + +/* + * Remove the mapping between program,version and port. + * Calls the pmap service remotely to do the un-mapping. + */ +bool_t +pmap_unset(program, version) + rpc_u_int32 program; + rpc_u_int32 version; +{ + struct sockaddr_in myaddress; + int socket = -1; + register CLIENT *client; + struct pmap parms; + bool_t rslt; + + get_myaddress(&myaddress); + 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); + (void)close(socket); + return (rslt); +} diff --git a/src/lib/rpc/pmap_clnt.h b/src/lib/rpc/pmap_clnt.h new file mode 100644 index 000000000..dfb00dcc5 --- /dev/null +++ b/src/lib/rpc/pmap_clnt.h @@ -0,0 +1,65 @@ +/* @(#)pmap_clnt.h 2.1 88/07/29 4.0 RPCSRC; from 1.11 88/02/08 SMI */ +/* + * 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 + */ + +/* + * pmap_clnt.h + * Supplies C routines to get to portmap services. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +/* + * Usage: + * success = pmap_set(program, version, protocol, port); + * success = pmap_unset(program, version); + * port = pmap_getport(address, program, version, protocol); + * head = pmap_getmaps(address); + * clnt_stat = pmap_rmtcall(address, program, version, procedure, + * xdrargs, argsp, xdrres, resp, tout, port_ptr) + * (works for udp only.) + * clnt_stat = clnt_broadcast(program, version, procedure, + * xdrargs, argsp, xdrres, resp, eachresult) + * (like pmap_rmtcall, except the call is broadcasted to all + * locally connected nets. For each valid response received, + * the procedure eachresult is called. Its form is: + * done = eachresult(resp, raddr) + * bool_t done; + * caddr_t resp; + * struct sockaddr_in raddr; + * where resp points to the results of the call and raddr is the + * address if the responder to the broadcast. + */ + +extern bool_t pmap_set(); +extern bool_t pmap_unset(); +extern struct pmaplist *pmap_getmaps(); +enum clnt_stat pmap_rmtcall(); +enum clnt_stat clnt_broadcast(); +extern unsigned short pmap_getport(); diff --git a/src/lib/rpc/pmap_getmaps.c b/src/lib/rpc/pmap_getmaps.c new file mode 100644 index 000000000..472b2a46d --- /dev/null +++ b/src/lib/rpc/pmap_getmaps.c @@ -0,0 +1,88 @@ +/* @(#)pmap_getmaps.c 2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)pmap_getmaps.c 1.10 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * pmap_getmap.c + * Client interface to pmap rpc service. + * contains pmap_getmaps, which is only tcp service involved + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <rpc/rpc.h> +#include <rpc/pmap_prot.h> +#include <rpc/pmap_clnt.h> +#include <sys/socket.h> +#include <netdb.h> +#include <stdio.h> +#include <errno.h> +#ifdef OSF1 +#include <net/route.h> +#include <sys/mbuf.h> +#endif +#include <net/if.h> +#include <sys/ioctl.h> +#define NAMELEN 255 +#define MAX_BROADCAST_SIZE 1400 + +extern int errno; + +/* + * Get a copy of the current port maps. + * Calls the pmap service remotely to do get the maps. + */ +struct pmaplist * +pmap_getmaps(address) + struct sockaddr_in *address; +{ + struct pmaplist *head = (struct pmaplist *)NULL; + int socket = -1; + struct timeval minutetimeout; + register CLIENT *client; + + 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) { + clnt_perror(client, "pmap_getmaps rpc problem"); + } + CLNT_DESTROY(client); + } + (void)close(socket); + address->sin_port = 0; + return (head); +} diff --git a/src/lib/rpc/pmap_getport.c b/src/lib/rpc/pmap_getport.c new file mode 100644 index 000000000..40b764880 --- /dev/null +++ b/src/lib/rpc/pmap_getport.c @@ -0,0 +1,91 @@ +/* @(#)pmap_getport.c 2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)pmap_getport.c 1.9 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * pmap_getport.c + * Client interface to pmap rpc service. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <rpc/rpc.h> +#include <rpc/pmap_prot.h> +#include <rpc/pmap_clnt.h> +#include <sys/socket.h> +#ifdef OSF1 +#include <net/route.h> +#include <sys/mbuf.h> +#endif +#include <net/if.h> + +static struct timeval timeout = { 5, 0 }; +static struct timeval tottimeout = { 60, 0 }; + +/* + * Find the mapped port for program,version. + * Calls the pmap service remotely to do the lookup. + * Returns 0 if no map exists. + */ +unsigned short +pmap_getport(address, program, version, protocol) + struct sockaddr_in *address; + rpc_u_int32 program; + rpc_u_int32 version; + unsigned int protocol; +{ + unsigned short port = 0; + int socket = -1; + register CLIENT *client; + struct pmap parms; + + address->sin_port = htons(PMAPPORT); + client = clntudp_bufcreate(address, PMAPPROG, + PMAPVERS, timeout, &socket, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE); + if (client != (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){ + rpc_createerr.cf_stat = RPC_PMAPFAILURE; + clnt_geterr(client, &rpc_createerr.cf_error); + } else if (port == 0) { + rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; + } + CLNT_DESTROY(client); + } + (void)close(socket); + address->sin_port = 0; + return (port); +} diff --git a/src/lib/rpc/pmap_prot.c b/src/lib/rpc/pmap_prot.c new file mode 100644 index 000000000..1dffffe17 --- /dev/null +++ b/src/lib/rpc/pmap_prot.c @@ -0,0 +1,57 @@ +/* @(#)pmap_prot.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)pmap_prot.c 1.17 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * pmap_prot.c + * Protocol for the local binder service, or pmap. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <rpc/pmap_prot.h> + + +bool_t +xdr_pmap(xdrs, regs) + XDR *xdrs; + struct pmap *regs; +{ + + if (xdr_u_int32(xdrs, ®s->pm_prog) && + xdr_u_int32(xdrs, ®s->pm_vers) && + xdr_u_int32(xdrs, ®s->pm_prot)) + return (xdr_u_int32(xdrs, ®s->pm_port)); + return (FALSE); +} diff --git a/src/lib/rpc/pmap_prot.h b/src/lib/rpc/pmap_prot.h new file mode 100644 index 000000000..4f76580f4 --- /dev/null +++ b/src/lib/rpc/pmap_prot.h @@ -0,0 +1,94 @@ +/* @(#)pmap_prot.h 2.1 88/07/29 4.0 RPCSRC; from 1.14 88/02/08 SMI */ +/* + * 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 + */ + +/* + * pmap_prot.h + * Protocol for the local binder service, or pmap. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * The following procedures are supported by the protocol: + * + * PMAPPROC_NULL() returns () + * takes nothing, returns nothing + * + * PMAPPROC_SET(struct pmap) returns (bool_t) + * TRUE is success, FALSE is failure. Registers the tuple + * [prog, vers, prot, port]. + * + * PMAPPROC_UNSET(struct pmap) returns (bool_t) + * TRUE is success, FALSE is failure. Un-registers pair + * [prog, vers]. prot and port are ignored. + * + * PMAPPROC_GETPORT(struct pmap) returns (rpc_int32 unsigned). + * 0 is failure. Otherwise returns the port number where the pair + * [prog, vers] is registered. It may lie! + * + * PMAPPROC_DUMP() RETURNS (struct pmaplist *) + * + * PMAPPROC_CALLIT(unsigned, unsigned, unsigned, string<>) + * RETURNS (port, string<>); + * usage: encapsulatedresults = PMAPPROC_CALLIT(prog, vers, proc, encapsulatedargs); + * Calls the procedure on the local machine. If it is not registered, + * this procedure is quite; ie it does not return error information!!! + * This procedure only is supported on rpc/udp and calls via + * rpc/udp. This routine only passes null authentication parameters. + * This file has no interface to xdr routines for PMAPPROC_CALLIT. + * + * The service supports remote procedure calls on udp/ip or tcp/ip socket 111. + */ + +#define PMAPPORT ((unsigned short)111) +#define PMAPPROG ((rpc_u_int32)100000) +#define PMAPVERS ((rpc_u_int32)2) +#define PMAPVERS_PROTO ((rpc_u_int32)2) +#define PMAPVERS_ORIG ((rpc_u_int32)1) +#define PMAPPROC_NULL ((rpc_u_int32)0) +#define PMAPPROC_SET ((rpc_u_int32)1) +#define PMAPPROC_UNSET ((rpc_u_int32)2) +#define PMAPPROC_GETPORT ((rpc_u_int32)3) +#define PMAPPROC_DUMP ((rpc_u_int32)4) +#define PMAPPROC_CALLIT ((rpc_u_int32)5) + +struct pmap { + rpc_u_int32 pm_prog; + rpc_u_int32 pm_vers; + rpc_u_int32 pm_prot; + rpc_u_int32 pm_port; +}; + +extern bool_t xdr_pmap(); + +struct pmaplist { + struct pmap pml_map; + struct pmaplist *pml_next; +}; + +extern bool_t xdr_pmaplist(); diff --git a/src/lib/rpc/pmap_prot2.c b/src/lib/rpc/pmap_prot2.c new file mode 100644 index 000000000..5f48f2a28 --- /dev/null +++ b/src/lib/rpc/pmap_prot2.c @@ -0,0 +1,116 @@ +/* @(#)pmap_prot2.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)pmap_prot2.c 1.3 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * pmap_prot2.c + * Protocol for the local binder service, or pmap. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <rpc/pmap_prot.h> + + +/* + * What is going on with linked lists? (!) + * First recall the link list declaration from pmap_prot.h: + * + * struct pmaplist { + * struct pmap pml_map; + * struct pmaplist *pml_map; + * }; + * + * Compare that declaration with a corresponding xdr declaration that + * is (a) pointer-less, and (b) recursive: + * + * typedef union switch (bool_t) { + * + * case TRUE: struct { + * struct pmap; + * pmaplist_t foo; + * }; + * + * case FALSE: struct {}; + * } pmaplist_t; + * + * Notice that the xdr declaration has no nxt pointer while + * the C declaration has no bool_t variable. The bool_t can be + * interpreted as ``more data follows me''; if FALSE then nothing + * follows this bool_t; if TRUE then the bool_t is followed by + * an actual struct pmap, and then (recursively) by the + * xdr union, pamplist_t. + * + * This could be implemented via the xdr_union primitive, though this + * would cause a one recursive call per element in the list. Rather than do + * that we can ``unwind'' the recursion + * into a while loop and do the union arms in-place. + * + * The head of the list is what the C programmer wishes to past around + * the net, yet is the data that the pointer points to which is interesting; + * this sounds like a job for xdr_reference! + */ +bool_t +xdr_pmaplist(xdrs, rp) + register XDR *xdrs; + register struct pmaplist **rp; +{ + /* + * more_elements is pre-computed in case the direction is + * XDR_ENCODE or XDR_FREE. more_elements is overwritten by + * xdr_bool when the direction is XDR_DECODE. + */ + bool_t more_elements; + register int freeing = (xdrs->x_op == XDR_FREE); + register struct pmaplist **next; + + while (TRUE) { + more_elements = (bool_t)(*rp != NULL); + if (! xdr_bool(xdrs, &more_elements)) + return (FALSE); + if (! more_elements) + return (TRUE); /* we are done */ + /* + * the unfortunate side effect of non-recursion is that in + * the case of freeing we must remember the next object + * before we free the current object ... + */ + if (freeing) + next = &((*rp)->pml_next); + if (! xdr_reference(xdrs, (caddr_t *)rp, + (unsigned int)sizeof(struct pmaplist), xdr_pmap)) + return (FALSE); + rp = (freeing) ? next : &((*rp)->pml_next); + } +} diff --git a/src/lib/rpc/pmap_rmt.c b/src/lib/rpc/pmap_rmt.c new file mode 100644 index 000000000..6a2376763 --- /dev/null +++ b/src/lib/rpc/pmap_rmt.c @@ -0,0 +1,403 @@ +/* @(#)pmap_rmt.c 2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)pmap_rmt.c 1.21 87/08/27 Copyr 1984 Sun Micro"; +#endif + +/* + * pmap_rmt.c + * Client interface to pmap rpc service. + * remote call and broadcast service + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <rpc/rpc.h> +#include <rpc/pmap_prot.h> +#include <rpc/pmap_clnt.h> +#include <rpc/pmap_rmt.h> +#include <sys/socket.h> +#ifdef sparc +#include <sys/sockio.h> +#endif +#include <stdio.h> +#include <errno.h> +#ifdef OSF1 +#include <net/route.h> +#include <sys/mbuf.h> +#endif +#include <net/if.h> +#include <sys/ioctl.h> +#include <arpa/inet.h> +#define MAX_BROADCAST_SIZE 1400 + +extern int errno; +static struct timeval timeout = { 3, 0 }; + + +/* + * pmapper remote-call-service interface. + * This routine is used to call the pmapper remote call service + * which will look up a service program in the port maps, and then + * remotely call that routine with the given parameters. This allows + * programs to do a lookup and call in one step. +*/ +enum clnt_stat +pmap_rmtcall(addr, prog, vers, proc, xdrargs, argsp, xdrres, resp, tout, port_ptr) + struct sockaddr_in *addr; + rpc_u_int32 prog, vers, proc; + xdrproc_t xdrargs, xdrres; + caddr_t argsp, resp; + struct timeval tout; + rpc_u_int32 *port_ptr; +{ + int socket = -1; + register CLIENT *client; + struct rmtcallargs a; + struct rmtcallres r; + enum clnt_stat stat; + + addr->sin_port = htons(PMAPPORT); + client = clntudp_create(addr, PMAPPROG, PMAPVERS, timeout, &socket); + if (client != (CLIENT *)NULL) { + a.prog = prog; + a.vers = vers; + a.proc = proc; + a.args_ptr = argsp; + a.xdr_args = xdrargs; + r.port_ptr = port_ptr; + r.results_ptr = resp; + r.xdr_results = xdrres; + stat = CLNT_CALL(client, PMAPPROC_CALLIT, xdr_rmtcall_args, &a, + xdr_rmtcallres, &r, tout); + CLNT_DESTROY(client); + } else { + stat = RPC_FAILED; + } + (void)close(socket); + addr->sin_port = 0; + return (stat); +} + + +/* + * XDR remote call arguments + * written for XDR_ENCODE direction only + */ +bool_t +xdr_rmtcall_args(xdrs, cap) + register XDR *xdrs; + register struct rmtcallargs *cap; +{ + unsigned int lenposition, argposition, position; + + if (xdr_u_int32(xdrs, &(cap->prog)) && + xdr_u_int32(xdrs, &(cap->vers)) && + xdr_u_int32(xdrs, &(cap->proc))) { + lenposition = XDR_GETPOS(xdrs); + if (! xdr_u_int32(xdrs, &(cap->arglen))) + return (FALSE); + argposition = XDR_GETPOS(xdrs); + if (! (*(cap->xdr_args))(xdrs, cap->args_ptr)) + return (FALSE); + position = XDR_GETPOS(xdrs); + cap->arglen = (rpc_u_int32)position - (rpc_u_int32)argposition; + XDR_SETPOS(xdrs, lenposition); + if (! xdr_u_int32(xdrs, &(cap->arglen))) + return (FALSE); + XDR_SETPOS(xdrs, position); + return (TRUE); + } + return (FALSE); +} + +/* + * XDR remote call results + * written for XDR_DECODE direction only + */ +bool_t +xdr_rmtcallres(xdrs, crp) + register XDR *xdrs; + register struct rmtcallres *crp; +{ + caddr_t port_ptr; + + port_ptr = (caddr_t)crp->port_ptr; + if (xdr_reference(xdrs, &port_ptr, sizeof (rpc_u_int32), + xdr_u_int32) && xdr_u_int32(xdrs, &crp->resultslen)) { + crp->port_ptr = (rpc_u_int32 *)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; + int n, i; + + ifc.ifc_len = UDPMSGSIZE; + ifc.ifc_buf = buf; + if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) { + perror("broadcast: ioctl (get interface configuration)"); + return (0); + } + ifr = ifc.ifc_req; + for (i = 0, n = ifc.ifc_len/sizeof (struct ifreq); n > 0; n--, ifr++) { + ifreq = *ifr; + 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) && + ifr->ifr_addr.sa_family == AF_INET) { + sin = (struct sockaddr_in *)&ifr->ifr_addr; +#ifdef SIOCGIFBRDADDR /* 4.3BSD */ + if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { + addrs[i++].s_addr = INADDR_ANY; +#if 0 /* this is uuuuugly */ + addrs[i++] = inet_makeaddr(inet_netof +#if defined(hpux) || (defined(sparc) && defined(__svr4__)) || defined(linux) || (defined(__osf__) && defined(__alpha__)) + (sin->sin_addr), INADDR_ANY); +#else /* hpux or solaris */ + (sin->sin_addr.s_addr), INADDR_ANY); +#endif +#endif + } else { + addrs[i++] = ((struct sockaddr_in*) + &ifreq.ifr_addr)->sin_addr; + } +#else /* 4.2 BSD */ + addrs[i++] = inet_makeaddr(inet_netof + (sin->sin_addr.s_addr), INADDR_ANY); +#endif + } + } + return (i); +} + +typedef bool_t (*resultproc_t)(); + +enum clnt_stat +clnt_broadcast(prog, vers, proc, xargs, argsp, xresults, resultsp, eachresult) + rpc_u_int32 prog; /* program number */ + rpc_u_int32 vers; /* version number */ + rpc_u_int32 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; +#ifdef FD_SETSIZE + fd_set mask; + fd_set readfds; +#else + int readfds; + register int mask; +#endif /* def FD_SETSIZE */ + register int i; + bool_t done = FALSE; + register rpc_u_int32 xid; + rpc_u_int32 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; + char outbuf[MAX_BROADCAST_SIZE], inbuf[UDPMSGSIZE]; + + /* + * 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, (char *) &on, + sizeof (on)) < 0) { + perror("Cannot set socket option SO_BROADCAST"); + stat = RPC_CANTSEND; + goto done_broad; + } +#endif /* def SO_BROADCAST */ +#ifdef FD_SETSIZE + FD_ZERO(&mask); + FD_SET(sock, &mask); +#else + mask = (1 << sock); +#endif /* def FD_SETSIZE */ + nets = getbroadcastnets(addrs, sock, inbuf); + bzero((char *)&baddr, sizeof (baddr)); + baddr.sin_family = AF_INET; + baddr.sin_port = htons(PMAPPORT); + baddr.sin_addr.s_addr = htonl(INADDR_ANY); +/* baddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); */ + (void)gettimeofday(&t, (struct timezone *)0); + msg.rm_xid = xid = 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. + */ + 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; + readfds = mask; + switch (select(_rpc_dtablesize(), &readfds, (fd_set *)NULL, + (fd_set *)NULL, &t)) { + + 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(rpc_u_int32)) + goto recv_again; + /* + * see if reply transaction id matches sent id. + * If so, decode the results. + */ + xdrmem_create(xdrs, inbuf, (unsigned 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((unsigned short)port); + done = (*eachresult)(resultsp, &raddr); + } + /* otherwise, we just ignore the errors ... */ + } else { +#ifdef notdef + /* some kind of deserialization problem ... */ + if (msg.rm_xid == xid) + fprintf(stderr, "Broadcast deserialization problem"); + /* otherwise, just random garbage */ +#endif + } + 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: + (void)close(sock); + AUTH_DESTROY(unix_auth); + return (stat); +} + diff --git a/src/lib/rpc/pmap_rmt.h b/src/lib/rpc/pmap_rmt.h new file mode 100644 index 000000000..2ea22120e --- /dev/null +++ b/src/lib/rpc/pmap_rmt.h @@ -0,0 +1,53 @@ +/* @(#)pmap_rmt.h 2.1 88/07/29 4.0 RPCSRC; from 1.2 88/02/08 SMI */ +/* + * 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 + */ + +/* + * Structures and XDR routines for parameters to and replies from + * the portmapper remote-call-service. + * + * Copyright (C) 1986, Sun Microsystems, Inc. + */ + +struct rmtcallargs { + rpc_u_int32 prog, vers, proc, arglen; + caddr_t args_ptr; + xdrproc_t xdr_args; +}; + +bool_t xdr_rmtcall_args(); + +struct rmtcallres { + rpc_u_int32 *port_ptr; + rpc_u_int32 resultslen; + caddr_t results_ptr; + xdrproc_t xdr_results; +}; + +bool_t xdr_rmtcallres(); diff --git a/src/lib/rpc/rpc.h b/src/lib/rpc/rpc.h new file mode 100644 index 000000000..d0280aaa0 --- /dev/null +++ b/src/lib/rpc/rpc.h @@ -0,0 +1,74 @@ +/* @(#)rpc.h 2.3 88/08/10 4.0 RPCSRC; from 1.9 88/02/08 SMI */ +/* + * 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 + */ + +/* + * rpc.h, Just includes the billions of rpc header files necessary to + * do remote procedure calling. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ +#ifndef __RPC_HEADER__ +#define __RPC_HEADER__ + +#include <rpc/types.h> /* some typedefs */ +#include <netinet/in.h> + +/* external data representation interfaces */ +#include <rpc/xdr.h> /* generic (de)serializer */ + +/* Client side only authentication */ +#include <rpc/auth.h> /* generic authenticator (client side) */ + +/* Client side (mostly) remote procedure call */ +#include <rpc/clnt.h> /* generic rpc stuff */ + +/* semi-private protocol headers */ +#include <rpc/rpc_msg.h> /* protocol for rpc messages */ +#include <rpc/auth_unix.h> /* protocol for unix style cred */ +/* + * Uncomment-out the next line if you are building the rpc library with + * DES Authentication (see the README file in the secure_rpc/ directory). + */ +/*#include <rpc/auth_des.h> protocol for des style cred */ + +/* Server side only remote procedure callee */ +#include <rpc/svc_auth.h> /* service side authenticator */ +#include <rpc/svc.h> /* service manager and multiplexer */ + +/* + * COMMENT OUT THE NEXT INCLUDE IF RUNNING ON SUN OS OR ON A VERSION + * OF UNIX BASED ON NFSSRC. These systems will already have the structures + * defined by <rpc/netdb.h> included in <netdb.h>. + */ +/* routines for parsing /etc/rpc */ +#include <netdb.h> +#include <rpc/netdb.h> /* structures and routines to parse /etc/rpc */ + +#endif /* ndef __RPC_HEADER__ */ diff --git a/src/lib/rpc/rpc_callmsg.c b/src/lib/rpc/rpc_callmsg.c new file mode 100644 index 000000000..370e79ff9 --- /dev/null +++ b/src/lib/rpc/rpc_callmsg.c @@ -0,0 +1,195 @@ +/* @(#)rpc_callmsg.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)rpc_callmsg.c 1.4 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * rpc_callmsg.c + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + */ + +#include <sys/param.h> + +#include <rpc/rpc.h> + +/* + * XDR a call message + */ +bool_t +xdr_callmsg(xdrs, cmsg) + register XDR *xdrs; + register struct rpc_msg *cmsg; +{ + register rpc_int32 *buf; + register struct opaque_auth *oa; + + if (xdrs->x_op == XDR_ENCODE) { + if (cmsg->rm_call.cb_cred.oa_length > MAX_AUTH_BYTES) { + return (FALSE); + } + if (cmsg->rm_call.cb_verf.oa_length > MAX_AUTH_BYTES) { + return (FALSE); + } + buf = (rpc_int32 *) XDR_INLINE(xdrs, 8 * BYTES_PER_XDR_UNIT + + RNDUP(cmsg->rm_call.cb_cred.oa_length) + + 2 * BYTES_PER_XDR_UNIT + + RNDUP(cmsg->rm_call.cb_verf.oa_length)); + if (buf != NULL) { + IXDR_PUT_LONG(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); + 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); + oa = &cmsg->rm_call.cb_cred; + IXDR_PUT_ENUM(buf, oa->oa_flavor); + IXDR_PUT_LONG(buf, oa->oa_length); + if (oa->oa_length) { + memmove((caddr_t)buf, oa->oa_base, + oa->oa_length); + buf += RNDUP(oa->oa_length) / sizeof (rpc_int32); + } + oa = &cmsg->rm_call.cb_verf; + IXDR_PUT_ENUM(buf, oa->oa_flavor); + IXDR_PUT_LONG(buf, oa->oa_length); + if (oa->oa_length) { + memmove((caddr_t)buf, oa->oa_base, + oa->oa_length); + /* no real need.... + buf += RNDUP(oa->oa_length) / sizeof (rpc_int32); + */ + } + return (TRUE); + } + } + if (xdrs->x_op == XDR_DECODE) { + buf = (rpc_int32 *) XDR_INLINE(xdrs, 8 * BYTES_PER_XDR_UNIT); + if (buf != NULL) { + cmsg->rm_xid = IXDR_GET_LONG(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); + 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); + oa = &cmsg->rm_call.cb_cred; + oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t); + oa->oa_length = IXDR_GET_LONG(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); + } + buf = (rpc_int32 *) + XDR_INLINE(xdrs, RNDUP(oa->oa_length)); + if (buf == NULL) { + if (xdr_opaque(xdrs, oa->oa_base, + oa->oa_length) == FALSE) { + return (FALSE); + } + } else { + memmove(oa->oa_base, (caddr_t)buf, + oa->oa_length); + /* no real need.... + buf += RNDUP(oa->oa_length) / + sizeof (rpc_int32); + */ + } + } + oa = &cmsg->rm_call.cb_verf; + buf = (rpc_int32 *) + XDR_INLINE(xdrs, 2 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (xdr_enum(xdrs, &oa->oa_flavor) == FALSE || + xdr_u_int(xdrs, &oa->oa_length) == FALSE) { + return (FALSE); + } + } else { + oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t); + oa->oa_length = IXDR_GET_LONG(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); + } + buf = (rpc_int32 *) + XDR_INLINE(xdrs, RNDUP(oa->oa_length)); + if (buf == NULL) { + if (xdr_opaque(xdrs, oa->oa_base, + oa->oa_length) == FALSE) { + return (FALSE); + } + } else { + memmove(oa->oa_base, (caddr_t) buf, + oa->oa_length); + /* no real need... + buf += RNDUP(oa->oa_length) / + sizeof (rpc_int32); + */ + } + } + return (TRUE); + } + } + if ( + xdr_u_int32(xdrs, &(cmsg->rm_xid)) && + xdr_enum(xdrs, (enum_t *)&(cmsg->rm_direction)) && + (cmsg->rm_direction == CALL) && + xdr_u_int32(xdrs, &(cmsg->rm_call.cb_rpcvers)) && + (cmsg->rm_call.cb_rpcvers == RPC_MSG_VERSION) && + xdr_u_int32(xdrs, &(cmsg->rm_call.cb_prog)) && + xdr_u_int32(xdrs, &(cmsg->rm_call.cb_vers)) && + xdr_u_int32(xdrs, &(cmsg->rm_call.cb_proc)) && + xdr_opaque_auth(xdrs, &(cmsg->rm_call.cb_cred)) ) + return (xdr_opaque_auth(xdrs, &(cmsg->rm_call.cb_verf))); + return (FALSE); +} + diff --git a/src/lib/rpc/rpc_commondata.c b/src/lib/rpc/rpc_commondata.c new file mode 100644 index 000000000..75cead087 --- /dev/null +++ b/src/lib/rpc/rpc_commondata.c @@ -0,0 +1,41 @@ +/* @(#)rpc_commondata.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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 <rpc/rpc.h> +/* + * This file should only contain common data (global data) that is exported + * by public interfaces + */ +struct opaque_auth _null_auth; +#ifdef FD_SETSIZE +fd_set svc_fdset; +#else +int svc_fds; +#endif /* def FD_SETSIZE */ +struct rpc_createerr rpc_createerr; diff --git a/src/lib/rpc/rpc_dtablesize.c b/src/lib/rpc/rpc_dtablesize.c new file mode 100644 index 000000000..d252d6acd --- /dev/null +++ b/src/lib/rpc/rpc_dtablesize.c @@ -0,0 +1,60 @@ +/* @(#)rpc_dtablesize.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)rpc_dtablesize.c 1.2 87/08/11 Copyr 1987 Sun Micro"; +#endif + +#include <unistd.h> + +/* + * Cache the result of getdtablesize(), so we don't have to do an + * expensive system call every time. + */ +_rpc_dtablesize() +{ + static int size; + + if (size == 0) { +#ifdef _SC_OPEN_MAX + size = (int) sysconf(_SC_OPEN_MAX); +#else + size = getdtablesize(); +#endif + +/* sysconf() can return a number larger than what will fit in an + fd_set. we can't use fd's larger than this, anyway. */ + +#ifdef FD_SETSIZE + if (size >= FD_SETSIZE) + size = FD_SETSIZE-1; +#endif + } + return (size); +} diff --git a/src/lib/rpc/rpc_msg.h b/src/lib/rpc/rpc_msg.h new file mode 100644 index 000000000..66b10c5fb --- /dev/null +++ b/src/lib/rpc/rpc_msg.h @@ -0,0 +1,187 @@ +/* @(#)rpc_msg.h 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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 + */ +/* @(#)rpc_msg.h 1.7 86/07/16 SMI */ + +/* + * rpc_msg.h + * rpc message definition + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#define RPC_MSG_VERSION ((rpc_u_int32) 2) +#define RPC_SERVICE_PORT ((unsigned short) 2048) + +/* + * Bottom up definition of an rpc message. + * NOTE: call and reply use the same overall stuct but + * different parts of unions within it. + */ + +enum msg_type { + CALL=0, + REPLY=1 +}; + +enum reply_stat { + MSG_ACCEPTED=0, + MSG_DENIED=1 +}; + +enum accept_stat { + SUCCESS=0, + PROG_UNAVAIL=1, + PROG_MISMATCH=2, + PROC_UNAVAIL=3, + GARBAGE_ARGS=4, + SYSTEM_ERR=5 +}; + +enum reject_stat { + RPC_MISMATCH=0, + AUTH_ERROR=1 +}; + +/* + * Reply part of an rpc exchange + */ + +/* + * Reply to an rpc request that was accepted by the server. + * Note: there could be an error even though the request was + * accepted. + */ +struct accepted_reply { + struct opaque_auth ar_verf; + enum accept_stat ar_stat; + union { + struct { + rpc_u_int32 low; + rpc_u_int32 high; + } AR_versions; + struct { + caddr_t where; + xdrproc_t proc; + } AR_results; + /* and many other null cases */ + } ru; +#define ar_results ru.AR_results +#define ar_vers ru.AR_versions +}; + +/* + * Reply to an rpc request that was rejected by the server. + */ +struct rejected_reply { + enum reject_stat rj_stat; + union { + struct { + rpc_u_int32 low; + rpc_u_int32 high; + } RJ_versions; + enum auth_stat RJ_why; /* why authentication did not work */ + } ru; +#define rj_vers ru.RJ_versions +#define rj_why ru.RJ_why +}; + +/* + * Body of a reply to an rpc request. + */ +struct reply_body { + enum reply_stat rp_stat; + union { + struct accepted_reply RP_ar; + struct rejected_reply RP_dr; + } ru; +#define rp_acpt ru.RP_ar +#define rp_rjct ru.RP_dr +}; + +/* + * Body of an rpc request call. + */ +struct call_body { + rpc_u_int32 cb_rpcvers; /* must be equal to two */ + rpc_u_int32 cb_prog; + rpc_u_int32 cb_vers; + rpc_u_int32 cb_proc; + struct opaque_auth cb_cred; + struct opaque_auth cb_verf; /* protocol specific - provided by client */ +}; + +/* + * The rpc message + */ +struct rpc_msg { + rpc_u_int32 rm_xid; + enum msg_type rm_direction; + union { + struct call_body RM_cmb; + struct reply_body RM_rmb; + } ru; +#define rm_call ru.RM_cmb +#define rm_reply ru.RM_rmb +}; +#define acpted_rply ru.RM_rmb.ru.RP_ar +#define rjcted_rply ru.RM_rmb.ru.RP_dr + + +/* + * XDR routine to handle a rpc message. + * xdr_callmsg(xdrs, cmsg) + * XDR *xdrs; + * struct rpc_msg *cmsg; + */ +extern bool_t xdr_callmsg(); + +/* + * XDR routine to pre-serialize the static part of a rpc message. + * xdr_callhdr(xdrs, cmsg) + * XDR *xdrs; + * struct rpc_msg *cmsg; + */ +extern bool_t xdr_callhdr(); + +/* + * XDR routine to handle a rpc reply. + * xdr_replymsg(xdrs, rmsg) + * XDR *xdrs; + * struct rpc_msg *rmsg; + */ +extern bool_t xdr_replymsg(); + +/* + * Fills in the error part of a reply message. + * _seterr_reply(msg, error) + * struct rpc_msg *msg; + * struct rpc_err *error; + */ +extern void _seterr_reply(); diff --git a/src/lib/rpc/rpc_prot.c b/src/lib/rpc/rpc_prot.c new file mode 100644 index 000000000..6fea605e6 --- /dev/null +++ b/src/lib/rpc/rpc_prot.c @@ -0,0 +1,287 @@ +/* @(#)rpc_prot.c 2.3 88/08/07 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)rpc_prot.c 1.36 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * rpc_prot.c + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * This set of routines implements the rpc message definition, + * its serializer and some common rpc utility routines. + * The routines are meant for various implementations of rpc - + * they are NOT for the rpc client or rpc service implementations! + * Because authentication stuff is easy and is part of rpc, the opaque + * routines are also in this program. + */ + +#include <sys/param.h> + +#include <rpc/rpc.h> + +/* * * * * * * * * * * * * * XDR Authentication * * * * * * * * * * * */ + +/* + * XDR an opaque authentication struct + * (see auth.h) + */ +bool_t +xdr_opaque_auth(xdrs, ap) + register XDR *xdrs; + register struct opaque_auth *ap; +{ + + if (xdr_enum(xdrs, &(ap->oa_flavor))) + return (xdr_bytes(xdrs, &ap->oa_base, + &ap->oa_length, MAX_AUTH_BYTES)); + return (FALSE); +} + +/* + * XDR a DES block + */ +bool_t +xdr_des_block(xdrs, blkp) + register XDR *xdrs; + register des_block *blkp; +{ + return (xdr_opaque(xdrs, (caddr_t)blkp, sizeof(des_block))); +} + +/* * * * * * * * * * * * * * XDR RPC MESSAGE * * * * * * * * * * * * * * * */ + +/* + * XDR the MSG_ACCEPTED part of a reply message union + */ +bool_t +xdr_accepted_reply(xdrs, ar) + register XDR *xdrs; + register struct accepted_reply *ar; +{ + + /* personalized union, rather than calling xdr_union */ + if (! xdr_opaque_auth(xdrs, &(ar->ar_verf))) + return (FALSE); + if (! xdr_enum(xdrs, (enum_t *)&(ar->ar_stat))) + return (FALSE); + switch (ar->ar_stat) { + + case SUCCESS: + return ((*(ar->ar_results.proc))(xdrs, ar->ar_results.where)); + + case PROG_MISMATCH: + if (! xdr_u_int32(xdrs, &(ar->ar_vers.low))) + return (FALSE); + return (xdr_u_int32(xdrs, &(ar->ar_vers.high))); + } + return (TRUE); /* TRUE => open ended set of problems */ +} + +/* + * XDR the MSG_DENIED part of a reply message union + */ +bool_t +xdr_rejected_reply(xdrs, rr) + register XDR *xdrs; + register struct rejected_reply *rr; +{ + + /* personalized union, rather than calling xdr_union */ + if (! xdr_enum(xdrs, (enum_t *)&(rr->rj_stat))) + return (FALSE); + switch (rr->rj_stat) { + + case RPC_MISMATCH: + if (! xdr_u_int32(xdrs, &(rr->rj_vers.low))) + return (FALSE); + return (xdr_u_int32(xdrs, &(rr->rj_vers.high))); + + case AUTH_ERROR: + return (xdr_enum(xdrs, (enum_t *)&(rr->rj_why))); + } + return (FALSE); +} + +static struct xdr_discrim reply_dscrm[3] = { + { (int)MSG_ACCEPTED, xdr_accepted_reply }, + { (int)MSG_DENIED, xdr_rejected_reply }, + { __dontcare__, NULL_xdrproc_t } }; + +/* + * XDR a reply message + */ +bool_t +xdr_replymsg(xdrs, rmsg) + register XDR *xdrs; + register struct rpc_msg *rmsg; +{ + if ( + xdr_u_int32(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)); + return (FALSE); +} + + +/* + * Serializes the "static part" of a call message header. + * The fields include: rm_xid, rm_direction, rpcvers, prog, and vers. + * The rm_xid is not really static, but the user can easily munge on the fly. + */ +bool_t +xdr_callhdr(xdrs, cmsg) + register XDR *xdrs; + register struct rpc_msg *cmsg; +{ + + cmsg->rm_direction = CALL; + cmsg->rm_call.cb_rpcvers = RPC_MSG_VERSION; + if ( + (xdrs->x_op == XDR_ENCODE) && + xdr_u_int32(xdrs, &(cmsg->rm_xid)) && + xdr_enum(xdrs, (enum_t *)&(cmsg->rm_direction)) && + xdr_u_int32(xdrs, &(cmsg->rm_call.cb_rpcvers)) && + xdr_u_int32(xdrs, &(cmsg->rm_call.cb_prog)) ) + return (xdr_u_int32(xdrs, &(cmsg->rm_call.cb_vers))); + return (FALSE); +} + +/* ************************** Client utility routine ************* */ + +static void +accepted(acpt_stat, error) + register enum accept_stat acpt_stat; + register struct rpc_err *error; +{ + + switch (acpt_stat) { + + case PROG_UNAVAIL: + error->re_status = RPC_PROGUNAVAIL; + return; + + case PROG_MISMATCH: + error->re_status = RPC_PROGVERSMISMATCH; + return; + + case PROC_UNAVAIL: + error->re_status = RPC_PROCUNAVAIL; + return; + + case GARBAGE_ARGS: + error->re_status = RPC_CANTDECODEARGS; + return; + + case SYSTEM_ERR: + error->re_status = RPC_SYSTEMERROR; + return; + + case SUCCESS: + error->re_status = RPC_SUCCESS; + return; + } + /* something's wrong, but we don't know what ... */ + error->re_status = RPC_FAILED; + error->re_lb.s1 = (rpc_int32)MSG_ACCEPTED; + error->re_lb.s2 = (rpc_int32)acpt_stat; +} + +static void +rejected(rjct_stat, error) + register enum reject_stat rjct_stat; + register struct rpc_err *error; +{ + + switch (rjct_stat) { + + case RPC_VERSMISMATCH: + error->re_status = RPC_VERSMISMATCH; + return; + + case AUTH_ERROR: + error->re_status = RPC_AUTHERROR; + return; + } + /* something's wrong, but we don't know what ... */ + error->re_status = RPC_FAILED; + error->re_lb.s1 = (rpc_int32)MSG_DENIED; + error->re_lb.s2 = (rpc_int32)rjct_stat; +} + +/* + * given a reply message, fills in the error + */ +void +sunrpc_seterr_reply(msg, error) + register struct rpc_msg *msg; + register struct rpc_err *error; +{ + + /* optimized for normal, SUCCESSful case */ + switch (msg->rm_reply.rp_stat) { + + case MSG_ACCEPTED: + if (msg->acpted_rply.ar_stat == SUCCESS) { + error->re_status = RPC_SUCCESS; + return; + }; + accepted(msg->acpted_rply.ar_stat, error); + break; + + case MSG_DENIED: + rejected(msg->rjcted_rply.rj_stat, error); + break; + + default: + error->re_status = RPC_FAILED; + error->re_lb.s1 = (rpc_int32)(msg->rm_reply.rp_stat); + break; + } + switch (error->re_status) { + + case RPC_VERSMISMATCH: + error->re_vers.low = msg->rjcted_rply.rj_vers.low; + error->re_vers.high = msg->rjcted_rply.rj_vers.high; + break; + + case RPC_AUTHERROR: + error->re_why = msg->rjcted_rply.rj_why; + break; + + case RPC_PROGVERSMISMATCH: + error->re_vers.low = msg->acpted_rply.ar_vers.low; + error->re_vers.high = msg->acpted_rply.ar_vers.high; + break; + } +} diff --git a/src/lib/rpc/svc.c b/src/lib/rpc/svc.c new file mode 100644 index 000000000..cb4d877a7 --- /dev/null +++ b/src/lib/rpc/svc.c @@ -0,0 +1,492 @@ +/* @(#)svc.c 2.4 88/08/11 4.0 RPCSRC; from 1.44 88/02/08 SMI */ +/* + * 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(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)svc.c 1.41 87/10/13 Copyr 1984 Sun Micro"; +#endif + +/* + * svc.c, Server-side remote procedure call interface. + * + * There are two sets of procedures here. The xprt routines are + * for handling transport handles. The svc routines handle the + * list of service routines. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <sys/errno.h> +#include <rpc/rpc.h> +#include <rpc/pmap_clnt.h> +#include <stdio.h> + +extern int errno; + +#ifdef FD_SETSIZE +static SVCXPRT **xports; +#else +#define NOFILE 32 + +static SVCXPRT *xports[NOFILE]; +#endif /* def FD_SETSIZE */ + +#define NULL_SVC ((struct svc_callout *)0) +#define RQCRED_SIZE 400 /* this size is excessive */ + +/* + * The services list + * Each entry represents a set of procedures (an rpc program). + * The dispatch routine takes request structs and runs the + * apropriate procedure. + */ +static struct svc_callout { + struct svc_callout *sc_next; + rpc_u_int32 sc_prog; + rpc_u_int32 sc_vers; + void (*sc_dispatch)(); +} *svc_head; + +static struct svc_callout *svc_find(); + +/* *************** SVCXPRT related stuff **************** */ + +/* + * Activate a transport handle. + */ +void +xprt_register(xprt) + SVCXPRT *xprt; +{ + register int sock = xprt->xp_sock; + +#ifdef FD_SETSIZE + if (xports == NULL) { + xports = (SVCXPRT **) + mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *)); + } + if (sock < _rpc_dtablesize()) { + xports[sock] = xprt; + FD_SET(sock, &svc_fdset); + } +#else + if (sock < NOFILE) { + xports[sock] = xprt; + svc_fds |= (1 << sock); + } +#endif /* def FD_SETSIZE */ + +} + +/* + * De-activate a transport handle. + */ +void +xprt_unregister(xprt) + SVCXPRT *xprt; +{ + register int sock = xprt->xp_sock; + +#ifdef FD_SETSIZE + if ((sock < _rpc_dtablesize()) && (xports[sock] == xprt)) { + xports[sock] = (SVCXPRT *)0; + FD_CLR(sock, &svc_fdset); + } +#else + if ((sock < NOFILE) && (xports[sock] == xprt)) { + xports[sock] = (SVCXPRT *)0; + svc_fds &= ~(1 << sock); + } +#endif /* def FD_SETSIZE */ +} + + +/* ********************** CALLOUT list related stuff ************* */ + +/* + * Add a service program to the callout list. + * The dispatch routine will be called when a rpc request for this + * program number comes in. + */ +bool_t +svc_register(xprt, prog, vers, dispatch, protocol) + SVCXPRT *xprt; + rpc_u_int32 prog; + rpc_u_int32 vers; + void (*dispatch)(); + int protocol; +{ + struct svc_callout *prev; + register struct svc_callout *s; + + if ((s = svc_find(prog, vers, &prev)) != NULL_SVC) { + 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) { + return (FALSE); + } + s->sc_prog = prog; + s->sc_vers = vers; + s->sc_dispatch = dispatch; + s->sc_next = svc_head; + svc_head = s; +pmap_it: + /* now register the information with the local binder service */ + if (protocol) { + return (pmap_set(prog, vers, protocol, xprt->xp_port)); + } + return (TRUE); +} + +/* + * Remove a service program from the callout list. + */ +void +svc_unregister(prog, vers) + rpc_u_int32 prog; + rpc_u_int32 vers; +{ + struct svc_callout *prev; + register struct svc_callout *s; + + if ((s = svc_find(prog, vers, &prev)) == NULL_SVC) + return; + if (prev == NULL_SVC) { + svc_head = s->sc_next; + } else { + prev->sc_next = s->sc_next; + } + s->sc_next = NULL_SVC; + mem_free((char *) s, (unsigned int) sizeof(struct svc_callout)); + /* now unregister the information with the local binder service */ + (void)pmap_unset(prog, vers); +} + +/* + * Search the callout list for a program number, return the callout + * struct. + */ +static struct svc_callout * +svc_find(prog, vers, prev) + rpc_u_int32 prog; + rpc_u_int32 vers; + struct svc_callout **prev; +{ + register struct svc_callout *s, *p; + + 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 = s; + } +done: + *prev = p; + return (s); +} + +/* ******************* REPLY GENERATION ROUTINES ************ */ + +/* + * Send a reply to an rpc request + */ +bool_t +svc_sendreply(xprt, xdr_results, xdr_location) + register SVCXPRT *xprt; + xdrproc_t xdr_results; + caddr_t xdr_location; +{ + struct rpc_msg rply; + + rply.rm_direction = REPLY; + rply.rm_reply.rp_stat = MSG_ACCEPTED; + rply.acpted_rply.ar_verf = xprt->xp_verf; + rply.acpted_rply.ar_stat = SUCCESS; + rply.acpted_rply.ar_results.where = xdr_location; + rply.acpted_rply.ar_results.proc = xdr_results; + return (SVC_REPLY(xprt, &rply)); +} + +/* + * No procedure error reply + */ +void +svcerr_noproc(xprt) + register SVCXPRT *xprt; +{ + struct rpc_msg rply; + + rply.rm_direction = REPLY; + rply.rm_reply.rp_stat = MSG_ACCEPTED; + rply.acpted_rply.ar_verf = xprt->xp_verf; + rply.acpted_rply.ar_stat = PROC_UNAVAIL; + SVC_REPLY(xprt, &rply); +} + +/* + * Can't decode args error reply + */ +void +svcerr_decode(xprt) + register SVCXPRT *xprt; +{ + struct rpc_msg rply; + + rply.rm_direction = REPLY; + rply.rm_reply.rp_stat = MSG_ACCEPTED; + rply.acpted_rply.ar_verf = xprt->xp_verf; + rply.acpted_rply.ar_stat = GARBAGE_ARGS; + SVC_REPLY(xprt, &rply); +} + +/* + * Some system error + */ +void +svcerr_systemerr(xprt) + register SVCXPRT *xprt; +{ + struct rpc_msg rply; + + 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); +} + +/* + * Authentication error reply + */ +void +svcerr_auth(xprt, why) + SVCXPRT *xprt; + enum auth_stat why; +{ + struct rpc_msg rply; + + rply.rm_direction = REPLY; + rply.rm_reply.rp_stat = MSG_DENIED; + rply.rjcted_rply.rj_stat = AUTH_ERROR; + rply.rjcted_rply.rj_why = why; + SVC_REPLY(xprt, &rply); +} + +/* + * Auth too weak error reply + */ +void +svcerr_weakauth(xprt) + SVCXPRT *xprt; +{ + + svcerr_auth(xprt, AUTH_TOOWEAK); +} + +/* + * Program unavailable error reply + */ +void +svcerr_noprog(xprt) + register SVCXPRT *xprt; +{ + struct rpc_msg rply; + + rply.rm_direction = REPLY; + rply.rm_reply.rp_stat = MSG_ACCEPTED; + rply.acpted_rply.ar_verf = xprt->xp_verf; + rply.acpted_rply.ar_stat = PROG_UNAVAIL; + SVC_REPLY(xprt, &rply); +} + +/* + * Program version mismatch error reply + */ +void +svcerr_progvers(xprt, low_vers, high_vers) + register SVCXPRT *xprt; + rpc_u_int32 low_vers; + rpc_u_int32 high_vers; +{ + struct rpc_msg rply; + + 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; + SVC_REPLY(xprt, &rply); +} + +/* ******************* SERVER INPUT STUFF ******************* */ + +/* + * Get server side input from some transport. + * + * Statement of authentication parameters management: + * This function owns and manages all authentication parameters, specifically + * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and + * the "cooked" credentials (rqst->rq_clntcred). + * However, this function does not know the structure of the cooked + * credentials, so it make the following assumptions: + * a) the structure is contiguous (no pointers), and + * b) the cred structure size does not exceed RQCRED_SIZE bytes. + * In all events, all three parameters are freed upon exit from this routine. + * The storage is trivially management on the call stack in user land, but + * is mallocated in kernel land. + */ + +void +svc_getreq(rdfds) + int rdfds; +{ +#ifdef FD_SETSIZE + fd_set readfds; + + FD_ZERO(&readfds); + readfds.fds_bits[0] = rdfds; + svc_getreqset(&readfds); +#else + int readfds = rdfds & svc_fds; + + svc_getreqset(&readfds); +#endif /* def FD_SETSIZE */ +} + +void +svc_getreqset(readfds) +#ifdef FD_SETSIZE + fd_set *readfds; +{ +#else + int *readfds; +{ + int readfds_local = *readfds; +#endif /* def FD_SETSIZE */ + enum xprt_stat stat; + struct rpc_msg msg; + int prog_found; + rpc_u_int32 low_vers; + rpc_u_int32 high_vers; + struct svc_req r; + register SVCXPRT *xprt; + rpc_u_int32 mask; + int bit; + rpc_u_int32 *maskp; + register int setsize; + register int sock; + bool_t no_dispatch; + + 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]); + +#ifdef FD_SETSIZE + setsize = _rpc_dtablesize(); + + maskp = (rpc_u_int32 *)readfds->fds_bits; + for (sock = 0; sock < setsize; sock += NFDBITS) { + for (mask = *maskp++; bit = ffs(mask); mask ^= (1 << (bit - 1))) { + /* sock has input waiting */ + xprt = xports[sock + bit - 1]; +#else + for (sock = 0; readfds_local != 0; sock++, readfds_local >>= 1) { + if ((readfds_local & 1) != 0) { + /* sock has input waiting */ + xprt = xports[sock]; +#endif /* def FD_SETSIZE */ + /* 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; + + 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; + + /* in case _authenticate has been replaced + with an old-style version */ + r.rq_xprt->xp_auth = &svc_auth_any; + no_dispatch = FALSE; + + /* first authenticate the message */ + why=_authenticate(&r, &msg, &no_dispatch); + if (why != AUTH_OK) { + svcerr_auth(xprt, why); + goto call_done; + } else if (no_dispatch) { + goto call_done; + } + + /* now match message with a registered service*/ + prog_found = FALSE; + low_vers = 0 - 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 ... */ + } + call_done: + if ((stat = SVC_STAT(xprt)) == XPRT_DIED){ + SVC_DESTROY(xprt); + break; + } + } while (stat == XPRT_MOREREQS); + } + } +} diff --git a/src/lib/rpc/svc.h b/src/lib/rpc/svc.h new file mode 100644 index 000000000..2114d6249 --- /dev/null +++ b/src/lib/rpc/svc.h @@ -0,0 +1,298 @@ +/* @(#)svc.h 2.2 88/07/29 4.0 RPCSRC; from 1.20 88/02/08 SMI */ +/* + * 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 + */ + +/* + * svc.h, Server-side remote procedure call interface. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#ifndef __SVC_HEADER__ +#define __SVC_HEADER__ + +/* + * This interface must manage two items concerning remote procedure calling: + * + * 1) An arbitrary number of transport connections upon which rpc requests + * are received. The two most notable transports are TCP and UDP; they are + * created and registered by routines in svc_tcp.c and svc_udp.c, respectively; + * they in turn call xprt_register and xprt_unregister. + * + * 2) An arbitrary number of locally registered services. Services are + * described by the following four data: program number, version number, + * "service dispatch" function, a transport handle, and a boolean that + * indicates whether or not the exported program should be registered with a + * local binder service; if true the program's number and version and the + * port number from the transport handle are registered with the binder. + * These data are registered with the rpc svc system via svc_register. + * + * A service's dispatch function is called whenever an rpc request comes in + * on a transport. The request's program and version numbers must match + * those of the registered service. The dispatch function is passed two + * parameters, struct svc_req * and SVCXPRT *, defined below. + */ + +enum xprt_stat { + XPRT_DIED, + XPRT_MOREREQS, + XPRT_IDLE +}; + +/* + * Server side transport handle + */ +typedef struct { + int xp_sock; + unsigned short xp_port; /* associated port number */ + struct xp_ops { + bool_t (*xp_recv)(); /* receive incomming 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 address */ + struct sockaddr_in xp_raddr; /* remote address */ + struct opaque_auth xp_verf; /* raw response verifier */ + SVCAUTH *xp_auth; /* auth flavor of current req */ + caddr_t xp_p1; /* private */ + caddr_t xp_p2; /* private */ +} SVCXPRT; + +/* + * Approved way of getting address of caller + */ +#define svc_getcaller(x) (&(x)->xp_raddr) + +/* + * Operations defined on an SVCXPRT handle + * + * SVCXPRT *xprt; + * struct rpc_msg *msg; + * xdrproc_t xargs; + * caddr_t argsp; + */ +#define SVC_RECV(xprt, msg) \ + (*(xprt)->xp_ops->xp_recv)((xprt), (msg)) +#define svc_recv(xprt, msg) \ + (*(xprt)->xp_ops->xp_recv)((xprt), (msg)) + +#define SVC_STAT(xprt) \ + (*(xprt)->xp_ops->xp_stat)(xprt) +#define svc_stat(xprt) \ + (*(xprt)->xp_ops->xp_stat)(xprt) + +#define SVC_GETARGS(xprt, xargs, argsp) \ + (*(xprt)->xp_ops->xp_getargs)((xprt), (xargs), (argsp)) +#define svc_getargs(xprt, xargs, argsp) \ + (*(xprt)->xp_ops->xp_getargs)((xprt), (xargs), (argsp)) + +#define SVC_GETARGS_REQ(xprt, req, xargs, argsp) \ + (*(xprt)->xp_ops->xp_getargs_req)((xprt), (req), (xargs), (argsp)) +#define svc_getargs_req(xprt, req, xargs, argsp) \ + (*(xprt)->xp_ops->xp_getargs_req)((xprt), (req), (xargs), (argsp)) + +#define SVC_REPLY(xprt, msg) \ + (*(xprt)->xp_ops->xp_reply) ((xprt), (msg)) +#define svc_reply(xprt, msg) \ + (*(xprt)->xp_ops->xp_reply) ((xprt), (msg)) + +#define SVC_REPLY_REQ(xprt, req, msg) \ + (*(xprt)->xp_ops->xp_reply_req) ((xprt), (req), (msg)) +#define svc_reply_req(xprt, msg) \ + (*(xprt)->xp_ops->xp_reply_req) ((xprt), (req), (msg)) + +#define SVC_FREEARGS(xprt, xargs, argsp) \ + (*(xprt)->xp_ops->xp_freeargs)((xprt), (xargs), (argsp)) +#define svc_freeargs(xprt, xargs, argsp) \ + (*(xprt)->xp_ops->xp_freeargs)((xprt), (xargs), (argsp)) + +#define SVC_DESTROY(xprt) \ + (*(xprt)->xp_ops->xp_destroy)(xprt) +#define svc_destroy(xprt) \ + (*(xprt)->xp_ops->xp_destroy)(xprt) + + +/* + * Service request + */ +struct svc_req { + rpc_u_int32 rq_prog; /* service program number */ + rpc_u_int32 rq_vers; /* service protocol version */ + rpc_u_int32 rq_proc; /* the desired procedure */ + struct opaque_auth rq_cred; /* raw creds from the wire */ + caddr_t rq_clntcred; /* read only cooked client cred */ + caddr_t rq_svccred; /* read only cooked svc cred */ + SVCXPRT *rq_xprt; /* associated transport */ + + /* The request's auth flavor *should* be here, but the svc_req */ + /* isn't passed around everywhere it is necessary. The */ + /* transport *is* passed around, so the auth flavor it stored */ + /* there. This means that the transport must be single */ + /* threaded, but other parts of SunRPC already require that. */ + /*SVCAUTH *rq_auth; associated auth flavor */ +}; + + +/* + * Service registration + * + * svc_register(xprt, prog, vers, dispatch, protocol) + * SVCXPRT *xprt; + * rpc_u_int32 prog; + * rpc_u_int32 vers; + * void (*dispatch)(); + * int protocol; like TCP or UDP, zero means do not register + */ +extern bool_t svc_register(); + +/* + * Service un-registration + * + * svc_unregister(prog, vers) + * rpc_u_int32 prog; + * rpc_u_int32 vers; + */ +extern void svc_unregister(); + +/* + * Transport registration. + * + * xprt_register(xprt) + * SVCXPRT *xprt; + */ +extern void xprt_register(); + +/* + * Transport un-register + * + * xprt_unregister(xprt) + * SVCXPRT *xprt; + */ +extern void xprt_unregister(); + + + + +/* + * When the service routine is called, it must first check to see if + * it knows about the procedure; if not, it should call svcerr_noproc + * and return. If so, it should deserialize its arguments via + * SVC_GETARGS or the new SVC_GETARGS_REQ (both defined above). If + * the deserialization does not work, svcerr_decode should be called + * followed by a return. Successful decoding of the arguments should + * be followed the execution of the procedure's code and a call to + * svc_sendreply or the new svc_sendreply_req. + * + * Also, if the service refuses to execute the procedure due to too- + * weak authentication parameters, svcerr_weakauth should be called. + * Note: do not confuse access-control failure with weak authentication! + * + * NB: In pure implementations of rpc, the caller always waits for a reply + * msg. This message is sent when svc_sendreply is called. + * Therefore pure service implementations should always call + * svc_sendreply even if the function logically returns void; use + * xdr.h - xdr_void for the xdr routine. HOWEVER, tcp based rpc allows + * for the abuse of pure rpc via batched calling or pipelining. In the + * case of a batched call, svc_sendreply should NOT be called since + * this would send a return message, which is what batching tries to avoid. + * It is the service/protocol writer's responsibility to know which calls are + * batched and which are not. Warning: responding to batch calls may + * deadlock the caller and server processes! + */ + +extern bool_t svc_sendreply(); +extern void svcerr_decode(); +extern void svcerr_weakauth(); +extern void svcerr_noproc(); +extern void svcerr_progvers(); +extern void svcerr_auth(); +extern void svcerr_noprog(); +extern void svcerr_systemerr(); + +/* + * Lowest level dispatching -OR- who owns this process anyway. + * Somebody has to wait for incoming requests and then call the correct + * service routine. The routine svc_run does infinite waiting; i.e., + * svc_run never returns. + * Since another (co-existant) package may wish to selectively wait for + * incoming calls or other events outside of the rpc architecture, the + * routine svc_getreq is provided. It must be passed readfds, the + * "in-place" results of a select system call (see select, section 2). + */ + +/* + * Global keeper of rpc service descriptors in use + * dynamic; must be inspected before each call to select + */ +#ifdef FD_SETSIZE +extern fd_set svc_fdset; +#define svc_fds svc_fdset.fds_bits[0] /* compatibility */ +#else +extern int svc_fds; +#endif /* def FD_SETSIZE */ + +/* + * a small program implemented by the svc_rpc implementation itself; + * also see clnt.h for protocol numbers. + */ +extern void rpctest_service(); + +extern void svc_getreq(); +extern void svc_getreqset(); /* takes fdset instead of int */ +extern void svc_run(); /* never returns */ + +/* + * Socket to use on svcxxx_create call to get default socket + */ +#define RPC_ANYSOCK -1 + +/* + * These are the existing service side transport implementations + */ + +/* + * Memory based rpc for testing and timing. + */ +extern SVCXPRT *svcraw_create(); + +/* + * Udp based rpc. + */ +extern SVCXPRT *svcudp_create(); +extern SVCXPRT *svcudp_bufcreate(); + +/* + * Tcp based rpc. + */ +extern SVCXPRT *svctcp_create(); + +#endif /* !__SVC_HEADER__ */ diff --git a/src/lib/rpc/svc_auth.c b/src/lib/rpc/svc_auth.c new file mode 100644 index 000000000..281d7cba4 --- /dev/null +++ b/src/lib/rpc/svc_auth.c @@ -0,0 +1,119 @@ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)svc_auth.c 2.1 88/08/07 4.0 RPCSRC; from 1.19 87/08/11 Copyr 1984 Sun Micro"; +#endif +/* + * 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 + */ + +/* + * svc_auth_nodes.c, Server-side rpc authenticator interface, + * *WITHOUT* DES authentication. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <rpc/rpc.h> + +/* + * Server side authenticators are called from authenticate by + * using the client auth struct flavor field to index into svcauthsw. + * The server auth flavors must implement a routine that looks + * like: + * + * enum auth_stat + * flavorx_auth(rqst, msg) + * register struct svc_req *rqst; + * register struct rpc_msg *msg; + * + */ + +enum auth_stat _svcauth_null(); /* no authentication */ +enum auth_stat _svcauth_unix(); /* unix style (uid, gids) */ +enum auth_stat _svcauth_short(); /* short hand unix style */ +enum auth_stat _svcauth_gssapi(); /* GSS-API style */ + +static struct svcauthsw_type { + unsigned int flavor; + enum auth_stat (*authenticator)(); +} svcauthsw[] = { + AUTH_GSSAPI, _svcauth_gssapi, /* AUTH_GSSAPI */ + AUTH_NONE, _svcauth_null, /* AUTH_NULL */ + AUTH_GSSAPI_COMPAT, _svcauth_gssapi, /* AUTH_GSSAPI_COMPAT */ + AUTH_UNIX, _svcauth_unix, /* AUTH_UNIX */ + AUTH_SHORT, _svcauth_short, /* AUTH_SHORT */ +}; +static int svcauthnum = sizeof(svcauthsw) / sizeof(struct svcauthsw_type); + +/* + * The call rpc message, msg has been obtained from the wire. The msg contains + * the raw form of credentials and verifiers. authenticate returns AUTH_OK + * if the msg is successfully authenticated. If AUTH_OK then the routine also + * does the following things: + * set rqst->rq_xprt->verf to the appropriate response verifier; + * sets rqst->rq_client_cred to the "cooked" form of the credentials. + * + * NB: rqst->rq_cxprt->verf must be pre-alloctaed; + * its length is set appropriately. + * + * The caller still owns and is responsible for msg->u.cmb.cred and + * msg->u.cmb.verf. The authentication system retains ownership of + * rqst->rq_client_cred, the cooked credentials. + */ +enum auth_stat +_authenticate(rqst, msg, no_dispatch) + register struct svc_req *rqst; + struct rpc_msg *msg; + bool_t *no_dispatch; +{ + register int cred_flavor, i; + + rqst->rq_cred = msg->rm_call.cb_cred; + rqst->rq_xprt->xp_verf.oa_flavor = _null_auth.oa_flavor; + rqst->rq_xprt->xp_verf.oa_length = 0; + cred_flavor = rqst->rq_cred.oa_flavor; + *no_dispatch = FALSE; + for (i = 0; i < svcauthnum; i++) { + if (cred_flavor == svcauthsw[i].flavor && + svcauthsw[i].authenticator != NULL) { + return ((*(svcauthsw[i].authenticator))(rqst, + msg, + no_dispatch)); + } + } + + return (AUTH_REJECTEDCRED); +} + +enum auth_stat +_svcauth_null(rqst, msg) + struct svc_req *rqst; + struct rpc_msg *msg; +{ + rqst->rq_xprt->xp_auth = &svc_auth_any; + return (AUTH_OK); +} diff --git a/src/lib/rpc/svc_auth.h b/src/lib/rpc/svc_auth.h new file mode 100644 index 000000000..4d5963144 --- /dev/null +++ b/src/lib/rpc/svc_auth.h @@ -0,0 +1,61 @@ +/* @(#)svc_auth.h 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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 + */ +/* @(#)svc_auth.h 1.6 86/07/16 SMI */ + +/* + * svc_auth.h, Service side of rpc authentication. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +/* + * Interface to server-side authentication flavors. + */ +typedef struct { + struct svc_auth_ops { + int (*svc_ah_wrap)(); + int (*svc_ah_unwrap)(); + } *svc_ah_ops; + caddr_t svc_ah_private; +} SVCAUTH; + +extern SVCAUTH svc_auth_any; + +/* + * Server side authenticator + */ +extern enum auth_stat _authenticate(); + +#define SVCAUTH_WRAP(auth, xdrs, xfunc, xwhere) \ + ((*((auth)->svc_ah_ops->svc_ah_wrap))(auth, xdrs, xfunc, xwhere)) +#define SVCAUTH_UNWRAP(auth, xdrs, xfunc, xwhere) \ + ((*((auth)->svc_ah_ops->svc_ah_unwrap))(auth, xdrs, xfunc, xwhere)) + + diff --git a/src/lib/rpc/svc_auth_any.c b/src/lib/rpc/svc_auth_any.c new file mode 100644 index 000000000..2f0a66dc8 --- /dev/null +++ b/src/lib/rpc/svc_auth_any.c @@ -0,0 +1,22 @@ +/* + * svc_auth_any.c + * Provides default service-side functions for authentication flavors + * that do not use all the fields in struct svc_auth_ops. + * + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. + */ + +#include <stdio.h> +#include <rpc/rpc.h> + +extern int authany_wrap(); + +struct svc_auth_ops svc_auth_any_ops = { + authany_wrap, + authany_wrap, +}; + +SVCAUTH svc_auth_any = { + &svc_auth_any_ops, + NULL, +}; diff --git a/src/lib/rpc/svc_auth_gssapi.c b/src/lib/rpc/svc_auth_gssapi.c new file mode 100644 index 000000000..07cf59ab8 --- /dev/null +++ b/src/lib/rpc/svc_auth_gssapi.c @@ -0,0 +1,1181 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. + * + * $Id$ + * $Source$ + * + * $Log$ + * Revision 1.37 1996/07/22 20:41:00 marc + * this commit includes all the changes on the OV_9510_INTEGRATION and + * OV_MERGE branches. This includes, but is not limited to, the new openvision + * admin system, and major changes to gssapi to add functionality, and bring + * the implementation in line with rfc1964. before committing, the + * code was built and tested for netbsd and solaris. + * + * Revision 1.36.4.1 1996/07/18 04:19:34 marc + * merged in changes from OV_9510_BP to OV_9510_FINAL1 + * + * Revision 1.36.2.1 1996/06/20 23:39:22 marc + * File added to the repository on a branch + * + * Revision 1.36 1996/05/30 19:25:02 bjaspan + * zero bindings structure before using it + * + * Revision 1.35 1996/05/12 06:17:25 marc + * changed around the file includes, since krb5 has changed some. + * + * added conditionalization GSS_BACKWARD_HACK until and if this hack is + * reimplemented in the newly merged gssapi. + * + * conditionalize out the host-specific cruft for setting the local + * address to INADDR_ANY, since you can just assign it that way on all + * platforms I know of. + * + * Revision 1.34 1996/02/12 15:14:00 grier + * [secure/3570] + * restore (struct sockaddr *) cast that got mangled + * + * Revision 1.33 1996/02/07 13:09:52 jik + * Actually, I should have used krb5_error_code, not krb5_int32. + * + * Revision 1.32 1996/02/07 13:08:31 jik + * Include <krb5/krb5.h> to get the krb5_int32 typedef, which we then use + * in a cast when checking if the GSS-API minor status value is equal to + * a krb5 error code. + * + * Revision 1.31 1996/02/01 18:29:29 grier + * Restore use of error code definition. + * Return original code structure. + * + * Revision 1.30 1996/01/31 19:15:49 grier + * [secure/3570] + * Remove (void *) casts to memcpy() args + * + * Revision 1.29 1996/01/25 03:58:04 grier + * Remove debug code + * + * Revision 1.28 1996/01/25 03:56:50 grier + * secure/3570 - missed Alpha checkin + * + * Revision 1.26 1995/11/07 23:17:23 grier + * memcpy() cast + * + * Revision 1.25 1995/08/24 21:05:48 bjaspan + * set acceptor channel bindings + * + * Revision 1.24 1995/08/23 20:28:02 bjaspan + * [secure-rpc/3392] add channel bindinds to the rpc + * + * Revision 1.23 1995/07/10 18:49:22 bjaspan + * [secure-build/3377] remove use of BSD db + * + * Revision 1.22 1995/05/25 18:35:53 bjaspan + * [secure-rpc/3103] log misc errors from RPC + * + * Revision 1.21 1995/05/24 17:34:03 bjaspan + * [secure-rpc/3302] don't allow client to make server exit unless + * debugging is enabled + * + * Revision 1.20 1995/05/08 22:32:44 marc + * if a new client is in use, set the krb5 gssapi mech into + * backward-compatibility mode. + * + * Revision 1.19 1994/10/27 12:38:51 jik + * [secure-rpc/2808: add credential versioning] + * + * Sandbox: + * + * [secure-rpc/2808] add version field to client creds + * + * Revision 1.22 1994/10/26 20:03:27 bjaspan + * [secure-rpc/2808] add version field to client creds + * + * Revision 1.21 1994/05/23 01:26:01 bjaspan + * [secure-rpc/1911] set rq_svccred to the context instead of the service + * gss name + * + * Revision 1.20 1994/05/09 17:48:39 shanzer + * change sys/fcntl.h to fcntl.h + * + * Revision 1.19 1994/04/08 17:21:32 bjaspan + * remove KRB5KTNAME hack + * + * Revision 1.18 1994/03/18 15:48:13 shanzer + * include sys/fcntl.h + * + * Revision 1.17 1994/03/08 00:05:56 shanzer + * call rand() instead random() + * + * Revision 1.16 1993/12/08 21:43:54 bjaspan + * gss_delete_sec_context failure is not fatal (in fact, the context + * will often be expired); use AUTH_GSSAPI_DISPLAY_STATUS macro + * + * Revision 1.15 1993/12/08 20:20:08 bjaspan + * add debugging info to expire_client, correct comment above btree->put + * + * Revision 1.14 1993/12/08 06:52:49 bjaspan + * *many* debugging improvements to help find secure-rpc/586, and (I hope) + * the fix: don't change client_data->expiration without deleting it + * and reinserting it into the btree + * + * Revision 1.13 1993/12/06 21:22:26 bjaspan + * debugging levels, #ifdef PURIFY, call abort() on impossible failures + * + * Revision 1.12 1993/11/12 02:33:14 bjaspan + * add badauth + * / + * + * Revision 1.11 1993/11/03 23:46:15 bjaspan + * new log_badverf format + * + * Revision 1.10 1993/11/03 21:23:30 bjaspan + * handle GSS_C_INDEFINITE expiration, add log_badverf, set rq_svccred + * + * Revision 1.9 1993/11/03 01:30:36 bjaspan + * don't include gssapi_krb5.h, it isn't needed + * + * Revision 1.8 1993/11/02 22:09:02 bjaspan + * support multiple service-side names via _svcauth_gssapi_set_names + * + * Revision 1.7 1993/11/01 19:56:22 bjaspan + * unstatic svc_debug_gssapi, and send gss_{major,minor} back if + * accept_sec_context fails + * + * Revision 1.6 1993/10/28 22:09:58 bjaspan + * fix verifier mem leak, clean_clients() first to avoid dangling ref, + * only include hacked kt_default_name if DEBUG_GSSAPI defined + * + * Revision 1.5 1993/10/27 18:26:51 bjaspan + * use xdr_free instead of gss_release_buffer; this fixes memory leaks + * that were probably caused by zero-length seal/unseal tokens + * + * Revision 1.4 1993/10/26 21:12:51 bjaspan + * fully working + * + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +/* + * svc_auth_gssapi.c + * Handles the GSS-API flavor authentication parameters on the service + * side of RPC. + */ + +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <rpc/rpc.h> + +#include <gssapi/gssapi_generic.h> +#include <rpc/auth_gssapi.h> + +#ifdef GSS_BACKWARD_HACK +#include <gssapi/gssapi_krb5.h> +#endif + +/* This is here for the krb5_error_code typedef and the + KRB5KRB_AP_WRONG_PRINC #define.*/ +#include <krb5.h> + +#include <sys/file.h> +#include <fcntl.h> + +#define INITIATION_TIMEOUT 60*15 /* seconds until partially created */ + /* context is destroed */ +#define INDEF_EXPIRE 60*60*24 /* seconds until an context with no */ + /* expiration time is expired */ + +#ifdef __CODECENTER__ +#define DEBUG_GSSAPI 1 +#endif + +#ifdef DEBUG_GSSAPI +int svc_debug_gssapi = DEBUG_GSSAPI; +#define L_PRINTF(l,args) if (svc_debug_gssapi >= l) printf args +#define PRINTF(args) L_PRINTF(99, args) +#define AUTH_GSSAPI_DISPLAY_STATUS(args) \ + if (svc_debug_gssapi) auth_gssapi_display_status args +#else +#define PRINTF(args) +#define L_PRINTF(l, args) +#define AUTH_GSSAPI_DISPLAY_STATUS(args) +#endif + +typedef struct _svc_auth_gssapi_data { + bool_t established; + + gss_ctx_id_t context; + gss_name_t client_name, server_name; + gss_cred_id_t server_creds; + + rpc_u_int32 expiration; + rpc_u_int32 seq_num; + rpc_u_int32 key; + + SVCAUTH svcauth; + + /* kludge to free verifiers on next call */ + gss_buffer_desc prev_verf; +} svc_auth_gssapi_data; + +#define SVCAUTH_PRIVATE(auth) \ + ((svc_auth_gssapi_data *)(auth)->svc_ah_private) + +static bool_t svc_auth_gssapi_wrap(); +static bool_t svc_auth_gssapi_unwrap(); +static svc_auth_gssapi_data *create_client(); +static svc_auth_gssapi_data *get_client(gss_buffer_t client_handle); +static void destroy_client(svc_auth_gssapi_data *client_data); +static void clean_client(), cleanup(); +static void client_expire(svc_auth_gssapi_data *client_data, rpc_u_int32 exp); +static void dump_db(char *msg); + +struct svc_auth_ops svc_auth_gssapi_ops = { + svc_auth_gssapi_wrap, + svc_auth_gssapi_unwrap, +}; + +/* + * Globals! Eeek! Run for the hills! + */ +static gss_cred_id_t *server_creds_list = NULL; +static gss_name_t *server_name_list = NULL; +static int server_creds_count = 0; + +static auth_gssapi_log_badauth_func log_badauth = NULL; +static caddr_t log_badauth_data = NULL; +static auth_gssapi_log_badverf_func log_badverf = NULL; +static caddr_t log_badverf_data = NULL; +static auth_gssapi_log_miscerr_func log_miscerr = NULL; +static caddr_t log_miscerr_data = NULL; + +#define LOG_MISCERR(arg) if (log_miscerr) \ + (*log_miscerr)(rqst, msg, arg, log_miscerr_data) + +typedef struct _client_list { + svc_auth_gssapi_data *client; + struct _client_list *next; +} client_list; + +static client_list *clients = NULL; + +extern int errno; + +enum auth_stat _svcauth_gssapi(rqst, msg, no_dispatch) + register struct svc_req *rqst; + register struct rpc_msg *msg; + bool_t *no_dispatch; +{ + XDR xdrs; + auth_gssapi_creds creds; + auth_gssapi_init_arg call_arg; + auth_gssapi_init_res call_res; + gss_buffer_desc output_token, in_buf, out_buf; + gss_cred_id_t server_creds; + struct gss_channel_bindings_struct bindings, *bindp; + struct sockaddr_in sockname; + OM_uint32 gssstat, minor_stat, time_rec; + struct opaque_auth *cred, *verf; + svc_auth_gssapi_data *client_data; + int ret_flags, ret, i; + rpc_u_int32 seq_num; + int flag; + + PRINTF(("svcauth_gssapi: starting\n")); + + /* clean up expired entries */ + clean_client(); + + /* use AUTH_NONE until there is a client_handle */ + rqst->rq_xprt->xp_auth = &svc_auth_any; + + memset((char *) &call_res, 0, sizeof(call_res)); + + cred = &msg->rm_call.cb_cred; + verf = &msg->rm_call.cb_verf; + + if (cred->oa_length == 0) { + PRINTF(("svcauth_gssapi: empty creds, failing\n")); + LOG_MISCERR("empty client credentials"); + ret = AUTH_BADCRED; + goto error; + } + + PRINTF(("svcauth_gssapi: decoding credentials\n")); + xdrmem_create(&xdrs, cred->oa_base, cred->oa_length, XDR_DECODE); + memset((char *) &creds, 0, sizeof(creds)); + if (! xdr_authgssapi_creds(&xdrs, &creds)) { + PRINTF(("svcauth_gssapi: failed decoding creds\n")); + LOG_MISCERR("protocol error in client credentials"); + XDR_DESTROY(&xdrs); + ret = AUTH_BADCRED; + goto error; + } + XDR_DESTROY(&xdrs); + + PRINTF(("svcauth_gssapi: got credentials, version %d, " + "client_handle len %d\n", creds.version, + creds.client_handle.length)); + + if (creds.version != 2) { + PRINTF(("svcauth_gssapi: bad credential version\n")); + LOG_MISCERR("unsupported client credentials version"); + ret = AUTH_BADCRED; + goto error; + } + +#ifdef DEBUG_GSSAPI + if (svc_debug_gssapi) { + if (creds.auth_msg && rqst->rq_proc == AUTH_GSSAPI_EXIT) { + PRINTF(("svcauth_gssapi: GSSAPI_EXIT, cleaning up\n")); + svc_sendreply(rqst->rq_xprt, xdr_void, NULL); + xdr_free(xdr_authgssapi_creds, &creds); + cleanup(); + exit(0); + } + } +#endif + + /* + * If this is an auth_msg and proc is GSSAPI_INIT, then create a + * client handle for this client. Otherwise, look up the + * existing handle. + */ + if (creds.auth_msg && rqst->rq_proc == AUTH_GSSAPI_INIT) { + if (creds.client_handle.length != 0) { + PRINTF(("svcauth_gssapi: non-empty handle on GSSAPI_INIT\n")); + LOG_MISCERR("protocol error in client handle"); + ret = AUTH_FAILED; + goto error; + } + + PRINTF(("svcauth_gssapi: GSSAPI_INIT, creating client.\n")); + + client_data = create_client(); + if (client_data == NULL) { + PRINTF(("svcauth_gssapi: create_client failed\n")); + LOG_MISCERR("internal error creating client record"); + ret = AUTH_FAILED; + goto error; + } + } else { + if (creds.client_handle.length == 0) { + PRINTF(("svcauth_gssapi: expected non-empty creds\n")); + LOG_MISCERR("protocol error in client credentials"); + ret = AUTH_FAILED; + goto error; + } + + PRINTF(("svcauth_gssapi: incoming client_handle %d, len %d\n", + *((rpc_u_int32 *) creds.client_handle.value), + creds.client_handle.length)); + + client_data = get_client(&creds.client_handle); + if (client_data == NULL) { + PRINTF(("svcauth_gssapi: client_handle lookup failed\n")); + LOG_MISCERR("invalid client handle received"); + ret = AUTH_BADCRED; + goto error; + } + PRINTF(("svcauth_gssapi: client_handle lookup succeeded\n")); + } + + /* any response we send will use client_handle, so set it now */ + call_res.client_handle.length = sizeof(client_data->key); + call_res.client_handle.value = (char *) &client_data->key; + + /* mark this call as using AUTH_GSSAPI via client_data's SVCAUTH */ + rqst->rq_xprt->xp_auth = &client_data->svcauth; + + if (client_data->established == FALSE) { + PRINTF(("svcauth_gssapi: context is not established\n")); + + if (creds.auth_msg == FALSE) { + PRINTF(("svcauth_gssapi: expected auth_msg TRUE\n")); + LOG_MISCERR("protocol error on incomplete connection"); + ret = AUTH_REJECTEDCRED; + goto error; + } + + /* + * If the context is not established, then only GSSAPI_INIT + * and _CONTINUE requests are valid. + */ + if (rqst->rq_proc != AUTH_GSSAPI_INIT && rqst->rq_proc != + AUTH_GSSAPI_CONTINUE_INIT) { + PRINTF(("svcauth_gssapi: unacceptable procedure %d\n", + rqst->rq_proc)); + LOG_MISCERR("protocol error on incomplete connection"); + ret = AUTH_FAILED; + goto error; + } + + /* call is for us, deserialize arguments */ + memset(&call_arg, 0, sizeof(call_arg)); + if (! svc_getargs(rqst->rq_xprt, xdr_authgssapi_init_arg, + &call_arg)) { + PRINTF(("svcauth_gssapi: cannot decode args\n")); + LOG_MISCERR("protocol error in procedure arguments"); + ret = AUTH_BADCRED; + goto error; + } + + /* + * Process the call arg version number. + * + * Set the krb5_gss backwards-compatibility mode based on client + * version. This controls whether the AP_REP message is + * encrypted with the session key (version 2+, correct) or the + * session subkey (version 1, incorrect). This function can + * never fail, so we don't bother checking its return value. + */ + switch (call_arg.version) { + case 1: + case 2: + LOG_MISCERR("Warning: Accepted old RPC protocol request"); + call_res.version = 1; + break; + case 3: + call_res.version = call_arg.version; + break; + default: + PRINTF(("svcauth_gssapi: bad GSSAPI_INIT version\n")); + LOG_MISCERR("unsupported GSSAPI_INIT version"); + ret = AUTH_BADCRED; + goto error; + } + +#ifdef GSS_BACKWARD_HACK + krb5_gss_set_backward_mode(&minor_stat, call_arg.version == 1); +#endif + + if (call_arg.version == 3) { + int len; + + memset(&bindings, 0, sizeof(bindings)); + bindings.application_data.length = 0; + bindings.initiator_addrtype = GSS_C_AF_INET; + bindings.initiator_address.length = 4; + bindings.initiator_address.value = + &svc_getcaller(rqst->rq_xprt)->sin_addr.s_addr; + + len = sizeof(sockname); + if (getsockname(rqst->rq_xprt->xp_sock, + (struct sockaddr *) &sockname, &len) < 0) { + LOG_MISCERR("cannot get local address"); + PRINTF(("svcauth_gssapi: errno %d while getting address", + errno)); + ret = AUTH_FAILED; + goto error; + } + + bindings.acceptor_addrtype = GSS_C_AF_INET; + bindings.acceptor_address.length = 4; + bindings.acceptor_address.value = &sockname.sin_addr.s_addr; + + bindp = &bindings; + } else { + bindp = GSS_C_NO_CHANNEL_BINDINGS; + } + + /* + * If the client's server_creds is already set, use it. + * Otherwise, try each credential in server_creds_list until + * one of them succeedes, then set the client server_creds + * to that. If all fail, the client's server_creds isn't + * set (which is fine, because the client will be gc'ed + * anyway). + * + * If accept_sec_context returns something other than + * success and GSS_S_FAILURE, then assume different + * credentials won't help and stop looping. + * + * Note that there are really two cases here: (1) the client + * has a server_creds already, and (2) it does not. They + * are both written in the same loop so that there is only + * one textual call to gss_accept_sec_context; in fact, in + * case (1), the loop is executed exactly once. + */ + for (i = 0; i < server_creds_count; i++) { + if (client_data->server_creds != NULL) { + PRINTF(("svcauth_gssapi: using's clients server_creds\n")); + server_creds = client_data->server_creds; + } else { + PRINTF(("svcauth_gssapi: trying creds %d\n", i)); + server_creds = server_creds_list[i]; + } + + call_res.gss_major = + gss_accept_sec_context(&call_res.gss_minor, + &client_data->context, + server_creds, + &call_arg.token, + bindp, + &client_data->client_name, + NULL, + &output_token, + &ret_flags, + &time_rec, + NULL); + + if (server_creds == client_data->server_creds) + break; + + if (call_res.gss_major == GSS_S_COMPLETE || + call_res.gss_major == GSS_S_CONTINUE_NEEDED) { + /* server_creds was right, set it! */ + PRINTF(("svcauth_gssapi: creds are correct, storing\n")); + client_data->server_creds = server_creds; + client_data->server_name = server_name_list[i]; + break; + } else if (call_res.gss_major != GSS_S_FAILURE || + /* + * XXX hard-coded because there is no other + * way to prevent all GSS_S_FAILURES from + * returning a "wrong principal in request" + * error + */ + ((krb5_error_code) call_res.gss_minor != + (krb5_error_code) KRB5KRB_AP_WRONG_PRINC)) { + break; + } + } + + gssstat = call_res.gss_major; + minor_stat = call_res.gss_minor; + + /* done with call args */ + xdr_free(xdr_authgssapi_init_arg, &call_arg); + + PRINTF(("svcauth_gssapi: accept_sec_context returned %#x\n", + call_res.gss_major)); + if (call_res.gss_major != GSS_S_COMPLETE && + call_res.gss_major != GSS_S_CONTINUE_NEEDED) { + AUTH_GSSAPI_DISPLAY_STATUS(("accepting context", + call_res.gss_major, + call_res.gss_minor)); + + if (log_badauth != NULL) + (*log_badauth)(call_res.gss_major, + call_res.gss_minor, + &rqst->rq_xprt->xp_raddr, + log_badauth_data); + + svc_sendreply(rqst->rq_xprt, xdr_authgssapi_init_res, + (caddr_t) &call_res); + *no_dispatch = TRUE; + ret = AUTH_OK; + goto error; + } + + if (output_token.length != 0) { + PRINTF(("svcauth_gssapi: got new output token\n")); + GSS_COPY_BUFFER(call_res.token, output_token); + } + + if (gssstat == GSS_S_COMPLETE) { + client_data->seq_num = rand(); + client_expire(client_data, + (time_rec == GSS_C_INDEFINITE ? + INDEF_EXPIRE : time_rec) + time(0)); + + PRINTF(("svcauth_gssapi: context established, isn %d\n", + client_data->seq_num)); + + if (auth_gssapi_seal_seq(client_data->context, + client_data->seq_num, + &call_res.signed_isn) == + FALSE) { + ret = AUTH_FAILED; + LOG_MISCERR("internal error sealing sequence number"); + goto error; + } + } + + PRINTF(("svcauth_gssapi: sending reply\n")); + svc_sendreply(rqst->rq_xprt, xdr_authgssapi_init_res, + (caddr_t) &call_res); + *no_dispatch = TRUE; + + /* + * If appropriate, set established to TRUE *after* sending + * response (otherwise, the client will receive the final + * token encrypted) + */ + if (gssstat == GSS_S_COMPLETE) { + gss_release_buffer(&minor_stat, &call_res.signed_isn); + client_data->established = TRUE; + } + gss_release_buffer(&minor_stat, &output_token); + } else { + PRINTF(("svcauth_gssapi: context is established\n")); + + /* check the verifier */ + PRINTF(("svcauth_gssapi: checking verifier, len %d\n", + verf->oa_length)); + + in_buf.length = verf->oa_length; + in_buf.value = verf->oa_base; + + if (auth_gssapi_unseal_seq(client_data->context, &in_buf, + &seq_num) == FALSE) { + ret = AUTH_BADVERF; + LOG_MISCERR("internal error unsealing sequence number"); + goto error; + } + + if (seq_num != client_data->seq_num + 1) { + PRINTF(("svcauth_gssapi: expected isn %d, got %d\n", + client_data->seq_num + 1, seq_num)); + if (log_badverf != NULL) + (*log_badverf)(client_data->client_name, + client_data->server_name, + rqst, msg, log_badverf_data); + + ret = AUTH_REJECTEDVERF; + goto error; + } + client_data->seq_num++; + + PRINTF(("svcauth_gssapi: seq_num %d okay\n", seq_num)); + + /* free previous response verifier, if any */ + if (client_data->prev_verf.length != 0) { + gss_release_buffer(&minor_stat, &client_data->prev_verf); + client_data->prev_verf.length = 0; + } + + /* prepare response verifier */ + seq_num = client_data->seq_num + 1; + if (auth_gssapi_seal_seq(client_data->context, seq_num, + &out_buf) == FALSE) { + ret = AUTH_FAILED; + LOG_MISCERR("internal error sealing sequence number"); + goto error; + } + + client_data->seq_num++; + + PRINTF(("svcauth_gssapi; response seq_num %d\n", seq_num)); + + rqst->rq_xprt->xp_verf.oa_flavor = AUTH_GSSAPI; + rqst->rq_xprt->xp_verf.oa_base = out_buf.value; + rqst->rq_xprt->xp_verf.oa_length = out_buf.length; + + /* save verifier so it can be freed next time */ + client_data->prev_verf.value = out_buf.value; + client_data->prev_verf.length = out_buf.length; + + /* + * Message is authentic. If auth_msg if true, process the + * call; otherwise, return AUTH_OK so it will be dispatched + * to the application server. + */ + + if (creds.auth_msg == TRUE) { + /* + * If process_token fails, then the token probably came + * from an attacker. No response (error or otherwise) + * should be returned to the client, since it won't be + * accepting one. + */ + + switch (rqst->rq_proc) { + case AUTH_GSSAPI_MSG: + PRINTF(("svcauth_gssapi: GSSAPI_MSG, getting args\n")); + memset(&call_arg, 0, sizeof(call_arg)); + if (! svc_getargs(rqst->rq_xprt, xdr_authgssapi_init_arg, + &call_arg)) { + PRINTF(("svcauth_gssapi: cannot decode args\n")); + LOG_MISCERR("protocol error in call arguments"); + ret = AUTH_BADCRED; + goto error; + } + + PRINTF(("svcauth_gssapi: processing token\n")); + gssstat = gss_process_context_token(&minor_stat, + client_data->context, + &call_arg.token); + + /* done with call args */ + xdr_free(xdr_authgssapi_init_arg, &call_arg); + + if (gssstat != GSS_S_COMPLETE) { + AUTH_GSSAPI_DISPLAY_STATUS(("processing token", + gssstat, minor_stat)); + ret = AUTH_FAILED; + goto error; + } + + svc_sendreply(rqst->rq_xprt, xdr_void, NULL); + *no_dispatch = TRUE; + break; + + case AUTH_GSSAPI_DESTROY: + PRINTF(("svcauth_gssapi: GSSAPI_DESTROY\n")); + + PRINTF(("svcauth_gssapi: sending reply\n")); + svc_sendreply(rqst->rq_xprt, xdr_void, NULL); + *no_dispatch = TRUE; + + destroy_client(client_data); + break; + + default: + PRINTF(("svcauth_gssapi: unacceptable procedure %d\n", + rqst->rq_proc)); + LOG_MISCERR("invalid call procedure number"); + ret = AUTH_FAILED; + goto error; + } + } else { + /* set credentials for app server; comment in svc.c */ + /* seems to imply this is incorrect, but I don't see */ + /* any problem with it... */ + rqst->rq_clntcred = (char *)client_data->client_name; + rqst->rq_svccred = (char *)client_data->context; + } + } + + if (creds.client_handle.length != 0) { + PRINTF(("svcauth_gssapi: freeing client_handle len %d\n", + creds.client_handle.length)); + xdr_free(xdr_authgssapi_creds, &creds); + } + + PRINTF(("\n")); + return AUTH_OK; + +error: + if (creds.client_handle.length != 0) { + PRINTF(("svcauth_gssapi: freeing client_handle len %d\n", + creds.client_handle.length)); + xdr_free(xdr_authgssapi_creds, &creds); + } + + PRINTF(("\n")); + return ret; +} + +static void cleanup() +{ + client_list *c, *c2; + + PRINTF(("cleanup_and_exit: starting\n")); + + c = clients; + while (c) { + c2 = c; + c = c->next; + destroy_client(c2->client); + free(c2); + } + + exit(0); +} + +/* + * Function: create_client + * + * Purpose: Creates an new client_data structure and stores it in the + * database. + * + * Returns: the new client_data structure, or NULL on failure. + * + * Effects: + * + * A new client_data is created and stored in the hash table and + * b-tree. A new key that is unique in the current database is + * chosen; this key should be used as the client's client_handle. + */ +static svc_auth_gssapi_data *create_client() +{ + client_list *c; + svc_auth_gssapi_data *client_data; + static int client_key = 1; + int ret; + + PRINTF(("svcauth_gssapi: empty creds, creating\n")); + + client_data = (svc_auth_gssapi_data *) malloc(sizeof(*client_data)); + if (client_data == NULL) + return NULL; + memset((char *) client_data, 0, sizeof(*client_data)); + L_PRINTF(2, ("create_client: new client_data = %#x\n", client_data)); + + /* set up client data structure */ + client_data->established = 0; + client_data->context = GSS_C_NO_CONTEXT; + client_data->expiration = time(0) + INITIATION_TIMEOUT; + + /* set up psycho-recursive SVCAUTH hack */ + client_data->svcauth.svc_ah_ops = &svc_auth_gssapi_ops; + client_data->svcauth.svc_ah_private = (caddr_t) client_data; + + client_data->key = client_key++; + + c = (client_list *) malloc(sizeof(client_list)); + if (c == NULL) + return NULL; + c->client = client_data; + c->next = NULL; + + + if (clients == NULL) + clients = c; + else { + c->next = clients; + clients = c; + } + + PRINTF(("svcauth_gssapi: new handle %d\n", client_data->key)); + L_PRINTF(2, ("create_client: done\n")); + + return client_data; +} + +/* + * Function: client_expire + * + * Purpose: change the expiration time of a client in the database + * + * Arguments: + * + * client_data (r) the client_data to expire + * exp (r) the new expiration time + * + * Effects: + * + * client_data->expiration = exp + * + * This function used to remove client_data from the database, change + * its expiration time, and re-add it, which was necessary because the + * database was sorted by expiration time so a simple modification + * would break the rep invariant. Now the database is an unsorted + * linked list, so it doesn't matter. + */ +static void client_expire(svc_auth_gssapi_data *client_data, rpc_u_int32 exp) +{ + client_data->expiration = exp; +} + +/* + * Function get_client + * + * Purpose: retrieve a client_data structure from the database based + * on its client handle (key) + * + * Arguments: + * + * client_handle (r) the handle (key) to retrieve + * + * Effects: + * + * Searches the list and returns the client_data whose key field + * matches the contents of client_handle, or returns NULL if none was + * found. + */ +static svc_auth_gssapi_data *get_client(gss_buffer_t client_handle) +{ + client_list *c; + rpc_u_int32 handle; + + memcpy(&handle, client_handle->value, 4); + + L_PRINTF(2, ("get_client: looking for client %d\n", handle)); + + c = clients; + while (c) { + if (c->client->key == handle) + return c->client; + c = c->next; + } + + L_PRINTF(2, ("get_client: client_handle lookup failed\n")); + return NULL; +} + +/* + * Function: destroy_client + * + * Purpose: destroys a client entry and removes it from the database + * + * Arguments: + * + * client_data (r) the client to be destroyed + * + * Effects: + * + * client_data->context is deleted with gss_delete_sec_context. + * client_data's entry in the database is destroyed. client_data is + * freed. + */ +static void destroy_client(svc_auth_gssapi_data *client_data) +{ + OM_uint32 gssstat, minor_stat; + gss_buffer_desc out_buf; + client_list *c, *c2; + int ret; + + PRINTF(("destroy_client: destroying client_data\n")); + L_PRINTF(2, ("destroy_client: client_data = %#x\n", client_data)); + +#ifdef DEBUG_GSSAPI + if (svc_debug_gssapi >= 3) + dump_db("before frees"); +#endif + + /* destroy client struct even if error occurs */ + + gssstat = gss_delete_sec_context(&minor_stat, &client_data->context, + &out_buf); + if (gssstat != GSS_S_COMPLETE) + AUTH_GSSAPI_DISPLAY_STATUS(("deleting context", gssstat, + minor_stat)); + + gss_release_buffer(&minor_stat, &out_buf); + gss_release_name(&minor_stat, &client_data->client_name); + if (client_data->prev_verf.length != 0) + gss_release_buffer(&minor_stat, &client_data->prev_verf); + + if (clients == NULL) { + PRINTF(("destroy_client: called on empty database\n")); + abort(); + } else if (clients->client == client_data) { + c = clients; + clients = clients->next; + free(c); + } else { + c2 = clients; + c = clients->next; + while (c) { + if (c->client == client_data) { + c2->next = c->next; + free(c); + goto done; + } else + c = c->next; + } + PRINTF(("destroy_client: client_handle delete failed\n")); + abort(); + } + +done: + + L_PRINTF(2, ("destroy_client: client %d destroyed\n", client_data->key)); + + free(client_data); + +#ifdef PURIFY + purify_watch_n(client_data, sizeof(*client_data), "rw"); +#endif +} + +static void dump_db(char *msg) +{ + svc_auth_gssapi_data *client_data; + client_list *c; + + L_PRINTF(3, ("dump_db: %s:\n", msg)); + + c = clients; + while (c) { + client_data = c->client; + L_PRINTF(3, ("\tclient_data = %#x, exp = %d\n", + client_data, client_data->expiration)); + c = c->next; + } + + L_PRINTF(3, ("\n")); +} + +static void clean_client() +{ + svc_auth_gssapi_data *client_data; + client_list *c; + + PRINTF(("clean_client: starting\n")); + + c = clients; + while (c) { + client_data = c->client; + + L_PRINTF(2, ("clean_client: client_data = %#x\n", + client_data)); + + if (client_data->expiration < time(0)) { + PRINTF(("clean_client: client %d expired\n", + client_data->key)); + destroy_client(client_data); + c = clients; /* start over, just to be safe */ + } else { + c = c->next; + } + } + +done: + PRINTF(("clean_client: done\n")); +} + +/* + * Function: _svcauth_gssapi_set_name + * + * Purpose: Sets the list of service names for which incoming + * authentication requests should be honored. + * + * See functional specifications. + */ +bool_t _svcauth_gssapi_set_names(auth_gssapi_name *names, int num) +{ + OM_uint32 gssstat, minor_stat; + gss_buffer_desc in_buf; + int i; + + if (num == 0) + for (; names[num].name != NULL; num++) + ; + + server_creds_list = NULL; + server_name_list = NULL; + + server_creds_list = (gss_cred_id_t *) malloc(num*sizeof(gss_cred_id_t)); + if (server_creds_list == NULL) + goto fail; + server_name_list = (gss_name_t *) malloc(num*sizeof(gss_name_t)); + if (server_name_list == NULL) + goto fail; + + for (i = 0; i < num; i++) { + in_buf.value = names[i].name; + in_buf.length = strlen(in_buf.value) + 1; + + gssstat = gss_import_name(&minor_stat, &in_buf, names[i].type, + &server_name_list[i]); + + if (gssstat != GSS_S_COMPLETE) { + AUTH_GSSAPI_DISPLAY_STATUS(("importing name", gssstat, + minor_stat)); + goto fail; + } + + gssstat = gss_acquire_cred(&minor_stat, server_name_list[i], 0, + GSS_C_NULL_OID_SET, GSS_C_ACCEPT, + &server_creds_list[i], NULL, NULL); + if (gssstat != GSS_S_COMPLETE) { + AUTH_GSSAPI_DISPLAY_STATUS(("acquiring credentials", + gssstat, minor_stat)); + goto fail; + } + } + + server_creds_count = num; + + return TRUE; + +fail: + /* memory leak: not releasing names/creds already acquired */ + if (server_creds_list) + free(server_creds_list); + if (server_name_list) + free(server_name_list); + return FALSE; +} + +/* + * Function: _svcauth_gssapi_set_log_badauth_func + * + * Purpose: sets the logging function called when an invalid RPC call + * arrives + * + * See functional specifications. + */ +void _svcauth_gssapi_set_log_badauth_func + (auth_gssapi_log_badauth_func func, caddr_t data) +{ + log_badauth = func; + log_badauth_data = data; +} + +/* + * Function: _svcauth_gssapi_set_log_badverf_func + * + * Purpose: sets the logging function called when an invalid RPC call + * arrives + * + * See functional specifications. + */ +void _svcauth_gssapi_set_log_badverf_func + (auth_gssapi_log_badverf_func func, caddr_t data) +{ + log_badverf = func; + log_badverf_data = data; +} + +/* + * Function: _svcauth_gssapi_set_log_miscerr_func + * + * Purpose: sets the logging function called when a miscellaneous + * AUTH_GSSAPI error occurs + * + * See functional specifications. + */ +void _svcauth_gssapi_set_log_miscerr_func + (auth_gssapi_log_miscerr_func func, caddr_t data) +{ + log_miscerr = func; + log_miscerr_data = data; +} + +/* + * Encrypt the serialized arguments from xdr_func applied to xdr_ptr + * and write the result to xdrs. + */ +static bool_t svc_auth_gssapi_wrap(auth, out_xdrs, xdr_func, xdr_ptr) + SVCAUTH *auth; + XDR *out_xdrs; + bool_t (*xdr_func)(); + caddr_t xdr_ptr; +{ + OM_uint32 gssstat, minor_stat; + + if (! SVCAUTH_PRIVATE(auth)->established) { + PRINTF(("svc_gssapi_wrap: not established, noop\n")); + return (*xdr_func)(out_xdrs, xdr_ptr); + } else if (! auth_gssapi_wrap_data(&gssstat, &minor_stat, + SVCAUTH_PRIVATE(auth)->context, + SVCAUTH_PRIVATE(auth)->seq_num, + out_xdrs, xdr_func, xdr_ptr)) { + if (gssstat != GSS_S_COMPLETE) + AUTH_GSSAPI_DISPLAY_STATUS(("encrypting function arguments", + gssstat, minor_stat)); + return FALSE; + } else + return TRUE; +} + +static bool_t svc_auth_gssapi_unwrap(auth, in_xdrs, xdr_func, xdr_ptr) + SVCAUTH *auth; + XDR *in_xdrs; + bool_t (*xdr_func)(); + caddr_t xdr_ptr; +{ + svc_auth_gssapi_data *client_data = SVCAUTH_PRIVATE(auth); + OM_uint32 gssstat, minor_stat; + + if (! client_data->established) { + PRINTF(("svc_gssapi_unwrap: not established, noop\n")); + return (*xdr_func)(in_xdrs, (auth_gssapi_init_arg *) xdr_ptr); + } else if (! auth_gssapi_unwrap_data(&gssstat, &minor_stat, + client_data->context, + client_data->seq_num-1, + in_xdrs, xdr_func, xdr_ptr)) { + if (gssstat != GSS_S_COMPLETE) + AUTH_GSSAPI_DISPLAY_STATUS(("decrypting function arguments", + gssstat, minor_stat)); + return FALSE; + } else + return TRUE; +} diff --git a/src/lib/rpc/svc_auth_unix.c b/src/lib/rpc/svc_auth_unix.c new file mode 100644 index 000000000..1ff21588c --- /dev/null +++ b/src/lib/rpc/svc_auth_unix.c @@ -0,0 +1,137 @@ +/* @(#)svc_auth_unix.c 2.3 88/08/01 4.0 RPCSRC; from 1.28 88/02/08 SMI */ +/* + * 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(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)svc_auth_unix.c 1.28 88/02/08 Copyr 1984 Sun Micro"; +#endif + +/* + * svc_auth_unix.c + * Handles UNIX flavor authentication parameters on the service side of rpc. + * There are two svc auth implementations here: AUTH_UNIX and AUTH_SHORT. + * _svcauth_unix does full blown unix style uid,gid+gids auth, + * _svcauth_short uses a shorthand auth to index into a cache of longhand auths. + * Note: the shorthand has been gutted for efficiency. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <stdio.h> +#include <rpc/rpc.h> + +/* + * Unix longhand authenticator + */ +enum auth_stat +_svcauth_unix(rqst, msg) + register struct svc_req *rqst; + register struct rpc_msg *msg; +{ + register enum auth_stat stat; + XDR xdrs; + register struct authunix_parms *aup; + register rpc_int32 *buf; + struct area { + struct authunix_parms area_aup; + char area_machname[MAX_MACHINE_NAME+1]; + int area_gids[NGRPS]; + } *area; + unsigned int auth_len; + int str_len, gid_len; + register int i; + + rqst->rq_xprt->xp_auth = &svc_auth_any; + + area = (struct area *) rqst->rq_clntcred; + aup = &area->area_aup; + aup->aup_machname = area->area_machname; + aup->aup_gids = area->area_gids; + auth_len = (unsigned int)msg->rm_call.cb_cred.oa_length; + xdrmem_create(&xdrs, msg->rm_call.cb_cred.oa_base, auth_len,XDR_DECODE); + buf = (rpc_int32 *) XDR_INLINE(&xdrs, auth_len); + if (buf != NULL) { + aup->aup_time = IXDR_GET_LONG(buf); + str_len = IXDR_GET_U_LONG(buf); + if (str_len > MAX_MACHINE_NAME) { + stat = AUTH_BADCRED; + goto done; + } + memmove(aup->aup_machname, (caddr_t)buf, (unsigned int)str_len); + aup->aup_machname[str_len] = 0; + str_len = RNDUP(str_len); + buf += str_len / sizeof (rpc_int32); + aup->aup_uid = IXDR_GET_LONG(buf); + aup->aup_gid = IXDR_GET_LONG(buf); + gid_len = IXDR_GET_U_LONG(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); + } + /* + * 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); + stat = AUTH_BADCRED; + goto done; + } + } else if (! xdr_authunix_parms(&xdrs, aup)) { + xdrs.x_op = XDR_FREE; + (void)xdr_authunix_parms(&xdrs, aup); + stat = AUTH_BADCRED; + goto done; + } + rqst->rq_xprt->xp_verf.oa_flavor = AUTH_NULL; + rqst->rq_xprt->xp_verf.oa_length = 0; + stat = AUTH_OK; +done: + XDR_DESTROY(&xdrs); + return (stat); +} + + +/* + * Shorthand unix authenticator + * Looks up longhand in a cache. + */ +/*ARGSUSED*/ +enum auth_stat +_svcauth_short(rqst, msg) + struct svc_req *rqst; + struct rpc_msg *msg; +{ + rqst->rq_xprt->xp_auth = &svc_auth_any; + return (AUTH_REJECTEDCRED); +} diff --git a/src/lib/rpc/svc_raw.c b/src/lib/rpc/svc_raw.c new file mode 100644 index 000000000..1170ecec8 --- /dev/null +++ b/src/lib/rpc/svc_raw.c @@ -0,0 +1,166 @@ +/* @(#)svc_raw.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)svc_raw.c 1.15 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * svc_raw.c, This a toy for simple testing and timing. + * Interface to create an rpc client and server in the same UNIX process. + * This lets us similate rpc and get rpc (round trip) overhead, without + * any interference from the kernal. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <rpc/rpc.h> + + +/* + * This is the "network" that we will be moving data over + */ +static struct svcraw_private { + char _raw_buf[UDPMSGSIZE]; + SVCXPRT server; + XDR xdr_stream; + char verf_body[MAX_AUTH_BYTES]; +} *svcraw_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(); + +static struct xp_ops server_ops = { + svcraw_recv, + svcraw_stat, + svcraw_getargs, + svcraw_reply, + svcraw_freeargs, + svcraw_destroy +}; + +SVCXPRT * +svcraw_create() +{ + register struct svcraw_private *srp = svcraw_private; + + if (srp == 0) { + srp = (struct svcraw_private *)calloc(1, sizeof (*srp)); + if (srp == 0) + return (0); + } + srp->server.xp_sock = 0; + srp->server.xp_port = 0; + srp->server.xp_ops = &server_ops; + srp->server.xp_verf.oa_base = srp->verf_body; + xdrmem_create(&srp->xdr_stream, srp->_raw_buf, UDPMSGSIZE, XDR_FREE); + return (&srp->server); +} + +static enum xprt_stat +svcraw_stat() +{ + + return (XPRT_IDLE); +} + +static bool_t +svcraw_recv(xprt, msg) + SVCXPRT *xprt; + struct rpc_msg *msg; +{ + register struct svcraw_private *srp = svcraw_private; + register XDR *xdrs; + + 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); + return (TRUE); +} + +static bool_t +svcraw_reply(xprt, msg) + SVCXPRT *xprt; + struct rpc_msg *msg; +{ + register struct svcraw_private *srp = svcraw_private; + register XDR *xdrs; + + if (srp == 0) + return (FALSE); + 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 */ + return (TRUE); +} + +static bool_t +svcraw_getargs(xprt, xdr_args, args_ptr) + SVCXPRT *xprt; + xdrproc_t xdr_args; + caddr_t args_ptr; +{ + register struct svcraw_private *srp = svcraw_private; + + if (srp == 0) + return (FALSE); + return ((*xdr_args)(&srp->xdr_stream, args_ptr)); +} + +static bool_t +svcraw_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; + + if (srp == 0) + return (FALSE); + xdrs = &srp->xdr_stream; + xdrs->x_op = XDR_FREE; + return ((*xdr_args)(xdrs, args_ptr)); +} + +static void +svcraw_destroy() +{ +} diff --git a/src/lib/rpc/svc_run.c b/src/lib/rpc/svc_run.c new file mode 100644 index 000000000..d43aa2425 --- /dev/null +++ b/src/lib/rpc/svc_run.c @@ -0,0 +1,72 @@ +/* @(#)svc_run.c 2.1 88/07/29 4.0 RPCSRC */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)svc_run.c 1.1 87/10/13 Copyr 1984 Sun Micro"; +#endif + +/* + * 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 + */ + +/* + * This is the rpc server side idle loop + * Wait for input, call server program. + */ +#include <rpc/rpc.h> +#include <sys/errno.h> + +void +svc_run() +{ +#ifdef FD_SETSIZE + fd_set readfds; +#else + int readfds; +#endif /* def FD_SETSIZE */ + extern int errno; + + for (;;) { +#ifdef FD_SETSIZE + readfds = svc_fdset; +#else + readfds = svc_fds; +#endif /* def FD_SETSIZE */ + switch (select(_rpc_dtablesize(), &readfds, (fd_set *)0, + (fd_set *)0, (struct timeval *)0)) { + case -1: + if (errno == EINTR) { + continue; + } + perror("svc_run: - select failed"); + return; + case 0: + continue; + default: + svc_getreqset(&readfds); + } + } +} diff --git a/src/lib/rpc/svc_simple.c b/src/lib/rpc/svc_simple.c new file mode 100644 index 000000000..2a22e5722 --- /dev/null +++ b/src/lib/rpc/svc_simple.c @@ -0,0 +1,143 @@ +/* @(#)svc_simple.c 2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)svc_simple.c 1.18 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * svc_simple.c + * Simplified front end to rpc. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <stdio.h> +#include <rpc/rpc.h> +#include <sys/socket.h> +#include <netdb.h> + +static struct proglst { + char *(*p_progname)(); + int p_prognum; + int p_procnum; + xdrproc_t p_inproc, p_outproc; + struct proglst *p_nxt; +} *proglst; +static void universal(); +static SVCXPRT *transp; +struct proglst *pl; + +registerrpc(prognum, versnum, procnum, progname, inproc, outproc) + char *(*progname)(); + xdrproc_t inproc, outproc; +{ + + if (procnum == NULLPROC) { + (void) fprintf(stderr, + "can't reassign procedure number %d\n", 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((rpc_u_int32)prognum, (rpc_u_int32)versnum); + if (!svc_register(transp, (rpc_u_int32)prognum, (rpc_u_int32)versnum, + universal, IPPROTO_UDP)) { + (void) fprintf(stderr, "couldn't register prog %d vers %d\n", + prognum, versnum); + return (-1); + } + pl = (struct proglst *)malloc(sizeof(struct proglst)); + if (pl == NULL) { + (void) fprintf(stderr, "registerrpc: out of memory\n"); + 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); +} + +static void +universal(rqstp, transp) + struct svc_req *rqstp; + SVCXPRT *transp; +{ + int prog, proc; + char *outdata; + char xdrbuf[UDPMSGSIZE]; + struct proglst *pl; + + /* + * enforce "procnum 0 is echo" convention + */ + if (rqstp->rq_proc == NULLPROC) { + if (svc_sendreply(transp, xdr_void, (char *)NULL) == FALSE) { + (void) fprintf(stderr, "xxx\n"); + exit(1); + } + return; + } + prog = rqstp->rq_prog; + proc = rqstp->rq_proc; + for (pl = proglst; pl != NULL; pl = pl->p_nxt) + if (pl->p_prognum == prog && pl->p_procnum == proc) { + /* decode arguments into a CLEAN buffer */ + memset(xdrbuf, 0, sizeof(xdrbuf)); /* required ! */ + if (!svc_getargs(transp, pl->p_inproc, xdrbuf)) { + svcerr_decode(transp); + return; + } + outdata = (*(pl->p_progname))(xdrbuf); + if (outdata == NULL && pl->p_outproc != xdr_void) + /* there was an error */ + return; + if (!svc_sendreply(transp, pl->p_outproc, outdata)) { + (void) fprintf(stderr, + "trouble replying to prog %d\n", + pl->p_prognum); + exit(1); + } + /* free the decoded arguments */ + (void)svc_freeargs(transp, pl->p_inproc, xdrbuf); + return; + } + (void) fprintf(stderr, "never registered prog %d\n", prog); + exit(1); +} + diff --git a/src/lib/rpc/svc_tcp.c b/src/lib/rpc/svc_tcp.c new file mode 100644 index 000000000..e20a29b19 --- /dev/null +++ b/src/lib/rpc/svc_tcp.c @@ -0,0 +1,453 @@ +/* @(#)svc_tcp.c 2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro"; +#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 <stdio.h> +#include <rpc/rpc.h> +#include <sys/socket.h> +#include <errno.h> +#include <stdlib.h> +/*extern bool_t abort();*. +extern errno; + +/* + * 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 bool_t abortx(); +static enum xprt_stat rendezvous_stat(); + +static struct xp_ops svctcp_rendezvous_op = { + rendezvous_request, + rendezvous_stat, + abortx, + abortx, + abortx, + svctcp_destroy +}; + +static int readtcp(), writetcp(); +static SVCXPRT *makefd_xprt(); + +struct tcp_rendezvous { /* kept in xprt->xp_p1 */ + unsigned int sendsize; + unsigned int recvsize; +}; + +struct tcp_conn { /* kept in xprt->xp_p1 */ + enum xprt_stat strm_stat; + rpc_u_int32 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; + unsigned int sendsize; + unsigned int recvsize; +{ + bool_t madesock = FALSE; + register SVCXPRT *xprt; + register struct tcp_rendezvous *r; + struct sockaddr_in addr; + int len = sizeof(struct sockaddr_in); + + 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; + } + memset((char *)&addr, 0, sizeof (addr)); + 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("svc_tcp.c - cannot getsockname"); + if (madesock) + (void) close(sock); + return ((SVCXPRT *)NULL); + } + if (listen(sock, 2) != 0) { + perror("svctcp_.c - cannot 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; + unsigned int sendsize; + unsigned int recvsize; +{ + + return (makefd_xprt(fd, sendsize, recvsize)); +} + +static SVCXPRT * +makefd_xprt(fd, sendsize, recvsize) + int fd; + unsigned int sendsize; + unsigned 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; + + 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); + } + /* + * 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.) + */ +static int +readtcp(xprt, buf, len) + register SVCXPRT *xprt; + caddr_t buf; + register int len; +{ + register int sock = xprt->xp_sock; +#ifdef FD_SETSIZE + fd_set mask; + fd_set readfds; + + FD_ZERO(&mask); + FD_SET(sock, &mask); +#else + register int mask = 1 << sock; + int readfds; +#endif /* def FD_SETSIZE */ + do { + readfds = mask; + if (select(_rpc_dtablesize(), &readfds, (fd_set*)NULL, + (fd_set*)NULL, &wait_per_try) <= 0) { + if (errno == EINTR) { + continue; + } + goto fatal_err; + } +#ifdef FD_SETSIZE + } while (!FD_ISSET(sock, &readfds)); +#else + } while (readfds != mask); +#endif /* def FD_SETSIZE */ + if ((len = read(sock, buf, len)) > 0) { + return (len); + } +fatal_err: + ((struct tcp_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 +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); + } + return (FALSE); +} + +static bool_t +svctcp_getargs(xprt, xdr_args, args_ptr) + SVCXPRT *xprt; + xdrproc_t xdr_args; + caddr_t args_ptr; +{ + return (SVCAUTH_UNWRAP(xprt->xp_auth, + &(((struct tcp_conn *)(xprt->xp_p1))->xdrs), + xdr_args, 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; + + xdrproc_t xdr_results; + caddr_t xdr_location; + bool_t has_args; + + if (msg->rm_reply.rp_stat == MSG_ACCEPTED && + msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { + has_args = TRUE; + xdr_results = msg->acpted_rply.ar_results.proc; + xdr_location = msg->acpted_rply.ar_results.where; + + msg->acpted_rply.ar_results.proc = xdr_void; + msg->acpted_rply.ar_results.where = NULL; + } else + has_args = FALSE; + + xdrs->x_op = XDR_ENCODE; + msg->rm_xid = cd->x_id; + stat = FALSE; + if (xdr_replymsg(xdrs, msg) && + (!has_args || + (SVCAUTH_WRAP(xprt->xp_auth, xdrs, xdr_results, xdr_location)))) { + stat = TRUE; + } + (void)xdrrec_endofrecord(xdrs, TRUE); + return (stat); +} + +static bool_t abortx() +{ + abort(); + return 1; +} + diff --git a/src/lib/rpc/svc_udp.c b/src/lib/rpc/svc_udp.c new file mode 100644 index 000000000..d44c7f5d8 --- /dev/null +++ b/src/lib/rpc/svc_udp.c @@ -0,0 +1,496 @@ +/* @(#)svc_udp.c 2.2 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)svc_udp.c 1.24 87/08/11 Copyr 1984 Sun Micro"; +#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 <stdio.h> +#include <rpc/rpc.h> +#include <sys/socket.h> +#include <errno.h> + + +#define rpc_buffer(xprt) ((xprt)->xp_p1) +#ifndef MAX +#define MAX(a, b) ((a > b) ? a : b) +#endif + +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(); +static int cache_get(); + +static struct xp_ops svcudp_op = { + svcudp_recv, + svcudp_stat, + svcudp_getargs, + svcudp_reply, + svcudp_freeargs, + svcudp_destroy +}; + +extern int errno; + +/* + * kept in xprt->xp_p2 + */ +struct svcudp_data { + unsigned int su_iosz; /* byte size of send.recv buffer */ + rpc_u_int32 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; + unsigned 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_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; + rpc_u_int32 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 < (int) 4*sizeof(rpc_u_int32)) + 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; + + xdrproc_t xdr_results; + caddr_t xdr_location; + bool_t has_args; + + if (msg->rm_reply.rp_stat == MSG_ACCEPTED && + msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { + has_args = TRUE; + xdr_results = msg->acpted_rply.ar_results.proc; + xdr_location = msg->acpted_rply.ar_results.where; + + msg->acpted_rply.ar_results.proc = xdr_void; + msg->acpted_rply.ar_results.where = NULL; + } else + has_args = FALSE; + + xdrs->x_op = XDR_ENCODE; + XDR_SETPOS(xdrs, 0); + msg->rm_xid = su->su_xid; + if (xdr_replymsg(xdrs, msg) && + (!has_args || + (SVCAUTH_WRAP(xprt->xp_auth, xdrs, xdr_results, xdr_location)))) { + 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, (rpc_u_int32) slen); + } + } + } + return (stat); +} + +static bool_t +svcudp_getargs(xprt, xdr_args, args_ptr) + SVCXPRT *xprt; + xdrproc_t xdr_args; + caddr_t args_ptr; +{ + return (SVCAUTH_UNWRAP(xprt->xp_auth, &(su_data(xprt)->su_xdrs), + xdr_args, 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 + */ + rpc_u_int32 cache_xid; + rpc_u_int32 cache_proc; + rpc_u_int32 cache_vers; + rpc_u_int32 cache_prog; + struct sockaddr_in cache_addr; + /* + * The cached reply and length + */ + char * cache_reply; + rpc_u_int32 cache_replylen; + /* + * Next node on the list, if there is a collision + */ + cache_ptr cache_next; +}; + + + +/* + * The entire cache + */ +struct udp_cache { + rpc_u_int32 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 */ + rpc_u_int32 uc_nextvictim; /* points to next victim in fifo list */ + rpc_u_int32 uc_prog; /* saved program number */ + rpc_u_int32 uc_vers; /* saved version number */ + rpc_u_int32 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. + */ +svcudp_enablecache(transp, size) + SVCXPRT *transp; + rpc_u_int32 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; + rpc_u_int32 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; + unsigned 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; + rpc_u_int32 *replylenp; +{ + unsigned 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((char*)&a1, (char*)&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/src/lib/rpc/types.hin b/src/lib/rpc/types.hin new file mode 100644 index 000000000..619a9ce20 --- /dev/null +++ b/src/lib/rpc/types.hin @@ -0,0 +1,90 @@ +/* @(#)types.h 2.3 88/08/15 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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 + */ +/* @(#)types.h 1.18 87/07/24 SMI */ + +/* + * Rpc additions to <sys/types.h> + */ +#ifndef __TYPES_RPC_HEADER__ +#define __TYPES_RPC_HEADER__ + +#include <sys/types.h> + +/* this is a 32-bit int type */ + +#if @SIZEOF_INT@ == 4 +typedef int rpc_int32; +typedef unsigned int rpc_u_int32; +#elif @SIZEOF_LONG@ == 4 +typedef long rpc_int32; +typedef unsigned long rpc_u_int32; +#endif + +#define bool_t int +#define enum_t int +#ifndef FALSE +# define FALSE (0) +#endif +#ifndef TRUE +# define TRUE (1) +#endif +#define __dontcare__ -1 +#ifndef NULL +# define NULL 0 +#endif + +#if defined(__osf__) +#include <stdlib.h> +#endif +#define mem_alloc(bsize) (char *) malloc(bsize) +#define mem_free(ptr, bsize) free(ptr) + +#ifndef makedev /* ie, we haven't already included it */ +#include <sys/types.h> +#endif +#ifdef _AIX +#include <sys/select.h> +#endif +#include <sys/time.h> +#include <netinet/in.h> +#include <sys/param.h> +#include <netdb.h> /* XXX This should not have to be here. + * I got sick of seeing the warnings for MAXHOSTNAMELEN + * and the two values were different. -- shanzer + */ + +#ifndef INADDR_LOOPBACK +#define INADDR_LOOPBACK (rpc_u_int32)0x7F000001 +#endif +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 64 +#endif + +#endif /* ndef __TYPES_RPC_HEADER__ */ diff --git a/src/lib/rpc/unit-test/Makefile b/src/lib/rpc/unit-test/Makefile new file mode 100644 index 000000000..31853cb35 --- /dev/null +++ b/src/lib/rpc/unit-test/Makefile @@ -0,0 +1,97 @@ +# Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. +# +# $Id$ +# $Source$ +# +# $Log$ +# Revision 1.9 1996/07/22 20:41:38 marc +# this commit includes all the changes on the OV_9510_INTEGRATION and +# OV_MERGE branches. This includes, but is not limited to, the new openvision +# admin system, and major changes to gssapi to add functionality, and bring +# the implementation in line with rfc1964. before committing, the +# code was built and tested for netbsd and solaris. +# +# Revision 1.8.4.1 1996/07/18 04:20:01 marc +# merged in changes from OV_9510_BP to OV_9510_FINAL1 +# +# Revision 1.8.2.1 1996/06/20 23:41:48 marc +# File added to the repository on a branch +# +# Revision 1.8 1995/12/07 17:36:54 jik +# Use "rpc_test" instead of "rpc-test", to avoid problems with rpcgen on +# some systems. See PR 3553. +# +# Revision 1.7 1995/10/02 08:02:49 jik +# Delete rpc-tset_clnt.c, rpc-test_svc.c and rpc-test.h before creating +# them, because rpcgen on some platforms won't output to a file that +# already exists. +# +# Revision 1.6 1994/10/24 19:35:57 bjaspan +# [secure-build/2649: cannot use -L when compiling] +# +# Sandbox: +# +# [secure-build/2649] don't use -L +# +# Revision 1.7 1994/10/11 20:06:14 bjaspan +# [secure-build/2649] don't use -L +# +# Revision 1.6 1994/09/30 22:25:29 jik +# Don't need to set MDFLAGS to -a anymore, because it's done +# automatically by the rules now. +# +# Revision 1.5 1994/03/22 19:55:34 shanzer +# change NETLIBS to NETLIB +# +# Revision 1.4 1994/03/18 17:47:00 shanzer +# added NETLIBS and BSDLIB +# +# Revision 1.3 1993/12/13 02:00:39 bjaspan +# recurse to testsuite subdir. +# +# Revision 1.2 1993/12/08 21:45:47 bjaspan +# misc +# +# Revision 1.1 1993/11/03 23:53:58 bjaspan +# Initial revision +# + +TOP = ../.. +include $(TOP)/config.mk/template + +SUBDIRS = testsuite + +expand SubdirTarget + +SRCS = client.c server.c + +CFLAGS := -I../.. -I. $(CFLAGS) + +#LIBS = ../librpclib.a $(LIBGSSAPI_TRUST) $(LIBDB) $(LIBCOM_ERR) $(LIBDYN) +LIBS = ../librpclib.a $(LIBGSSAPI_KRB5) $(LIBDB) $(LIBKRB5) \ + $(LIBCRYPTO) $(LIBISODE) $(LIBCOM_ERR) $(LIBDYN) $(BSDLIB) $(NETLIB) +DEPS = ../librpclib.a rpc_test.h +DEPENDS = rpc_test.h + +PROG = client +SRCS = client.c +OBJS = client.o rpc_test_clnt.o + +expand Program +expand Depend + +PROG = server +SRCS = server.c +OBJS = server.o rpc_test_svc.o + +expand Program +expand Depend + +rpc_test.h rpc_test_clnt.c rpc_test_svc.c: rpc_test.x + -rm -f rpc_test_clnt.c rpc_test_svc.c rpc_test.h + rpcgen -l rpc_test.x -o rpc_test_clnt.c + rpcgen -m rpc_test.x -o rpc_test_svc.c + rpcgen -h rpc_test.x -o rpc_test.h + +clean:: + rm -f rpc_test.h rpc_test_clnt.c rpc_test_svc.c diff --git a/src/lib/rpc/unit-test/client.c b/src/lib/rpc/unit-test/client.c new file mode 100644 index 000000000..bcf2700e5 --- /dev/null +++ b/src/lib/rpc/unit-test/client.c @@ -0,0 +1,320 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. + * + * $Id$ + * $Source$ + * + * $Log$ + * Revision 1.13 1996/07/22 20:41:40 marc + * this commit includes all the changes on the OV_9510_INTEGRATION and + * OV_MERGE branches. This includes, but is not limited to, the new openvision + * admin system, and major changes to gssapi to add functionality, and bring + * the implementation in line with rfc1964. before committing, the + * code was built and tested for netbsd and solaris. + * + * Revision 1.12.4.1 1996/07/18 04:20:03 marc + * merged in changes from OV_9510_BP to OV_9510_FINAL1 + * + * Revision 1.12.2.1 1996/06/20 23:41:56 marc + * File added to the repository on a branch + * + * Revision 1.12 1996/05/12 06:58:10 marc + * type renamings for compatibility with beta6 + * + * Revision 1.11 1996/02/12 15:58:42 grier + * [secure/3570] + * long conversion + * + * Revision 1.10 1995/12/07 17:37:03 jik + * Use "rpc_test" instead of "rpc-test", to avoid problems with rpcgen on + * some systems. See PR 3553. + * + * Revision 1.9 1994/09/21 18:38:56 bjaspan + * [secure-rpc/2536: unit test client.c: memory initialization and out-of-bounds reference bugs] + * [secure-releng/2537: audit secure-rpc/2536: minor memory problems in unit-test client] + * + * Sandbox: + * + * 1. Don't allow the count specifie on the command line to be bigger + * than the size of the buffer use for testing. + * 2. When initializing the buffer for the lengths test, initialize it to + * count bytes. + * + * Revision 1.9 1994/09/19 01:28:04 root + * 1. Don't allow the count specifie on the command line to be bigger + * than the size of the buffer use for testing. + * 2. When initializing the buffer for the lengths test, initialize it to + * count bytes. + * + * Revision 1.8 1994/04/06 22:13:01 jik + * Change -auth_once to -o, add -a, -m and -s arguments to set + * auth_debug_gssapi, svc_debug_gssapi and misc_debug_gssapi variables. + * + * Revision 1.7 1994/04/05 20:50:09 bjaspan + * fix typo that causes coredump when server blocks/fails + * + * Revision 1.6 1993/12/08 21:44:45 bjaspan + * test fix for secure-rpc/586, improve arg handlng + * + * Revision 1.5 1993/12/06 21:23:30 bjaspan + * accept count arg for RPC_TEST_LENGTHS + * + * Revision 1.4 1993/12/01 23:41:45 bjaspan + * don't free echo_resp if call fails + * + * Revision 1.3 1993/11/15 19:53:09 bjaspan + * test auto-syncrhonization + * + * Revision 1.2 1993/11/12 02:33:43 bjaspan + * use clnt_pcreateerror for auth failures + * + * Revision 1.1 1993/11/03 23:53:58 bjaspan + * Initial revision + * + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +#include <stdio.h> +#include <rpc/rpc.h> +#include <gssapi/gssapi.h> +#include <rpc/rpc.h> +#include <rpc/auth_gssapi.h> +#include "rpc_test.h" + +#define BIG_BUF 4096 +/* copied from auth_gssapi.c for hackery */ +struct auth_gssapi_data { + bool_t established; + CLIENT *clnt; + gss_ctx_id_t context; + gss_buffer_desc client_handle; + OM_uint32 seq_num; + int def_cred; + + /* pre-serialized ah_cred */ + u_char cred_buf[MAX_AUTH_BYTES]; + rpc_int32 cred_len; +}; +#define AUTH_PRIVATE(auth) ((struct auth_gssapi_data *)auth->ah_private) + +extern int auth_debug_gssapi; +char *whoami; + +main(argc, argv) + int argc; + char **argv; +{ + char *host, *target, *echo_arg, **echo_resp, buf[BIG_BUF]; + CLIENT *clnt; + AUTH *tmp_auth; + struct rpc_err e; + int i, count, auth_once; + extern int optind; + extern char *optarg; + extern int svc_debug_gssapi, misc_debug_gssapi, auth_debug_gssapi; + int c; + + whoami = argv[0]; + count = 1026; + auth_once = 0; + + while ((c = getopt(argc, argv, "a:m:os:")) != -1) { + switch (c) { + case 'a': + auth_debug_gssapi = atoi(optarg); + break; + case 'm': + misc_debug_gssapi = atoi(optarg); + break; + case 'o': + auth_once++; + break; + case 's': + svc_debug_gssapi = atoi(optarg); + break; + case '?': + usage(); + break; + } + } + + argv += optind; + argc -= optind; + + switch (argc) { + case 3: + count = atoi(argv[2]); + if (count > BIG_BUF) { + fprintf(stderr, "Test count cannot exceed %d.\n", BIG_BUF); + usage(); + } + case 2: + host = argv[0]; + target = argv[1]; + break; + default: + usage(); + } + + /* client handle to rstat */ + clnt = clnt_create(host, RPC_TEST_PROG, RPC_TEST_VERS_1, "tcp"); + if (clnt == NULL) { + clnt_pcreateerror(whoami); + exit(1); + } + + clnt->cl_auth = auth_gssapi_create_default(clnt, target); + if (clnt->cl_auth == NULL) { + clnt_pcreateerror(whoami); + exit(2); + } + + /* + * Call the echo service multiple times. + */ + echo_arg = buf; + for (i = 0; i < 3; i++) { + sprintf(buf, "testing %d\n", i); + + echo_resp = rpc_test_echo_1(&echo_arg, clnt); + if (echo_resp == NULL) { + fprintf(stderr, "RPC_TEST_ECHO call %d%s", i, + clnt_sperror(clnt, "")); + } + if (strncmp(*echo_resp, "Echo: ", 6) && + strcmp(echo_arg, (*echo_resp) + 6) != 0) + fprintf(stderr, "RPC_TEST_ECHO call %d response wrong: " + "arg = %s, resp = %s\n", echo_arg, *echo_resp); + xdr_free(xdr_wrapstring, echo_resp); + } + + /* + * Make a call with an invalid verifier and check for error; + * server should log error message. It is important to + *increment* seq_num here, since a decrement would be fixed (see + * below). Note that seq_num will be incremented (by + * authg_gssapi_refresh) twice, so we need to decrement by three + * to reset. + */ + AUTH_PRIVATE(clnt->cl_auth)->seq_num++; + + echo_arg = "testing with bad verf"; + + echo_resp = rpc_test_echo_1(&echo_arg, clnt); + if (echo_resp == NULL) { + CLNT_GETERR(clnt, &e); + if (e.re_status != RPC_AUTHERROR || e.re_why != AUTH_REJECTEDVERF) + clnt_perror(clnt, whoami); + } else { + fprintf(stderr, "bad seq didn't cause failure\n"); + } + + AUTH_PRIVATE(clnt->cl_auth)->seq_num -= 3; + + /* + * Make sure we're resyncronized. + */ + echo_arg = "testing for reset"; + echo_resp = rpc_test_echo_1(&echo_arg, clnt); + if (echo_resp == NULL) + clnt_perror(clnt, "Sequence number improperly reset"); + + /* + * Now simulate a lost server response, and see if + * auth_gssapi_refresh recovers. + */ + AUTH_PRIVATE(clnt->cl_auth)->seq_num--; + echo_arg = "forcing auto-resynchronization"; + echo_resp = rpc_test_echo_1(&echo_arg, clnt); + if (echo_resp == NULL) + clnt_perror(clnt, "Auto-resynchronization failed"); + + /* + * Now make sure auto-resyncrhonization actually worked + */ + echo_arg = "testing for resynchronization"; + echo_resp = rpc_test_echo_1(&echo_arg, clnt); + if (echo_resp == NULL) + clnt_perror(clnt, "Auto-resynchronization did not work"); + + /* + * Test fix for secure-rpc/586, part 1: btree keys must be + * unique. Create another context from the same credentials; it + * should have the same expiration time and will cause the server + * to abort if the clients are not differentiated. + * + * Test fix for secure-rpc/586, part 2: btree keys cannot be + * mutated in place. To test this: a second client, *with a + * later expiration time*, must be run. The second client should + * destroy itself *after* the first one; if the key-mutating bug + * is not fixed, the second client_data will be in the btree + * before the first, but its key will be larger; thus, when the + * first client calls AUTH_DESTROY, the server won't find it in + * the btree and call abort. + * + * For unknown reasons, running just a second client didn't + * tickle the bug; the btree code seemed to guess which node to + * look at first. Running a total of three clients does ticket + * the bug. Thus, the full test sequence looks like this: + * + * kinit -l 20m user && client server test@ddn 200 + * sleep 1 + * kini -l 30m user && client server test@ddn 300 + * sleep 1 + * kinit -l 40m user && client server test@ddn 400 + */ + if (! auth_once) { + tmp_auth = clnt->cl_auth; + clnt->cl_auth = auth_gssapi_create_default(clnt, target); + if (clnt->cl_auth == NULL) { + clnt_pcreateerror(whoami); + exit(2); + } + AUTH_DESTROY(clnt->cl_auth); + clnt->cl_auth = tmp_auth; + } + + /* + * Try RPC calls with argument/result lengths [0, 1025]. Do + * this last, since it takes a while.. + */ + echo_arg = buf; + memset(buf, 0, count); + for (i = 0; i < count; i++) { + echo_resp = rpc_test_echo_1(&echo_arg, clnt); + if (echo_resp == NULL) { + fprintf(stderr, "RPC_TEST_LENGTHS call %d%s", i, + clnt_sperror(clnt, "")); + break; + } else { + if (strncmp(*echo_resp, "Echo: ", 6) && + strcmp(echo_arg, (*echo_resp) + 6) != 0) + fprintf(stderr, + "RPC_TEST_LENGTHS call %d response wrong\n"); + xdr_free(xdr_wrapstring, echo_resp); + } + + /* cycle from 1 to 255 */ + buf[i] = (i % 255) + 1; + + if (i % 100 == 0) { + fputc('.', stdout); + fflush(stdout); + } + } + fputc('\n', stdout); + + AUTH_DESTROY(clnt->cl_auth); + CLNT_DESTROY(clnt); + exit(0); +} + +usage() +{ + fprintf(stderr, "usage: %s [-a] [-s num] [-m num] host service [count]\n", + whoami); + exit(1); +} diff --git a/src/lib/rpc/unit-test/rpc_test.x b/src/lib/rpc/unit-test/rpc_test.x new file mode 100644 index 000000000..e9ae27c97 --- /dev/null +++ b/src/lib/rpc/unit-test/rpc_test.x @@ -0,0 +1,30 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. + * + * $Id$ + * $Source$ + * + * $Log$ + * Revision 1.2 1996/07/22 20:41:42 marc + * this commit includes all the changes on the OV_9510_INTEGRATION and + * OV_MERGE branches. This includes, but is not limited to, the new openvision + * admin system, and major changes to gssapi to add functionality, and bring + * the implementation in line with rfc1964. before committing, the + * code was built and tested for netbsd and solaris. + * + * Revision 1.1.4.1 1996/07/18 04:20:04 marc + * merged in changes from OV_9510_BP to OV_9510_FINAL1 + * +# Revision 1.1.2.1 1996/06/20 23:42:06 marc +# File added to the repository on a branch +# +# Revision 1.1 1993/11/03 23:53:58 bjaspan +# Initial revision +# + */ + +program RPC_TEST_PROG { + version RPC_TEST_VERS_1 { + string RPC_TEST_ECHO(string) = 1; + } = 1; +} = 1000001; diff --git a/src/lib/rpc/unit-test/server.c b/src/lib/rpc/unit-test/server.c new file mode 100644 index 000000000..d98b2df0b --- /dev/null +++ b/src/lib/rpc/unit-test/server.c @@ -0,0 +1,306 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. + * + * $Id$ + * $Source$ + * + * $Log$ + * Revision 1.15 1996/07/22 20:41:44 marc + * this commit includes all the changes on the OV_9510_INTEGRATION and + * OV_MERGE branches. This includes, but is not limited to, the new openvision + * admin system, and major changes to gssapi to add functionality, and bring + * the implementation in line with rfc1964. before committing, the + * code was built and tested for netbsd and solaris. + * + * Revision 1.14.4.1 1996/07/18 04:20:06 marc + * merged in changes from OV_9510_BP to OV_9510_FINAL1 + * + * Revision 1.14.2.1 1996/06/20 23:42:16 marc + * File added to the repository on a branch + * + * Revision 1.14 1996/05/12 06:59:06 marc + * change SERVICE_NAME to "host" instead of "server" + * + * remove KRB5KTNAME support, since the library supports it internally now. + * + * Revision 1.13 1995/12/07 17:36:58 jik + * Use "rpc_test" instead of "rpc-test", to avoid problems with rpcgen on + * some systems. See PR 3553. + * + * Revision 1.12 1995/11/07 23:20:44 grier + * Add stdlib.h + * Add string.h + * + * Revision 1.11 1995/03/24 19:55:28 jik + * Cast a const gss_OID to (gss_OID) to prevent a compiler warning. + * + * Revision 1.10 1995/02/22 15:54:17 jik + * I was a moron in revision 1.8. This is the server function, not the + * client function, so it gets a struct svc_req *, not a CLIENT *. + * + * Revision 1.9 1995/02/22 15:21:51 jik + * Linux's rpcgen names the server function differently from the client + * function ("_svc" is appended to the end of it). + * + * Revision 1.8 1995/02/22 14:35:05 jik + * RPC server functions have CLIENT * passed into them, so I added it as + * an argument to rpc_test_echo_1. + * + * Revision 1.7 1994/09/21 18:35:57 bjaspan + * [gssapi/438: gss_nt_service_name should default to local host] + * [secure-releng/2513: audit gssapi/438: gss_nt_service_name should default to local host] + * + * Sandbox: + * + * Don't need to get local host name and put it in the service name, + * since the gssapi library does that now. See PR 438. + * + * Revision 1.8 1994/09/01 17:21:59 jik + * Don't need to get local host name and put it in the service name, + * since the gssapi library does that now. See PR 438. + * + * Revision 1.7 1994/04/08 17:22:11 bjaspan + * add KRB5KTNAME hack so unit tests continue to work + * + * Revision 1.6 1994/04/05 20:50:26 bjaspan + * print "running" when ready to tests can proceed + * + * Revision 1.5 1994/04/05 19:49:54 jik + * Use host name instead of localhost. + * + * Revision 1.4 1994/03/08 00:14:58 shanzer + * changed call to inet_ntoa + * + * Revision 1.3 1993/12/13 01:37:54 bjaspan + * update for new test system + * ,. + * + * Revision 1.2 1993/12/08 21:45:16 bjaspan + * display badauth errors, improve arg handling + * + * Revision 1.1 1993/11/03 23:53:58 bjaspan + * Initial revision + * + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <rpc/rpc.h> +#include <arpa/inet.h> /* inet_ntoa */ +#include <gssapi/gssapi.h> +#include <gssapi/gssapi_generic.h> +#include <rpc/auth_gssapi.h> +#include <sys/param.h> /* MAXHOSTNAMELEN */ +#include "rpc_test.h" + +#ifdef linux +/* + For some reason, Linux's rpcgen names the server function + differently from the client function. I suppose this is useful if + you want to include them both in the same library or something, but + not useful at all if you want to link the client code directly to + the server code for testing, instead of going through the RPC layer. + */ +#define rpc_test_echo_1 rpc_test_echo_1_svc +#endif + +extern void rpc_test_prog_1(); + +extern int svc_debug_gssapi, misc_debug_gssapi; + +void rpc_test_badauth(OM_uint32 major, OM_uint32 minor, + struct sockaddr_in *addr, void *data); +void log_badauth_display_status(OM_uint32 major, OM_uint32 minor); +void log_badauth_display_status_1(OM_uint32 code, int type, int rec); +static void rpc_test_badverf(gss_name_t client, gss_name_t server, + struct svc_req *rqst, struct rpc_msg *msg, + caddr_t data); + +#ifndef SERVICE_NAME +#define SERVICE_NAME "host" +#endif + +main(int argc, char **argv) +{ + auth_gssapi_name names[2]; + register SVCXPRT *transp; + + names[0].name = SERVICE_NAME; + names[0].type = (gss_OID) gss_nt_service_name; + names[1].name = 0; + names[1].type = 0; + + switch (argc) { + case 3: + misc_debug_gssapi = atoi(argv[2]); + case 2: + svc_debug_gssapi = atoi(argv[1]); + case 1: + break; + default: + fprintf(stderr, "Usage: server [svc-debug] [misc-debug]\n"); + exit(1); + } + + (void) pmap_unset(RPC_TEST_PROG, RPC_TEST_VERS_1); + + transp = svctcp_create(RPC_ANYSOCK, 0, 0); + if (transp == NULL) { + fprintf(stderr, "cannot create tcp service."); + exit(1); + } + if (!svc_register(transp, RPC_TEST_PROG, RPC_TEST_VERS_1, + rpc_test_prog_1, IPPROTO_TCP)) { + fprintf(stderr, + "unable to register (RPC_TEST_PROG, RPC_TEST_VERS_1, tcp)."); + exit(1); + } + + if (_svcauth_gssapi_set_names(names, 0) == FALSE) { + fprintf(stderr, "unable to set gssapi names\n"); + exit(1); + } + + _svcauth_gssapi_set_log_badauth_func(rpc_test_badauth, NULL); + _svcauth_gssapi_set_log_badverf_func(rpc_test_badverf, NULL); + + printf("running\n"); + + svc_run(); + fprintf(stderr, "svc_run returned"); + exit(1); + /* NOTREACHED */ +} + +char **rpc_test_echo_1(char **arg, struct svc_req *h) +{ + static char *res = NULL; + + if (res) + free(res); + res = (char *) malloc(strlen(*arg) + strlen("Echo: ") + 1); + sprintf(res, "Echo: %s", *arg); + return &res; +} + +static void rpc_test_badverf(gss_name_t client, gss_name_t server, + struct svc_req *rqst, struct rpc_msg *msg, + caddr_t data) +{ + OM_uint32 minor_stat; + gss_OID type; + gss_buffer_desc client_name, server_name; + + (void) gss_display_name(&minor_stat, client, &client_name, &type); + (void) gss_display_name(&minor_stat, server, &server_name, &type); + + printf("rpc_test server: bad verifier from %s at %s:%d for %s\n", + client_name.value, + inet_ntoa(rqst->rq_xprt->xp_raddr.sin_addr), + ntohs(rqst->rq_xprt->xp_raddr.sin_port), + server_name.value); + + (void) gss_release_buffer(&minor_stat, &client_name); + (void) gss_release_buffer(&minor_stat, &server_name); +} + +/* + * Function: log_badauth + * + * Purpose: Callback from GSS-API Sun RPC for authentication + * failures/errors. + * + * Arguments: + * major (r) GSS-API major status + * minor (r) GSS-API minor status + * addr (r) originating address + * data (r) arbitrary data (NULL), not used + * + * Effects: + * + * Logs the GSS-API error to stdout. + */ +void rpc_test_badauth(OM_uint32 major, OM_uint32 minor, + struct sockaddr_in *addr, void *data) +{ + char *a; + + /* Authentication attempt failed: <IP address>, <GSS-API error */ + /* strings> */ + + a = inet_ntoa(addr->sin_addr); + + printf("rpc_test server: Authentication attempt failed: %s", a); + log_badauth_display_status(major, minor); + printf("\n"); +} + +void log_badauth_display_status(OM_uint32 major, OM_uint32 minor) +{ + log_badauth_display_status_1(major, GSS_C_GSS_CODE, 0); + log_badauth_display_status_1(minor, GSS_C_MECH_CODE, 0); +} + +void log_badauth_display_status_1(OM_uint32 code, int type, int rec) +{ + OM_uint32 gssstat, minor_stat; + gss_buffer_desc msg; + int msg_ctx; + + msg_ctx = 0; + while (1) { + gssstat = gss_display_status(&minor_stat, code, + type, GSS_C_NULL_OID, + &msg_ctx, &msg); + if (gssstat != GSS_S_COMPLETE) { + if (!rec) { + log_badauth_display_status_1(gssstat,GSS_C_GSS_CODE,1); + log_badauth_display_status_1(minor_stat, + GSS_C_MECH_CODE, 1); + } else + printf("GSS-API authentication error %s: " + "recursive failure!\n", msg); + return; + } + + printf(", %s", (char *)msg.value); + (void) gss_release_buffer(&minor_stat, &msg); + + if (!msg_ctx) + break; + } +} + + +#if 0 + +/* this hack is no longer necessary, since the library supports it + internally */ + +/* This is a hack to change the default keytab name */ + +#include <krb5/krb5.h> +extern char *krb5_defkeyname; + +krb5_error_code +krb5_kt_default_name(char *name, int namesize) +{ + char *ktname; + + if ((ktname = getenv("KRB5KTNAME")) == NULL) + ktname = krb5_defkeyname; + + if (namesize < strlen(ktname)+1) + return(KRB5_CONFIG_NOTENUFSPACE); + + strcpy(name, ktname); + + return(0); +} + +#endif diff --git a/src/lib/rpc/unit-test/testsuite/Makefile b/src/lib/rpc/unit-test/testsuite/Makefile new file mode 100644 index 000000000..8a2cccdc2 --- /dev/null +++ b/src/lib/rpc/unit-test/testsuite/Makefile @@ -0,0 +1,24 @@ +# +# $Id$ +# + +TOP = ../../.. +include $(TOP)/config.mk/template + +export RPC_TEST_SRVTAB := /tmp/rpc_test_v5srvtab + +unit-test:: unit-test-setup unit-test-body unit-test-cleanup + +unit-test-setup:: + $(START_SERVERS) + ./rpc_test_setup.sh + +unit-test-body:: + $(RUNTEST) SERVER=../server CLIENT=../client --tool rpc_test + +unit-test-cleanup:: + $(STOP_SERVERS) + -rm -f /tmp/rpc_test_v5srvtab /tmp/krb5cc_rpc_test_fullrun + +clean:: + $(CLEAN) rpc_test.log rpc_test.plog rpc_test.sum rpc_test.psum diff --git a/src/lib/rpc/unit-test/testsuite/config/unix.exp b/src/lib/rpc/unit-test/testsuite/config/unix.exp new file mode 100644 index 000000000..030837d49 --- /dev/null +++ b/src/lib/rpc/unit-test/testsuite/config/unix.exp @@ -0,0 +1,79 @@ +# +# $Id$ +# + +set kill /bin/kill +set sleep /bin/sleep +set kinit $env(TOP)/install/bin/kinit +set kdestroy $env(TOP)/install/bin/kdestroy + +set hostname [exec hostname] + +proc rpc_test_version {} { + global CLIENT + global SERVER + + clone_output "$CLIENT version <unknown>" + clone_output "$SERVER version <unknown>" +} + +proc rpc_test_load {} { + # +} + +# rpc_test_exit -- clean up and exit +proc rpc_test_exit {} { + global server_id + global server_pid + global server_started + global kill + + if {[catch { + expect { + -i $server_id + eof { + fail "server exited!" + verbose $expect_out(buffer) 1 + } + timeout { pass "server survived" } + } + } tmp]} { + fail "server exited! (expect failed)" + } +} + +# +# rpc_test_start -- start the rpc_test server running +# +proc rpc_test_start { } { + global SERVER + global server_id + global server_pid + global server_started + global env + + set env(KRB5KTNAME) FILE:$env(RPC_TEST_SRVTAB) + + verbose "% $SERVER" 1 + set server_pid [spawn $SERVER] + set server_id $spawn_id + + unset env(KRB5KTNAME) + + set timeout 30 + + expect { + "running" { } + eof { + fail "server exited!" + verbose $expect_out(buffer) 1 + } + timeout { + fail "server didn't start in $timeout seconds" + verbose $expect_out(buffer) 1 + } + } + +} + +rpc_test_start diff --git a/src/lib/rpc/unit-test/testsuite/helpers.exp b/src/lib/rpc/unit-test/testsuite/helpers.exp new file mode 100644 index 000000000..1a37ad512 --- /dev/null +++ b/src/lib/rpc/unit-test/testsuite/helpers.exp @@ -0,0 +1,128 @@ +if {[info commands exp_version] != {}} { + set exp_version_4 [regexp {^4} [exp_version]] +} else { + set exp_version_4 [regexp {^4} [expect_version]] +} + +# Backward compatibility until we're using expect 5 everywhere +if {$exp_version_4} { + global wait_error_index wait_errno_index wait_status_index + set wait_error_index 0 + set wait_errno_index 1 + set wait_status_index 1 +} else { + set wait_error_index 2 + set wait_errno_index 3 + set wait_status_index 3 +} + + +proc kinit {princ pass lifetime} { + global kinit + global wait_error_index wait_errno_index wait_status_index + + spawn -noecho $kinit -l $lifetime $princ + expect { + -re "Password for $princ.*: " { send "$pass\n" } + timeout { error "Timeout waiting for kinit"; close } + } + expect { eof {} } + + set ret [wait] + if {[lindex $ret $wait_error_index] == -1} { + error \ + "wait(kinit $princ) returned error [lindex $ret $wait_errno_index]" + } else { + if {[lindex $ret $wait_status_index] != 0} { + error \ + "kinit $princ failed with [lindex $ret $wait_status_index]" + } + } +} + +proc flush_server {} { + global server_id + global expect_out + + verbose "flushing server output" 1 + + while {1} { + set timeout 5 + + expect { + -i $server_id + -re "^.+$" { + verbose "server output: $expect_out(buffer)" + } + timeout { break } + } + } +} + +proc start_client {testname ccname user password lifetime count + {target ""}} { + global env + global CLIENT + global hostname + global spawn_id + global verbose + + if {$target == ""} { + set target "server@$hostname" + } + + set env(KRB5CCNAME) FILE:/tmp/krb5cc_rpc_test_$ccname + kinit $user $password $lifetime + + if {$verbose > 0} { + spawn $CLIENT -a 1 -s 1 -m 1 $hostname $target $count + } else { + spawn $CLIENT $hostname $target $count + } + + verbose "$testname: client $ccname started" + + unset env(KRB5CCNAME) +} + +proc eof_client {testname ccname id status} { + verbose "$testname: eof'ing for client $ccname" 1 + + expect { + -i $id + eof { verbose $expect_out(buffer) 1 } + timeout { + fail "$testname: timeout waiting for client $ccname to exit" + } + } + wait_client $testname $ccname $id $status +} + + +proc wait_client {testname ccname id status} { + global env + global kill + global kdestroy + global wait_error_index wait_errno_index wait_status_index + + verbose "$testname: waiting for client $ccname" 1 + + set ret [wait -i $id] + if {[lindex $ret $wait_error_index] == -1} { + fail \ + "$testname: wait $ccname returned error [lindex $ret $wait_errno_index]" + } else { + if {[lindex $ret $wait_status_index] == $status} { + pass "$testname: client $ccname" + } else { + fail "$testname: client $ccname: unexpected return status [lindex $ret $wait_status_index], should be $status." + } + } + + set env(KRB5CCNAME) FILE:/tmp/krb5cc_rpc_test_$ccname + if {[catch "exec $kdestroy"] != 0} { + error "$testname: cannot destroy client $ccname ccache" + } + + unset env(KRB5CCNAME) +} diff --git a/src/lib/rpc/unit-test/testsuite/rpc_test.0/expire.exp b/src/lib/rpc/unit-test/testsuite/rpc_test.0/expire.exp new file mode 100644 index 000000000..d80bae6da --- /dev/null +++ b/src/lib/rpc/unit-test/testsuite/rpc_test.0/expire.exp @@ -0,0 +1,21 @@ +set timeout 40 + +load_lib "helpers.exp" + +global spawn_id + +start_client expire 1 testuser notathena 20m 100 +set client1_id $spawn_id +flush_server + +start_client expire 2 testuser notathena 40m 300 +set client2_id $spawn_id +flush_server + +start_client expire 3 testuser notathena 60m 500 +set client3_id $spawn_id +flush_server + +eof_client expire 1 $client1_id 0 +eof_client expire 2 $client2_id 0 +eof_client expire 3 $client3_id 0 diff --git a/src/lib/rpc/unit-test/testsuite/rpc_test.0/fullrun.exp b/src/lib/rpc/unit-test/testsuite/rpc_test.0/fullrun.exp new file mode 100644 index 000000000..6e8acf80e --- /dev/null +++ b/src/lib/rpc/unit-test/testsuite/rpc_test.0/fullrun.exp @@ -0,0 +1,95 @@ +set timeout 120 + +load_lib "helpers.exp" + +global spawn_id +global server_id + +# Start the client and do a full run +start_client "full run" fullrun testuser notathena 8 1026 +set client_id $spawn_id + +# +# test: did we get 11 dots? +# +verbose "Starting RPC echo test. This will take about 50 seconds.\n" + +set ver_line "rpc_test server: bad verifier\[^\r\n\]*\n" + +set dots 0 +set server_lines 0 +while {1} { + set oldtimeout $timeout + set timeout 5 + while {1} { + expect { + -i $server_id + -re $ver_line { + verbose "Got line from server." + incr server_lines + } + default { + break + } + } + } + set timeout $oldtimeout + expect { + -i $client_id + . { + incr dots + verbose "$expect_out(buffer)" 1 + if ($dots==11) { break } + } + eof { + # + # test: was the exit status right? + # + wait_client "full run" fullrun $client_id 0 + break + } + + timeout { + verbose "Timeout waiting for dot\n" 1 + fail "full run: timeout waiting for dot" + break + } + + } +} +if {$dots==11} { + pass "fullrun: echo test" +} else { + fail "fullrun: echo test: expected 11 dots, got $dots" +} + +# +# test: server logged four bad verifiers? +# +verbose "full run: checking server output" + +# Small timeout, since the server should have already printed everything +set timeout 5 + +while {$server_lines < 4} { + expect { + -i $server_id + -re $ver_line { + incr server_lines + } + -re ".+\r\n" { + verbose "Unexpected server output: $expect_out(buffer)" + } + default { + break + } + } +} + +if {$server_lines == 4} { + pass "fullrun: bad verifiers" +} else { + fail "fullrun: expected four bad verifiers, got $server_lines" +} + +flush_server diff --git a/src/lib/rpc/unit-test/testsuite/rpc_test.0/gsserr.exp b/src/lib/rpc/unit-test/testsuite/rpc_test.0/gsserr.exp new file mode 100644 index 000000000..f9d53052d --- /dev/null +++ b/src/lib/rpc/unit-test/testsuite/rpc_test.0/gsserr.exp @@ -0,0 +1,27 @@ +set timeout 30 + +load_lib "helpers.exp" + +global spawn_id +global server_id +global hostname + +start_client "gss err" gsserr testuser notathena 8 1026 notserver@$hostname + +eof_client "gss err" gsserr $spawn_id 2 + +# +# test: server logged an authentication attempted failed? +# +verbose "gss err: checking server output" + +expect { + -i $server_id + -re "rpc_test server: Authent.*failed: .* Wrong princ" { + pass "gss err: server logged auth error" + } + eof { fail "gss err: server exited" } + timeout { fail "gss err: timeout waiting for server output" } +} + +flush_server diff --git a/src/lib/rpc/unit-test/testsuite/rpc_test_setup.sh b/src/lib/rpc/unit-test/testsuite/rpc_test_setup.sh new file mode 100644 index 000000000..2a97af4d3 --- /dev/null +++ b/src/lib/rpc/unit-test/testsuite/rpc_test_setup.sh @@ -0,0 +1,56 @@ +#!/bin/sh +# +# This script performs additional setup for the RPC unit test. It +# assumes that gmake has put TOP and RPC_TEST_SRVTAB into the +# environment. +# +# $Id$ +# $Source$ + +DUMMY=${TESTDIR=$TOP/testing} +DUMMY=${CLNTTCL=$TESTDIR/util/ovsec_kadm_clnt_tcl} +DUMMY=${TCLUTIL=$TESTDIR/tcl/util.t}; export TCLUTIL +DUMMY=${MAKE_KEYTAB=$TESTDIR/scripts/make-host-keytab.pl} + +# If it's set, set it to true +VERBOSE=${VERBOSE_TEST:+true} +# Otherwise, set it to false +DUMMY=${VERBOSE:=false} + +if $VERBOSE; then + REDIRECT= +else + REDIRECT='>/dev/null' +fi + +PATH=$TOP/install/admin:$PATH; export PATH + +CANON_HOST=`perl -e 'chop($_=\`hostname\`);($n,$a,$t,$l,@a)=gethostbyname($_);($_)=gethostbyaddr($a[0],$t); print;'` +export CANON_HOST + +eval $CLNTTCL <<'EOF' $REDIRECT +source $env(TCLUTIL) +set h $env(CANON_HOST) +puts stdout [ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 server_handle] +puts stdout [ovsec_kadm_create_principal $server_handle [simple_principal server/$h] {OVSEC_KADM_PRINCIPAL} admin] +puts stdout [ovsec_kadm_randkey_principal $server_handle server/$h key] +puts stdout [ovsec_kadm_create_principal $server_handle [simple_principal notserver/$h] {OVSEC_KADM_PRINCIPAL} admin] +puts stdout [ovsec_kadm_randkey_principal $server_handle notserver/$h key] +puts stdout [ovsec_kadm_destroy $server_handle] +EOF + +rm -f $RPC_TEST_SRVTAB + +eval $MAKE_KEYTAB -princ server/$CANON_HOST $RPC_TEST_SRVTAB $REDIRECT + +grep -s "$CANON_HOST SECURE-TEST.OV.COM" /etc/krb.realms +if [ $? != 0 ]; then + eval echo \"Adding \$CANON_HOST SECURE-TEST.OV.COM to /etc/krb.realms\" $REDIRECT + ed /etc/krb.realms <<EOF >/dev/null +1i +$CANON_HOST SECURE-TEST.OV.COM +. +w +q +EOF +fi diff --git a/src/lib/rpc/xdr.c b/src/lib/rpc/xdr.c new file mode 100644 index 000000000..7f4418162 --- /dev/null +++ b/src/lib/rpc/xdr.c @@ -0,0 +1,674 @@ +/* @(#)xdr.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)xdr.c 1.35 87/08/12"; +#endif + +/* + * xdr.c, Generic XDR routines implementation. + * + * Copyright (C) 1986, Sun Microsystems, Inc. + * + * These are the "generic" xdr routines used to serialize and de-serialize + * most common data items. See xdr.h for more info on the interface to + * xdr. + */ + +#include <stdio.h> +#include <string.h> +char *malloc(); + +#include <rpc/types.h> +#include <rpc/xdr.h> + +/* + * constants specific to the xdr "protocol" + */ +#define XDR_FALSE ((rpc_int32) 0) +#define XDR_TRUE ((rpc_int32) 1) +#define LASTUNSIGNED ((unsigned int) 0-1) + +/* + * for unit alignment + */ +static char xdr_zero[BYTES_PER_XDR_UNIT] = { 0, 0, 0, 0 }; + +/* + * Free a data structure using XDR + * Not a filter, but a convenient utility nonetheless + */ +void +xdr_free(proc, objp) + xdrproc_t proc; + char *objp; +{ + XDR x; + + x.x_op = XDR_FREE; + (*proc)(&x, objp); +} + +/* + * XDR nothing + */ +bool_t +xdr_void(/* xdrs, addr */) + /* XDR *xdrs; */ + /* caddr_t addr; */ +{ + + return (TRUE); +} + +/* + * XDR integers + */ +bool_t +xdr_int(xdrs, ip) + XDR *xdrs; + int *ip; +{ + +#ifdef lint + (void) (xdr_short(xdrs, (short *)ip)); + return (xdr_long(xdrs, (rpc_int32 *)ip)); +#else + if (sizeof (int) >= 4) { + long l; + switch (xdrs->x_op) { + case XDR_ENCODE: + l = *ip; + return (xdr_long(xdrs, &l)); + + case XDR_DECODE: + if (!xdr_long(xdrs, &l)) { + return (FALSE); + } + *ip = l; + return (TRUE); + + case XDR_FREE: + return (TRUE); + } + } else { + return (xdr_short(xdrs, (short *)ip)); + } +#endif +} + +/* + * XDR unsigned integers + */ +bool_t +xdr_u_int(xdrs, up) + XDR *xdrs; + unsigned int *up; +{ +#ifdef lint + (void) (xdr_short(xdrs, (short *)up)); + return (xdr_u_long(xdrs, (rpc_u_int32 *)up)); +#else + if (sizeof (unsigned int) >= 4) { + unsigned long l; + switch (xdrs->x_op) { + case XDR_ENCODE: + l = *up; + return (xdr_u_long(xdrs, &l)); + + case XDR_DECODE: + if (!xdr_u_long(xdrs, &l)) { + return (FALSE); + } + *up = l; + return (TRUE); + + case XDR_FREE: + return (TRUE); + } + } else { + return (xdr_short(xdrs, (short *)up)); + } +#endif +} + +/* + * XDR long integers + * same as xdr_u_long - open coded to save a proc call! + */ +bool_t +xdr_long(xdrs, lp) + register XDR *xdrs; + long *lp; +{ + if (xdrs->x_op == XDR_ENCODE) { + if (sizeof (long) > 4) { + /* See if the dereferenced value fits in 4 bytes. If not, return FALSE. + * Check by loading value into a rpc_int32, then loading back and comparing + * results. + */ + rpc_int32 i = (int) *lp; + long l = i; + if (l != *lp) { + return (FALSE); + } + } + return (XDR_PUTLONG(xdrs, lp)); + } + if (xdrs->x_op == XDR_DECODE) + return (XDR_GETLONG(xdrs, lp)); + + if (xdrs->x_op == XDR_FREE) + return (TRUE); + + return (FALSE); +} + +/* + * XDR unsigned long integers + * same as xdr_long - open coded to save a proc call! + */ +bool_t +xdr_u_long(xdrs, ulp) + register XDR *xdrs; + unsigned long *ulp; +{ + if (xdrs->x_op == XDR_ENCODE) { + if (sizeof (unsigned long) > 4) { + /* See if the dereferenced value fits in 4 bytes. If not, return FALSE. + * Check by loading value into a rpc_int32, then loading back and comparing + * results. + */ + unsigned int ui = *ulp; + unsigned long ul = ui; + if (ul != *ulp) { + return (FALSE); + } + } + return (XDR_PUTLONG(xdrs, ulp)); + } + if (xdrs->x_op == XDR_DECODE) { + return (XDR_GETLONG(xdrs, (long *)ulp)); + } + if (xdrs->x_op == XDR_FREE) + return (TRUE); + return (FALSE); +} + +/* + * XDR short integers + */ +bool_t +xdr_short(xdrs, sp) + register XDR *xdrs; + short *sp; +{ + long l; + + switch (xdrs->x_op) { + + case XDR_ENCODE: + l = (long) *sp; + return (XDR_PUTLONG(xdrs, &l)); + + case XDR_DECODE: + if (!XDR_GETLONG(xdrs, &l)) { + return (FALSE); + } + *sp = (short) l; + return (TRUE); + + case XDR_FREE: + return (TRUE); + } + return (FALSE); +} + +/* + * XDR unsigned short integers + */ +bool_t +xdr_u_short(xdrs, usp) + register XDR *xdrs; + unsigned short *usp; +{ + unsigned long l; + + switch (xdrs->x_op) { + + case XDR_ENCODE: + l = (unsigned long) *usp; + return (XDR_PUTLONG(xdrs, &l)); + + case XDR_DECODE: + if (!XDR_GETLONG(xdrs, &l)) { + return (FALSE); + } + *usp = (unsigned short) l; + return (TRUE); + + case XDR_FREE: + return (TRUE); + } + return (FALSE); +} + + +/* + * XDR a char + */ +bool_t +xdr_char(xdrs, cp) + XDR *xdrs; + char *cp; +{ + int i; + + i = (*cp); + if (!xdr_int(xdrs, &i)) { + return (FALSE); + } + *cp = i; + return (TRUE); +} + +/* + * XDR an unsigned char + */ +bool_t +xdr_u_char(xdrs, cp) + XDR *xdrs; + char *cp; +{ + unsigned int u; + + u = (*cp); + if (!xdr_u_int(xdrs, &u)) { + return (FALSE); + } + *cp = u; + return (TRUE); +} + +/* + * XDR booleans + */ +bool_t +xdr_bool(xdrs, bp) + register XDR *xdrs; + bool_t *bp; +{ + long lb; + + switch (xdrs->x_op) { + + case XDR_ENCODE: + lb = *bp ? XDR_TRUE : XDR_FALSE; + return (XDR_PUTLONG(xdrs, &lb)); + + case XDR_DECODE: + if (!XDR_GETLONG(xdrs, &lb)) { + return (FALSE); + } + *bp = (lb == XDR_FALSE) ? FALSE : TRUE; + return (TRUE); + + case XDR_FREE: + return (TRUE); + } + return (FALSE); +} + +/* + * XDR enumerations + */ +bool_t +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 (rpc_int32)) { + return (xdr_int32(xdrs, (rpc_int32 *)ep)); + } else if (sizeof (enum sizecheck) == sizeof (short)) { + return (xdr_short(xdrs, (short *)ep)); + } else { + return (FALSE); + } +#else + (void) (xdr_short(xdrs, (short *)ep)); + return (xdr_long(xdrs, (long *)ep)); +#endif +} + +/* + * XDR opaque data + * Allows the specification of a fixed size sequence of opaque bytes. + * cp points to the opaque object and cnt gives the byte length. + */ +bool_t +xdr_opaque(xdrs, cp, cnt) + register XDR *xdrs; + caddr_t cp; + register unsigned int cnt; +{ + register unsigned int rndup; + static crud[BYTES_PER_XDR_UNIT]; + + /* + * if no data we are done + */ + if (cnt == 0) + return (TRUE); + + /* + * round byte count to full xdr units + */ + rndup = cnt % BYTES_PER_XDR_UNIT; + if (rndup > 0) + rndup = BYTES_PER_XDR_UNIT - rndup; + + if (xdrs->x_op == XDR_DECODE) { + if (!XDR_GETBYTES(xdrs, cp, cnt)) { + return (FALSE); + } + if (rndup == 0) + return (TRUE); + return (XDR_GETBYTES(xdrs, crud, rndup)); + } + + if (xdrs->x_op == XDR_ENCODE) { + if (!XDR_PUTBYTES(xdrs, cp, cnt)) { + return (FALSE); + } + if (rndup == 0) + return (TRUE); + return (XDR_PUTBYTES(xdrs, xdr_zero, rndup)); + } + + if (xdrs->x_op == XDR_FREE) { + return (TRUE); + } + + return (FALSE); +} + +/* + * XDR counted bytes + * *cpp is a pointer to the bytes, *sizep is the count. + * If *cpp is NULL maxsize bytes are allocated + */ +bool_t +xdr_bytes(xdrs, cpp, sizep, maxsize) + register XDR *xdrs; + char **cpp; + register unsigned int *sizep; + unsigned int maxsize; +{ + register char *sp = *cpp; /* sp is the actual string pointer */ + register unsigned int nodesize; + + /* + * first deal with the length since xdr bytes are counted + */ + if (! xdr_u_int(xdrs, sizep)) { + return (FALSE); + } + nodesize = *sizep; + if ((nodesize > maxsize) && (xdrs->x_op != XDR_FREE)) { + return (FALSE); + } + + /* + * now deal with the actual bytes + */ + switch (xdrs->x_op) { + + case XDR_DECODE: + if (nodesize == 0) { + return (TRUE); + } + if (sp == NULL) { + *cpp = sp = (char *)mem_alloc(nodesize); + } + if (sp == NULL) { + (void) fprintf(stderr, "xdr_bytes: out of memory\n"); + return (FALSE); + } + /* fall into ... */ + + case XDR_ENCODE: + return (xdr_opaque(xdrs, sp, nodesize)); + + case XDR_FREE: + if (sp != NULL) { + mem_free(sp, nodesize); + *cpp = NULL; + } + return (TRUE); + } + return (FALSE); +} + +/* + * Implemented here due to commonality of the object. + */ +bool_t +xdr_netobj(xdrs, np) + XDR *xdrs; + struct netobj *np; +{ + + return (xdr_bytes(xdrs, &np->n_bytes, &np->n_len, MAX_NETOBJ_SZ)); +} + +bool_t +xdr_int32(xdrs, ip) + XDR *xdrs; + rpc_int32 *ip; +{ + long l; + switch (xdrs->x_op) { + case XDR_ENCODE: + l = *ip; + return (xdr_long(xdrs, &l)); + + case XDR_DECODE: + if (!xdr_long(xdrs, &l)) { + return (FALSE); + } + *ip = l; + return (TRUE); + + case XDR_FREE: + return (TRUE); + } +} + +xdr_u_int32(xdrs, up) + XDR *xdrs; + rpc_u_int32 *up; +{ + unsigned long ul; + switch (xdrs->x_op) { + case XDR_ENCODE: + ul = *up; + return (xdr_u_long(xdrs, &ul)); + + case XDR_DECODE: + if (!xdr_u_long(xdrs, &ul)) { + return (FALSE); + } + *up = ul; + return (TRUE); + + case XDR_FREE: + return (TRUE); + } +} + +/* + * XDR a descriminated union + * Support routine for discriminated unions. + * You create an array of xdrdiscrim structures, terminated with + * an entry with a null procedure pointer. The routine gets + * the discriminant value and then searches the array of xdrdiscrims + * looking for that value. It calls the procedure given in the xdrdiscrim + * to handle the discriminant. If there is no specific routine a default + * routine may be called. + * If there is no specific or default routine an error is returned. + */ +bool_t +xdr_union(xdrs, dscmp, unp, choices, dfault) + register 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 */ + xdrproc_t dfault; /* default xdr routine */ +{ + register enum_t dscm; + + /* + * we deal with the discriminator; it's an enum + */ + if (! xdr_enum(xdrs, dscmp)) { + return (FALSE); + } + dscm = *dscmp; + + /* + * search choices for a value that matches the discriminator. + * if we find one, execute the xdr routine for that value. + */ + for (; choices->proc != NULL_xdrproc_t; choices++) { + if (choices->value == dscm) + return ((*(choices->proc))(xdrs, unp, LASTUNSIGNED)); + } + + /* + * no match - execute the default xdr routine if there is one + */ + return ((dfault == NULL_xdrproc_t) ? FALSE : + (*dfault)(xdrs, unp, LASTUNSIGNED)); +} + + +/* + * Non-portable xdr primitives. + * Care should be taken when moving these routines to new architectures. + */ + + +/* + * XDR null terminated ASCII strings + * xdr_string deals with "C strings" - arrays of bytes that are + * terminated by a NULL character. The parameter cpp references a + * pointer to storage; If the pointer is null, then the necessary + * storage is allocated. The last parameter is the max allowed length + * of the string as specified by a protocol. + */ +bool_t +xdr_string(xdrs, cpp, maxsize) + register XDR *xdrs; + char **cpp; + unsigned int maxsize; +{ + register char *sp = *cpp; /* sp is the actual string pointer */ + unsigned int size; + unsigned int nodesize; + + /* + * first deal with the length since xdr strings are counted-strings + */ + switch (xdrs->x_op) { + case XDR_FREE: + if (sp == NULL) { + return(TRUE); /* already free */ + } + /* fall through... */ + case XDR_ENCODE: + size = strlen(sp); + break; + } + if (! xdr_u_int(xdrs, &size)) { + return (FALSE); + } + if (size > maxsize) { + return (FALSE); + } + nodesize = size + 1; + + /* + * now deal with the actual bytes + */ + switch (xdrs->x_op) { + + case XDR_DECODE: + if (nodesize == 0) { + return (TRUE); + } + if (sp == NULL) + *cpp = sp = (char *)mem_alloc(nodesize); + if (sp == NULL) { + (void) fprintf(stderr, "xdr_string: out of memory\n"); + return (FALSE); + } + sp[size] = 0; + /* fall into ... */ + + case XDR_ENCODE: + return (xdr_opaque(xdrs, sp, size)); + + case XDR_FREE: + mem_free(sp, nodesize); + *cpp = NULL; + return (TRUE); + } + return (FALSE); +} + +/* + * Wrapper for xdr_string that can be called directly from + * routines like clnt_call + */ +bool_t +xdr_wrapstring(xdrs, cpp) + XDR *xdrs; + char **cpp; +{ + if (xdr_string(xdrs, cpp, LASTUNSIGNED)) { + return (TRUE); + } + return (FALSE); +} diff --git a/src/lib/rpc/xdr.h b/src/lib/rpc/xdr.h new file mode 100644 index 000000000..9f0819b61 --- /dev/null +++ b/src/lib/rpc/xdr.h @@ -0,0 +1,276 @@ +/* @(#)xdr.h 2.2 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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 + */ +/* @(#)xdr.h 1.19 87/04/22 SMI */ + +/* + * xdr.h, External Data Representation Serialization Routines. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#ifndef __XDR_HEADER__ +#define __XDR_HEADER__ + +/* + * XDR provides a conventional way for converting between C data + * types and an external bit-string representation. Library supplied + * routines provide for the conversion on built-in C data types. These + * routines and utility routines defined here are used to help implement + * a type encode/decode routine for each user-defined type. + * + * Each data type provides a single procedure which takes two arguments: + * + * bool_t + * xdrproc(xdrs, argresp) + * XDR *xdrs; + * <type> *argresp; + * + * xdrs is an instance of a XDR handle, to which or from which the data + * type is to be converted. argresp is a pointer to the structure to be + * converted. The XDR handle contains an operation field which indicates + * which of the operations (ENCODE, DECODE * or FREE) is to be performed. + * + * XDR_DECODE may allocate space if the pointer argresp is null. This + * data can be freed with the XDR_FREE operation. + * + * We write only one procedure per data type to make it easy + * to keep the encode and decode procedures for a data type consistent. + * In many cases the same code performs all operations on a user defined type, + * because all the hard work is done in the component type routines. + * decode as a series of calls on the nested data types. + */ + +/* + * Xdr operations. XDR_ENCODE causes the type to be encoded into the + * stream. XDR_DECODE causes the type to be extracted from the stream. + * XDR_FREE can be used to release the space allocated by an XDR_DECODE + * request. + */ +enum xdr_op { + XDR_ENCODE=0, + XDR_DECODE=1, + XDR_FREE=2 +}; + +/* + * This is the number of bytes per unit of external data. + */ +#define BYTES_PER_XDR_UNIT (4) +#define RNDUP(x) ((((x) + BYTES_PER_XDR_UNIT - 1) / BYTES_PER_XDR_UNIT) \ + * BYTES_PER_XDR_UNIT) + +/* + * A xdrproc_t exists for each data type which is to be encoded or decoded. + * + * The second argument to the xdrproc_t is a pointer to an opaque pointer. + * The opaque pointer generally points to a structure of the data type + * to be decoded. If this pointer is 0, then the type routines should + * allocate dynamic storage of the appropriate size and return it. + * 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 paticular implementation (e.g. see xdr_mem.c), + * and two private fields for the use of the particular impelementation. + */ +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 " */ + bool_t (*x_getbytes)();/* get some bytes from " */ + bool_t (*x_putbytes)();/* put some bytes to " */ + unsigned int (*x_getpostn)();/* returns bytes off from beginning */ + bool_t (*x_setpostn)();/* lets you reposition the stream */ + rpc_int32 * (*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; + +/* + * Operations defined on a XDR handle + * + * XDR *xdrs; + * rpc_int32 *longp; + * caddr_t addr; + * unsigned int len; + * unsigned int pos; + */ +#define XDR_GETLONG(xdrs, longp) \ + (*(xdrs)->x_ops->x_getlong)(xdrs, longp) +#define xdr_getlong(xdrs, longp) \ + (*(xdrs)->x_ops->x_getlong)(xdrs, longp) + +#define XDR_PUTLONG(xdrs, longp) \ + (*(xdrs)->x_ops->x_putlong)(xdrs, longp) +#define xdr_putlong(xdrs, longp) \ + (*(xdrs)->x_ops->x_putlong)(xdrs, longp) + +#define XDR_GETBYTES(xdrs, addr, len) \ + (*(xdrs)->x_ops->x_getbytes)(xdrs, addr, len) +#define xdr_getbytes(xdrs, addr, len) \ + (*(xdrs)->x_ops->x_getbytes)(xdrs, addr, len) + +#define XDR_PUTBYTES(xdrs, addr, len) \ + (*(xdrs)->x_ops->x_putbytes)(xdrs, addr, len) +#define xdr_putbytes(xdrs, addr, len) \ + (*(xdrs)->x_ops->x_putbytes)(xdrs, addr, len) + +#define XDR_GETPOS(xdrs) \ + (*(xdrs)->x_ops->x_getpostn)(xdrs) +#define xdr_getpos(xdrs) \ + (*(xdrs)->x_ops->x_getpostn)(xdrs) + +#define XDR_SETPOS(xdrs, pos) \ + (*(xdrs)->x_ops->x_setpostn)(xdrs, pos) +#define xdr_setpos(xdrs, pos) \ + (*(xdrs)->x_ops->x_setpostn)(xdrs, pos) + +#define XDR_INLINE(xdrs, len) \ + (*(xdrs)->x_ops->x_inline)(xdrs, len) +#define xdr_inline(xdrs, len) \ + (*(xdrs)->x_ops->x_inline)(xdrs, len) + +#define XDR_DESTROY(xdrs) \ + if ((xdrs)->x_ops->x_destroy) \ + (*(xdrs)->x_ops->x_destroy)(xdrs) +#define xdr_destroy(xdrs) \ + if ((xdrs)->x_ops->x_destroy) \ + (*(xdrs)->x_ops->x_destroy)(xdrs) + +/* + * Support struct for discriminated unions. + * You create an array of xdrdiscrim structures, terminated with + * a entry with a null procedure pointer. The xdr_union routine gets + * the discriminant value and then searches the array of structures + * for a matching value. If a match is found the associated xdr routine + * is called to handle that part of the union. If there is + * no match, then a default routine may be called. + * If there is no match and no default routine it is an error. + */ +#define NULL_xdrproc_t ((xdrproc_t)0) +struct xdr_discrim { + int value; + xdrproc_t proc; +}; + +/* + * In-line routines for fast encode/decode of primitve data types. + * Caveat emptor: these use single memory cycles to get the + * data from the underlying buffer, and will fail to operate + * properly if the data is not aligned. The standard way to use these + * is to say: + * if ((buf = XDR_INLINE(xdrs, count)) == NULL) + * return (FALSE); + * <<< macro calls >>> + * where ``count'' is the number of bytes of data occupied + * by the primitive data types. + * + * N.B. and frozen for all time: each data type here uses 4 bytes + * of external representation. + */ +#define IXDR_GET_LONG(buf) ((long)ntohl((rpc_u_int32)*(buf)++)) +#define IXDR_PUT_LONG(buf, v) (*(buf)++ = (rpc_int32)htonl((rpc_u_int32)v)) + +#define IXDR_GET_BOOL(buf) ((bool_t)IXDR_GET_LONG(buf)) +#define IXDR_GET_ENUM(buf, t) ((t)IXDR_GET_LONG(buf)) +#define IXDR_GET_U_LONG(buf) ((rpc_u_int32)IXDR_GET_LONG(buf)) +#define IXDR_GET_SHORT(buf) ((short)IXDR_GET_LONG(buf)) +#define IXDR_GET_U_SHORT(buf) ((unsigned short)IXDR_GET_LONG(buf)) + +#define IXDR_PUT_BOOL(buf, v) IXDR_PUT_LONG((buf), ((rpc_int32)(v))) +#define IXDR_PUT_ENUM(buf, v) IXDR_PUT_LONG((buf), ((rpc_int32)(v))) +#define IXDR_PUT_U_LONG(buf, v) IXDR_PUT_LONG((buf), ((rpc_int32)(v))) +#define IXDR_PUT_SHORT(buf, v) IXDR_PUT_LONG((buf), ((rpc_int32)(v))) +#define IXDR_PUT_U_SHORT(buf, v) IXDR_PUT_LONG((buf), ((rpc_int32)(v))) + +/* + * These are the "generic" xdr routines. + */ +extern bool_t xdr_void(); +extern bool_t xdr_int(XDR *, int *); +extern bool_t xdr_u_int(XDR *, unsigned int *); +extern bool_t xdr_long(XDR *, long *); +extern bool_t xdr_u_long(XDR *, unsigned long *); +extern bool_t xdr_short(XDR *, short *); +extern bool_t xdr_u_short(XDR *, unsigned short *); +extern bool_t xdr_bool(XDR *, bool_t *); +extern bool_t xdr_enum(XDR *, enum_t *); +extern bool_t xdr_array(XDR *, caddr_t *, unsigned int*, unsigned int, unsigned int, xdrproc_t); +extern bool_t xdr_bytes(XDR *, char **, unsigned int *, unsigned int); +extern bool_t xdr_opaque(XDR *, caddr_t, unsigned int); +extern bool_t xdr_string(XDR *, char **, unsigned int); +extern bool_t xdr_union(XDR *, enum_t *, char *, struct xdr_discrim *, xdrproc_t); +extern bool_t xdr_char(XDR *, char *); +extern bool_t xdr_u_char(XDR *, char *); +extern bool_t xdr_vector(XDR *, char *, unsigned int, unsigned int, xdrproc_t); +extern bool_t xdr_float(XDR *, float *); +extern bool_t xdr_double(XDR *, double *); +extern bool_t xdr_reference(XDR *, caddr_t *, unsigned int, xdrproc_t); +extern bool_t xdr_pointer(XDR *, char **, unsigned int, xdrproc_t); +extern bool_t xdr_wrapstring(XDR *, char **); + +/* + * Common opaque bytes objects used by many rpc protocols; + * declared here due to commonality. + */ +#define MAX_NETOBJ_SZ 1024 +struct netobj { + unsigned int n_len; + char *n_bytes; +}; +typedef struct netobj netobj; +extern bool_t xdr_netobj(XDR *, struct netobj *); + +extern bool_t xdr_int32(XDR *, rpc_int32 *); +extern bool_t xdr_u_int32(XDR *, rpc_u_int32 *); + +/* + * These are the public routines for the various implementations of + * xdr streams. + */ +extern void xdrmem_create(); /* XDR using memory buffers */ +extern void xdrstdio_create(); /* XDR using stdio library */ +extern void xdrrec_create(); /* XDR pseudo records for tcp */ +extern void xdralloc_create(); /* XDR allocating memory buffer */ +extern void xdralloc_release(); /* destroy xdralloc, save buf */ +extern bool_t xdrrec_endofrecord(); /* make end of xdr record */ +extern bool_t xdrrec_skiprecord(); /* move to beginning of next record */ +extern bool_t xdrrec_eof(); /* true if no more input */ +extern caddr_t xdralloc_getdata(); /* get buffer from xdralloc */ + +#endif /* !__XDR_HEADER__ */ diff --git a/src/lib/rpc/xdr_alloc.c b/src/lib/rpc/xdr_alloc.c new file mode 100644 index 000000000..37ae71e82 --- /dev/null +++ b/src/lib/rpc/xdr_alloc.c @@ -0,0 +1,173 @@ +/* @(#)xdr_mem.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)xdr_mem.c 1.19 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. + * + * $Header$ + * + * $Log$ + * Revision 1.6 1996/07/22 20:41:21 marc + * this commit includes all the changes on the OV_9510_INTEGRATION and + * OV_MERGE branches. This includes, but is not limited to, the new openvision + * admin system, and major changes to gssapi to add functionality, and bring + * the implementation in line with rfc1964. before committing, the + * code was built and tested for netbsd and solaris. + * + * Revision 1.5.4.1 1996/07/18 04:19:49 marc + * merged in changes from OV_9510_BP to OV_9510_FINAL1 + * + * Revision 1.5.2.1 1996/06/20 23:40:30 marc + * File added to the repository on a branch + * + * Revision 1.5 1996/05/12 06:19:25 marc + * renamed lots of types: u_foo to unsigned foo, and foo32 to rpc_foo32. This is to make autoconfiscation less painful. + * + * Revision 1.4 1995/12/13 14:03:14 grier + * Longs to ints for Alpha + * + * Revision 1.3 1993/12/09 18:57:25 bjaspan + * [secure-releng/833] misc bugfixes to admin library + * + * Revision 1.3 1993/12/06 21:23:08 bjaspan + * add xdralloc_release + * + * Revision 1.2 1993/10/26 21:13:19 bjaspan + * add casts for correctness + * + * Revision 1.1 1993/10/19 03:11:39 bjaspan + * Initial revision + * + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <dyn.h> + +static bool_t xdralloc_putlong(); +static bool_t xdralloc_putbytes(); +static unsigned int xdralloc_getpos(); +static rpc_int32 * xdralloc_inline(); +static void xdralloc_destroy(); +static bool_t xdralloc_notsup(); + +static struct xdr_ops xdralloc_ops = { + xdralloc_notsup, + xdralloc_putlong, + xdralloc_notsup, + xdralloc_putbytes, + xdralloc_getpos, + xdralloc_notsup, + xdralloc_inline, + xdralloc_destroy, +}; + +/* + * The procedure xdralloc_create initializes a stream descriptor for a + * memory buffer. + */ +void xdralloc_create(xdrs, op) + register XDR *xdrs; + enum xdr_op op; +{ + xdrs->x_op = op; + xdrs->x_ops = &xdralloc_ops; + xdrs->x_private = (caddr_t) DynCreate(sizeof(char), -4); + /* not allowed to fail */ +} + +caddr_t xdralloc_getdata(xdrs) + XDR *xdrs; +{ + return (caddr_t) DynGet((DynObject) xdrs->x_private, 0); +} + +void xdralloc_release(xdrs) + XDR *xdrs; +{ + DynRelease((DynObject) xdrs->x_private); +} + +static void xdralloc_destroy(xdrs) + XDR *xdrs; +{ + DynDestroy((DynObject) xdrs->x_private); +} + +static bool_t xdralloc_notsup() +{ + return FALSE; +} + +static bool_t xdralloc_putlong(xdrs, lp) + register XDR *xdrs; + rpc_int32 *lp; +{ + int l = htonl((rpc_u_int32) *(int *)lp); + + if (DynInsert((DynObject) xdrs->x_private, + DynSize((DynObject) xdrs->x_private), &l, + sizeof(int)) != DYN_OK) + return FALSE; + return (TRUE); +} + +static bool_t xdralloc_putbytes(xdrs, addr, len) + register XDR *xdrs; + caddr_t addr; + register unsigned int len; +{ + if (DynInsert((DynObject) xdrs->x_private, + DynSize((DynObject) xdrs->x_private), + addr, len) != DYN_OK) + return FALSE; + return TRUE; +} + +static unsigned int xdralloc_getpos(xdrs) + register XDR *xdrs; +{ + return DynSize((DynObject) xdrs->x_private); +} + + +static rpc_int32 *xdralloc_inline(xdrs, len) + register XDR *xdrs; + int len; +{ + return (rpc_int32 *) 0; +} diff --git a/src/lib/rpc/xdr_array.c b/src/lib/rpc/xdr_array.c new file mode 100644 index 000000000..09bd50abd --- /dev/null +++ b/src/lib/rpc/xdr_array.c @@ -0,0 +1,153 @@ +/* @(#)xdr_array.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)xdr_array.c 1.10 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * xdr_array.c, Generic XDR routines impelmentation. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * These are the "non-trivial" xdr primitives used to serialize and de-serialize + * arrays. See xdr.h for more info on the interface to xdr. + */ + +#include <stdio.h> + +#include <rpc/types.h> +#include <rpc/xdr.h> + +#define LASTUNSIGNED ((unsigned int)0-1) + + +/* + * XDR an array of arbitrary elements + * *addrp is a pointer to the array, *sizep is the number of elements. + * If addrp is NULL (*sizep * elsize) bytes are allocated. + * elsize is the size (in bytes) of each element, and elproc is the + * xdr procedure to call to handle each element of the array. + */ +bool_t +xdr_array(xdrs, addrp, sizep, maxsize, elsize, elproc) + register XDR *xdrs; + caddr_t *addrp; /* array pointer */ + unsigned int *sizep; /* number of elements */ + unsigned int maxsize; /* max numberof elements */ + unsigned int elsize; /* size in bytes of each element */ + xdrproc_t elproc; /* xdr routine to handle each element */ +{ + register unsigned int i; + register caddr_t target = *addrp; + register unsigned int c; /* the actual element count */ + register bool_t stat = TRUE; + register unsigned int nodesize; + + /* like strings, arrays are really counted arrays */ + if (! xdr_u_int(xdrs, sizep)) { + return (FALSE); + } + c = *sizep; + if ((c > maxsize) && (xdrs->x_op != XDR_FREE)) { + return (FALSE); + } + nodesize = c * elsize; + + /* + * if we are deserializing, we may need to allocate an array. + * We also save time by checking for a null array if we are freeing. + */ + if (target == NULL) + switch (xdrs->x_op) { + case XDR_DECODE: + if (c == 0) + return (TRUE); + *addrp = target = mem_alloc(nodesize); + if (target == NULL) { + (void) fprintf(stderr, + "xdr_array: out of memory\n"); + return (FALSE); + } + memset(target, 0, nodesize); + break; + + case XDR_FREE: + return (TRUE); + } + + /* + * now we xdr each element of array + */ + for (i = 0; (i < c) && stat; i++) { + stat = (*elproc)(xdrs, target, LASTUNSIGNED); + target += elsize; + } + + /* + * the array may need freeing + */ + if (xdrs->x_op == XDR_FREE) { + mem_free(*addrp, nodesize); + *addrp = NULL; + } + return (stat); +} + +/* + * xdr_vector(): + * + * XDR a fixed length array. Unlike variable-length arrays, + * the storage of fixed length arrays is static and unfreeable. + * > basep: base of the array + * > size: size of the array + * > elemsize: size of each element + * > xdr_elem: routine to XDR each element + */ +bool_t +xdr_vector(xdrs, basep, nelem, elemsize, xdr_elem) + register XDR *xdrs; + register char *basep; + register unsigned int nelem; + register unsigned int elemsize; + register xdrproc_t xdr_elem; +{ + register unsigned int i; + register char *elptr; + + elptr = basep; + for (i = 0; i < nelem; i++) { + if (! (*xdr_elem)(xdrs, elptr, LASTUNSIGNED)) { + return(FALSE); + } + elptr += elemsize; + } + return(TRUE); +} + diff --git a/src/lib/rpc/xdr_float.c b/src/lib/rpc/xdr_float.c new file mode 100644 index 000000000..0c153c472 --- /dev/null +++ b/src/lib/rpc/xdr_float.c @@ -0,0 +1,293 @@ +/* @(#)xdr_float.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)xdr_float.c 1.12 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * xdr_float.c, Generic XDR routines impelmentation. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * These are the "floating point" xdr routines used to (de)serialize + * most common data items. See xdr.h for more info on the interface to + * xdr. + */ + +#include <stdio.h> + +#include <rpc/types.h> +#include <rpc/xdr.h> + +/* + * NB: Not portable. + * This routine works on Suns (Sky / 68000's) and Vaxen. + */ +#ifdef IGNORE + +#ifdef vax + +/* What IEEE single precision floating point looks like on a Vax */ +struct ieee_single { + unsigned int mantissa: 23; + unsigned int exp : 8; + unsigned int sign : 1; +}; + +/* Vax single precision floating point */ +struct vax_single { + unsigned int mantissa1 : 7; + unsigned int exp : 8; + unsigned int sign : 1; + unsigned int mantissa2 : 16; +}; + +#define VAX_SNG_BIAS 0x81 +#define IEEE_SNG_BIAS 0x7f + +static struct sgl_limits { + struct vax_single s; + struct ieee_single ieee; +} sgl_limits[2] = { + {{ 0x7f, 0xff, 0x0, 0xffff }, /* Max Vax */ + { 0x0, 0xff, 0x0 }}, /* Max IEEE */ + {{ 0x0, 0x0, 0x0, 0x0 }, /* Min Vax */ + { 0x0, 0x0, 0x0 }} /* Min IEEE */ +}; +#endif /* vax */ + +bool_t +xdr_float(xdrs, fp) + register XDR *xdrs; + register float *fp; +{ +#if defined(vax) + struct ieee_single is; + struct vax_single vs, *vsp; + struct sgl_limits *lim; + int i; +#endif + long lg; + + switch (xdrs->x_op) { + + case XDR_ENCODE: +#if !defined(vax) + lg = * (int_32 *) fp; + return (XDR_PUTLONG(xdrs, &lg)); +#else + vs = *((struct vax_single *)fp); + for (i = 0, lim = sgl_limits; + i < sizeof(sgl_limits)/sizeof(struct sgl_limits); + i++, lim++) { + if ((vs.mantissa2 == lim->s.mantissa2) && + (vs.exp == lim->s.exp) && + (vs.mantissa1 == lim->s.mantissa1)) { + is = lim->ieee; + goto shipit; + } + } + is.exp = vs.exp - VAX_SNG_BIAS + IEEE_SNG_BIAS; + is.mantissa = (vs.mantissa1 << 16) | vs.mantissa2; + shipit: + is.sign = vs.sign; + return (XDR_PUTLONG(xdrs, (rpc_int32 *)&is)); +#endif + + case XDR_DECODE: +#if !defined(vax) + if (!(XDR_GETLONG(xdrs, &lg))) { + return (FALSE); + } + *fp = (float) ((int) lg); + return (TRUE); +#else + vsp = (struct vax_single *)fp; + if (!XDR_GETLONG(xdrs, (rpc_int32 *)&is)) + return (FALSE); + for (i = 0, lim = sgl_limits; + i < sizeof(sgl_limits)/sizeof(struct sgl_limits); + i++, lim++) { + if ((is.exp == lim->ieee.exp) && + (is.mantissa == lim->ieee.mantissa)) { + *vsp = lim->s; + goto doneit; + } + } + vsp->exp = is.exp - IEEE_SNG_BIAS + VAX_SNG_BIAS; + vsp->mantissa2 = is.mantissa; + vsp->mantissa1 = (is.mantissa >> 16); + doneit: + vsp->sign = is.sign; + return (TRUE); +#endif + + case XDR_FREE: + return (TRUE); + } + return (FALSE); +} + +/* + * This routine works on Suns (Sky / 68000's) and Vaxen. + */ + +#ifdef vax +/* What IEEE double precision floating point looks like on a Vax */ +struct ieee_double { + unsigned int mantissa1 : 20; + unsigned int exp : 11; + unsigned int sign : 1; + unsigned int mantissa2 : 32; +}; + +/* Vax double precision floating point */ +struct vax_double { + unsigned int mantissa1 : 7; + unsigned int exp : 8; + unsigned int sign : 1; + unsigned int mantissa2 : 16; + unsigned int mantissa3 : 16; + unsigned int mantissa4 : 16; +}; + +#define VAX_DBL_BIAS 0x81 +#define IEEE_DBL_BIAS 0x3ff +#define MASK(nbits) ((1 << nbits) - 1) + +static struct dbl_limits { + struct vax_double d; + struct ieee_double ieee; +} dbl_limits[2] = { + {{ 0x7f, 0xff, 0x0, 0xffff, 0xffff, 0xffff }, /* Max Vax */ + { 0x0, 0x7ff, 0x0, 0x0 }}, /* Max IEEE */ + {{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, /* Min Vax */ + { 0x0, 0x0, 0x0, 0x0 }} /* Min IEEE */ +}; + +#endif /* vax */ + + +bool_t +xdr_double(xdrs, dp) + register XDR *xdrs; + double *dp; +{ + register rpc_int32 *lp; +#if defined(vax) + struct ieee_double id; + struct vax_double vd; + register struct dbl_limits *lim; + int i; +#endif + + switch (xdrs->x_op) { + + case XDR_ENCODE: +#if !defined(vax) + lp = (rpc_int32 *)dp; + if (sizeof(rpc_int32) == sizeof(long)) { + return (XDR_PUTLONG(xdrs, lp++) && XDR_PUTLONG(xdrs, lp)); + } else { + long lg1 = *lp++;; + long lg2 = *lp; + return (XDR_PUTLONG(xdrs, &lg1) && XDR_PUTLONG(xdrs, &lg2)); + } +#else + vd = *((struct vax_double *)dp); + for (i = 0, lim = dbl_limits; + i < sizeof(dbl_limits)/sizeof(struct dbl_limits); + i++, lim++) { + if ((vd.mantissa4 == lim->d.mantissa4) && + (vd.mantissa3 == lim->d.mantissa3) && + (vd.mantissa2 == lim->d.mantissa2) && + (vd.mantissa1 == lim->d.mantissa1) && + (vd.exp == lim->d.exp)) { + id = lim->ieee; + goto shipit; + } + } + id.exp = vd.exp - VAX_DBL_BIAS + IEEE_DBL_BIAS; + id.mantissa1 = (vd.mantissa1 << 13) | (vd.mantissa2 >> 3); + id.mantissa2 = ((vd.mantissa2 & MASK(3)) << 29) | + (vd.mantissa3 << 13) | + ((vd.mantissa4 >> 3) & MASK(13)); + shipit: + id.sign = vd.sign; + lp = (rpc_int32 *)&id; + return (XDR_PUTLONG(xdrs, lp++) && XDR_PUTLONG(xdrs, lp)); +#endif + + case XDR_DECODE: +#if !defined(vax) + lp = (rpc_int32 *)dp; + if (sizeof(rpc_int32) == sizeof(long)) { + return (XDR_GETLONG(xdrs, lp++) && XDR_GETLONG(xdrs, lp)); + } else { + long lg1, lg2; + bool_t flag = + (XDR_GETLONG(xdrs, &lg1) && XDR_GETLONG(xdrs, &lg2)); + *lp++ = lg1; + *lp = lg2; + return flag; + } +#else + lp = (rpc_int32 *)&id; + if (!XDR_GETLONG(xdrs, lp++) || !XDR_GETLONG(xdrs, lp)) + return (FALSE); + for (i = 0, lim = dbl_limits; + i < sizeof(dbl_limits)/sizeof(struct dbl_limits); + i++, lim++) { + if ((id.mantissa2 == lim->ieee.mantissa2) && + (id.mantissa1 == lim->ieee.mantissa1) && + (id.exp == lim->ieee.exp)) { + vd = lim->d; + goto doneit; + } + } + vd.exp = id.exp - IEEE_DBL_BIAS + VAX_DBL_BIAS; + vd.mantissa1 = (id.mantissa1 >> 13); + vd.mantissa2 = ((id.mantissa1 & MASK(13)) << 3) | + (id.mantissa2 >> 29); + vd.mantissa3 = (id.mantissa2 >> 13); + vd.mantissa4 = (id.mantissa2 << 3); + doneit: + vd.sign = id.sign; + *dp = *((double *)&vd); + return (TRUE); +#endif + + case XDR_FREE: + return (TRUE); + } + return (FALSE); +} + +#endif /* IGNORE */ diff --git a/src/lib/rpc/xdr_mem.c b/src/lib/rpc/xdr_mem.c new file mode 100644 index 000000000..39c0df203 --- /dev/null +++ b/src/lib/rpc/xdr_mem.c @@ -0,0 +1,188 @@ +/* @(#)xdr_mem.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)xdr_mem.c 1.19 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * xdr_mem.h, XDR implementation using memory buffers. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * If you have some data to be interpreted as external data representation + * or to be converted to external data representation in a memory buffer, + * then this is the package for you. + * + */ + + +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <netinet/in.h> +#include <stdio.h> + +static bool_t xdrmem_getlong(); +static bool_t xdrmem_putlong(); +static bool_t xdrmem_getbytes(); +static bool_t xdrmem_putbytes(); +static unsigned int xdrmem_getpos(); +static bool_t xdrmem_setpos(); +static rpc_int32 * xdrmem_inline(); +static void xdrmem_destroy(); + +static struct xdr_ops xdrmem_ops = { + xdrmem_getlong, + xdrmem_putlong, + xdrmem_getbytes, + xdrmem_putbytes, + xdrmem_getpos, + xdrmem_setpos, + xdrmem_inline, + xdrmem_destroy +}; + +/* + * The procedure xdrmem_create initializes a stream descriptor for a + * memory buffer. + */ +void +xdrmem_create(xdrs, addr, size, op) + register XDR *xdrs; + caddr_t addr; + unsigned int size; + enum xdr_op op; +{ + + xdrs->x_op = op; + xdrs->x_ops = &xdrmem_ops; + xdrs->x_private = xdrs->x_base = addr; + xdrs->x_handy = size; +} + +static void +xdrmem_destroy(/*xdrs*/) + /*XDR *xdrs;*/ +{ +} + +static bool_t +xdrmem_getlong(xdrs, lp) + register XDR *xdrs; + long *lp; +{ + + if ((xdrs->x_handy -= sizeof(rpc_int32)) < 0) + return (FALSE); + *lp = (long)ntohl(*((rpc_u_int32 *)(xdrs->x_private))); + xdrs->x_private += sizeof(rpc_int32); + return (TRUE); +} + +static bool_t +xdrmem_putlong(xdrs, lp) + register XDR *xdrs; + long *lp; +{ + + if ((xdrs->x_handy -= sizeof(rpc_int32)) < 0) + return (FALSE); + *(rpc_int32 *)xdrs->x_private = (rpc_int32)htonl((rpc_u_int32)(*lp)); + xdrs->x_private += sizeof(rpc_int32); + return (TRUE); +} + +static bool_t +xdrmem_getbytes(xdrs, addr, len) + register XDR *xdrs; + caddr_t addr; + register unsigned int len; +{ + + if ((xdrs->x_handy -= len) < 0) + return (FALSE); + memmove(addr, xdrs->x_private, len); + xdrs->x_private += len; + return (TRUE); +} + +static bool_t +xdrmem_putbytes(xdrs, addr, len) + register XDR *xdrs; + caddr_t addr; + register unsigned int len; +{ + + if ((xdrs->x_handy -= len) < 0) + return (FALSE); + memmove(xdrs->x_private, addr, len); + xdrs->x_private += len; + return (TRUE); +} + +static unsigned int +xdrmem_getpos(xdrs) + register XDR *xdrs; +{ +/* + * 11/3/95 - JRG - Rather than recast everything for 64 bit, just convert + * pointers to longs, then cast to int. + */ + return (unsigned int)((unsigned long)xdrs->x_private - (unsigned long)xdrs->x_base); +} + +static bool_t +xdrmem_setpos(xdrs, pos) + register XDR *xdrs; + unsigned int pos; +{ + register caddr_t newaddr = xdrs->x_base + pos; + register caddr_t lastaddr = xdrs->x_private + xdrs->x_handy; + + if ((long)newaddr > (long)lastaddr) + return (FALSE); + xdrs->x_private = newaddr; + xdrs->x_handy = (int)((long)lastaddr - (long)newaddr); + return (TRUE); +} + +static rpc_int32 * +xdrmem_inline(xdrs, len) + register XDR *xdrs; + int len; +{ + rpc_int32 *buf = 0; + + if (xdrs->x_handy >= len) { + xdrs->x_handy -= len; + buf = (rpc_int32 *) xdrs->x_private; + xdrs->x_private += len; + } + return (buf); +} diff --git a/src/lib/rpc/xdr_rec.c b/src/lib/rpc/xdr_rec.c new file mode 100644 index 000000000..99ce9235a --- /dev/null +++ b/src/lib/rpc/xdr_rec.c @@ -0,0 +1,596 @@ +/* @(#)xdr_rec.c 2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)xdr_rec.c 1.21 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * xdr_rec.c, Implements TCP/IP based XDR streams with a "record marking" + * layer above tcp (for rpc's use). + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * These routines interface XDRSTREAMS to a tcp/ip connection. + * There is a record marking layer between the xdr stream + * and the tcp transport level. A record is composed on one or more + * record fragments. A record fragment is a thirty-two bit header followed + * by n bytes of data, where n is contained in the header. The header + * is represented as a htonl(rpc_u_int32). Thegh order bit encodes + * whether or not the fragment is the last fragment of the record + * (1 => fragment is last, 0 => more fragments to follow. + * The other 31 bits encode the byte length of the fragment. + */ + +#include <stdio.h> +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <netinet/in.h> + +#include <unistd.h> + +static unsigned 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(); +static bool_t xdrrec_putlong(); +static bool_t xdrrec_getbytes(); +static bool_t xdrrec_putbytes(); +static unsigned int xdrrec_getpos(); +static bool_t xdrrec_setpos(); +static rpc_int32 * xdrrec_inline(); +static void xdrrec_destroy(); + +static struct xdr_ops xdrrec_ops = { + xdrrec_getlong, + xdrrec_putlong, + xdrrec_getbytes, + xdrrec_putbytes, + xdrrec_getpos, + xdrrec_setpos, + xdrrec_inline, + xdrrec_destroy +}; + +/* + * A record is composed of one or more record fragments. + * A record fragment is a two-byte header followed by zero to + * 2**32-1 bytes. The header is treated as an unsigned 32 bit integer and is + * encode/decoded to the network via htonl/ntohl. The low order 31 bits + * are a byte count of the fragment. The highest order bit is a boolean: + * 1 => this fragment is the last fragment of the record, + * 0 => this fragment is followed by more fragment(s). + * + * The fragment/record machinery is not general; it is constructed to + * meet the needs of xdr and rpc based on tcp. + */ + +#define LAST_FRAG ((rpc_u_int32)(1 << 31)) + +typedef struct rec_strm { + caddr_t tcp_handle; + caddr_t the_buffer; + /* + * out-goung bits + */ + int (*writeit)(); + 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 */ + rpc_u_int32 *frag_header; /* beginning of curren fragment */ + bool_t frag_sent; /* true if buffer sent in middle of record */ + /* + * in-coming bits + */ + int (*readit)(); + rpc_u_int32 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 */ + rpc_int32 fbtbc; /* fragment bytes to be consumed */ + bool_t last_frag; + unsigned int sendsize; + unsigned int recvsize; +} RECSTREAM; + + +/* + * Create an xdr handle for xdrrec + * xdrrec_create fills in xdrs. Sendsize and recvsize are + * send and recv buffer sizes (0 => use default). + * tcp_handle is an opaque handle that is passed as the first parameter to + * the procedures readit and writeit. Readit and writeit are read and + * write respectively. They are like the system + * calls expect that they take an opaque handle rather than an fd. + */ +void +xdrrec_create(xdrs, sendsize, recvsize, tcp_handle, readit, writeit) + register XDR *xdrs; + register unsigned int sendsize; + register unsigned 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 */ +{ + register RECSTREAM *rstrm = + (RECSTREAM *)mem_alloc(sizeof(RECSTREAM)); + + if (rstrm == NULL) { + (void)fprintf(stderr, "xdrrec_create: out of memory\n"); + /* + * This is bad. Should rework xdrrec_create to + * return a handle, and in this case return NULL + */ + return; + } + /* + * adjust sizes and allocate buffer quad byte aligned + */ + rstrm->sendsize = sendsize = fix_buf_size(sendsize); + 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"); + return; + } + for (rstrm->out_base = rstrm->the_buffer; + /* Pointer arithmetic - long cast allowed... */ + (unsigned long)rstrm->out_base % BYTES_PER_XDR_UNIT != 0; + rstrm->out_base++); + rstrm->in_base = rstrm->out_base + sendsize; + /* + * now the rest ... + */ + xdrs->x_ops = &xdrrec_ops; + xdrs->x_private = (caddr_t)rstrm; + rstrm->tcp_handle = tcp_handle; + rstrm->readit = readit; + rstrm->writeit = writeit; + rstrm->out_finger = rstrm->out_boundry = rstrm->out_base; + rstrm->frag_header = (rpc_u_int32 *)rstrm->out_base; + rstrm->out_finger += sizeof(rpc_u_int32); + rstrm->out_boundry += sendsize; + rstrm->frag_sent = FALSE; + rstrm->in_size = recvsize; + rstrm->in_boundry = rstrm->in_base; + rstrm->in_finger = (rstrm->in_boundry += recvsize); + rstrm->fbtbc = 0; + rstrm->last_frag = TRUE; +} + + +/* + * The reoutines defined below are the xdr ops which will go into the + * xdr handle filled in by xdrrec_create. + */ + +static bool_t +xdrrec_getlong(xdrs, lp) + XDR *xdrs; + long *lp; +{ + register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); + register rpc_int32 *buflp = (rpc_int32 *)(rstrm->in_finger); + int mylong; + + /* first try the inline, fast case */ + if ((rstrm->fbtbc >= sizeof(rpc_int32)) && + (((long)rstrm->in_boundry - (long)buflp) >= sizeof(rpc_int32))) { + *lp = (long)ntohl((rpc_u_int32)(*buflp)); + rstrm->fbtbc -= sizeof(rpc_int32); + rstrm->in_finger += sizeof(rpc_int32); + } else { + if (! xdrrec_getbytes(xdrs, (caddr_t)&mylong, sizeof(rpc_int32))) + return (FALSE); + *lp = (long)ntohl((unsigned int)mylong); + } + return (TRUE); +} + +static bool_t +xdrrec_putlong(xdrs, lp) + XDR *xdrs; + long *lp; +{ + register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); + register rpc_int32 *dest_lp = ((rpc_int32 *)(rstrm->out_finger)); + + if ((rstrm->out_finger += sizeof(rpc_int32)) > rstrm->out_boundry) { + /* + * this case should almost never happen so the code is + * inefficient + */ + rstrm->out_finger -= sizeof(rpc_int32); + rstrm->frag_sent = TRUE; + if (! flush_out(rstrm, FALSE)) + return (FALSE); + dest_lp = ((rpc_int32 *)(rstrm->out_finger)); + rstrm->out_finger += sizeof(rpc_int32); + } + *dest_lp = (rpc_int32)htonl((rpc_u_int32)(*lp)); + return (TRUE); +} + +static bool_t /* must manage buffers, fragments, and records */ +xdrrec_getbytes(xdrs, addr, len) + XDR *xdrs; + register caddr_t addr; + register unsigned int len; +{ + register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); + register int current; + + while (len > 0) { + current = rstrm->fbtbc; + if (current == 0) { + if (rstrm->last_frag) + return (FALSE); + if (! set_input_fragment(rstrm)) + return (FALSE); + continue; + } + current = (len < current) ? len : current; + if (! get_input_bytes(rstrm, addr, current)) + return (FALSE); + addr += current; + rstrm->fbtbc -= current; + len -= current; + } + return (TRUE); +} + +static bool_t +xdrrec_putbytes(xdrs, addr, len) + XDR *xdrs; + register caddr_t addr; + register unsigned int len; +{ + register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); + register int current; + + while (len > 0) { + current = (int) ((long)rstrm->out_boundry - + (long)rstrm->out_finger); + current = (len < current) ? len : current; + memmove(rstrm->out_finger, addr, current); + rstrm->out_finger += current; + addr += current; + len -= current; + if (rstrm->out_finger == rstrm->out_boundry) { + rstrm->frag_sent = TRUE; + if (! flush_out(rstrm, FALSE)) + return (FALSE); + } + } + return (TRUE); +} + +static unsigned int +xdrrec_getpos(xdrs) + register XDR *xdrs; +{ + register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; + register int pos; + +/* 11/5/95 JRG HELP! lseek() can't take a pointer as the first arg + * This code must have always failed, and the failure let the arithmetic + * calculations proceed + */ +#ifdef __osf__ + pos = -1; +#else + pos = lseek((int)rstrm->tcp_handle, (long) 0, 1); +#endif + if (pos != -1) + switch (xdrs->x_op) { + + case XDR_ENCODE: + pos += rstrm->out_finger - rstrm->out_base; + break; + + case XDR_DECODE: + pos -= rstrm->in_boundry - rstrm->in_finger; + break; + + default: + pos = (unsigned int) -1; + break; + } + return ((unsigned int) pos); +} + +static bool_t +xdrrec_setpos(xdrs, pos) + register XDR *xdrs; + unsigned int pos; +{ + register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; + unsigned int currpos = xdrrec_getpos(xdrs); + int delta = currpos - pos; + caddr_t newpos; + + if ((int)currpos != -1) + switch (xdrs->x_op) { + + case XDR_ENCODE: + newpos = rstrm->out_finger - delta; + if ((newpos > (caddr_t)(rstrm->frag_header)) && + (newpos < rstrm->out_boundry)) { + rstrm->out_finger = newpos; + return (TRUE); + } + break; + + case XDR_DECODE: + newpos = rstrm->in_finger - delta; + if ((delta < (int)(rstrm->fbtbc)) && + (newpos <= rstrm->in_boundry) && + (newpos >= rstrm->in_base)) { + rstrm->in_finger = newpos; + rstrm->fbtbc -= delta; + return (TRUE); + } + break; + } + return (FALSE); +} + +static rpc_int32 * +xdrrec_inline(xdrs, len) + register XDR *xdrs; + int len; +{ + register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; + rpc_int32 * buf = NULL; + + switch (xdrs->x_op) { + + case XDR_ENCODE: + if ((rstrm->out_finger + len) <= rstrm->out_boundry) { + buf = (rpc_int32 *) rstrm->out_finger; + rstrm->out_finger += len; + } + break; + + case XDR_DECODE: + if ((len <= rstrm->fbtbc) && + ((rstrm->in_finger + len) <= rstrm->in_boundry)) { + buf = (rpc_int32 *) rstrm->in_finger; + rstrm->fbtbc -= len; + rstrm->in_finger += len; + } + break; + } + return (buf); +} + +static void +xdrrec_destroy(xdrs) + register XDR *xdrs; +{ + register 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)); +} + + +/* + * Exported routines to manage xdr records + */ + +/* + * Before reading (deserializing from the stream, one should always call + * this procedure to guarantee proper record alignment. + */ +bool_t +xdrrec_skiprecord(xdrs) + XDR *xdrs; +{ + register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); + + while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) { + if (! skip_input_bytes(rstrm, rstrm->fbtbc)) + return (FALSE); + rstrm->fbtbc = 0; + if ((! rstrm->last_frag) && (! set_input_fragment(rstrm))) + return (FALSE); + } + rstrm->last_frag = FALSE; + return (TRUE); +} + +/* + * Look ahead fuction. + * Returns TRUE iff there is no more input in the buffer + * after consuming the rest of the current record. + */ +bool_t +xdrrec_eof(xdrs) + XDR *xdrs; +{ + register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); + + while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) { + if (! skip_input_bytes(rstrm, rstrm->fbtbc)) + return (TRUE); + rstrm->fbtbc = 0; + if ((! rstrm->last_frag) && (! set_input_fragment(rstrm))) + return (TRUE); + } + if (rstrm->in_finger == rstrm->in_boundry) + return (TRUE); + return (FALSE); +} + +/* + * The client must tell the package when an end-of-record has occurred. + * The second paraemters tells whether the record should be flushed to the + * (output) tcp stream. (This let's the package support batched or + * pipelined procedure calls.) TRUE => immmediate flush to tcp connection. + */ +bool_t +xdrrec_endofrecord(xdrs, sendnow) + XDR *xdrs; + bool_t sendnow; +{ + register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); + register rpc_u_int32 len; /* fragment length */ + + if (sendnow || rstrm->frag_sent || + ((long)rstrm->out_finger + sizeof(unsigned int) >= + (long)rstrm->out_boundry)) { + rstrm->frag_sent = FALSE; + return (flush_out(rstrm, TRUE)); + } + len = (long)(rstrm->out_finger) - (long)(rstrm->frag_header) - + sizeof(unsigned int); + *(rstrm->frag_header) = htonl((unsigned int)len | LAST_FRAG); + rstrm->frag_header = (rpc_u_int32 *)rstrm->out_finger; + rstrm->out_finger += sizeof(unsigned int); + return (TRUE); +} + + +/* + * Internal useful routines + */ +static bool_t +flush_out(rstrm, eor) + register RECSTREAM *rstrm; + bool_t eor; +{ + register rpc_u_int32 eormask = (eor == TRUE) ? LAST_FRAG : 0; + register rpc_u_int32 len = (unsigned long)(rstrm->out_finger) - + (unsigned long)(rstrm->frag_header) - sizeof(rpc_u_int32); + + *(rstrm->frag_header) = htonl(len | eormask); + len = (unsigned long)(rstrm->out_finger) - (unsigned long)(rstrm->out_base); + if ((*(rstrm->writeit))(rstrm->tcp_handle, rstrm->out_base, (int)len) + != (int)len) + return (FALSE); + rstrm->frag_header = (rpc_u_int32 *)rstrm->out_base; + rstrm->out_finger = (caddr_t)rstrm->out_base + sizeof(rpc_u_int32); + return (TRUE); +} + +static bool_t /* knows nothing about records! Only about input buffers */ +fill_input_buf(rstrm) + register RECSTREAM *rstrm; +{ + register caddr_t where; + unsigned int i; + register int len; + + where = rstrm->in_base; + i = (unsigned int)((unsigned long)rstrm->in_boundry % BYTES_PER_XDR_UNIT); + where += i; + len = rstrm->in_size - i; + if ((len = (*(rstrm->readit))(rstrm->tcp_handle, where, len)) == -1) + return (FALSE); + rstrm->in_finger = where; + where += len; + rstrm->in_boundry = where; + return (TRUE); +} + +static bool_t /* knows nothing about records! Only about input buffers */ +get_input_bytes(rstrm, addr, len) + register RECSTREAM *rstrm; + register caddr_t addr; + register int len; +{ + register int current; + + while (len > 0) { + current = (int)((long)rstrm->in_boundry - + (long)rstrm->in_finger); + if (current == 0) { + if (! fill_input_buf(rstrm)) + return (FALSE); + continue; + } + current = (len < current) ? len : current; + memmove(addr, rstrm->in_finger, current); + rstrm->in_finger += current; + addr += current; + len -= current; + } + return (TRUE); +} + +static bool_t /* next two bytes of the input stream are treated as a header */ +set_input_fragment(rstrm) + register RECSTREAM *rstrm; +{ + rpc_u_int32 header; + + if (! get_input_bytes(rstrm, (caddr_t)&header, sizeof(header))) + return (FALSE); + header = (int)ntohl(header); + rstrm->last_frag = ((header & LAST_FRAG) == 0) ? FALSE : TRUE; + rstrm->fbtbc = header & (~LAST_FRAG); + return (TRUE); +} + +static bool_t /* consumes input bytes; knows nothing about records! */ +skip_input_bytes(rstrm, cnt) + register RECSTREAM *rstrm; + rpc_int32 cnt; +{ + register int current; + + while (cnt > 0) { + current = (int)((long)rstrm->in_boundry - + (long)rstrm->in_finger); + if (current == 0) { + if (! fill_input_buf(rstrm)) + return (FALSE); + continue; + } + current = (cnt < current) ? cnt : current; + rstrm->in_finger += current; + cnt -= current; + } + return (TRUE); +} + +static unsigned int +fix_buf_size(s) + register unsigned int s; +{ + + if (s < 100) + s = 4000; + return (RNDUP(s)); +} diff --git a/src/lib/rpc/xdr_reference.c b/src/lib/rpc/xdr_reference.c new file mode 100644 index 000000000..ebf14b68e --- /dev/null +++ b/src/lib/rpc/xdr_reference.c @@ -0,0 +1,132 @@ +/* @(#)xdr_reference.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)xdr_reference.c 1.11 87/08/11 SMI"; +#endif + +/* + * xdr_reference.c, Generic XDR routines impelmentation. + * + * Copyright (C) 1987, Sun Microsystems, Inc. + * + * These are the "non-trivial" xdr primitives used to serialize and de-serialize + * "pointers". See xdr.h for more info on the interface to xdr. + */ + +#include <stdio.h> +#include <rpc/types.h> +#include <rpc/xdr.h> + +#define LASTUNSIGNED ((unsigned int)0-1) + +/* + * XDR an indirect pointer + * xdr_reference is for recursively translating a structure that is + * referenced by a pointer inside the structure that is currently being + * translated. pp references a pointer to storage. If *pp is null + * the necessary storage is allocated. + * size is the sizeof the referneced structure. + * proc is the routine to handle the referenced structure. + */ +bool_t +xdr_reference(xdrs, pp, size, proc) + register XDR *xdrs; + caddr_t *pp; /* the pointer to work on */ + unsigned 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; + + if (loc == NULL) + switch (xdrs->x_op) { + case XDR_FREE: + return (TRUE); + + case XDR_DECODE: + *pp = loc = (caddr_t) mem_alloc(size); + if (loc == NULL) { + (void) fprintf(stderr, + "xdr_reference: out of memory\n"); + return (FALSE); + } + memset(loc, 0, (int)size); + break; + } + + stat = (*proc)(xdrs, loc, LASTUNSIGNED); + + if (xdrs->x_op == XDR_FREE) { + mem_free(loc, size); + *pp = NULL; + } + return (stat); +} + + +/* + * xdr_pointer(): + * + * XDR a pointer to a possibly recursive data structure. This + * differs with xdr_reference in that it can serialize/deserialiaze + * trees correctly. + * + * What's sent is actually a union: + * + * union object_pointer switch (boolean b) { + * case TRUE: object_data data; + * case FALSE: void nothing; + * } + * + * > objpp: Pointer to the pointer to the object. + * > obj_size: size of the object. + * > xdr_obj: routine to XDR an object. + * + */ +bool_t +xdr_pointer(xdrs,objpp,obj_size,xdr_obj) + register XDR *xdrs; + char **objpp; + unsigned int obj_size; + xdrproc_t xdr_obj; +{ + + bool_t more_data; + + more_data = (*objpp != NULL); + if (! xdr_bool(xdrs,&more_data)) { + return (FALSE); + } + if (! more_data) { + *objpp = NULL; + return (TRUE); + } + return (xdr_reference(xdrs,objpp,obj_size,xdr_obj)); +} diff --git a/src/lib/rpc/xdr_stdio.c b/src/lib/rpc/xdr_stdio.c new file mode 100644 index 000000000..6d59ad5c6 --- /dev/null +++ b/src/lib/rpc/xdr_stdio.c @@ -0,0 +1,189 @@ +/* @(#)xdr_stdio.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * 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(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)xdr_stdio.c 1.16 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * xdr_stdio.c, XDR implementation on standard i/o file. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * This set of routines implements a XDR on a stdio stream. + * XDR_ENCODE serializes onto the stream, XDR_DECODE de-serializes + * from the stream. + */ + +#include <rpc/types.h> +#include <stdio.h> +#include <rpc/xdr.h> + +static bool_t xdrstdio_getlong(); +static bool_t xdrstdio_putlong(); +static bool_t xdrstdio_getbytes(); +static bool_t xdrstdio_putbytes(); +static unsigned int xdrstdio_getpos(); +static bool_t xdrstdio_setpos(); +static rpc_int32 * xdrstdio_inline(); +static void xdrstdio_destroy(); + +/* + * Ops vector for stdio type XDR + */ +static struct xdr_ops xdrstdio_ops = { + xdrstdio_getlong, /* deseraialize a long int */ + xdrstdio_putlong, /* seraialize a long int */ + xdrstdio_getbytes, /* deserialize counted bytes */ + xdrstdio_putbytes, /* serialize counted bytes */ + xdrstdio_getpos, /* get offset in the stream */ + xdrstdio_setpos, /* set offset in the stream */ + xdrstdio_inline, /* prime stream for inline macros */ + xdrstdio_destroy /* destroy stream */ +}; + +/* + * Initialize a stdio xdr stream. + * Sets the xdr stream handle xdrs for use on the stream file. + * Operation flag is set to op. + */ +void +xdrstdio_create(xdrs, file, op) + register 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_handy = 0; + xdrs->x_base = 0; +} + +/* + * Destroy a stdio xdr stream. + * Cleans up the xdr stream handle xdrs previously set up by xdrstdio_create. + */ +static void +xdrstdio_destroy(xdrs) + register XDR *xdrs; +{ + (void)fflush((FILE *)xdrs->x_private); + /* xx should we close the file ?? */ +} + +static bool_t +xdrstdio_getlong(xdrs, lp) + XDR *xdrs; + register long *lp; +{ + rpc_int32 tmp; + if (fread((caddr_t)&tmp, + sizeof(rpc_int32), 1, (FILE *)xdrs->x_private) != 1) + return (FALSE); +#ifndef mc68000 + *lp = ntohl(tmp); +#endif + return (TRUE); +} + +static bool_t +xdrstdio_putlong(xdrs, lp) + XDR *xdrs; + long *lp; +{ + +#ifndef mc68000 + rpc_int32 mycopy = htonl((rpc_int32)*lp); +#endif + if (fwrite((caddr_t)&mycopy, sizeof(rpc_int32), 1, (FILE *)xdrs->x_private) != 1) + return (FALSE); + return (TRUE); +} + +static bool_t +xdrstdio_getbytes(xdrs, addr, len) + XDR *xdrs; + caddr_t addr; + unsigned int len; +{ + + if ((len != 0) && (fread(addr, (int)len, 1, (FILE *)xdrs->x_private) != 1)) + return (FALSE); + return (TRUE); +} + +static bool_t +xdrstdio_putbytes(xdrs, addr, len) + XDR *xdrs; + caddr_t addr; + unsigned int len; +{ + + if ((len != 0) && (fwrite(addr, (int)len, 1, (FILE *)xdrs->x_private) != 1)) + return (FALSE); + return (TRUE); +} + +static unsigned int +xdrstdio_getpos(xdrs) + XDR *xdrs; +{ + + return ((unsigned int) ftell((FILE *)xdrs->x_private)); +} + +static bool_t +xdrstdio_setpos(xdrs, pos) + XDR *xdrs; + unsigned int pos; +{ + + return ((fseek((FILE *)xdrs->x_private, (long)pos, 0) < 0) ? + FALSE : TRUE); +} + +static rpc_int32 * +xdrstdio_inline(xdrs, len) + XDR *xdrs; + unsigned int len; +{ + + /* + * Must do some work to implement this: must insure + * enough data in the underlying stdio buffer, + * that the buffer is aligned so that we can indirect through a + * long *, and stuff this pointer in xdrs->x_buf. Doing + * a fread or fwrite to a scratch buffer would defeat + * most of the gains to be had here and require storage + * management on this buffer, so we don't do this. + */ + return (NULL); +} |
