diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2016-06-09 10:23:57 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2016-06-10 14:09:30 +0200 |
commit | 60b1d40751c8b3235b7ccbf3bb6ad0c562562f01 (patch) | |
tree | e507b6d648231ceaf6eeed51796f40f497ba29df /freebsd/lib | |
parent | ftpfs: Import from RTEMS (diff) | |
download | rtems-libbsd-60b1d40751c8b3235b7ccbf3bb6ad0c562562f01.tar.bz2 |
RPC(3): Import from FreeBSD
Diffstat (limited to 'freebsd/lib')
57 files changed, 19078 insertions, 0 deletions
diff --git a/freebsd/lib/libc/rpc/auth_des.c b/freebsd/lib/libc/rpc/auth_des.c new file mode 100644 index 00000000..b3002301 --- /dev/null +++ b/freebsd/lib/libc/rpc/auth_des.c @@ -0,0 +1,499 @@ +#include <machine/rtems-bsd-user-space.h> + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1988 by Sun Microsystems, Inc. + */ +/* + * auth_des.c, client-side implementation of DES authentication + */ + +#include "namespace.h" +#include "reentrant.h" +#include <err.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/cdefs.h> +#include <rpc/des_crypt.h> +#include <syslog.h> +#include <rpc/types.h> +#include <rpc/auth.h> +#include <rpc/auth_des.h> +#include <rpc/clnt.h> +#include <rpc/xdr.h> +#include <sys/socket.h> +#undef NIS +#include <rpcsvc/nis.h> +#include "un-namespace.h" +#include "mt_misc.h" + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)auth_des.c 2.2 88/07/29 4.0 RPCSRC; from 1.9 88/02/08 SMI"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#define USEC_PER_SEC 1000000 +#define RTIME_TIMEOUT 5 /* seconds to wait for sync */ + +#define AUTH_PRIVATE(auth) (struct ad_private *) auth->ah_private +#define ALLOC(object_type) (object_type *) mem_alloc(sizeof(object_type)) +#define FREE(ptr, size) mem_free((char *)(ptr), (int) size) +#define ATTEMPT(xdr_op) if (!(xdr_op)) return (FALSE) + +extern bool_t xdr_authdes_cred( XDR *, struct authdes_cred *); +extern bool_t xdr_authdes_verf( XDR *, struct authdes_verf *); +extern int key_encryptsession_pk(); + +extern bool_t __rpc_get_time_offset(struct timeval *, nis_server *, char *, + char **, char **); + +/* + * DES authenticator operations vector + */ +static void authdes_nextverf(AUTH *); +static bool_t authdes_marshal(AUTH *, XDR *); +static bool_t authdes_validate(AUTH *, struct opaque_auth *); +static bool_t authdes_refresh(AUTH *, void *); +static void authdes_destroy(AUTH *); + +static struct auth_ops *authdes_ops(void); + +/* + * This struct is pointed to by the ah_private field of an "AUTH *" + */ +struct ad_private { + char *ad_fullname; /* client's full name */ + u_int ad_fullnamelen; /* length of name, rounded up */ + char *ad_servername; /* server's full name */ + u_int ad_servernamelen; /* length of name, rounded up */ + u_int ad_window; /* client specified window */ + bool_t ad_dosync; /* synchronize? */ + struct netbuf ad_syncaddr; /* remote host to synch with */ + char *ad_timehost; /* remote host to synch with */ + struct timeval ad_timediff; /* server's time - client's time */ + u_int ad_nickname; /* server's nickname for client */ + struct authdes_cred ad_cred; /* storage for credential */ + struct authdes_verf ad_verf; /* storage for verifier */ + struct timeval ad_timestamp; /* timestamp sent */ + des_block ad_xkey; /* encrypted conversation key */ + u_char ad_pkey[1024]; /* Server's actual public key */ + char *ad_netid; /* Timehost netid */ + char *ad_uaddr; /* Timehost uaddr */ + nis_server *ad_nis_srvr; /* NIS+ server struct */ +}; + +AUTH *authdes_pk_seccreate(const char *, netobj *, u_int, const char *, + const des_block *, nis_server *); + +/* + * documented version of authdes_seccreate + */ +/* + servername: network name of server + win: time to live + timehost: optional hostname to sync with + ckey: optional conversation key to use +*/ + +AUTH * +authdes_seccreate(const char *servername, const u_int win, + const char *timehost, const des_block *ckey) +{ + u_char pkey_data[1024]; + netobj pkey; + AUTH *dummy; + + if (! getpublickey(servername, (char *) pkey_data)) { + syslog(LOG_ERR, + "authdes_seccreate: no public key found for %s", + servername); + return (NULL); + } + + pkey.n_bytes = (char *) pkey_data; + pkey.n_len = (u_int)strlen((char *)pkey_data) + 1; + dummy = authdes_pk_seccreate(servername, &pkey, win, timehost, + ckey, NULL); + return (dummy); +} + +/* + * Slightly modified version of authdessec_create which takes the public key + * of the server principal as an argument. This spares us a call to + * getpublickey() which in the nameserver context can cause a deadlock. + */ +AUTH * +authdes_pk_seccreate(const char *servername, netobj *pkey, u_int window, + const char *timehost, const des_block *ckey, nis_server *srvr) +{ + AUTH *auth; + struct ad_private *ad; + char namebuf[MAXNETNAMELEN+1]; + + /* + * Allocate everything now + */ + auth = ALLOC(AUTH); + if (auth == NULL) { + syslog(LOG_ERR, "authdes_pk_seccreate: out of memory"); + return (NULL); + } + ad = ALLOC(struct ad_private); + if (ad == NULL) { + syslog(LOG_ERR, "authdes_pk_seccreate: out of memory"); + goto failed; + } + ad->ad_fullname = ad->ad_servername = NULL; /* Sanity reasons */ + ad->ad_timehost = NULL; + ad->ad_netid = NULL; + ad->ad_uaddr = NULL; + ad->ad_nis_srvr = NULL; + ad->ad_timediff.tv_sec = 0; + ad->ad_timediff.tv_usec = 0; + memcpy(ad->ad_pkey, pkey->n_bytes, pkey->n_len); + if (!getnetname(namebuf)) + goto failed; + ad->ad_fullnamelen = RNDUP((u_int) strlen(namebuf)); + ad->ad_fullname = (char *)mem_alloc(ad->ad_fullnamelen + 1); + ad->ad_servernamelen = strlen(servername); + ad->ad_servername = (char *)mem_alloc(ad->ad_servernamelen + 1); + + if (ad->ad_fullname == NULL || ad->ad_servername == NULL) { + syslog(LOG_ERR, "authdes_seccreate: out of memory"); + goto failed; + } + if (timehost != NULL) { + ad->ad_timehost = (char *)mem_alloc(strlen(timehost) + 1); + if (ad->ad_timehost == NULL) { + syslog(LOG_ERR, "authdes_seccreate: out of memory"); + goto failed; + } + memcpy(ad->ad_timehost, timehost, strlen(timehost) + 1); + ad->ad_dosync = TRUE; + } else if (srvr != NULL) { + ad->ad_nis_srvr = srvr; /* transient */ + ad->ad_dosync = TRUE; + } else { + ad->ad_dosync = FALSE; + } + memcpy(ad->ad_fullname, namebuf, ad->ad_fullnamelen + 1); + memcpy(ad->ad_servername, servername, ad->ad_servernamelen + 1); + ad->ad_window = window; + if (ckey == NULL) { + if (key_gendes(&auth->ah_key) < 0) { + syslog(LOG_ERR, + "authdes_seccreate: keyserv(1m) is unable to generate session key"); + goto failed; + } + } else { + auth->ah_key = *ckey; + } + + /* + * Set up auth handle + */ + auth->ah_cred.oa_flavor = AUTH_DES; + auth->ah_verf.oa_flavor = AUTH_DES; + auth->ah_ops = authdes_ops(); + auth->ah_private = (caddr_t)ad; + + if (!authdes_refresh(auth, NULL)) { + goto failed; + } + ad->ad_nis_srvr = NULL; /* not needed any longer */ + return (auth); + +failed: + if (auth) + FREE(auth, sizeof (AUTH)); + if (ad) { + if (ad->ad_fullname) + FREE(ad->ad_fullname, ad->ad_fullnamelen + 1); + if (ad->ad_servername) + FREE(ad->ad_servername, ad->ad_servernamelen + 1); + if (ad->ad_timehost) + FREE(ad->ad_timehost, strlen(ad->ad_timehost) + 1); + if (ad->ad_netid) + FREE(ad->ad_netid, strlen(ad->ad_netid) + 1); + if (ad->ad_uaddr) + FREE(ad->ad_uaddr, strlen(ad->ad_uaddr) + 1); + FREE(ad, sizeof (struct ad_private)); + } + return (NULL); +} + +/* + * Implement the five authentication operations + */ + + +/* + * 1. Next Verifier + */ +/*ARGSUSED*/ +static void +authdes_nextverf(AUTH *auth) +{ + /* what the heck am I supposed to do??? */ +} + + +/* + * 2. Marshal + */ +static bool_t +authdes_marshal(AUTH *auth, XDR *xdrs) +{ +/* LINTED pointer alignment */ + struct ad_private *ad = AUTH_PRIVATE(auth); + struct authdes_cred *cred = &ad->ad_cred; + struct authdes_verf *verf = &ad->ad_verf; + des_block cryptbuf[2]; + des_block ivec; + int status; + int len; + rpc_inline_t *ixdr; + + /* + * Figure out the "time", accounting for any time difference + * with the server if necessary. + */ + (void) gettimeofday(&ad->ad_timestamp, (struct timezone *)NULL); + ad->ad_timestamp.tv_sec += ad->ad_timediff.tv_sec; + ad->ad_timestamp.tv_usec += ad->ad_timediff.tv_usec; + while (ad->ad_timestamp.tv_usec >= USEC_PER_SEC) { + ad->ad_timestamp.tv_usec -= USEC_PER_SEC; + ad->ad_timestamp.tv_sec++; + } + + /* + * XDR the timestamp and possibly some other things, then + * encrypt them. + */ + ixdr = (rpc_inline_t *)cryptbuf; + IXDR_PUT_INT32(ixdr, ad->ad_timestamp.tv_sec); + IXDR_PUT_INT32(ixdr, ad->ad_timestamp.tv_usec); + if (ad->ad_cred.adc_namekind == ADN_FULLNAME) { + IXDR_PUT_U_INT32(ixdr, ad->ad_window); + IXDR_PUT_U_INT32(ixdr, ad->ad_window - 1); + ivec.key.high = ivec.key.low = 0; + status = cbc_crypt((char *)&auth->ah_key, (char *)cryptbuf, + (u_int) 2 * sizeof (des_block), + DES_ENCRYPT | DES_HW, (char *)&ivec); + } else { + status = ecb_crypt((char *)&auth->ah_key, (char *)cryptbuf, + (u_int) sizeof (des_block), + DES_ENCRYPT | DES_HW); + } + if (DES_FAILED(status)) { + syslog(LOG_ERR, "authdes_marshal: DES encryption failure"); + return (FALSE); + } + ad->ad_verf.adv_xtimestamp = cryptbuf[0]; + if (ad->ad_cred.adc_namekind == ADN_FULLNAME) { + ad->ad_cred.adc_fullname.window = cryptbuf[1].key.high; + ad->ad_verf.adv_winverf = cryptbuf[1].key.low; + } else { + ad->ad_cred.adc_nickname = ad->ad_nickname; + ad->ad_verf.adv_winverf = 0; + } + + /* + * Serialize the credential and verifier into opaque + * authentication data. + */ + if (ad->ad_cred.adc_namekind == ADN_FULLNAME) { + len = ((1 + 1 + 2 + 1)*BYTES_PER_XDR_UNIT + ad->ad_fullnamelen); + } else { + len = (1 + 1)*BYTES_PER_XDR_UNIT; + } + + if ((ixdr = xdr_inline(xdrs, 2*BYTES_PER_XDR_UNIT))) { + IXDR_PUT_INT32(ixdr, AUTH_DES); + IXDR_PUT_INT32(ixdr, len); + } else { + ATTEMPT(xdr_putint32(xdrs, (int *)&auth->ah_cred.oa_flavor)); + ATTEMPT(xdr_putint32(xdrs, &len)); + } + ATTEMPT(xdr_authdes_cred(xdrs, cred)); + + len = (2 + 1)*BYTES_PER_XDR_UNIT; + if ((ixdr = xdr_inline(xdrs, 2*BYTES_PER_XDR_UNIT))) { + IXDR_PUT_INT32(ixdr, AUTH_DES); + IXDR_PUT_INT32(ixdr, len); + } else { + ATTEMPT(xdr_putint32(xdrs, (int *)&auth->ah_verf.oa_flavor)); + ATTEMPT(xdr_putint32(xdrs, &len)); + } + ATTEMPT(xdr_authdes_verf(xdrs, verf)); + return (TRUE); +} + + +/* + * 3. Validate + */ +static bool_t +authdes_validate(AUTH *auth, struct opaque_auth *rverf) +{ +/* LINTED pointer alignment */ + struct ad_private *ad = AUTH_PRIVATE(auth); + struct authdes_verf verf; + int status; + uint32_t *ixdr; + des_block buf; + + if (rverf->oa_length != (2 + 1) * BYTES_PER_XDR_UNIT) { + return (FALSE); + } +/* LINTED pointer alignment */ + ixdr = (uint32_t *)rverf->oa_base; + buf.key.high = (uint32_t)*ixdr++; + buf.key.low = (uint32_t)*ixdr++; + verf.adv_int_u = (uint32_t)*ixdr++; + + /* + * Decrypt the timestamp + */ + status = ecb_crypt((char *)&auth->ah_key, (char *)&buf, + (u_int)sizeof (des_block), DES_DECRYPT | DES_HW); + + if (DES_FAILED(status)) { + syslog(LOG_ERR, "authdes_validate: DES decryption failure"); + return (FALSE); + } + + /* + * xdr the decrypted timestamp + */ +/* LINTED pointer alignment */ + ixdr = (uint32_t *)buf.c; + verf.adv_timestamp.tv_sec = IXDR_GET_INT32(ixdr) + 1; + verf.adv_timestamp.tv_usec = IXDR_GET_INT32(ixdr); + + /* + * validate + */ + if (bcmp((char *)&ad->ad_timestamp, (char *)&verf.adv_timestamp, + sizeof(struct timeval)) != 0) { + syslog(LOG_DEBUG, "authdes_validate: verifier mismatch"); + return (FALSE); + } + + /* + * We have a nickname now, let's use it + */ + ad->ad_nickname = verf.adv_nickname; + ad->ad_cred.adc_namekind = ADN_NICKNAME; + return (TRUE); +} + +/* + * 4. Refresh + */ +/*ARGSUSED*/ +static bool_t +authdes_refresh(AUTH *auth, void *dummy) +{ +/* LINTED pointer alignment */ + struct ad_private *ad = AUTH_PRIVATE(auth); + struct authdes_cred *cred = &ad->ad_cred; + int ok; + netobj pkey; + + if (ad->ad_dosync) { + ok = __rpc_get_time_offset(&ad->ad_timediff, ad->ad_nis_srvr, + ad->ad_timehost, &(ad->ad_uaddr), + &(ad->ad_netid)); + if (! ok) { + /* + * Hope the clocks are synced! + */ + ad->ad_dosync = 0; + syslog(LOG_DEBUG, + "authdes_refresh: unable to synchronize clock"); + } + } + ad->ad_xkey = auth->ah_key; + pkey.n_bytes = (char *)(ad->ad_pkey); + pkey.n_len = (u_int)strlen((char *)ad->ad_pkey) + 1; + if (key_encryptsession_pk(ad->ad_servername, &pkey, &ad->ad_xkey) < 0) { + syslog(LOG_INFO, + "authdes_refresh: keyserv(1m) is unable to encrypt session key"); + return (FALSE); + } + cred->adc_fullname.key = ad->ad_xkey; + cred->adc_namekind = ADN_FULLNAME; + cred->adc_fullname.name = ad->ad_fullname; + return (TRUE); +} + + +/* + * 5. Destroy + */ +static void +authdes_destroy(AUTH *auth) +{ +/* LINTED pointer alignment */ + struct ad_private *ad = AUTH_PRIVATE(auth); + + FREE(ad->ad_fullname, ad->ad_fullnamelen + 1); + FREE(ad->ad_servername, ad->ad_servernamelen + 1); + if (ad->ad_timehost) + FREE(ad->ad_timehost, strlen(ad->ad_timehost) + 1); + if (ad->ad_netid) + FREE(ad->ad_netid, strlen(ad->ad_netid) + 1); + if (ad->ad_uaddr) + FREE(ad->ad_uaddr, strlen(ad->ad_uaddr) + 1); + FREE(ad, sizeof (struct ad_private)); + FREE(auth, sizeof(AUTH)); +} + +static struct auth_ops * +authdes_ops(void) +{ + static struct auth_ops ops; + + /* VARIABLES PROTECTED BY ops_lock: ops */ + + mutex_lock(&authdes_ops_lock); + if (ops.ah_nextverf == NULL) { + ops.ah_nextverf = authdes_nextverf; + ops.ah_marshal = authdes_marshal; + ops.ah_validate = authdes_validate; + ops.ah_refresh = authdes_refresh; + ops.ah_destroy = authdes_destroy; + } + mutex_unlock(&authdes_ops_lock); + return (&ops); +} diff --git a/freebsd/lib/libc/rpc/auth_none.c b/freebsd/lib/libc/rpc/auth_none.c new file mode 100644 index 00000000..821771de --- /dev/null +++ b/freebsd/lib/libc/rpc/auth_none.c @@ -0,0 +1,177 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: auth_none.c,v 1.13 2000/01/22 22:19:17 mycroft Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *sccsid2 = "@(#)auth_none.c 1.19 87/08/11 Copyr 1984 Sun Micro"; +static char *sccsid = "@(#)auth_none.c 2.1 88/07/29 4.0 RPCSRC"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * auth_none.c + * Creates a client authentication handle for passing "null" + * credentials and verifiers to remote systems. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include "namespace.h" +#include "reentrant.h" +#include <assert.h> +#include <stdlib.h> +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <rpc/auth.h> +#include "un-namespace.h" +#include "mt_misc.h" + +#define MAX_MARSHAL_SIZE 20 + +/* + * Authenticator operations routines + */ + +static bool_t authnone_marshal (AUTH *, XDR *); +static void authnone_verf (AUTH *); +static bool_t authnone_validate (AUTH *, struct opaque_auth *); +static bool_t authnone_refresh (AUTH *, void *); +static void authnone_destroy (AUTH *); + +extern bool_t xdr_opaque_auth(); + +static struct auth_ops *authnone_ops(); + +static struct authnone_private { + AUTH no_client; + char marshalled_client[MAX_MARSHAL_SIZE]; + u_int mcnt; +} *authnone_private; + +AUTH * +authnone_create() +{ + struct authnone_private *ap = authnone_private; + XDR xdr_stream; + XDR *xdrs; + + mutex_lock(&authnone_lock); + if (ap == 0) { + ap = (struct authnone_private *)calloc(1, sizeof (*ap)); + if (ap == 0) { + mutex_unlock(&authnone_lock); + return (0); + } + authnone_private = ap; + } + if (!ap->mcnt) { + ap->no_client.ah_cred = ap->no_client.ah_verf = _null_auth; + ap->no_client.ah_ops = authnone_ops(); + xdrs = &xdr_stream; + xdrmem_create(xdrs, ap->marshalled_client, + (u_int)MAX_MARSHAL_SIZE, XDR_ENCODE); + (void)xdr_opaque_auth(xdrs, &ap->no_client.ah_cred); + (void)xdr_opaque_auth(xdrs, &ap->no_client.ah_verf); + ap->mcnt = XDR_GETPOS(xdrs); + XDR_DESTROY(xdrs); + } + mutex_unlock(&authnone_lock); + return (&ap->no_client); +} + +/*ARGSUSED*/ +static bool_t +authnone_marshal(AUTH *client, XDR *xdrs) +{ + struct authnone_private *ap; + bool_t dummy; + + assert(xdrs != NULL); + + ap = authnone_private; + if (ap == NULL) { + mutex_unlock(&authnone_lock); + return (FALSE); + } + dummy = (*xdrs->x_ops->x_putbytes)(xdrs, + ap->marshalled_client, ap->mcnt); + mutex_unlock(&authnone_lock); + return (dummy); +} + +/* All these unused parameters are required to keep ANSI-C from grumbling */ +/*ARGSUSED*/ +static void +authnone_verf(AUTH *client) +{ +} + +/*ARGSUSED*/ +static bool_t +authnone_validate(AUTH *client, struct opaque_auth *opaque) +{ + + return (TRUE); +} + +/*ARGSUSED*/ +static bool_t +authnone_refresh(AUTH *client, void *dummy) +{ + + return (FALSE); +} + +/*ARGSUSED*/ +static void +authnone_destroy(AUTH *client) +{ +} + +static struct auth_ops * +authnone_ops() +{ + static struct auth_ops ops; + +/* VARIABLES PROTECTED BY ops_lock: ops */ + + mutex_lock(&ops_lock); + if (ops.ah_nextverf == NULL) { + ops.ah_nextverf = authnone_verf; + ops.ah_marshal = authnone_marshal; + ops.ah_validate = authnone_validate; + ops.ah_refresh = authnone_refresh; + ops.ah_destroy = authnone_destroy; + } + mutex_unlock(&ops_lock); + return (&ops); +} diff --git a/freebsd/lib/libc/rpc/auth_time.c b/freebsd/lib/libc/rpc/auth_time.c new file mode 100644 index 00000000..09e197a7 --- /dev/null +++ b/freebsd/lib/libc/rpc/auth_time.c @@ -0,0 +1,509 @@ +#include <machine/rtems-bsd-user-space.h> + +/* #pragma ident "@(#)auth_time.c 1.4 92/11/10 SMI" */ + +/* + * auth_time.c + * + * This module contains the private function __rpc_get_time_offset() + * which will return the difference in seconds between the local system's + * notion of time and a remote server's notion of time. This must be + * possible without calling any functions that may invoke the name + * service. (netdir_getbyxxx, getXbyY, etc). The function is used in the + * synchronize call of the authdes code to synchronize clocks between + * NIS+ clients and their servers. + * + * Note to minimize the amount of duplicate code, portions of the + * synchronize() function were folded into this code, and the synchronize + * call becomes simply a wrapper around this function. Further, if this + * function is called with a timehost it *DOES* recurse to the name + * server so don't use it in that mode if you are doing name service code. + * + * Copyright (c) 1992 Sun Microsystems Inc. + * All rights reserved. + * + * Side effects : + * When called a client handle to a RPCBIND process is created + * and destroyed. Two strings "netid" and "uaddr" are malloc'd + * and returned. The SIGALRM processing is modified only if + * needed to deal with TCP connections. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "namespace.h" +#include <stdio.h> +#include <syslog.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <netdb.h> +#include <sys/signal.h> +#include <rtems/bsd/sys/errno.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <rpc/rpc.h> +#include <rpc/rpc_com.h> +#include <rpc/rpcb_prot.h> +#undef NIS +#include <rpcsvc/nis.h> +#include "un-namespace.h" + +extern int _rpc_dtablesize( void ); + +#ifdef TESTING +#define msg(x) printf("ERROR: %s\n", x) +/* #define msg(x) syslog(LOG_ERR, "%s", x) */ +#else +#define msg(x) +#endif + +static int saw_alarm = 0; + +static void +alarm_hndler(s) + int s; +{ + saw_alarm = 1; + return; +} + +/* + * The internet time server defines the epoch to be Jan 1, 1900 + * whereas UNIX defines it to be Jan 1, 1970. To adjust the result + * from internet time-service time, into UNIX time we subtract the + * following offset : + */ +#define NYEARS (1970 - 1900) +#define TOFFSET ((u_long)60*60*24*(365*NYEARS + (NYEARS/4))) + + +/* + * Stolen from rpc.nisd: + * Turn a 'universal address' into a struct sockaddr_in. + * Bletch. + */ +static int uaddr_to_sockaddr(uaddr, sin) +#ifdef foo + endpoint *endpt; +#endif + char *uaddr; + struct sockaddr_in *sin; +{ + unsigned char p_bytes[2]; + int i; + unsigned long a[6]; + + i = sscanf(uaddr, "%lu.%lu.%lu.%lu.%lu.%lu", &a[0], &a[1], &a[2], + &a[3], &a[4], &a[5]); + + if (i < 6) + return(1); + + for (i = 0; i < 4; i++) + sin->sin_addr.s_addr |= (a[i] & 0x000000FF) << (8 * i); + + p_bytes[0] = (unsigned char)a[4] & 0x000000FF; + p_bytes[1] = (unsigned char)a[5] & 0x000000FF; + + sin->sin_family = AF_INET; /* always */ + bcopy((char *)&p_bytes, (char *)&sin->sin_port, 2); + + return (0); +} + +/* + * free_eps() + * + * Free the strings that were strduped into the eps structure. + */ +static void +free_eps(eps, num) + endpoint eps[]; + int num; +{ + int i; + + for (i = 0; i < num; i++) { + free(eps[i].uaddr); + free(eps[i].proto); + free(eps[i].family); + } + return; +} + +/* + * get_server() + * + * This function constructs a nis_server structure description for the + * indicated hostname. + * + * NOTE: There is a chance we may end up recursing here due to the + * fact that gethostbyname() could do an NIS search. Ideally, the + * NIS+ server will call __rpc_get_time_offset() with the nis_server + * structure already populated. + */ +static nis_server * +get_server(sin, host, srv, eps, maxep) + struct sockaddr_in *sin; + char *host; /* name of the time host */ + nis_server *srv; /* nis_server struct to use. */ + endpoint eps[]; /* array of endpoints */ + int maxep; /* max array size */ +{ + char hname[256]; + int num_ep = 0, i; + struct hostent *he; + struct hostent dummy; + char *ptr[2]; + endpoint *ep; + + if (host == NULL && sin == NULL) + return (NULL); + + if (sin == NULL) { + he = gethostbyname(host); + if (he == NULL) + return(NULL); + } else { + he = &dummy; + ptr[0] = (char *)&sin->sin_addr.s_addr; + ptr[1] = NULL; + dummy.h_addr_list = ptr; + } + + /* + * This is lame. We go around once for TCP, then again + * for UDP. + */ + for (i = 0, ep = eps; (he->h_addr_list[i] != NULL) && (num_ep < maxep); + i++, ep++, num_ep++) { + struct in_addr *a; + + a = (struct in_addr *)he->h_addr_list[i]; + snprintf(hname, sizeof(hname), "%s.0.111", inet_ntoa(*a)); + ep->uaddr = strdup(hname); + ep->family = strdup("inet"); + ep->proto = strdup("tcp"); + if (ep->uaddr == NULL || ep->family == NULL || ep->proto == NULL) { + free_eps(eps, num_ep + 1); + return (NULL); + } + } + + for (i = 0; (he->h_addr_list[i] != NULL) && (num_ep < maxep); + i++, ep++, num_ep++) { + struct in_addr *a; + + a = (struct in_addr *)he->h_addr_list[i]; + snprintf(hname, sizeof(hname), "%s.0.111", inet_ntoa(*a)); + ep->uaddr = strdup(hname); + ep->family = strdup("inet"); + ep->proto = strdup("udp"); + if (ep->uaddr == NULL || ep->family == NULL || ep->proto == NULL) { + free_eps(eps, num_ep + 1); + return (NULL); + } + } + + srv->name = (nis_name) host; + srv->ep.ep_len = num_ep; + srv->ep.ep_val = eps; + srv->key_type = NIS_PK_NONE; + srv->pkey.n_bytes = NULL; + srv->pkey.n_len = 0; + return (srv); +} + +/* + * __rpc_get_time_offset() + * + * This function uses a nis_server structure to contact the a remote + * machine (as named in that structure) and returns the offset in time + * between that machine and this one. This offset is returned in seconds + * and may be positive or negative. + * + * The first time through, a lot of fiddling is done with the netconfig + * stuff to find a suitable transport. The function is very aggressive + * about choosing UDP or at worst TCP if it can. This is because + * those transports support both the RCPBIND call and the internet + * time service. + * + * Once through, *uaddr is set to the universal address of + * the machine and *netid is set to the local netid for the transport + * that uaddr goes with. On the second call, the netconfig stuff + * is skipped and the uaddr/netid pair are used to fetch the netconfig + * structure and to then contact the machine for the time. + * + * td = "server" - "client" + */ +int +__rpc_get_time_offset(td, srv, thost, uaddr, netid) + struct timeval *td; /* Time difference */ + nis_server *srv; /* NIS Server description */ + char *thost; /* if no server, this is the timehost */ + char **uaddr; /* known universal address */ + struct sockaddr_in *netid; /* known network identifier */ +{ + CLIENT *clnt; /* Client handle */ + endpoint *ep, /* useful endpoints */ + *useep = NULL; /* endpoint of xp */ + char *useua = NULL; /* uaddr of selected xp */ + int epl, i; /* counters */ + enum clnt_stat status; /* result of clnt_call */ + u_long thetime, delta; + int needfree = 0; + struct timeval tv; + int time_valid; + int udp_ep = -1, tcp_ep = -1; + int a1, a2, a3, a4; + char ut[64], ipuaddr[64]; + endpoint teps[32]; + nis_server tsrv; + void (*oldsig)() = NULL; /* old alarm handler */ + struct sockaddr_in sin; + socklen_t len; + int s = RPC_ANYSOCK; + int type = 0; + + td->tv_sec = 0; + td->tv_usec = 0; + + /* + * First check to see if we need to find and address for this + * server. + */ + if (*uaddr == NULL) { + if ((srv != NULL) && (thost != NULL)) { + msg("both timehost and srv pointer used!"); + return (0); + } + if (! srv) { + srv = get_server(netid, thost, &tsrv, teps, 32); + if (srv == NULL) { + msg("unable to contruct server data."); + return (0); + } + needfree = 1; /* need to free data in endpoints */ + } + + ep = srv->ep.ep_val; + epl = srv->ep.ep_len; + + /* Identify the TCP and UDP endpoints */ + for (i = 0; + (i < epl) && ((udp_ep == -1) || (tcp_ep == -1)); i++) { + if (strcasecmp(ep[i].proto, "udp") == 0) + udp_ep = i; + if (strcasecmp(ep[i].proto, "tcp") == 0) + tcp_ep = i; + } + + /* Check to see if it is UDP or TCP */ + if (tcp_ep > -1) { + useep = &ep[tcp_ep]; + useua = ep[tcp_ep].uaddr; + type = SOCK_STREAM; + } else if (udp_ep > -1) { + useep = &ep[udp_ep]; + useua = ep[udp_ep].uaddr; + type = SOCK_DGRAM; + } + + if (useep == NULL) { + msg("no acceptable transport endpoints."); + if (needfree) + free_eps(teps, tsrv.ep.ep_len); + return (0); + } + } + + /* + * Create a sockaddr from the uaddr. + */ + if (*uaddr != NULL) + useua = *uaddr; + + /* Fixup test for NIS+ */ + sscanf(useua, "%d.%d.%d.%d.", &a1, &a2, &a3, &a4); + sprintf(ipuaddr, "%d.%d.%d.%d.0.111", a1, a2, a3, a4); + useua = &ipuaddr[0]; + + bzero((char *)&sin, sizeof(sin)); + if (uaddr_to_sockaddr(useua, &sin)) { + msg("unable to translate uaddr to sockaddr."); + if (needfree) + free_eps(teps, tsrv.ep.ep_len); + return (0); + } + + /* + * Create the client handle to rpcbind. Note we always try + * version 3 since that is the earliest version that supports + * the RPCB_GETTIME call. Also it is the version that comes + * standard with SVR4. Since most everyone supports TCP/IP + * we could consider trying the rtime call first. + */ + clnt = clnttcp_create(&sin, RPCBPROG, RPCBVERS, &s, 0, 0); + if (clnt == NULL) { + msg("unable to create client handle to rpcbind."); + if (needfree) + free_eps(teps, tsrv.ep.ep_len); + return (0); + } + + tv.tv_sec = 5; + tv.tv_usec = 0; + time_valid = 0; + status = clnt_call(clnt, RPCBPROC_GETTIME, (xdrproc_t)xdr_void, NULL, + (xdrproc_t)xdr_u_long, &thetime, tv); + /* + * The only error we check for is anything but success. In + * fact we could have seen PROGMISMATCH if talking to a 4.1 + * machine (pmap v2) or TIMEDOUT if the net was busy. + */ + if (status == RPC_SUCCESS) + time_valid = 1; + else { + int save; + + /* Blow away possible stale CLNT handle. */ + if (clnt != NULL) { + clnt_destroy(clnt); + clnt = NULL; + } + + /* + * Convert PMAP address into timeservice address + * We take advantage of the fact that we "know" what + * the universal address looks like for inet transports. + * + * We also know that the internet timeservice is always + * listening on port 37. + */ + sscanf(useua, "%d.%d.%d.%d.", &a1, &a2, &a3, &a4); + sprintf(ut, "%d.%d.%d.%d.0.37", a1, a2, a3, a4); + + if (uaddr_to_sockaddr(ut, &sin)) { + msg("cannot convert timeservice uaddr to sockaddr."); + goto error; + } + + s = _socket(AF_INET, type, 0); + if (s == -1) { + msg("unable to open fd to network."); + goto error; + } + + /* + * Now depending on whether or not we're talking to + * UDP we set a timeout or not. + */ + if (type == SOCK_DGRAM) { + struct timeval timeout = { 20, 0 }; + struct sockaddr_in from; + fd_set readfds; + int res; + + if (_sendto(s, &thetime, sizeof(thetime), 0, + (struct sockaddr *)&sin, sizeof(sin)) == -1) { + msg("udp : sendto failed."); + goto error; + } + do { + FD_ZERO(&readfds); + FD_SET(s, &readfds); + res = _select(_rpc_dtablesize(), &readfds, + (fd_set *)NULL, (fd_set *)NULL, &timeout); + } while (res < 0 && errno == EINTR); + if (res <= 0) + goto error; + len = sizeof(from); + res = _recvfrom(s, (char *)&thetime, sizeof(thetime), 0, + (struct sockaddr *)&from, &len); + if (res == -1) { + msg("recvfrom failed on udp transport."); + goto error; + } + time_valid = 1; + } else { + int res; + + oldsig = (void (*)())signal(SIGALRM, alarm_hndler); + saw_alarm = 0; /* global tracking the alarm */ + alarm(20); /* only wait 20 seconds */ + res = _connect(s, (struct sockaddr *)&sin, sizeof(sin)); + if (res == -1) { + msg("failed to connect to tcp endpoint."); + goto error; + } + if (saw_alarm) { + msg("alarm caught it, must be unreachable."); + goto error; + } + res = _read(s, (char *)&thetime, sizeof(thetime)); + if (res != sizeof(thetime)) { + if (saw_alarm) + msg("timed out TCP call."); + else + msg("wrong size of results returned"); + + goto error; + } + time_valid = 1; + } + save = errno; + (void)_close(s); + errno = save; + s = RPC_ANYSOCK; + + if (time_valid) { + thetime = ntohl(thetime); + thetime = thetime - TOFFSET; /* adjust to UNIX time */ + } else + thetime = 0; + } + + gettimeofday(&tv, 0); + +error: + /* + * clean up our allocated data structures. + */ + + if (s != RPC_ANYSOCK) + (void)_close(s); + + if (clnt != NULL) + clnt_destroy(clnt); + + alarm(0); /* reset that alarm if its outstanding */ + if (oldsig) { + signal(SIGALRM, oldsig); + } + + /* + * note, don't free uaddr strings until after we've made a + * copy of them. + */ + if (time_valid) { + if (*uaddr == NULL) + *uaddr = strdup(useua); + + /* Round to the nearest second */ + tv.tv_sec += (tv.tv_sec > 500000) ? 1 : 0; + delta = (thetime > tv.tv_sec) ? thetime - tv.tv_sec : + tv.tv_sec - thetime; + td->tv_sec = (thetime < tv.tv_sec) ? - delta : delta; + td->tv_usec = 0; + } else { + msg("unable to get the server's time."); + } + + if (needfree) + free_eps(teps, tsrv.ep.ep_len); + + return (time_valid); +} diff --git a/freebsd/lib/libc/rpc/auth_unix.c b/freebsd/lib/libc/rpc/auth_unix.c new file mode 100644 index 00000000..1d9130df --- /dev/null +++ b/freebsd/lib/libc/rpc/auth_unix.c @@ -0,0 +1,384 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: auth_unix.c,v 1.18 2000/07/06 03:03:30 christos Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *sccsid2 = "@(#)auth_unix.c 1.19 87/08/11 Copyr 1984 Sun Micro"; +static char *sccsid = "@(#)auth_unix.c 2.2 88/08/01 4.0 RPCSRC"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * 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 "namespace.h" +#include "reentrant.h" +#include <rtems/bsd/sys/param.h> + +#include <assert.h> +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <rpc/auth.h> +#include <rpc/auth_unix.h> +#include "un-namespace.h" +#include "mt_misc.h" + +/* auth_unix.c */ +static void authunix_nextverf (AUTH *); +static bool_t authunix_marshal (AUTH *, XDR *); +static bool_t authunix_validate (AUTH *, struct opaque_auth *); +static bool_t authunix_refresh (AUTH *, void *); +static void authunix_destroy (AUTH *); +static void marshal_new_auth (AUTH *); +static struct auth_ops *authunix_ops (void); + +/* + * This struct is pointed to by the ah_private field of an auth_handle. + */ +struct audata { + struct opaque_auth au_origcred; /* original credentials */ + struct opaque_auth au_shcred; /* short hand cred */ + u_long au_shfaults; /* short hand cache faults */ + char au_marshed[MAX_AUTH_BYTES]; + u_int au_mpos; /* xdr pos at end of marshed */ +}; +#define AUTH_PRIVATE(auth) ((struct audata *)auth->ah_private) + +/* + * Create a unix style authenticator. + * Returns an auth handle with the given stuff in it. + */ +AUTH * +authunix_create(machname, uid, gid, len, aup_gids) + char *machname; + u_int uid; + u_int gid; + int len; + u_int *aup_gids; +{ + struct authunix_parms aup; + char mymem[MAX_AUTH_BYTES]; + struct timeval now; + XDR xdrs; + AUTH *auth; + struct audata *au; + + /* + * Allocate and set up auth handle + */ + au = NULL; + auth = mem_alloc(sizeof(*auth)); +#ifndef _KERNEL + if (auth == NULL) { + warnx("authunix_create: out of memory"); + goto cleanup_authunix_create; + } +#endif + au = mem_alloc(sizeof(*au)); +#ifndef _KERNEL + if (au == NULL) { + warnx("authunix_create: out of memory"); + goto cleanup_authunix_create; + } +#endif + auth->ah_ops = authunix_ops(); + auth->ah_private = (caddr_t)au; + auth->ah_verf = au->au_shcred = _null_auth; + au->au_shfaults = 0; + au->au_origcred.oa_base = NULL; + + /* + * fill in param struct from the given params + */ + (void)gettimeofday(&now, NULL); + aup.aup_time = now.tv_sec; + aup.aup_machname = machname; + aup.aup_uid = uid; + aup.aup_gid = gid; + aup.aup_len = (u_int)len; + aup.aup_gids = aup_gids; + + /* + * Serialize the parameters into origcred + */ + xdrmem_create(&xdrs, mymem, MAX_AUTH_BYTES, XDR_ENCODE); + if (! xdr_authunix_parms(&xdrs, &aup)) + 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((u_int) len); +#else + if ((au->au_origcred.oa_base = mem_alloc((u_int) len)) == NULL) { + warnx("authunix_create: out of memory"); + goto cleanup_authunix_create; + } +#endif + memmove(au->au_origcred.oa_base, mymem, (size_t)len); + + /* + * set auth handle to reflect new cred. + */ + auth->ah_cred = au->au_origcred; + marshal_new_auth(auth); + return (auth); +#ifndef _KERNEL + cleanup_authunix_create: + if (auth) + mem_free(auth, sizeof(*auth)); + if (au) { + if (au->au_origcred.oa_base) + mem_free(au->au_origcred.oa_base, (u_int)len); + mem_free(au, sizeof(*au)); + } + return (NULL); +#endif +} + +/* + * Returns an auth handle with parameters determined by doing lots of + * syscalls. + */ +AUTH * +authunix_create_default() +{ + AUTH *auth; + int ngids; + long ngids_max; + char machname[MAXHOSTNAMELEN + 1]; + u_int uid; + u_int gid; + u_int *gids; + + ngids_max = sysconf(_SC_NGROUPS_MAX) + 1; + gids = malloc(sizeof(gid_t) * ngids_max); + if (gids == NULL) + return (NULL); + + if (gethostname(machname, sizeof machname) == -1) + abort(); + machname[sizeof(machname) - 1] = 0; + uid = geteuid(); + gid = getegid(); + if ((ngids = getgroups(ngids_max, gids)) < 0) + abort(); + if (ngids > NGRPS) + ngids = NGRPS; + /* XXX: interface problem; we should translate from uid_t and gid_t */ + auth = authunix_create(machname, uid, gid, ngids, gids); + free(gids); + return (auth); +} + +/* + * authunix operations + */ + +/* ARGSUSED */ +static void +authunix_nextverf(auth) + AUTH *auth; +{ + /* no action necessary */ +} + +static bool_t +authunix_marshal(auth, xdrs) + AUTH *auth; + XDR *xdrs; +{ + struct audata *au; + + assert(auth != NULL); + assert(xdrs != NULL); + + au = AUTH_PRIVATE(auth); + return (XDR_PUTBYTES(xdrs, au->au_marshed, au->au_mpos)); +} + +static bool_t +authunix_validate(auth, verf) + AUTH *auth; + struct opaque_auth *verf; +{ + struct audata *au; + XDR xdrs; + + assert(auth != NULL); + assert(verf != NULL); + + if (verf->oa_flavor == AUTH_SHORT) { + au = AUTH_PRIVATE(auth); + xdrmem_create(&xdrs, verf->oa_base, verf->oa_length, + XDR_DECODE); + + if (au->au_shcred.oa_base != NULL) { + mem_free(au->au_shcred.oa_base, + au->au_shcred.oa_length); + au->au_shcred.oa_base = NULL; + } + if (xdr_opaque_auth(&xdrs, &au->au_shcred)) { + auth->ah_cred = au->au_shcred; + } else { + xdrs.x_op = XDR_FREE; + (void)xdr_opaque_auth(&xdrs, &au->au_shcred); + au->au_shcred.oa_base = NULL; + auth->ah_cred = au->au_origcred; + } + marshal_new_auth(auth); + } + return (TRUE); +} + +static bool_t +authunix_refresh(AUTH *auth, void *dummy) +{ + struct audata *au = AUTH_PRIVATE(auth); + struct authunix_parms aup; + struct timeval now; + XDR xdrs; + int stat; + + assert(auth != NULL); + + if (auth->ah_cred.oa_base == au->au_origcred.oa_base) { + /* there is no hope. Punt */ + return (FALSE); + } + au->au_shfaults ++; + + /* first deserialize the creds back into a struct authunix_parms */ + aup.aup_machname = NULL; + aup.aup_gids = NULL; + xdrmem_create(&xdrs, au->au_origcred.oa_base, + au->au_origcred.oa_length, XDR_DECODE); + stat = xdr_authunix_parms(&xdrs, &aup); + if (! stat) + goto done; + + /* update the time and serialize in place */ + (void)gettimeofday(&now, NULL); + aup.aup_time = now.tv_sec; + xdrs.x_op = XDR_ENCODE; + XDR_SETPOS(&xdrs, 0); + stat = xdr_authunix_parms(&xdrs, &aup); + if (! stat) + goto done; + auth->ah_cred = au->au_origcred; + marshal_new_auth(auth); +done: + /* free the struct authunix_parms created by deserializing */ + xdrs.x_op = XDR_FREE; + (void)xdr_authunix_parms(&xdrs, &aup); + XDR_DESTROY(&xdrs); + return (stat); +} + +static void +authunix_destroy(auth) + AUTH *auth; +{ + struct audata *au; + + assert(auth != NULL); + + au = AUTH_PRIVATE(auth); + mem_free(au->au_origcred.oa_base, au->au_origcred.oa_length); + + if (au->au_shcred.oa_base != NULL) + mem_free(au->au_shcred.oa_base, au->au_shcred.oa_length); + + mem_free(auth->ah_private, sizeof(struct audata)); + + if (auth->ah_verf.oa_base != NULL) + mem_free(auth->ah_verf.oa_base, auth->ah_verf.oa_length); + + mem_free(auth, sizeof(*auth)); +} + +/* + * Marshals (pre-serializes) an auth struct. + * sets private data, au_marshed and au_mpos + */ +static void +marshal_new_auth(auth) + AUTH *auth; +{ + XDR xdr_stream; + XDR *xdrs = &xdr_stream; + struct audata *au; + + assert(auth != NULL); + + au = AUTH_PRIVATE(auth); + xdrmem_create(xdrs, au->au_marshed, MAX_AUTH_BYTES, XDR_ENCODE); + if ((! xdr_opaque_auth(xdrs, &(auth->ah_cred))) || + (! xdr_opaque_auth(xdrs, &(auth->ah_verf)))) + warnx("auth_none.c - Fatal marshalling problem"); + else + au->au_mpos = XDR_GETPOS(xdrs); + XDR_DESTROY(xdrs); +} + +static struct auth_ops * +authunix_ops() +{ + static struct auth_ops ops; + + /* VARIABLES PROTECTED BY ops_lock: ops */ + + mutex_lock(&ops_lock); + if (ops.ah_nextverf == NULL) { + ops.ah_nextverf = authunix_nextverf; + ops.ah_marshal = authunix_marshal; + ops.ah_validate = authunix_validate; + ops.ah_refresh = authunix_refresh; + ops.ah_destroy = authunix_destroy; + } + mutex_unlock(&ops_lock); + return (&ops); +} diff --git a/freebsd/lib/libc/rpc/authdes_prot.c b/freebsd/lib/libc/rpc/authdes_prot.c new file mode 100644 index 00000000..af77afdd --- /dev/null +++ b/freebsd/lib/libc/rpc/authdes_prot.c @@ -0,0 +1,95 @@ +#include <machine/rtems-bsd-user-space.h> + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)authdes_prot.c 2.1 88/07/29 4.0 RPCSRC; from 1.6 88/02/08 SMI"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ + +/* + * authdes_prot.c, XDR routines for DES authentication + */ + +#include "namespace.h" +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <rpc/auth.h> +#include <rpc/auth_des.h> +#include "un-namespace.h" + +#define ATTEMPT(xdr_op) if (!(xdr_op)) return (FALSE) + +bool_t +xdr_authdes_cred(xdrs, cred) + XDR *xdrs; + struct authdes_cred *cred; +{ + enum authdes_namekind *padc_namekind = &cred->adc_namekind; + /* + * Unrolled xdr + */ + ATTEMPT(xdr_enum(xdrs, (enum_t *) padc_namekind)); + switch (cred->adc_namekind) { + case ADN_FULLNAME: + ATTEMPT(xdr_string(xdrs, &cred->adc_fullname.name, + MAXNETNAMELEN)); + ATTEMPT(xdr_opaque(xdrs, (caddr_t)&cred->adc_fullname.key, + sizeof(des_block))); + ATTEMPT(xdr_opaque(xdrs, (caddr_t)&cred->adc_fullname.window, + sizeof(cred->adc_fullname.window))); + return (TRUE); + case ADN_NICKNAME: + ATTEMPT(xdr_opaque(xdrs, (caddr_t)&cred->adc_nickname, + sizeof(cred->adc_nickname))); + return (TRUE); + default: + return (FALSE); + } +} + + +bool_t +xdr_authdes_verf(xdrs, verf) + XDR *xdrs; + struct authdes_verf *verf; +{ + /* + * Unrolled xdr + */ + ATTEMPT(xdr_opaque(xdrs, (caddr_t)&verf->adv_xtimestamp, + sizeof(des_block))); + ATTEMPT(xdr_opaque(xdrs, (caddr_t)&verf->adv_int_u, + sizeof(verf->adv_int_u))); + return (TRUE); +} diff --git a/freebsd/lib/libc/rpc/authunix_prot.c b/freebsd/lib/libc/rpc/authunix_prot.c new file mode 100644 index 00000000..e5413b2d --- /dev/null +++ b/freebsd/lib/libc/rpc/authunix_prot.c @@ -0,0 +1,80 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: authunix_prot.c,v 1.12 2000/01/22 22:19:17 mycroft Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *sccsid2 = "@(#)authunix_prot.c 1.15 87/08/11 Copyr 1984 Sun Micro"; +static char *sccsid = "@(#)authunix_prot.c 2.1 88/07/29 4.0 RPCSRC"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * authunix_prot.c + * XDR for UNIX style authentication parameters for RPC + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include "namespace.h" +#include <assert.h> + +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <rpc/auth.h> +#include <rpc/auth_unix.h> +#include "un-namespace.h" + +/* + * XDR for unix authentication parameters. + */ +bool_t +xdr_authunix_parms(xdrs, p) + XDR *xdrs; + struct authunix_parms *p; +{ + u_int **paup_gids; + + assert(xdrs != NULL); + assert(p != NULL); + + paup_gids = &p->aup_gids; + + if (xdr_u_long(xdrs, &(p->aup_time)) && + xdr_string(xdrs, &(p->aup_machname), MAX_MACHINE_NAME) && + xdr_u_int(xdrs, &(p->aup_uid)) && + xdr_u_int(xdrs, &(p->aup_gid)) && + xdr_array(xdrs, (char **) paup_gids, + &(p->aup_len), NGRPS, sizeof(u_int), (xdrproc_t)xdr_u_int) ) { + return (TRUE); + } + return (FALSE); +} diff --git a/freebsd/lib/libc/rpc/bindresvport.c b/freebsd/lib/libc/rpc/bindresvport.c new file mode 100644 index 00000000..baf5cbd4 --- /dev/null +++ b/freebsd/lib/libc/rpc/bindresvport.c @@ -0,0 +1,162 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: bindresvport.c,v 1.19 2000/07/06 03:03:59 christos Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *sccsid2 = "from: @(#)bindresvport.c 1.8 88/02/08 SMI"; +static char *sccsid = "from: @(#)bindresvport.c 2.2 88/07/29 4.0 RPCSRC"; +#endif +/* from: $OpenBSD: bindresvport.c,v 1.7 1996/07/30 16:25:47 downsj Exp $ */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Copyright (c) 1987 by Sun Microsystems, Inc. + * + * Portions Copyright(C) 1996, Jason Downs. All rights reserved. + */ + +#include "namespace.h" +#include <sys/types.h> +#include <sys/socket.h> + +#include <netinet/in.h> + +#include <errno.h> +#include <string.h> +#include <unistd.h> + +#include <rpc/rpc.h> + +#include <string.h> +#include "un-namespace.h" + +/* + * Bind a socket to a privileged IP port + */ +int +bindresvport(sd, sin) + int sd; + struct sockaddr_in *sin; +{ + return bindresvport_sa(sd, (struct sockaddr *)sin); +} + +/* + * Bind a socket to a privileged IP port + */ +int +bindresvport_sa(sd, sa) + int sd; + struct sockaddr *sa; +{ + int old, error, af; + struct sockaddr_storage myaddr; + struct sockaddr_in *sin; +#ifdef INET6 + struct sockaddr_in6 *sin6; +#endif + int proto, portrange, portlow; + u_int16_t *portp; + socklen_t salen; + + if (sa == NULL) { + salen = sizeof(myaddr); + sa = (struct sockaddr *)&myaddr; + + if (_getsockname(sd, sa, &salen) == -1) + return -1; /* errno is correctly set */ + + af = sa->sa_family; + memset(sa, 0, salen); + } else + af = sa->sa_family; + + switch (af) { + case AF_INET: + proto = IPPROTO_IP; + portrange = IP_PORTRANGE; + portlow = IP_PORTRANGE_LOW; + sin = (struct sockaddr_in *)sa; + salen = sizeof(struct sockaddr_in); + portp = &sin->sin_port; + break; +#ifdef INET6 + case AF_INET6: + proto = IPPROTO_IPV6; + portrange = IPV6_PORTRANGE; + portlow = IPV6_PORTRANGE_LOW; + sin6 = (struct sockaddr_in6 *)sa; + salen = sizeof(struct sockaddr_in6); + portp = &sin6->sin6_port; + break; +#endif + default: + errno = EPFNOSUPPORT; + return (-1); + } + sa->sa_family = af; + sa->sa_len = salen; + + if (*portp == 0) { + socklen_t oldlen = sizeof(old); + + error = _getsockopt(sd, proto, portrange, &old, &oldlen); + if (error < 0) + return (error); + + error = _setsockopt(sd, proto, portrange, &portlow, + sizeof(portlow)); + if (error < 0) + return (error); + } + + error = _bind(sd, sa, salen); + + if (*portp == 0) { + int saved_errno = errno; + + if (error < 0) { + if (_setsockopt(sd, proto, portrange, &old, + sizeof(old)) < 0) + errno = saved_errno; + return (error); + } + + if (sa != (struct sockaddr *)&myaddr) { + /* Hmm, what did the kernel assign? */ + if (_getsockname(sd, sa, &salen) < 0) + errno = saved_errno; + return (error); + } + } + return (error); +} diff --git a/freebsd/lib/libc/rpc/clnt_bcast.c b/freebsd/lib/libc/rpc/clnt_bcast.c new file mode 100644 index 00000000..3a12c1e9 --- /dev/null +++ b/freebsd/lib/libc/rpc/clnt_bcast.c @@ -0,0 +1,674 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: clnt_bcast.c,v 1.3 2000/07/06 03:05:20 christos Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +#ident "@(#)clnt_bcast.c 1.18 94/05/03 SMI" +static char sccsid[] = "@(#)clnt_bcast.c 1.15 89/04/21 Copyr 1988 Sun Micro"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + + +/* + * clnt_bcast.c + * Client interface to broadcast service. + * + * Copyright (C) 1988, Sun Microsystems, Inc. + * + * The following is kludged-up support for simple rpc broadcasts. + * Someday a large, complicated system will replace these routines. + */ + +#include "namespace.h" +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/queue.h> +#include <net/if.h> +#include <netinet/in.h> +#include <ifaddrs.h> +#include <sys/poll.h> +#include <rpc/rpc.h> +#ifdef PORTMAP +#include <rpc/pmap_prot.h> +#include <rpc/pmap_clnt.h> +#include <rpc/pmap_rmt.h> +#endif /* PORTMAP */ +#include <rpc/nettype.h> +#include <arpa/inet.h> +#ifdef RPC_DEBUG +#include <stdio.h> +#endif +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <netdb.h> +#include <err.h> +#include <string.h> +#include "un-namespace.h" + +#include "rpc_com.h" + +#define MAXBCAST 20 /* Max no of broadcasting transports */ +#define INITTIME 4000 /* Time to wait initially */ +#define WAITTIME 8000 /* Maximum time to wait */ + +/* + * If nettype is NULL, it broadcasts on all the available + * datagram_n transports. May potentially lead to broadacst storms + * and hence should be used with caution, care and courage. + * + * The current parameter xdr packet size is limited by the max tsdu + * size of the transport. If the max tsdu size of any transport is + * smaller than the parameter xdr packet, then broadcast is not + * sent on that transport. + * + * Also, the packet size should be less the packet size of + * the data link layer (for ethernet it is 1400 bytes). There is + * no easy way to find out the max size of the data link layer and + * we are assuming that the args would be smaller than that. + * + * The result size has to be smaller than the transport tsdu size. + * + * If PORTMAP has been defined, we send two packets for UDP, one for + * rpcbind and one for portmap. For those machines which support + * both rpcbind and portmap, it will cause them to reply twice, and + * also here it will get two responses ... inefficient and clumsy. + */ + +struct broadif { + int index; + struct sockaddr_storage broadaddr; + TAILQ_ENTRY(broadif) link; +}; + +typedef TAILQ_HEAD(, broadif) broadlist_t; + +int __rpc_getbroadifs(int, int, int, broadlist_t *); +void __rpc_freebroadifs(broadlist_t *); +int __rpc_broadenable(int, int, struct broadif *); + +int __rpc_lowvers = 0; + +int +__rpc_getbroadifs(int af, int proto, int socktype, broadlist_t *list) +{ + int count = 0; + struct broadif *bip; + struct ifaddrs *ifap, *ifp; +#ifdef INET6 + struct sockaddr_in6 *sin6; +#endif + struct sockaddr_in *sin; + struct addrinfo hints, *res; + + if (getifaddrs(&ifp) < 0) + return 0; + + memset(&hints, 0, sizeof hints); + + hints.ai_family = af; + hints.ai_protocol = proto; + hints.ai_socktype = socktype; + + if (getaddrinfo(NULL, "sunrpc", &hints, &res) != 0) { + freeifaddrs(ifp); + return 0; + } + + for (ifap = ifp; ifap != NULL; ifap = ifap->ifa_next) { + if (ifap->ifa_addr->sa_family != af || + !(ifap->ifa_flags & IFF_UP)) + continue; + bip = (struct broadif *)malloc(sizeof *bip); + if (bip == NULL) + break; + bip->index = if_nametoindex(ifap->ifa_name); + if ( +#ifdef INET6 + af != AF_INET6 && +#endif + (ifap->ifa_flags & IFF_BROADCAST) && + ifap->ifa_broadaddr) { + memcpy(&bip->broadaddr, ifap->ifa_broadaddr, + (size_t)ifap->ifa_broadaddr->sa_len); + sin = (struct sockaddr_in *)(void *)&bip->broadaddr; + sin->sin_port = + ((struct sockaddr_in *) + (void *)res->ai_addr)->sin_port; + } else +#ifdef INET6 + if (af == AF_INET6 && (ifap->ifa_flags & IFF_MULTICAST)) { + sin6 = (struct sockaddr_in6 *)(void *)&bip->broadaddr; + inet_pton(af, RPCB_MULTICAST_ADDR, &sin6->sin6_addr); + sin6->sin6_family = af; + sin6->sin6_len = sizeof *sin6; + sin6->sin6_port = + ((struct sockaddr_in6 *) + (void *)res->ai_addr)->sin6_port; + sin6->sin6_scope_id = bip->index; + } else +#endif + { + free(bip); + continue; + } + TAILQ_INSERT_TAIL(list, bip, link); + count++; + } + freeifaddrs(ifp); + freeaddrinfo(res); + + return count; +} + +void +__rpc_freebroadifs(broadlist_t *list) +{ + struct broadif *bip, *next; + + bip = TAILQ_FIRST(list); + + while (bip != NULL) { + next = TAILQ_NEXT(bip, link); + free(bip); + bip = next; + } +} + +int +/*ARGSUSED*/ +__rpc_broadenable(int af, int s, struct broadif *bip) +{ + int o = 1; + +#if 0 + if (af == AF_INET6) { + fprintf(stderr, "set v6 multicast if to %d\n", bip->index); + if (_setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &bip->index, + sizeof bip->index) < 0) + return -1; + } else +#endif + if (_setsockopt(s, SOL_SOCKET, SO_BROADCAST, &o, sizeof o) < 0) + return -1; + + return 0; +} + + +enum clnt_stat +rpc_broadcast_exp(prog, vers, proc, xargs, argsp, xresults, resultsp, + eachresult, inittime, waittime, nettype) + rpcprog_t prog; /* program number */ + rpcvers_t vers; /* version number */ + rpcproc_t proc; /* procedure number */ + xdrproc_t xargs; /* xdr routine for args */ + caddr_t argsp; /* pointer to args */ + xdrproc_t xresults; /* xdr routine for results */ + caddr_t resultsp; /* pointer to results */ + resultproc_t eachresult; /* call with each result obtained */ + int inittime; /* how long to wait initially */ + int waittime; /* maximum time to wait */ + const char *nettype; /* transport type */ +{ + enum clnt_stat stat = RPC_SUCCESS; /* Return status */ + XDR xdr_stream; /* XDR stream */ + XDR *xdrs = &xdr_stream; + struct rpc_msg msg; /* RPC message */ + struct timeval t; + char *outbuf = NULL; /* Broadcast msg buffer */ + char *inbuf = NULL; /* Reply buf */ + int inlen; + u_int maxbufsize = 0; + AUTH *sys_auth = authunix_create_default(); + int i; + void *handle; + char uaddress[1024]; /* A self imposed limit */ + char *uaddrp = uaddress; + int pmap_reply_flag; /* reply recvd from PORTMAP */ + /* An array of all the suitable broadcast transports */ + struct { + int fd; /* File descriptor */ + int af; + int proto; + struct netconfig *nconf; /* Netconfig structure */ + u_int asize; /* Size of the addr buf */ + u_int dsize; /* Size of the data buf */ + struct sockaddr_storage raddr; /* Remote address */ + broadlist_t nal; + } fdlist[MAXBCAST]; + struct pollfd pfd[MAXBCAST]; + size_t fdlistno = 0; + struct r_rpcb_rmtcallargs barg; /* Remote arguments */ + struct r_rpcb_rmtcallres bres; /* Remote results */ + size_t outlen; + struct netconfig *nconf; + int msec; + int pollretval; + int fds_found; + +#ifdef PORTMAP + size_t outlen_pmap = 0; + u_long port; /* Remote port number */ + int pmap_flag = 0; /* UDP exists ? */ + char *outbuf_pmap = NULL; + struct rmtcallargs barg_pmap; /* Remote arguments */ + struct rmtcallres bres_pmap; /* Remote results */ + u_int udpbufsz = 0; +#endif /* PORTMAP */ + + if (sys_auth == NULL) { + return (RPC_SYSTEMERROR); + } + /* + * initialization: create a fd, a broadcast address, and send the + * request on the broadcast transport. + * Listen on all of them and on replies, call the user supplied + * function. + */ + + if (nettype == NULL) + nettype = "datagram_n"; + if ((handle = __rpc_setconf(nettype)) == NULL) { + AUTH_DESTROY(sys_auth); + return (RPC_UNKNOWNPROTO); + } + while ((nconf = __rpc_getconf(handle)) != NULL) { + int fd; + struct __rpc_sockinfo si; + + if (nconf->nc_semantics != NC_TPI_CLTS) + continue; + if (fdlistno >= MAXBCAST) + break; /* No more slots available */ + if (!__rpc_nconf2sockinfo(nconf, &si)) + continue; + + TAILQ_INIT(&fdlist[fdlistno].nal); + if (__rpc_getbroadifs(si.si_af, si.si_proto, si.si_socktype, + &fdlist[fdlistno].nal) == 0) + continue; + + fd = _socket(si.si_af, si.si_socktype, si.si_proto); + if (fd < 0) { + stat = RPC_CANTSEND; + continue; + } + fdlist[fdlistno].af = si.si_af; + fdlist[fdlistno].proto = si.si_proto; + fdlist[fdlistno].fd = fd; + fdlist[fdlistno].nconf = nconf; + fdlist[fdlistno].asize = __rpc_get_a_size(si.si_af); + pfd[fdlistno].events = POLLIN | POLLPRI | + POLLRDNORM | POLLRDBAND; + pfd[fdlistno].fd = fdlist[fdlistno].fd = fd; + fdlist[fdlistno].dsize = __rpc_get_t_size(si.si_af, si.si_proto, + 0); + + if (maxbufsize <= fdlist[fdlistno].dsize) + maxbufsize = fdlist[fdlistno].dsize; + +#ifdef PORTMAP + if (si.si_af == AF_INET && si.si_proto == IPPROTO_UDP) { + udpbufsz = fdlist[fdlistno].dsize; + if ((outbuf_pmap = malloc(udpbufsz)) == NULL) { + _close(fd); + stat = RPC_SYSTEMERROR; + goto done_broad; + } + pmap_flag = 1; + } +#endif /* PORTMAP */ + fdlistno++; + } + + if (fdlistno == 0) { + if (stat == RPC_SUCCESS) + stat = RPC_UNKNOWNPROTO; + goto done_broad; + } + if (maxbufsize == 0) { + if (stat == RPC_SUCCESS) + stat = RPC_CANTSEND; + goto done_broad; + } + inbuf = malloc(maxbufsize); + outbuf = malloc(maxbufsize); + if ((inbuf == NULL) || (outbuf == NULL)) { + stat = RPC_SYSTEMERROR; + goto done_broad; + } + + /* Serialize all the arguments which have to be sent */ + (void) gettimeofday(&t, NULL); + msg.rm_xid = __RPC_GETXID(&t); + msg.rm_direction = CALL; + msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; + msg.rm_call.cb_prog = RPCBPROG; + msg.rm_call.cb_vers = RPCBVERS; + msg.rm_call.cb_proc = RPCBPROC_CALLIT; + barg.prog = prog; + barg.vers = vers; + barg.proc = proc; + barg.args.args_val = argsp; + barg.xdr_args = xargs; + bres.addr = uaddrp; + bres.results.results_val = resultsp; + bres.xdr_res = xresults; + msg.rm_call.cb_cred = sys_auth->ah_cred; + msg.rm_call.cb_verf = sys_auth->ah_verf; + xdrmem_create(xdrs, outbuf, maxbufsize, XDR_ENCODE); + if ((!xdr_callmsg(xdrs, &msg)) || + (!xdr_rpcb_rmtcallargs(xdrs, + (struct rpcb_rmtcallargs *)(void *)&barg))) { + stat = RPC_CANTENCODEARGS; + goto done_broad; + } + outlen = xdr_getpos(xdrs); + xdr_destroy(xdrs); + +#ifdef PORTMAP + /* Prepare the packet for version 2 PORTMAP */ + if (pmap_flag) { + msg.rm_xid++; /* One way to distinguish */ + msg.rm_call.cb_prog = PMAPPROG; + msg.rm_call.cb_vers = PMAPVERS; + msg.rm_call.cb_proc = PMAPPROC_CALLIT; + barg_pmap.prog = prog; + barg_pmap.vers = vers; + barg_pmap.proc = proc; + barg_pmap.args_ptr = argsp; + barg_pmap.xdr_args = xargs; + bres_pmap.port_ptr = &port; + bres_pmap.xdr_results = xresults; + bres_pmap.results_ptr = resultsp; + xdrmem_create(xdrs, outbuf_pmap, udpbufsz, XDR_ENCODE); + if ((! xdr_callmsg(xdrs, &msg)) || + (! xdr_rmtcall_args(xdrs, &barg_pmap))) { + stat = RPC_CANTENCODEARGS; + goto done_broad; + } + outlen_pmap = xdr_getpos(xdrs); + xdr_destroy(xdrs); + } +#endif /* PORTMAP */ + + /* + * Basic loop: broadcast the packets to transports which + * support data packets of size such that one can encode + * all the arguments. + * Wait a while for response(s). + * The response timeout grows larger per iteration. + */ + for (msec = inittime; msec <= waittime; msec += msec) { + struct broadif *bip; + + /* Broadcast all the packets now */ + for (i = 0; i < fdlistno; i++) { + if (fdlist[i].dsize < outlen) { + stat = RPC_CANTSEND; + continue; + } + for (bip = TAILQ_FIRST(&fdlist[i].nal); bip != NULL; + bip = TAILQ_NEXT(bip, link)) { + void *addr; + + addr = &bip->broadaddr; + + __rpc_broadenable(fdlist[i].af, fdlist[i].fd, + bip); + + /* + * Only use version 3 if lowvers is not set + */ + + if (!__rpc_lowvers) + if (_sendto(fdlist[i].fd, outbuf, + outlen, 0, (struct sockaddr*)addr, + (size_t)fdlist[i].asize) != + outlen) { +#ifdef RPC_DEBUG + perror("sendto"); +#endif + warnx("clnt_bcast: cannot send " + "broadcast packet"); + stat = RPC_CANTSEND; + continue; + }; +#ifdef RPC_DEBUG + if (!__rpc_lowvers) + fprintf(stderr, "Broadcast packet sent " + "for %s\n", + fdlist[i].nconf->nc_netid); +#endif +#ifdef PORTMAP + /* + * Send the version 2 packet also + * for UDP/IP + */ + if (pmap_flag && + fdlist[i].proto == IPPROTO_UDP) { + if (_sendto(fdlist[i].fd, outbuf_pmap, + outlen_pmap, 0, addr, + (size_t)fdlist[i].asize) != + outlen_pmap) { + warnx("clnt_bcast: " + "Cannot send broadcast packet"); + stat = RPC_CANTSEND; + continue; + } + } +#ifdef RPC_DEBUG + fprintf(stderr, "PMAP Broadcast packet " + "sent for %s\n", + fdlist[i].nconf->nc_netid); +#endif +#endif /* PORTMAP */ + } + /* End for sending all packets on this transport */ + } /* End for sending on all transports */ + + if (eachresult == NULL) { + stat = RPC_SUCCESS; + goto done_broad; + } + + /* + * Get all the replies from these broadcast requests + */ + recv_again: + + switch (pollretval = _poll(pfd, fdlistno, msec)) { + case 0: /* timed out */ + stat = RPC_TIMEDOUT; + continue; + case -1: /* some kind of error - we ignore it */ + goto recv_again; + } /* end of poll results switch */ + + for (i = fds_found = 0; + i < fdlistno && fds_found < pollretval; i++) { + bool_t done = FALSE; + + if (pfd[i].revents == 0) + continue; + else if (pfd[i].revents & POLLNVAL) { + /* + * Something bad has happened to this descri- + * ptor. We can cause _poll() to ignore + * it simply by using a negative fd. We do that + * rather than compacting the pfd[] and fdlist[] + * arrays. + */ + pfd[i].fd = -1; + fds_found++; + continue; + } else + fds_found++; +#ifdef RPC_DEBUG + fprintf(stderr, "response for %s\n", + fdlist[i].nconf->nc_netid); +#endif + try_again: + inlen = _recvfrom(fdlist[i].fd, inbuf, fdlist[i].dsize, + 0, (struct sockaddr *)(void *)&fdlist[i].raddr, + &fdlist[i].asize); + if (inlen < 0) { + if (errno == EINTR) + goto try_again; + warnx("clnt_bcast: Cannot receive reply to " + "broadcast"); + stat = RPC_CANTRECV; + continue; + } + if (inlen < sizeof (u_int32_t)) + continue; /* Drop that and go ahead */ + /* + * see if reply transaction id matches sent id. + * If so, decode the results. If return id is xid + 1 + * it was a PORTMAP reply + */ + if (*((u_int32_t *)(void *)(inbuf)) == + *((u_int32_t *)(void *)(outbuf))) { + pmap_reply_flag = 0; + msg.acpted_rply.ar_verf = _null_auth; + msg.acpted_rply.ar_results.where = + (caddr_t)(void *)&bres; + msg.acpted_rply.ar_results.proc = + (xdrproc_t)xdr_rpcb_rmtcallres; +#ifdef PORTMAP + } else if (pmap_flag && + *((u_int32_t *)(void *)(inbuf)) == + *((u_int32_t *)(void *)(outbuf_pmap))) { + pmap_reply_flag = 1; + msg.acpted_rply.ar_verf = _null_auth; + msg.acpted_rply.ar_results.where = + (caddr_t)(void *)&bres_pmap; + msg.acpted_rply.ar_results.proc = + (xdrproc_t)xdr_rmtcallres; +#endif /* PORTMAP */ + } else + continue; + xdrmem_create(xdrs, inbuf, (u_int)inlen, XDR_DECODE); + if (xdr_replymsg(xdrs, &msg)) { + if ((msg.rm_reply.rp_stat == MSG_ACCEPTED) && + (msg.acpted_rply.ar_stat == SUCCESS)) { + struct netbuf taddr, *np; + struct sockaddr_in *sin; + +#ifdef PORTMAP + if (pmap_flag && pmap_reply_flag) { + sin = (struct sockaddr_in *) + (void *)&fdlist[i].raddr; + sin->sin_port = + htons((u_short)port); + taddr.len = taddr.maxlen = + fdlist[i].raddr.ss_len; + taddr.buf = &fdlist[i].raddr; + done = (*eachresult)(resultsp, + &taddr, fdlist[i].nconf); + } else { +#endif /* PORTMAP */ +#ifdef RPC_DEBUG + fprintf(stderr, "uaddr %s\n", + uaddrp); +#endif + np = uaddr2taddr( + fdlist[i].nconf, uaddrp); + done = (*eachresult)(resultsp, + np, fdlist[i].nconf); + free(np); +#ifdef PORTMAP + } +#endif /* PORTMAP */ + } + /* otherwise, we just ignore the errors ... */ + } + /* else some kind of deserialization problem ... */ + + xdrs->x_op = XDR_FREE; + msg.acpted_rply.ar_results.proc = (xdrproc_t) xdr_void; + (void) xdr_replymsg(xdrs, &msg); + (void) (*xresults)(xdrs, resultsp); + XDR_DESTROY(xdrs); + if (done) { + stat = RPC_SUCCESS; + goto done_broad; + } else { + goto recv_again; + } + } /* The recv for loop */ + } /* The giant for loop */ + +done_broad: + if (inbuf) + (void) free(inbuf); + if (outbuf) + (void) free(outbuf); +#ifdef PORTMAP + if (outbuf_pmap) + (void) free(outbuf_pmap); +#endif /* PORTMAP */ + for (i = 0; i < fdlistno; i++) { + (void)_close(fdlist[i].fd); + __rpc_freebroadifs(&fdlist[i].nal); + } + AUTH_DESTROY(sys_auth); + (void) __rpc_endconf(handle); + + return (stat); +} + + +enum clnt_stat +rpc_broadcast(prog, vers, proc, xargs, argsp, xresults, resultsp, + eachresult, nettype) + rpcprog_t prog; /* program number */ + rpcvers_t vers; /* version number */ + rpcproc_t proc; /* procedure number */ + xdrproc_t xargs; /* xdr routine for args */ + caddr_t argsp; /* pointer to args */ + xdrproc_t xresults; /* xdr routine for results */ + caddr_t resultsp; /* pointer to results */ + resultproc_t eachresult; /* call with each result obtained */ + const char *nettype; /* transport type */ +{ + enum clnt_stat dummy; + + dummy = rpc_broadcast_exp(prog, vers, proc, xargs, argsp, + xresults, resultsp, eachresult, + INITTIME, WAITTIME, nettype); + return (dummy); +} diff --git a/freebsd/lib/libc/rpc/clnt_dg.c b/freebsd/lib/libc/rpc/clnt_dg.c new file mode 100644 index 00000000..c3694337 --- /dev/null +++ b/freebsd/lib/libc/rpc/clnt_dg.c @@ -0,0 +1,860 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: clnt_dg.c,v 1.4 2000/07/14 08:40:41 fvdl Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +#ident "@(#)clnt_dg.c 1.23 94/04/22 SMI" +static char sccsid[] = "@(#)clnt_dg.c 1.19 89/03/16 Copyr 1988 Sun Micro"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Implements a connectionless client side RPC. + */ + +#include "namespace.h" +#include "reentrant.h" +#include <sys/types.h> +#include <sys/event.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <arpa/inet.h> +#include <rpc/rpc.h> +#include <rpc/rpcsec_gss.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <unistd.h> +#include <err.h> +#include "un-namespace.h" +#include "rpc_com.h" +#include "mt_misc.h" + + +#ifdef _FREEFALL_CONFIG +/* + * Disable RPC exponential back-off for FreeBSD.org systems. + */ +#define RPC_MAX_BACKOFF 1 /* second */ +#else +#define RPC_MAX_BACKOFF 30 /* seconds */ +#endif + + +static struct clnt_ops *clnt_dg_ops(void); +static bool_t time_not_ok(struct timeval *); +static enum clnt_stat clnt_dg_call(CLIENT *, rpcproc_t, xdrproc_t, void *, + xdrproc_t, void *, struct timeval); +static void clnt_dg_geterr(CLIENT *, struct rpc_err *); +static bool_t clnt_dg_freeres(CLIENT *, xdrproc_t, void *); +static void clnt_dg_abort(CLIENT *); +static bool_t clnt_dg_control(CLIENT *, u_int, void *); +static void clnt_dg_destroy(CLIENT *); + + + + +/* + * This machinery implements per-fd locks for MT-safety. It is not + * sufficient to do per-CLIENT handle locks for MT-safety because a + * user may create more than one CLIENT handle with the same fd behind + * it. Therfore, we allocate an array of flags (dg_fd_locks), protected + * by the clnt_fd_lock mutex, and an array (dg_cv) of condition variables + * similarly protected. Dg_fd_lock[fd] == 1 => a call is activte on some + * CLIENT handle created for that fd. + * The current implementation holds locks across the entire RPC and reply, + * including retransmissions. Yes, this is silly, and as soon as this + * code is proven to work, this should be the first thing fixed. One step + * at a time. + */ +static int *dg_fd_locks; +static cond_t *dg_cv; +#define release_fd_lock(fd, mask) { \ + mutex_lock(&clnt_fd_lock); \ + dg_fd_locks[fd] = 0; \ + mutex_unlock(&clnt_fd_lock); \ + thr_sigsetmask(SIG_SETMASK, &(mask), NULL); \ + cond_signal(&dg_cv[fd]); \ +} + +static const char mem_err_clnt_dg[] = "clnt_dg_create: out of memory"; + +/* VARIABLES PROTECTED BY clnt_fd_lock: dg_fd_locks, dg_cv */ + +#define MCALL_MSG_SIZE 24 + +/* + * Private data kept per client handle + */ +struct cu_data { + int cu_fd; /* connections fd */ + bool_t cu_closeit; /* opened by library */ + struct sockaddr_storage cu_raddr; /* remote address */ + int cu_rlen; + struct timeval cu_wait; /* retransmit interval */ + struct timeval cu_total; /* total time for the call */ + struct rpc_err cu_error; + XDR cu_outxdrs; + u_int cu_xdrpos; + u_int cu_sendsz; /* send size */ + char cu_outhdr[MCALL_MSG_SIZE]; + char *cu_outbuf; + u_int cu_recvsz; /* recv size */ + int cu_async; + int cu_connect; /* Use connect(). */ + int cu_connected; /* Have done connect(). */ + struct kevent cu_kin; + int cu_kq; + char cu_inbuf[1]; +}; + +/* + * Connection less client creation returns with client handle parameters. + * Default options are set, which the user can change using clnt_control(). + * fd should be open and bound. + * NB: The rpch->cl_auth is initialized to null authentication. + * Caller may wish to set this something more useful. + * + * sendsz and recvsz are the maximum allowable packet sizes that can be + * sent and received. Normally they are the same, but they can be + * changed to improve the program efficiency and buffer allocation. + * If they are 0, use the transport default. + * + * If svcaddr is NULL, returns NULL. + */ +CLIENT * +clnt_dg_create(fd, svcaddr, program, version, sendsz, recvsz) + int fd; /* open file descriptor */ + const struct netbuf *svcaddr; /* servers address */ + rpcprog_t program; /* program number */ + rpcvers_t version; /* version number */ + u_int sendsz; /* buffer recv size */ + u_int recvsz; /* buffer send size */ +{ + CLIENT *cl = NULL; /* client handle */ + struct cu_data *cu = NULL; /* private data */ + struct timeval now; + struct rpc_msg call_msg; + sigset_t mask; + sigset_t newmask; + struct __rpc_sockinfo si; + int one = 1; + + sigfillset(&newmask); + thr_sigsetmask(SIG_SETMASK, &newmask, &mask); + mutex_lock(&clnt_fd_lock); + if (dg_fd_locks == (int *) NULL) { + int cv_allocsz; + size_t fd_allocsz; + int dtbsize = __rpc_dtbsize(); + + fd_allocsz = dtbsize * sizeof (int); + dg_fd_locks = (int *) mem_alloc(fd_allocsz); + if (dg_fd_locks == (int *) NULL) { + mutex_unlock(&clnt_fd_lock); + thr_sigsetmask(SIG_SETMASK, &(mask), NULL); + goto err1; + } else + memset(dg_fd_locks, '\0', fd_allocsz); + + cv_allocsz = dtbsize * sizeof (cond_t); + dg_cv = (cond_t *) mem_alloc(cv_allocsz); + if (dg_cv == (cond_t *) NULL) { + mem_free(dg_fd_locks, fd_allocsz); + dg_fd_locks = (int *) NULL; + mutex_unlock(&clnt_fd_lock); + thr_sigsetmask(SIG_SETMASK, &(mask), NULL); + goto err1; + } else { + int i; + + for (i = 0; i < dtbsize; i++) + cond_init(&dg_cv[i], 0, (void *) 0); + } + } + + mutex_unlock(&clnt_fd_lock); + thr_sigsetmask(SIG_SETMASK, &(mask), NULL); + + if (svcaddr == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNADDR; + return (NULL); + } + + if (!__rpc_fd2sockinfo(fd, &si)) { + rpc_createerr.cf_stat = RPC_TLIERROR; + rpc_createerr.cf_error.re_errno = 0; + return (NULL); + } + /* + * Find the receive and the send size + */ + sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); + recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); + if ((sendsz == 0) || (recvsz == 0)) { + rpc_createerr.cf_stat = RPC_TLIERROR; /* XXX */ + rpc_createerr.cf_error.re_errno = 0; + return (NULL); + } + + if ((cl = mem_alloc(sizeof (CLIENT))) == NULL) + goto err1; + /* + * Should be multiple of 4 for XDR. + */ + sendsz = ((sendsz + 3) / 4) * 4; + recvsz = ((recvsz + 3) / 4) * 4; + cu = mem_alloc(sizeof (*cu) + sendsz + recvsz); + if (cu == NULL) + goto err1; + (void) memcpy(&cu->cu_raddr, svcaddr->buf, (size_t)svcaddr->len); + cu->cu_rlen = svcaddr->len; + cu->cu_outbuf = &cu->cu_inbuf[recvsz]; + /* Other values can also be set through clnt_control() */ + cu->cu_wait.tv_sec = 15; /* heuristically chosen */ + cu->cu_wait.tv_usec = 0; + cu->cu_total.tv_sec = -1; + cu->cu_total.tv_usec = -1; + cu->cu_sendsz = sendsz; + cu->cu_recvsz = recvsz; + cu->cu_async = FALSE; + cu->cu_connect = FALSE; + cu->cu_connected = FALSE; + (void) gettimeofday(&now, NULL); + call_msg.rm_xid = __RPC_GETXID(&now); + call_msg.rm_call.cb_prog = program; + call_msg.rm_call.cb_vers = version; + xdrmem_create(&(cu->cu_outxdrs), cu->cu_outhdr, MCALL_MSG_SIZE, + XDR_ENCODE); + if (! xdr_callhdr(&cu->cu_outxdrs, &call_msg)) { + rpc_createerr.cf_stat = RPC_CANTENCODEARGS; /* XXX */ + rpc_createerr.cf_error.re_errno = 0; + goto err2; + } + cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs)); + XDR_DESTROY(&cu->cu_outxdrs); + xdrmem_create(&cu->cu_outxdrs, cu->cu_outbuf, sendsz, XDR_ENCODE); + + /* XXX fvdl - do we still want this? */ +#if 0 + (void)bindresvport_sa(fd, (struct sockaddr *)svcaddr->buf); +#endif + _ioctl(fd, FIONBIO, (char *)(void *)&one); + + /* + * By default, closeit is always FALSE. It is users responsibility + * to do a close on it, else the user may use clnt_control + * to let clnt_destroy do it for him/her. + */ + cu->cu_closeit = FALSE; + cu->cu_fd = fd; + cl->cl_ops = clnt_dg_ops(); + cl->cl_private = (caddr_t)(void *)cu; + cl->cl_auth = authnone_create(); + cl->cl_tp = NULL; + cl->cl_netid = NULL; + cu->cu_kq = -1; + EV_SET(&cu->cu_kin, cu->cu_fd, EVFILT_READ, EV_ADD, 0, 0, 0); + return (cl); +err1: + warnx(mem_err_clnt_dg); + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; +err2: + if (cl) { + mem_free(cl, sizeof (CLIENT)); + if (cu) + mem_free(cu, sizeof (*cu) + sendsz + recvsz); + } + return (NULL); +} + +static enum clnt_stat +clnt_dg_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout) + CLIENT *cl; /* client handle */ + rpcproc_t proc; /* procedure number */ + xdrproc_t xargs; /* xdr routine for args */ + void *argsp; /* pointer to args */ + xdrproc_t xresults; /* xdr routine for results */ + void *resultsp; /* pointer to results */ + struct timeval utimeout; /* seconds to wait before giving up */ +{ + struct cu_data *cu = (struct cu_data *)cl->cl_private; + XDR *xdrs; + size_t outlen = 0; + struct rpc_msg reply_msg; + XDR reply_xdrs; + bool_t ok; + int nrefreshes = 2; /* number of times to refresh cred */ + int nretries = 0; /* number of times we retransmitted */ + struct timeval timeout; + struct timeval retransmit_time; + struct timeval next_sendtime, starttime, time_waited, tv; + struct timespec ts; + struct kevent kv; + struct sockaddr *sa; + sigset_t mask; + sigset_t newmask; + socklen_t inlen, salen; + ssize_t recvlen = 0; + int kin_len, n, rpc_lock_value; + u_int32_t xid; + + outlen = 0; + sigfillset(&newmask); + thr_sigsetmask(SIG_SETMASK, &newmask, &mask); + mutex_lock(&clnt_fd_lock); + while (dg_fd_locks[cu->cu_fd]) + cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock); + if (__isthreaded) + rpc_lock_value = 1; + else + rpc_lock_value = 0; + dg_fd_locks[cu->cu_fd] = rpc_lock_value; + mutex_unlock(&clnt_fd_lock); + if (cu->cu_total.tv_usec == -1) { + timeout = utimeout; /* use supplied timeout */ + } else { + timeout = cu->cu_total; /* use default timeout */ + } + + if (cu->cu_connect && !cu->cu_connected) { + if (_connect(cu->cu_fd, (struct sockaddr *)&cu->cu_raddr, + cu->cu_rlen) < 0) { + cu->cu_error.re_errno = errno; + cu->cu_error.re_status = RPC_CANTSEND; + goto out; + } + cu->cu_connected = 1; + } + if (cu->cu_connected) { + sa = NULL; + salen = 0; + } else { + sa = (struct sockaddr *)&cu->cu_raddr; + salen = cu->cu_rlen; + } + time_waited.tv_sec = 0; + time_waited.tv_usec = 0; + retransmit_time = next_sendtime = cu->cu_wait; + gettimeofday(&starttime, NULL); + + /* Clean up in case the last call ended in a longjmp(3) call. */ + if (cu->cu_kq >= 0) + _close(cu->cu_kq); + if ((cu->cu_kq = kqueue()) < 0) { + cu->cu_error.re_errno = errno; + cu->cu_error.re_status = RPC_CANTSEND; + goto out; + } + kin_len = 1; + +call_again: + if (cu->cu_async == TRUE && xargs == NULL) + goto get_reply; + /* + * the transaction is the first thing in the out buffer + * XXX Yes, and it's in network byte order, so we should to + * be careful when we increment it, shouldn't we. + */ + xid = ntohl(*(u_int32_t *)(void *)(cu->cu_outhdr)); + xid++; + *(u_int32_t *)(void *)(cu->cu_outhdr) = htonl(xid); +call_again_same_xid: + xdrs = &(cu->cu_outxdrs); + xdrs->x_op = XDR_ENCODE; + XDR_SETPOS(xdrs, 0); + + if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) { + if ((! XDR_PUTBYTES(xdrs, cu->cu_outhdr, cu->cu_xdrpos)) || + (! XDR_PUTINT32(xdrs, &proc)) || + (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || + (! (*xargs)(xdrs, argsp))) { + cu->cu_error.re_status = RPC_CANTENCODEARGS; + goto out; + } + } else { + *(uint32_t *) &cu->cu_outhdr[cu->cu_xdrpos] = htonl(proc); + if (!__rpc_gss_wrap(cl->cl_auth, cu->cu_outhdr, + cu->cu_xdrpos + sizeof(uint32_t), + xdrs, xargs, argsp)) { + cu->cu_error.re_status = RPC_CANTENCODEARGS; + goto out; + } + } + outlen = (size_t)XDR_GETPOS(xdrs); + +send_again: + if (_sendto(cu->cu_fd, cu->cu_outbuf, outlen, 0, sa, salen) != outlen) { + cu->cu_error.re_errno = errno; + cu->cu_error.re_status = RPC_CANTSEND; + goto out; + } + + /* + * Hack to provide rpc-based message passing + */ + if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { + cu->cu_error.re_status = RPC_TIMEDOUT; + goto out; + } + +get_reply: + + /* + * sub-optimal code appears here because we have + * some clock time to spare while the packets are in flight. + * (We assume that this is actually only executed once.) + */ + reply_msg.acpted_rply.ar_verf = _null_auth; + if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) { + reply_msg.acpted_rply.ar_results.where = resultsp; + reply_msg.acpted_rply.ar_results.proc = xresults; + } else { + reply_msg.acpted_rply.ar_results.where = NULL; + reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void; + } + + for (;;) { + /* Decide how long to wait. */ + if (timercmp(&next_sendtime, &timeout, <)) + timersub(&next_sendtime, &time_waited, &tv); + else + timersub(&timeout, &time_waited, &tv); + if (tv.tv_sec < 0 || tv.tv_usec < 0) + tv.tv_sec = tv.tv_usec = 0; + TIMEVAL_TO_TIMESPEC(&tv, &ts); + + n = _kevent(cu->cu_kq, &cu->cu_kin, kin_len, &kv, 1, &ts); + /* We don't need to register the event again. */ + kin_len = 0; + + if (n == 1) { + if (kv.flags & EV_ERROR) { + cu->cu_error.re_errno = kv.data; + cu->cu_error.re_status = RPC_CANTRECV; + goto out; + } + /* We have some data now */ + do { + recvlen = _recvfrom(cu->cu_fd, cu->cu_inbuf, + cu->cu_recvsz, 0, NULL, NULL); + } while (recvlen < 0 && errno == EINTR); + if (recvlen < 0 && errno != EWOULDBLOCK) { + cu->cu_error.re_errno = errno; + cu->cu_error.re_status = RPC_CANTRECV; + goto out; + } + if (recvlen >= sizeof(u_int32_t) && + (cu->cu_async == TRUE || + *((u_int32_t *)(void *)(cu->cu_inbuf)) == + *((u_int32_t *)(void *)(cu->cu_outbuf)))) { + /* We now assume we have the proper reply. */ + break; + } + } + if (n == -1 && errno != EINTR) { + cu->cu_error.re_errno = errno; + cu->cu_error.re_status = RPC_CANTRECV; + goto out; + } + gettimeofday(&tv, NULL); + timersub(&tv, &starttime, &time_waited); + + /* Check for timeout. */ + if (timercmp(&time_waited, &timeout, >)) { + cu->cu_error.re_status = RPC_TIMEDOUT; + goto out; + } + + /* Retransmit if necessary. */ + if (timercmp(&time_waited, &next_sendtime, >)) { + /* update retransmit_time */ + if (retransmit_time.tv_sec < RPC_MAX_BACKOFF) + timeradd(&retransmit_time, &retransmit_time, + &retransmit_time); + timeradd(&next_sendtime, &retransmit_time, + &next_sendtime); + nretries++; + + /* + * When retransmitting a RPCSEC_GSS message, + * we must use a new sequence number (handled + * by __rpc_gss_wrap above). + */ + if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) + goto send_again; + else + goto call_again_same_xid; + } + } + inlen = (socklen_t)recvlen; + + /* + * now decode and validate the response + */ + + xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)recvlen, XDR_DECODE); + ok = xdr_replymsg(&reply_xdrs, &reply_msg); + /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */ + if (ok) { + if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) && + (reply_msg.acpted_rply.ar_stat == SUCCESS)) + cu->cu_error.re_status = RPC_SUCCESS; + else + _seterr_reply(&reply_msg, &(cu->cu_error)); + + if (cu->cu_error.re_status == RPC_SUCCESS) { + if (! AUTH_VALIDATE(cl->cl_auth, + &reply_msg.acpted_rply.ar_verf)) { + if (nretries && + cl->cl_auth->ah_cred.oa_flavor + == RPCSEC_GSS) + /* + * If we retransmitted, its + * possible that we will + * receive a reply for one of + * the earlier transmissions + * (which will use an older + * RPCSEC_GSS sequence + * number). In this case, just + * go back and listen for a + * new reply. We could keep a + * record of all the seq + * numbers we have transmitted + * so far so that we could + * accept a reply for any of + * them here. + */ + goto get_reply; + cu->cu_error.re_status = RPC_AUTHERROR; + cu->cu_error.re_why = AUTH_INVALIDRESP; + } else { + if (cl->cl_auth->ah_cred.oa_flavor + == RPCSEC_GSS) { + if (!__rpc_gss_unwrap(cl->cl_auth, + &reply_xdrs, xresults, + resultsp)) + cu->cu_error.re_status = + RPC_CANTDECODERES; + } + } + if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { + xdrs->x_op = XDR_FREE; + (void) xdr_opaque_auth(xdrs, + &(reply_msg.acpted_rply.ar_verf)); + } + } /* end successful completion */ + /* + * If unsuccesful AND error is an authentication error + * then refresh credentials and try again, else break + */ + else if (cu->cu_error.re_status == RPC_AUTHERROR) + /* maybe our credentials need to be refreshed ... */ + if (nrefreshes > 0 && + AUTH_REFRESH(cl->cl_auth, &reply_msg)) { + nrefreshes--; + goto call_again; + } + /* end of unsuccessful completion */ + } /* end of valid reply message */ + else { + cu->cu_error.re_status = RPC_CANTDECODERES; + + } +out: + if (cu->cu_kq >= 0) + _close(cu->cu_kq); + cu->cu_kq = -1; + release_fd_lock(cu->cu_fd, mask); + return (cu->cu_error.re_status); +} + +static void +clnt_dg_geterr(cl, errp) + CLIENT *cl; + struct rpc_err *errp; +{ + struct cu_data *cu = (struct cu_data *)cl->cl_private; + + *errp = cu->cu_error; +} + +static bool_t +clnt_dg_freeres(cl, xdr_res, res_ptr) + CLIENT *cl; + xdrproc_t xdr_res; + void *res_ptr; +{ + struct cu_data *cu = (struct cu_data *)cl->cl_private; + XDR *xdrs = &(cu->cu_outxdrs); + bool_t dummy; + sigset_t mask; + sigset_t newmask; + + sigfillset(&newmask); + thr_sigsetmask(SIG_SETMASK, &newmask, &mask); + mutex_lock(&clnt_fd_lock); + while (dg_fd_locks[cu->cu_fd]) + cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock); + xdrs->x_op = XDR_FREE; + dummy = (*xdr_res)(xdrs, res_ptr); + mutex_unlock(&clnt_fd_lock); + thr_sigsetmask(SIG_SETMASK, &mask, NULL); + cond_signal(&dg_cv[cu->cu_fd]); + return (dummy); +} + +/*ARGSUSED*/ +static void +clnt_dg_abort(h) + CLIENT *h; +{ +} + +static bool_t +clnt_dg_control(cl, request, info) + CLIENT *cl; + u_int request; + void *info; +{ + struct cu_data *cu = (struct cu_data *)cl->cl_private; + struct netbuf *addr; + sigset_t mask; + sigset_t newmask; + int rpc_lock_value; + + sigfillset(&newmask); + thr_sigsetmask(SIG_SETMASK, &newmask, &mask); + mutex_lock(&clnt_fd_lock); + while (dg_fd_locks[cu->cu_fd]) + cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock); + if (__isthreaded) + rpc_lock_value = 1; + else + rpc_lock_value = 0; + dg_fd_locks[cu->cu_fd] = rpc_lock_value; + mutex_unlock(&clnt_fd_lock); + switch (request) { + case CLSET_FD_CLOSE: + cu->cu_closeit = TRUE; + release_fd_lock(cu->cu_fd, mask); + return (TRUE); + case CLSET_FD_NCLOSE: + cu->cu_closeit = FALSE; + release_fd_lock(cu->cu_fd, mask); + return (TRUE); + } + + /* for other requests which use info */ + if (info == NULL) { + release_fd_lock(cu->cu_fd, mask); + return (FALSE); + } + switch (request) { + case CLSET_TIMEOUT: + if (time_not_ok((struct timeval *)info)) { + release_fd_lock(cu->cu_fd, mask); + return (FALSE); + } + cu->cu_total = *(struct timeval *)info; + break; + case CLGET_TIMEOUT: + *(struct timeval *)info = cu->cu_total; + break; + case CLGET_SERVER_ADDR: /* Give him the fd address */ + /* Now obsolete. Only for backward compatibility */ + (void) memcpy(info, &cu->cu_raddr, (size_t)cu->cu_rlen); + break; + case CLSET_RETRY_TIMEOUT: + if (time_not_ok((struct timeval *)info)) { + release_fd_lock(cu->cu_fd, mask); + return (FALSE); + } + cu->cu_wait = *(struct timeval *)info; + break; + case CLGET_RETRY_TIMEOUT: + *(struct timeval *)info = cu->cu_wait; + break; + case CLGET_FD: + *(int *)info = cu->cu_fd; + break; + case CLGET_SVC_ADDR: + addr = (struct netbuf *)info; + addr->buf = &cu->cu_raddr; + addr->len = cu->cu_rlen; + addr->maxlen = sizeof cu->cu_raddr; + break; + case CLSET_SVC_ADDR: /* set to new address */ + addr = (struct netbuf *)info; + if (addr->len < sizeof cu->cu_raddr) { + release_fd_lock(cu->cu_fd, mask); + return (FALSE); + } + (void) memcpy(&cu->cu_raddr, addr->buf, addr->len); + cu->cu_rlen = addr->len; + break; + case CLGET_XID: + /* + * use the knowledge that xid is the + * first element in the call structure *. + * This will get the xid of the PREVIOUS call + */ + *(u_int32_t *)info = + ntohl(*(u_int32_t *)(void *)cu->cu_outhdr); + break; + + case CLSET_XID: + /* This will set the xid of the NEXT call */ + *(u_int32_t *)(void *)cu->cu_outhdr = + htonl(*(u_int32_t *)info - 1); + /* decrement by 1 as clnt_dg_call() increments once */ + break; + + case CLGET_VERS: + /* + * This RELIES on the information that, in the call body, + * the version number field is the fifth field from the + * begining of the RPC header. MUST be changed if the + * call_struct is changed + */ + *(u_int32_t *)info = + ntohl(*(u_int32_t *)(void *)(cu->cu_outhdr + + 4 * BYTES_PER_XDR_UNIT)); + break; + + case CLSET_VERS: + *(u_int32_t *)(void *)(cu->cu_outhdr + 4 * BYTES_PER_XDR_UNIT) + = htonl(*(u_int32_t *)info); + break; + + case CLGET_PROG: + /* + * This RELIES on the information that, in the call body, + * the program number field is the fourth field from the + * begining of the RPC header. MUST be changed if the + * call_struct is changed + */ + *(u_int32_t *)info = + ntohl(*(u_int32_t *)(void *)(cu->cu_outhdr + + 3 * BYTES_PER_XDR_UNIT)); + break; + + case CLSET_PROG: + *(u_int32_t *)(void *)(cu->cu_outhdr + 3 * BYTES_PER_XDR_UNIT) + = htonl(*(u_int32_t *)info); + break; + case CLSET_ASYNC: + cu->cu_async = *(int *)info; + break; + case CLSET_CONNECT: + cu->cu_connect = *(int *)info; + break; + default: + release_fd_lock(cu->cu_fd, mask); + return (FALSE); + } + release_fd_lock(cu->cu_fd, mask); + return (TRUE); +} + +static void +clnt_dg_destroy(cl) + CLIENT *cl; +{ + struct cu_data *cu = (struct cu_data *)cl->cl_private; + int cu_fd = cu->cu_fd; + sigset_t mask; + sigset_t newmask; + + sigfillset(&newmask); + thr_sigsetmask(SIG_SETMASK, &newmask, &mask); + mutex_lock(&clnt_fd_lock); + while (dg_fd_locks[cu_fd]) + cond_wait(&dg_cv[cu_fd], &clnt_fd_lock); + if (cu->cu_closeit) + (void)_close(cu_fd); + if (cu->cu_kq >= 0) + _close(cu->cu_kq); + XDR_DESTROY(&(cu->cu_outxdrs)); + mem_free(cu, (sizeof (*cu) + cu->cu_sendsz + cu->cu_recvsz)); + if (cl->cl_netid && cl->cl_netid[0]) + mem_free(cl->cl_netid, strlen(cl->cl_netid) +1); + if (cl->cl_tp && cl->cl_tp[0]) + mem_free(cl->cl_tp, strlen(cl->cl_tp) +1); + mem_free(cl, sizeof (CLIENT)); + mutex_unlock(&clnt_fd_lock); + thr_sigsetmask(SIG_SETMASK, &mask, NULL); + cond_signal(&dg_cv[cu_fd]); +} + +static struct clnt_ops * +clnt_dg_ops() +{ + static struct clnt_ops ops; + sigset_t mask; + sigset_t newmask; + +/* VARIABLES PROTECTED BY ops_lock: ops */ + + sigfillset(&newmask); + thr_sigsetmask(SIG_SETMASK, &newmask, &mask); + mutex_lock(&ops_lock); + if (ops.cl_call == NULL) { + ops.cl_call = clnt_dg_call; + ops.cl_abort = clnt_dg_abort; + ops.cl_geterr = clnt_dg_geterr; + ops.cl_freeres = clnt_dg_freeres; + ops.cl_destroy = clnt_dg_destroy; + ops.cl_control = clnt_dg_control; + } + mutex_unlock(&ops_lock); + thr_sigsetmask(SIG_SETMASK, &mask, NULL); + return (&ops); +} + +/* + * Make sure that the time is not garbage. -1 value is allowed. + */ +static bool_t +time_not_ok(t) + struct timeval *t; +{ + return (t->tv_sec < -1 || t->tv_sec > 100000000 || + t->tv_usec < -1 || t->tv_usec > 1000000); +} + diff --git a/freebsd/lib/libc/rpc/clnt_generic.c b/freebsd/lib/libc/rpc/clnt_generic.c new file mode 100644 index 00000000..cca7f3e3 --- /dev/null +++ b/freebsd/lib/libc/rpc/clnt_generic.c @@ -0,0 +1,450 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: clnt_generic.c,v 1.18 2000/07/06 03:10:34 christos Exp $ */ + +/*- + * Copyright (c) 2010, Oracle America, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of the "Oracle America, Inc." nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* #ident "@(#)clnt_generic.c 1.40 99/04/21 SMI" */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *sccsid2 = "from: @(#)clnt_generic.c 1.4 87/08/11 (C) 1987 SMI"; +static char *sccsid = "from: @(#)clnt_generic.c 2.2 88/08/01 4.0 RPCSRC"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Copyright (c) 1986-1996,1998 by Sun Microsystems, Inc. + * All rights reserved. + */ +#include "namespace.h" +#include "reentrant.h" +#include <sys/types.h> +#include <sys/fcntl.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <stdio.h> +#include <errno.h> +#include <netdb.h> +#include <syslog.h> +#include <rpc/rpc.h> +#include <rpc/nettype.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include "un-namespace.h" +#include "rpc_com.h" + +extern bool_t __rpc_is_local_host(const char *); +int __rpc_raise_fd(int); + +#ifndef NETIDLEN +#define NETIDLEN 32 +#endif + + +/* + * Generic client creation with version checking the value of + * vers_out is set to the highest server supported value + * vers_low <= vers_out <= vers_high AND an error results + * if this can not be done. + * + * It calls clnt_create_vers_timed() with a NULL value for the timeout + * pointer, which indicates that the default timeout should be used. + */ +CLIENT * +clnt_create_vers(const char *hostname, rpcprog_t prog, rpcvers_t *vers_out, + rpcvers_t vers_low, rpcvers_t vers_high, const char *nettype) +{ + + return (clnt_create_vers_timed(hostname, prog, vers_out, vers_low, + vers_high, nettype, NULL)); +} + +/* + * This the routine has the same definition as clnt_create_vers(), + * except it takes an additional timeout parameter - a pointer to + * a timeval structure. A NULL value for the pointer indicates + * that the default timeout value should be used. + */ +CLIENT * +clnt_create_vers_timed(const char *hostname, rpcprog_t prog, + rpcvers_t *vers_out, rpcvers_t vers_low, rpcvers_t vers_high, + const char *nettype, const struct timeval *tp) +{ + CLIENT *clnt; + struct timeval to; + enum clnt_stat rpc_stat; + struct rpc_err rpcerr; + + clnt = clnt_create_timed(hostname, prog, vers_high, nettype, tp); + if (clnt == NULL) { + return (NULL); + } + to.tv_sec = 10; + to.tv_usec = 0; + rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void, + (char *)NULL, (xdrproc_t)xdr_void, (char *)NULL, to); + if (rpc_stat == RPC_SUCCESS) { + *vers_out = vers_high; + return (clnt); + } + while (rpc_stat == RPC_PROGVERSMISMATCH && vers_high > vers_low) { + unsigned int minvers, maxvers; + + clnt_geterr(clnt, &rpcerr); + minvers = rpcerr.re_vers.low; + maxvers = rpcerr.re_vers.high; + if (maxvers < vers_high) + vers_high = maxvers; + else + vers_high--; + if (minvers > vers_low) + vers_low = minvers; + if (vers_low > vers_high) { + goto error; + } + CLNT_CONTROL(clnt, CLSET_VERS, (char *)&vers_high); + rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void, + (char *)NULL, (xdrproc_t)xdr_void, + (char *)NULL, to); + if (rpc_stat == RPC_SUCCESS) { + *vers_out = vers_high; + return (clnt); + } + } + clnt_geterr(clnt, &rpcerr); + +error: + rpc_createerr.cf_stat = rpc_stat; + rpc_createerr.cf_error = rpcerr; + clnt_destroy(clnt); + return (NULL); +} + +/* + * Top level client creation routine. + * Generic client creation: takes (servers name, program-number, nettype) and + * returns client handle. Default options are set, which the user can + * change using the rpc equivalent of _ioctl()'s. + * + * It tries for all the netids in that particular class of netid until + * it succeeds. + * XXX The error message in the case of failure will be the one + * pertaining to the last create error. + * + * It calls clnt_create_timed() with the default timeout. + */ +CLIENT * +clnt_create(const char *hostname, rpcprog_t prog, rpcvers_t vers, + const char *nettype) +{ + + return (clnt_create_timed(hostname, prog, vers, nettype, NULL)); +} + +/* + * This the routine has the same definition as clnt_create(), + * except it takes an additional timeout parameter - a pointer to + * a timeval structure. A NULL value for the pointer indicates + * that the default timeout value should be used. + * + * This function calls clnt_tp_create_timed(). + */ +CLIENT * +clnt_create_timed(const char *hostname, rpcprog_t prog, rpcvers_t vers, + const char *netclass, const struct timeval *tp) +{ + struct netconfig *nconf; + CLIENT *clnt = NULL; + void *handle; + enum clnt_stat save_cf_stat = RPC_SUCCESS; + struct rpc_err save_cf_error; + char nettype_array[NETIDLEN]; + char *nettype = &nettype_array[0]; + + if (netclass == NULL) + nettype = NULL; + else { + size_t len = strlen(netclass); + if (len >= sizeof (nettype_array)) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return (NULL); + } + strcpy(nettype, netclass); + } + + if ((handle = __rpc_setconf((char *)nettype)) == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return (NULL); + } + rpc_createerr.cf_stat = RPC_SUCCESS; + while (clnt == NULL) { + if ((nconf = __rpc_getconf(handle)) == NULL) { + if (rpc_createerr.cf_stat == RPC_SUCCESS) + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + break; + } +#ifdef CLNT_DEBUG + printf("trying netid %s\n", nconf->nc_netid); +#endif + clnt = clnt_tp_create_timed(hostname, prog, vers, nconf, tp); + if (clnt) + break; + else + /* + * Since we didn't get a name-to-address + * translation failure here, we remember + * this particular error. The object of + * this is to enable us to return to the + * caller a more-specific error than the + * unhelpful ``Name to address translation + * failed'' which might well occur if we + * merely returned the last error (because + * the local loopbacks are typically the + * last ones in /etc/netconfig and the most + * likely to be unable to translate a host + * name). We also check for a more + * meaningful error than ``unknown host + * name'' for the same reasons. + */ + if (rpc_createerr.cf_stat != RPC_N2AXLATEFAILURE && + rpc_createerr.cf_stat != RPC_UNKNOWNHOST) { + save_cf_stat = rpc_createerr.cf_stat; + save_cf_error = rpc_createerr.cf_error; + } + } + + /* + * Attempt to return an error more specific than ``Name to address + * translation failed'' or ``unknown host name'' + */ + if ((rpc_createerr.cf_stat == RPC_N2AXLATEFAILURE || + rpc_createerr.cf_stat == RPC_UNKNOWNHOST) && + (save_cf_stat != RPC_SUCCESS)) { + rpc_createerr.cf_stat = save_cf_stat; + rpc_createerr.cf_error = save_cf_error; + } + __rpc_endconf(handle); + return (clnt); +} + +/* + * Generic client creation: takes (servers name, program-number, netconf) and + * returns client handle. Default options are set, which the user can + * change using the rpc equivalent of _ioctl()'s : clnt_control() + * It finds out the server address from rpcbind and calls clnt_tli_create(). + * + * It calls clnt_tp_create_timed() with the default timeout. + */ +CLIENT * +clnt_tp_create(const char *hostname, rpcprog_t prog, rpcvers_t vers, + const struct netconfig *nconf) +{ + + return (clnt_tp_create_timed(hostname, prog, vers, nconf, NULL)); +} + +/* + * This has the same definition as clnt_tp_create(), except it + * takes an additional parameter - a pointer to a timeval structure. + * A NULL value for the timeout pointer indicates that the default + * value for the timeout should be used. + */ +CLIENT * +clnt_tp_create_timed(const char *hostname, rpcprog_t prog, rpcvers_t vers, + const struct netconfig *nconf, const struct timeval *tp) +{ + struct netbuf *svcaddr; /* servers address */ + CLIENT *cl = NULL; /* client handle */ + + if (nconf == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return (NULL); + } + + /* + * Get the address of the server + */ + if ((svcaddr = __rpcb_findaddr_timed(prog, vers, + (struct netconfig *)nconf, (char *)hostname, + &cl, (struct timeval *)tp)) == NULL) { + /* appropriate error number is set by rpcbind libraries */ + return (NULL); + } + if (cl == NULL) { + cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr, + prog, vers, 0, 0); + } else { + /* Reuse the CLIENT handle and change the appropriate fields */ + if (CLNT_CONTROL(cl, CLSET_SVC_ADDR, (void *)svcaddr) == TRUE) { + if (cl->cl_netid == NULL) + cl->cl_netid = strdup(nconf->nc_netid); + if (cl->cl_tp == NULL) + cl->cl_tp = strdup(nconf->nc_device); + (void) CLNT_CONTROL(cl, CLSET_PROG, (void *)&prog); + (void) CLNT_CONTROL(cl, CLSET_VERS, (void *)&vers); + } else { + CLNT_DESTROY(cl); + cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr, + prog, vers, 0, 0); + } + } + free(svcaddr->buf); + free(svcaddr); + return (cl); +} + +/* + * Generic client creation: returns client handle. + * Default options are set, which the user can + * change using the rpc equivalent of _ioctl()'s : clnt_control(). + * If fd is RPC_ANYFD, it will be opened using nconf. + * It will be bound if not so. + * If sizes are 0; appropriate defaults will be chosen. + */ +CLIENT * +clnt_tli_create(int fd, const struct netconfig *nconf, + struct netbuf *svcaddr, rpcprog_t prog, rpcvers_t vers, + uint sendsz, uint recvsz) +{ + CLIENT *cl; /* client handle */ + bool_t madefd = FALSE; /* whether fd opened here */ + long servtype; + int one = 1; + struct __rpc_sockinfo si; + extern int __rpc_minfd; + + if (fd == RPC_ANYFD) { + if (nconf == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return (NULL); + } + + fd = __rpc_nconf2fd(nconf); + + if (fd == -1) + goto err; + if (fd < __rpc_minfd) + fd = __rpc_raise_fd(fd); + madefd = TRUE; + servtype = nconf->nc_semantics; + if (!__rpc_fd2sockinfo(fd, &si)) + goto err; + bindresvport(fd, NULL); + } else { + if (!__rpc_fd2sockinfo(fd, &si)) + goto err; + servtype = __rpc_socktype2seman(si.si_socktype); + if (servtype == -1) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return (NULL); + } + } + + if (si.si_af != ((struct sockaddr *)svcaddr->buf)->sa_family) { + rpc_createerr.cf_stat = RPC_UNKNOWNHOST; /* XXX */ + goto err1; + } + + switch (servtype) { + case NC_TPI_COTS: + cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz); + break; + case NC_TPI_COTS_ORD: + if (nconf && ((strcmp(nconf->nc_protofmly, "inet") == 0))) { + _setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, + sizeof (one)); + } + cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz); + break; + case NC_TPI_CLTS: + cl = clnt_dg_create(fd, svcaddr, prog, vers, sendsz, recvsz); + break; + default: + goto err; + } + + if (cl == NULL) + goto err1; /* borrow errors from clnt_dg/vc creates */ + if (nconf) { + cl->cl_netid = strdup(nconf->nc_netid); + cl->cl_tp = strdup(nconf->nc_device); + } else { + cl->cl_netid = ""; + cl->cl_tp = ""; + } + if (madefd) { + (void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL); +/* (void) CLNT_CONTROL(cl, CLSET_POP_TIMOD, NULL); */ + }; + + return (cl); + +err: + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; +err1: if (madefd) + (void)_close(fd); + return (NULL); +} + +/* + * To avoid conflicts with the "magic" file descriptors (0, 1, and 2), + * we try to not use them. The __rpc_raise_fd() routine will dup + * a descriptor to a higher value. If we fail to do it, we continue + * to use the old one (and hope for the best). + */ +int __rpc_minfd = 3; + +int +__rpc_raise_fd(int fd) +{ + int nfd; + + if (fd >= __rpc_minfd) + return (fd); + + if ((nfd = _fcntl(fd, F_DUPFD, __rpc_minfd)) == -1) + return (fd); + + if (_fsync(nfd) == -1) { + _close(nfd); + return (fd); + } + + if (_close(fd) == -1) { + /* this is okay, we will syslog an error, then use the new fd */ + (void) syslog(LOG_ERR, + "could not close() fd %d; mem & fd leak", fd); + } + + return (nfd); +} diff --git a/freebsd/lib/libc/rpc/clnt_perror.c b/freebsd/lib/libc/rpc/clnt_perror.c new file mode 100644 index 00000000..56155728 --- /dev/null +++ b/freebsd/lib/libc/rpc/clnt_perror.c @@ -0,0 +1,334 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: clnt_perror.c,v 1.24 2000/06/02 23:11:07 fvdl Exp $ */ + + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *sccsid2 = "@(#)clnt_perror.c 1.15 87/10/07 Copyr 1984 Sun Micro"; +static char *sccsid = "@(#)clnt_perror.c 2.1 88/07/29 4.0 RPCSRC"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * clnt_perror.c + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + */ +#include "namespace.h" +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <rpc/rpc.h> +#include <rpc/types.h> +#include <rpc/auth.h> +#include <rpc/clnt.h> +#include "un-namespace.h" + +static char *buf; + +static char *_buf(void); +static char *auth_errmsg(enum auth_stat); +#define CLNT_PERROR_BUFLEN 256 + +static char * +_buf() +{ + + if (buf == 0) + buf = (char *)malloc(CLNT_PERROR_BUFLEN); + return (buf); +} + +/* + * Print reply error info + */ +char * +clnt_sperror(rpch, s) + CLIENT *rpch; + const char *s; +{ + struct rpc_err e; + char *err; + char *str; + char *strstart; + size_t len, i; + + assert(rpch != NULL); + assert(s != NULL); + + str = _buf(); /* side effect: sets CLNT_PERROR_BUFLEN */ + if (str == 0) + return (0); + len = CLNT_PERROR_BUFLEN; + strstart = str; + CLNT_GETERR(rpch, &e); + + if ((i = snprintf(str, len, "%s: ", s)) > 0) { + str += i; + len -= i; + } + + (void)strncpy(str, clnt_sperrno(e.re_status), len - 1); + i = strlen(str); + str += i; + len -= i; + + switch (e.re_status) { + case RPC_SUCCESS: + case RPC_CANTENCODEARGS: + case RPC_CANTDECODERES: + case RPC_TIMEDOUT: + case RPC_PROGUNAVAIL: + case RPC_PROCUNAVAIL: + case RPC_CANTDECODEARGS: + case RPC_SYSTEMERROR: + case RPC_UNKNOWNHOST: + case RPC_UNKNOWNPROTO: + case RPC_PMAPFAILURE: + case RPC_PROGNOTREGISTERED: + case RPC_FAILED: + break; + + case RPC_CANTSEND: + case RPC_CANTRECV: + i = snprintf(str, len, "; errno = %s", strerror(e.re_errno)); + if (i > 0) { + str += i; + len -= i; + } + break; + + case RPC_VERSMISMATCH: + i = snprintf(str, len, "; low version = %u, high version = %u", + e.re_vers.low, e.re_vers.high); + if (i > 0) { + str += i; + len -= i; + } + break; + + case RPC_AUTHERROR: + err = auth_errmsg(e.re_why); + i = snprintf(str, len, "; why = "); + if (i > 0) { + str += i; + len -= i; + } + if (err != NULL) { + i = snprintf(str, len, "%s",err); + } else { + i = snprintf(str, len, + "(unknown authentication error - %d)", + (int) e.re_why); + } + if (i > 0) { + str += i; + len -= i; + } + break; + + case RPC_PROGVERSMISMATCH: + i = snprintf(str, len, "; low version = %u, high version = %u", + e.re_vers.low, e.re_vers.high); + if (i > 0) { + str += i; + len -= i; + } + break; + + default: /* unknown */ + i = snprintf(str, len, "; s1 = %u, s2 = %u", + e.re_lb.s1, e.re_lb.s2); + if (i > 0) { + str += i; + len -= i; + } + break; + } + strstart[CLNT_PERROR_BUFLEN-1] = '\0'; + return(strstart) ; +} + +void +clnt_perror(rpch, s) + CLIENT *rpch; + const char *s; +{ + + assert(rpch != NULL); + assert(s != NULL); + + (void) fprintf(stderr, "%s\n", clnt_sperror(rpch,s)); +} + +static const char *const rpc_errlist[] = { + "RPC: Success", /* 0 - RPC_SUCCESS */ + "RPC: Can't encode arguments", /* 1 - RPC_CANTENCODEARGS */ + "RPC: Can't decode result", /* 2 - RPC_CANTDECODERES */ + "RPC: Unable to send", /* 3 - RPC_CANTSEND */ + "RPC: Unable to receive", /* 4 - RPC_CANTRECV */ + "RPC: Timed out", /* 5 - RPC_TIMEDOUT */ + "RPC: Incompatible versions of RPC", /* 6 - RPC_VERSMISMATCH */ + "RPC: Authentication error", /* 7 - RPC_AUTHERROR */ + "RPC: Program unavailable", /* 8 - RPC_PROGUNAVAIL */ + "RPC: Program/version mismatch", /* 9 - RPC_PROGVERSMISMATCH */ + "RPC: Procedure unavailable", /* 10 - RPC_PROCUNAVAIL */ + "RPC: Server can't decode arguments", /* 11 - RPC_CANTDECODEARGS */ + "RPC: Remote system error", /* 12 - RPC_SYSTEMERROR */ + "RPC: Unknown host", /* 13 - RPC_UNKNOWNHOST */ + "RPC: Port mapper failure", /* 14 - RPC_PMAPFAILURE */ + "RPC: Program not registered", /* 15 - RPC_PROGNOTREGISTERED */ + "RPC: Failed (unspecified error)", /* 16 - RPC_FAILED */ + "RPC: Unknown protocol" /* 17 - RPC_UNKNOWNPROTO */ +}; + + +/* + * This interface for use by clntrpc + */ +char * +clnt_sperrno(stat) + enum clnt_stat stat; +{ + unsigned int errnum = stat; + + if (errnum < (sizeof(rpc_errlist)/sizeof(rpc_errlist[0]))) + /* LINTED interface problem */ + return (char *)rpc_errlist[errnum]; + + return ("RPC: (unknown error code)"); +} + +void +clnt_perrno(num) + enum clnt_stat num; +{ + (void) fprintf(stderr, "%s\n", clnt_sperrno(num)); +} + + +char * +clnt_spcreateerror(s) + const char *s; +{ + char *str; + size_t len, i; + + assert(s != NULL); + + str = _buf(); /* side effect: sets CLNT_PERROR_BUFLEN */ + if (str == 0) + return(0); + len = CLNT_PERROR_BUFLEN; + i = snprintf(str, len, "%s: ", s); + if (i > 0) + len -= i; + (void)strncat(str, clnt_sperrno(rpc_createerr.cf_stat), len - 1); + switch (rpc_createerr.cf_stat) { + case RPC_PMAPFAILURE: + (void) strncat(str, " - ", len - 1); + (void) strncat(str, + clnt_sperrno(rpc_createerr.cf_error.re_status), len - 4); + break; + + case RPC_SYSTEMERROR: + (void)strncat(str, " - ", len - 1); + (void)strncat(str, strerror(rpc_createerr.cf_error.re_errno), + len - 4); + break; + + case RPC_CANTSEND: + case RPC_CANTDECODERES: + case RPC_CANTENCODEARGS: + case RPC_SUCCESS: + case RPC_UNKNOWNPROTO: + case RPC_PROGNOTREGISTERED: + case RPC_FAILED: + case RPC_UNKNOWNHOST: + case RPC_CANTDECODEARGS: + case RPC_PROCUNAVAIL: + case RPC_PROGVERSMISMATCH: + case RPC_PROGUNAVAIL: + case RPC_AUTHERROR: + case RPC_VERSMISMATCH: + case RPC_TIMEDOUT: + case RPC_CANTRECV: + default: + break; + } + str[CLNT_PERROR_BUFLEN-1] = '\0'; + return (str); +} + +void +clnt_pcreateerror(s) + const char *s; +{ + + assert(s != NULL); + + (void) fprintf(stderr, "%s\n", clnt_spcreateerror(s)); +} + +static const char *const auth_errlist[] = { + "Authentication OK", /* 0 - AUTH_OK */ + "Invalid client credential", /* 1 - AUTH_BADCRED */ + "Server rejected credential", /* 2 - AUTH_REJECTEDCRED */ + "Invalid client verifier", /* 3 - AUTH_BADVERF */ + "Server rejected verifier", /* 4 - AUTH_REJECTEDVERF */ + "Client credential too weak", /* 5 - AUTH_TOOWEAK */ + "Invalid server verifier", /* 6 - AUTH_INVALIDRESP */ + "Failed (unspecified error)", /* 7 - AUTH_FAILED */ + "Kerberos generic error", /* 8 - AUTH_KERB_GENERIC*/ + "Kerberos credential expired", /* 9 - AUTH_TIMEEXPIRE */ + "Bad kerberos ticket file", /* 10 - AUTH_TKT_FILE */ + "Can't decode kerberos authenticator", /* 11 - AUTH_DECODE */ + "Address wrong in kerberos ticket", /* 12 - AUTH_NET_ADDR */ + "GSS-API crediential problem", /* 13 - RPCSEC_GSS_CREDPROBLEM */ + "GSS-API context problem" /* 14 - RPCSEC_GSS_CTXPROBLEM */ +}; + +static char * +auth_errmsg(stat) + enum auth_stat stat; +{ + unsigned int errnum = stat; + + if (errnum < (sizeof(auth_errlist)/sizeof(auth_errlist[0]))) + /* LINTED interface problem */ + return (char *)auth_errlist[errnum]; + + return(NULL); +} diff --git a/freebsd/lib/libc/rpc/clnt_raw.c b/freebsd/lib/libc/rpc/clnt_raw.c new file mode 100644 index 00000000..ec130c14 --- /dev/null +++ b/freebsd/lib/libc/rpc/clnt_raw.c @@ -0,0 +1,316 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: clnt_raw.c,v 1.20 2000/12/10 04:12:03 christos Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *sccsid2 = "@(#)clnt_raw.c 1.22 87/08/11 Copyr 1984 Sun Micro"; +static char *sccsid = "@(#)clnt_raw.c 2.2 88/08/01 4.0 RPCSRC"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * clnt_raw.c + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * Memory based rpc for simple testing and timing. + * Interface to create an rpc client and server in the same process. + * This lets us similate rpc and get round trip overhead, without + * any interference from the kernel. + */ + +#include "namespace.h" +#include "reentrant.h" +#include <assert.h> +#include <err.h> +#include <stdio.h> +#include <stdlib.h> + +#include <rpc/rpc.h> +#include <rpc/raw.h> +#include "un-namespace.h" +#include "mt_misc.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; + union { + struct rpc_msg mashl_rpcmsg; + char mashl_callmsg[MCALL_MSG_SIZE]; + } u; + u_int mcnt; +} *clntraw_private; + +static enum clnt_stat clnt_raw_call(CLIENT *, rpcproc_t, xdrproc_t, void *, + xdrproc_t, void *, struct timeval); +static void clnt_raw_geterr(CLIENT *, struct rpc_err *); +static bool_t clnt_raw_freeres(CLIENT *, xdrproc_t, void *); +static void clnt_raw_abort(CLIENT *); +static bool_t clnt_raw_control(CLIENT *, u_int, void *); +static void clnt_raw_destroy(CLIENT *); +static struct clnt_ops *clnt_raw_ops(void); + +/* + * Create a client handle for memory based rpc. + */ +CLIENT * +clnt_raw_create(prog, vers) + rpcprog_t prog; + rpcvers_t vers; +{ + struct clntraw_private *clp; + struct rpc_msg call_msg; + XDR *xdrs; + CLIENT *client; + + mutex_lock(&clntraw_lock); + if ((clp = clntraw_private) == NULL) { + clp = (struct clntraw_private *)calloc(1, sizeof (*clp)); + if (clp == NULL) { + mutex_unlock(&clntraw_lock); + return NULL; + } + if (__rpc_rawcombuf == NULL) + __rpc_rawcombuf = + (char *)calloc(UDPMSGSIZE, sizeof (char)); + clp->_raw_buf = __rpc_rawcombuf; + clntraw_private = clp; + } + xdrs = &clp->xdr_stream; + client = &clp->client_object; + + /* + * pre-serialize the static part of the call msg and stash it away + */ + call_msg.rm_direction = CALL; + call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; + /* XXX: prog and vers have been long historically :-( */ + call_msg.rm_call.cb_prog = (u_int32_t)prog; + call_msg.rm_call.cb_vers = (u_int32_t)vers; + xdrmem_create(xdrs, clp->u.mashl_callmsg, MCALL_MSG_SIZE, XDR_ENCODE); + if (! xdr_callhdr(xdrs, &call_msg)) + warnx("clntraw_create - Fatal header serialization error."); + clp->mcnt = XDR_GETPOS(xdrs); + XDR_DESTROY(xdrs); + + /* + * Set xdrmem for client/server shared buffer + */ + xdrmem_create(xdrs, clp->_raw_buf, UDPMSGSIZE, XDR_FREE); + + /* + * create client handle + */ + client->cl_ops = clnt_raw_ops(); + client->cl_auth = authnone_create(); + mutex_unlock(&clntraw_lock); + return (client); +} + +/* ARGSUSED */ +static enum clnt_stat +clnt_raw_call(h, proc, xargs, argsp, xresults, resultsp, timeout) + CLIENT *h; + rpcproc_t proc; + xdrproc_t xargs; + void *argsp; + xdrproc_t xresults; + void *resultsp; + struct timeval timeout; +{ + struct clntraw_private *clp = clntraw_private; + XDR *xdrs = &clp->xdr_stream; + struct rpc_msg msg; + enum clnt_stat status; + struct rpc_err error; + + assert(h != NULL); + + mutex_lock(&clntraw_lock); + if (clp == NULL) { + mutex_unlock(&clntraw_lock); + return (RPC_FAILED); + } + mutex_unlock(&clntraw_lock); + +call_again: + /* + * send request + */ + xdrs->x_op = XDR_ENCODE; + XDR_SETPOS(xdrs, 0); + clp->u.mashl_rpcmsg.rm_xid ++ ; + if ((! XDR_PUTBYTES(xdrs, clp->u.mashl_callmsg, clp->mcnt)) || + (! XDR_PUTINT32(xdrs, &proc)) || + (! AUTH_MARSHALL(h->cl_auth, xdrs)) || + (! (*xargs)(xdrs, argsp))) { + return (RPC_CANTENCODEARGS); + } + (void)XDR_GETPOS(xdrs); /* called just to cause overhead */ + + /* + * We have to call server input routine here because this is + * all going on in one process. Yuk. + */ + svc_getreq_common(FD_SETSIZE); + + /* + * get results + */ + xdrs->x_op = XDR_DECODE; + XDR_SETPOS(xdrs, 0); + msg.acpted_rply.ar_verf = _null_auth; + msg.acpted_rply.ar_results.where = resultsp; + msg.acpted_rply.ar_results.proc = xresults; + if (! xdr_replymsg(xdrs, &msg)) { + /* + * It's possible for xdr_replymsg() to fail partway + * through its attempt to decode the result from the + * server. If this happens, it will leave the reply + * structure partially populated with dynamically + * allocated memory. (This can happen if someone uses + * clntudp_bufcreate() to create a CLIENT handle and + * specifies a receive buffer size that is too small.) + * This memory must be free()ed to avoid a leak. + */ + int op = xdrs->x_op; + xdrs->x_op = XDR_FREE; + xdr_replymsg(xdrs, &msg); + xdrs->x_op = op; + return (RPC_CANTDECODERES); + } + _seterr_reply(&msg, &error); + status = error.re_status; + + if (status == RPC_SUCCESS) { + if (! AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf)) { + status = RPC_AUTHERROR; + } + } /* end successful completion */ + else { + if (AUTH_REFRESH(h->cl_auth, &msg)) + goto call_again; + } /* end of unsuccessful completion */ + + if (status == RPC_SUCCESS) { + if (! AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf)) { + status = RPC_AUTHERROR; + } + if (msg.acpted_rply.ar_verf.oa_base != NULL) { + xdrs->x_op = XDR_FREE; + (void)xdr_opaque_auth(xdrs, &(msg.acpted_rply.ar_verf)); + } + } + + return (status); +} + +/*ARGSUSED*/ +static void +clnt_raw_geterr(cl, err) + CLIENT *cl; + struct rpc_err *err; +{ +} + + +/* ARGSUSED */ +static bool_t +clnt_raw_freeres(cl, xdr_res, res_ptr) + CLIENT *cl; + xdrproc_t xdr_res; + void *res_ptr; +{ + struct clntraw_private *clp = clntraw_private; + XDR *xdrs = &clp->xdr_stream; + bool_t rval; + + mutex_lock(&clntraw_lock); + if (clp == NULL) { + rval = (bool_t) RPC_FAILED; + mutex_unlock(&clntraw_lock); + return (rval); + } + mutex_unlock(&clntraw_lock); + xdrs->x_op = XDR_FREE; + return ((*xdr_res)(xdrs, res_ptr)); +} + +/*ARGSUSED*/ +static void +clnt_raw_abort(cl) + CLIENT *cl; +{ +} + +/*ARGSUSED*/ +static bool_t +clnt_raw_control(cl, ui, str) + CLIENT *cl; + u_int ui; + void *str; +{ + return (FALSE); +} + +/*ARGSUSED*/ +static void +clnt_raw_destroy(cl) + CLIENT *cl; +{ +} + +static struct clnt_ops * +clnt_raw_ops() +{ + static struct clnt_ops ops; + + /* VARIABLES PROTECTED BY ops_lock: ops */ + + mutex_lock(&ops_lock); + if (ops.cl_call == NULL) { + ops.cl_call = clnt_raw_call; + ops.cl_abort = clnt_raw_abort; + ops.cl_geterr = clnt_raw_geterr; + ops.cl_freeres = clnt_raw_freeres; + ops.cl_destroy = clnt_raw_destroy; + ops.cl_control = clnt_raw_control; + } + mutex_unlock(&ops_lock); + return (&ops); +} diff --git a/freebsd/lib/libc/rpc/clnt_simple.c b/freebsd/lib/libc/rpc/clnt_simple.c new file mode 100644 index 00000000..56d76b8a --- /dev/null +++ b/freebsd/lib/libc/rpc/clnt_simple.c @@ -0,0 +1,207 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: clnt_simple.c,v 1.21 2000/07/06 03:10:34 christos Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *sccsid2 = "from: @(#)clnt_simple.c 1.35 87/08/11 Copyr 1984 Sun Micro"; +static char *sccsid = "from: @(#)clnt_simple.c 2.2 88/08/01 4.0 RPCSRC"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * clnt_simple.c + * Simplified front end to client rpc. + * + */ + +#include "namespace.h" +#include "reentrant.h" +#include <rtems/bsd/sys/param.h> +#include <stdio.h> +#include <errno.h> +#include <rpc/rpc.h> +#include <string.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include "un-namespace.h" +#include "mt_misc.h" + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 64 +#endif + +#ifndef NETIDLEN +#define NETIDLEN 32 +#endif + +struct rpc_call_private { + int valid; /* Is this entry valid ? */ + CLIENT *client; /* Client handle */ + pid_t pid; /* process-id at moment of creation */ + rpcprog_t prognum; /* Program */ + rpcvers_t versnum; /* Version */ + char host[MAXHOSTNAMELEN]; /* Servers host */ + char nettype[NETIDLEN]; /* Network type */ +}; +static struct rpc_call_private *rpc_call_private_main; +static thread_key_t rpc_call_key; +static once_t rpc_call_once = ONCE_INITIALIZER; +static int rpc_call_key_error; + +static void rpc_call_key_init(void); +static void rpc_call_destroy(void *); + +static void +rpc_call_destroy(void *vp) +{ + struct rpc_call_private *rcp = (struct rpc_call_private *)vp; + + if (rcp) { + if (rcp->client) + CLNT_DESTROY(rcp->client); + free(rcp); + } +} + +static void +rpc_call_key_init(void) +{ + + rpc_call_key_error = thr_keycreate(&rpc_call_key, rpc_call_destroy); +} + +/* + * This is the simplified interface to the client rpc layer. + * The client handle is not destroyed here and is reused for + * the future calls to same prog, vers, host and nettype combination. + * + * The total time available is 25 seconds. + */ +enum clnt_stat +rpc_call(host, prognum, versnum, procnum, inproc, in, outproc, out, nettype) + const char *host; /* host name */ + rpcprog_t prognum; /* program number */ + rpcvers_t versnum; /* version number */ + rpcproc_t procnum; /* procedure number */ + xdrproc_t inproc, outproc; /* in/out XDR procedures */ + const char *in; + char *out; /* recv/send data */ + const char *nettype; /* nettype */ +{ + struct rpc_call_private *rcp = (struct rpc_call_private *) 0; + enum clnt_stat clnt_stat; + struct timeval timeout, tottimeout; + int main_thread = 1; + + if ((main_thread = thr_main())) { + rcp = rpc_call_private_main; + } else { + if (thr_once(&rpc_call_once, rpc_call_key_init) != 0 || + rpc_call_key_error != 0) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = rpc_call_key_error; + return (rpc_createerr.cf_stat); + } + rcp = (struct rpc_call_private *)thr_getspecific(rpc_call_key); + } + if (rcp == NULL) { + rcp = malloc(sizeof (*rcp)); + if (rcp == NULL) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + return (rpc_createerr.cf_stat); + } + if (main_thread) + rpc_call_private_main = rcp; + else + thr_setspecific(rpc_call_key, (void *) rcp); + rcp->valid = 0; + rcp->client = NULL; + } + if ((nettype == NULL) || (nettype[0] == 0)) + nettype = "netpath"; + if (!(rcp->valid && rcp->pid == getpid() && + (rcp->prognum == prognum) && + (rcp->versnum == versnum) && + (!strcmp(rcp->host, host)) && + (!strcmp(rcp->nettype, nettype)))) { + int fd; + + rcp->valid = 0; + if (rcp->client) + CLNT_DESTROY(rcp->client); + /* + * Using the first successful transport for that type + */ + rcp->client = clnt_create(host, prognum, versnum, nettype); + rcp->pid = getpid(); + if (rcp->client == NULL) { + return (rpc_createerr.cf_stat); + } + /* + * Set time outs for connectionless case. Do it + * unconditionally. Faster than doing a t_getinfo() + * and then doing the right thing. + */ + timeout.tv_usec = 0; + timeout.tv_sec = 5; + (void) CLNT_CONTROL(rcp->client, + CLSET_RETRY_TIMEOUT, (char *)(void *)&timeout); + if (CLNT_CONTROL(rcp->client, CLGET_FD, (char *)(void *)&fd)) + _fcntl(fd, F_SETFD, 1); /* make it "close on exec" */ + rcp->prognum = prognum; + rcp->versnum = versnum; + if ((strlen(host) < (size_t)MAXHOSTNAMELEN) && + (strlen(nettype) < (size_t)NETIDLEN)) { + (void) strcpy(rcp->host, host); + (void) strcpy(rcp->nettype, nettype); + rcp->valid = 1; + } else { + rcp->valid = 0; + } + } /* else reuse old client */ + tottimeout.tv_sec = 25; + tottimeout.tv_usec = 0; + /*LINTED const castaway*/ + clnt_stat = CLNT_CALL(rcp->client, procnum, inproc, (char *) in, + outproc, out, tottimeout); + /* + * if call failed, empty cache + */ + if (clnt_stat != RPC_SUCCESS) + rcp->valid = 0; + return (clnt_stat); +} diff --git a/freebsd/lib/libc/rpc/clnt_vc.c b/freebsd/lib/libc/rpc/clnt_vc.c new file mode 100644 index 00000000..6c34cccc --- /dev/null +++ b/freebsd/lib/libc/rpc/clnt_vc.c @@ -0,0 +1,874 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: clnt_vc.c,v 1.4 2000/07/14 08:40:42 fvdl Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *sccsid2 = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro"; +static char *sccsid = "@(#)clnt_tcp.c 2.2 88/08/01 4.0 RPCSRC"; +static char sccsid3[] = "@(#)clnt_vc.c 1.19 89/03/16 Copyr 1988 Sun Micro"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * clnt_tcp.c, Implements a TCP/IP based, client side RPC. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * TCP based RPC supports 'batched calls'. + * A sequence of calls may be batched-up in a send buffer. The rpc call + * return immediately to the client even though the call was not necessarily + * sent. The batching occurs if the results' xdr routine is NULL (0) AND + * the rpc timeout value is zero (see clnt.h, rpc). + * + * Clients should NOT casually batch calls that in fact return results; that is, + * the server side should be aware that a call is batched and not produce any + * return message. Batched calls that produce many result messages can + * deadlock (netlock) the client and the server.... + * + * Now go hang yourself. + */ + +#include "namespace.h" +#include "reentrant.h" +#include <sys/types.h> +#include <sys/poll.h> +#include <sys/syslog.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/uio.h> + +#include <arpa/inet.h> +#include <assert.h> +#include <err.h> +#include <errno.h> +#include <netdb.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> + +#include <rpc/rpc.h> +#include <rpc/rpcsec_gss.h> +#include "un-namespace.h" +#include "rpc_com.h" +#include "mt_misc.h" + +#define MCALL_MSG_SIZE 24 + +struct cmessage { + struct cmsghdr cmsg; + struct cmsgcred cmcred; +}; + +static enum clnt_stat clnt_vc_call(CLIENT *, rpcproc_t, xdrproc_t, void *, + xdrproc_t, void *, struct timeval); +static void clnt_vc_geterr(CLIENT *, struct rpc_err *); +static bool_t clnt_vc_freeres(CLIENT *, xdrproc_t, void *); +static void clnt_vc_abort(CLIENT *); +static bool_t clnt_vc_control(CLIENT *, u_int, void *); +static void clnt_vc_destroy(CLIENT *); +static struct clnt_ops *clnt_vc_ops(void); +static bool_t time_not_ok(struct timeval *); +static int read_vc(void *, void *, int); +static int write_vc(void *, void *, int); +static int __msgwrite(int, void *, size_t); +static int __msgread(int, void *, size_t); + +struct ct_data { + int ct_fd; /* connection's fd */ + bool_t ct_closeit; /* close it on destroy */ + struct timeval ct_wait; /* wait interval in milliseconds */ + bool_t ct_waitset; /* wait set by clnt_control? */ + struct netbuf ct_addr; /* remote addr */ + struct rpc_err ct_error; + union { + char ct_mcallc[MCALL_MSG_SIZE]; /* marshalled callmsg */ + u_int32_t ct_mcalli; + } ct_u; + u_int ct_mpos; /* pos after marshal */ + XDR ct_xdrs; /* XDR stream */ +}; + +/* + * This machinery implements per-fd locks for MT-safety. It is not + * sufficient to do per-CLIENT handle locks for MT-safety because a + * user may create more than one CLIENT handle with the same fd behind + * it. Therfore, we allocate an array of flags (vc_fd_locks), protected + * by the clnt_fd_lock mutex, and an array (vc_cv) of condition variables + * similarly protected. Vc_fd_lock[fd] == 1 => a call is activte on some + * CLIENT handle created for that fd. + * The current implementation holds locks across the entire RPC and reply. + * Yes, this is silly, and as soon as this code is proven to work, this + * should be the first thing fixed. One step at a time. + */ +static int *vc_fd_locks; +static cond_t *vc_cv; +#define release_fd_lock(fd, mask) { \ + mutex_lock(&clnt_fd_lock); \ + vc_fd_locks[fd] = 0; \ + mutex_unlock(&clnt_fd_lock); \ + thr_sigsetmask(SIG_SETMASK, &(mask), (sigset_t *) NULL); \ + cond_signal(&vc_cv[fd]); \ +} + +static const char clnt_vc_errstr[] = "%s : %s"; +static const char clnt_vc_str[] = "clnt_vc_create"; +static const char clnt_read_vc_str[] = "read_vc"; +static const char __no_mem_str[] = "out of memory"; + +/* + * Create a client handle for a connection. + * Default options are set, which the user can change using clnt_control()'s. + * The rpc/vc package does buffering similar to stdio, so the client + * must pick send and receive buffer sizes, 0 => use the default. + * NB: fd is copied into a private area. + * NB: The rpch->cl_auth is set null authentication. Caller may wish to + * set this something more useful. + * + * fd should be an open socket + */ +CLIENT * +clnt_vc_create(fd, raddr, prog, vers, sendsz, recvsz) + int fd; /* open file descriptor */ + const struct netbuf *raddr; /* servers address */ + const rpcprog_t prog; /* program number */ + const rpcvers_t vers; /* version number */ + u_int sendsz; /* buffer recv size */ + u_int recvsz; /* buffer send size */ +{ + CLIENT *cl; /* client handle */ + struct ct_data *ct = NULL; /* client handle */ + struct timeval now; + struct rpc_msg call_msg; + static u_int32_t disrupt; + sigset_t mask; + sigset_t newmask; + struct sockaddr_storage ss; + socklen_t slen; + struct __rpc_sockinfo si; + + if (disrupt == 0) + disrupt = (u_int32_t)(long)raddr; + + cl = (CLIENT *)mem_alloc(sizeof (*cl)); + ct = (struct ct_data *)mem_alloc(sizeof (*ct)); + if ((cl == (CLIENT *)NULL) || (ct == (struct ct_data *)NULL)) { + (void) syslog(LOG_ERR, clnt_vc_errstr, + clnt_vc_str, __no_mem_str); + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + goto err; + } + ct->ct_addr.buf = NULL; + sigfillset(&newmask); + thr_sigsetmask(SIG_SETMASK, &newmask, &mask); + mutex_lock(&clnt_fd_lock); + if (vc_fd_locks == (int *) NULL) { + int cv_allocsz, fd_allocsz; + int dtbsize = __rpc_dtbsize(); + + fd_allocsz = dtbsize * sizeof (int); + vc_fd_locks = (int *) mem_alloc(fd_allocsz); + if (vc_fd_locks == (int *) NULL) { + mutex_unlock(&clnt_fd_lock); + thr_sigsetmask(SIG_SETMASK, &(mask), NULL); + goto err; + } else + memset(vc_fd_locks, '\0', fd_allocsz); + + assert(vc_cv == (cond_t *) NULL); + cv_allocsz = dtbsize * sizeof (cond_t); + vc_cv = (cond_t *) mem_alloc(cv_allocsz); + if (vc_cv == (cond_t *) NULL) { + mem_free(vc_fd_locks, fd_allocsz); + vc_fd_locks = (int *) NULL; + mutex_unlock(&clnt_fd_lock); + thr_sigsetmask(SIG_SETMASK, &(mask), NULL); + goto err; + } else { + int i; + + for (i = 0; i < dtbsize; i++) + cond_init(&vc_cv[i], 0, (void *) 0); + } + } else + assert(vc_cv != (cond_t *) NULL); + + /* + * XXX - fvdl connecting while holding a mutex? + */ + slen = sizeof ss; + if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { + if (errno != ENOTCONN) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + mutex_unlock(&clnt_fd_lock); + thr_sigsetmask(SIG_SETMASK, &(mask), NULL); + goto err; + } + if (_connect(fd, (struct sockaddr *)raddr->buf, raddr->len) < 0){ + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + mutex_unlock(&clnt_fd_lock); + thr_sigsetmask(SIG_SETMASK, &(mask), NULL); + goto err; + } + } + mutex_unlock(&clnt_fd_lock); + thr_sigsetmask(SIG_SETMASK, &(mask), NULL); + if (!__rpc_fd2sockinfo(fd, &si)) + goto err; + + ct->ct_closeit = FALSE; + + /* + * Set up private data struct + */ + ct->ct_fd = fd; + ct->ct_wait.tv_usec = 0; + ct->ct_waitset = FALSE; + ct->ct_addr.buf = malloc(raddr->maxlen); + if (ct->ct_addr.buf == NULL) + goto err; + memcpy(ct->ct_addr.buf, raddr->buf, raddr->len); + ct->ct_addr.len = raddr->maxlen; + ct->ct_addr.maxlen = raddr->maxlen; + + /* + * Initialize call message + */ + (void)gettimeofday(&now, NULL); + call_msg.rm_xid = ((u_int32_t)++disrupt) ^ __RPC_GETXID(&now); + call_msg.rm_direction = CALL; + call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; + call_msg.rm_call.cb_prog = (u_int32_t)prog; + call_msg.rm_call.cb_vers = (u_int32_t)vers; + + /* + * pre-serialize the static part of the call msg and stash it away + */ + xdrmem_create(&(ct->ct_xdrs), ct->ct_u.ct_mcallc, MCALL_MSG_SIZE, + XDR_ENCODE); + if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { + if (ct->ct_closeit) { + (void)_close(fd); + } + goto err; + } + ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs)); + XDR_DESTROY(&(ct->ct_xdrs)); + assert(ct->ct_mpos + sizeof(uint32_t) <= MCALL_MSG_SIZE); + + /* + * Create a client handle which uses xdrrec for serialization + * and authnone for authentication. + */ + cl->cl_ops = clnt_vc_ops(); + cl->cl_private = ct; + cl->cl_auth = authnone_create(); + sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); + recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); + xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, + cl->cl_private, read_vc, write_vc); + return (cl); + +err: + if (ct) { + if (ct->ct_addr.len) + mem_free(ct->ct_addr.buf, ct->ct_addr.len); + mem_free(ct, sizeof (struct ct_data)); + } + if (cl) + mem_free(cl, sizeof (CLIENT)); + return ((CLIENT *)NULL); +} + +static enum clnt_stat +clnt_vc_call(cl, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout) + CLIENT *cl; + rpcproc_t proc; + xdrproc_t xdr_args; + void *args_ptr; + xdrproc_t xdr_results; + void *results_ptr; + struct timeval timeout; +{ + struct ct_data *ct = (struct ct_data *) cl->cl_private; + XDR *xdrs = &(ct->ct_xdrs); + struct rpc_msg reply_msg; + u_int32_t x_id; + u_int32_t *msg_x_id = &ct->ct_u.ct_mcalli; /* yuk */ + bool_t shipnow; + int refreshes = 2; + sigset_t mask, newmask; + int rpc_lock_value; + bool_t reply_stat; + + assert(cl != NULL); + + sigfillset(&newmask); + thr_sigsetmask(SIG_SETMASK, &newmask, &mask); + mutex_lock(&clnt_fd_lock); + while (vc_fd_locks[ct->ct_fd]) + cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock); + if (__isthreaded) + rpc_lock_value = 1; + else + rpc_lock_value = 0; + vc_fd_locks[ct->ct_fd] = rpc_lock_value; + mutex_unlock(&clnt_fd_lock); + if (!ct->ct_waitset) { + /* If time is not within limits, we ignore it. */ + if (time_not_ok(&timeout) == FALSE) + ct->ct_wait = timeout; + } + + shipnow = + (xdr_results == NULL && timeout.tv_sec == 0 + && timeout.tv_usec == 0) ? FALSE : TRUE; + +call_again: + xdrs->x_op = XDR_ENCODE; + ct->ct_error.re_status = RPC_SUCCESS; + x_id = ntohl(--(*msg_x_id)); + + if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) { + if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcallc, ct->ct_mpos)) || + (! XDR_PUTINT32(xdrs, &proc)) || + (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || + (! (*xdr_args)(xdrs, args_ptr))) { + if (ct->ct_error.re_status == RPC_SUCCESS) + ct->ct_error.re_status = RPC_CANTENCODEARGS; + (void)xdrrec_endofrecord(xdrs, TRUE); + release_fd_lock(ct->ct_fd, mask); + return (ct->ct_error.re_status); + } + } else { + *(uint32_t *) &ct->ct_u.ct_mcallc[ct->ct_mpos] = htonl(proc); + if (! __rpc_gss_wrap(cl->cl_auth, ct->ct_u.ct_mcallc, + ct->ct_mpos + sizeof(uint32_t), + xdrs, xdr_args, args_ptr)) { + if (ct->ct_error.re_status == RPC_SUCCESS) + ct->ct_error.re_status = RPC_CANTENCODEARGS; + (void)xdrrec_endofrecord(xdrs, TRUE); + release_fd_lock(ct->ct_fd, mask); + return (ct->ct_error.re_status); + } + } + if (! xdrrec_endofrecord(xdrs, shipnow)) { + release_fd_lock(ct->ct_fd, mask); + return (ct->ct_error.re_status = RPC_CANTSEND); + } + if (! shipnow) { + release_fd_lock(ct->ct_fd, mask); + return (RPC_SUCCESS); + } + /* + * Hack to provide rpc-based message passing + */ + if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { + release_fd_lock(ct->ct_fd, mask); + return(ct->ct_error.re_status = RPC_TIMEDOUT); + } + + + /* + * Keep receiving until we get a valid transaction id + */ + xdrs->x_op = XDR_DECODE; + while (TRUE) { + reply_msg.acpted_rply.ar_verf = _null_auth; + reply_msg.acpted_rply.ar_results.where = NULL; + reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void; + if (! xdrrec_skiprecord(xdrs)) { + release_fd_lock(ct->ct_fd, mask); + return (ct->ct_error.re_status); + } + /* now decode and validate the response header */ + if (! xdr_replymsg(xdrs, &reply_msg)) { + if (ct->ct_error.re_status == RPC_SUCCESS) + continue; + release_fd_lock(ct->ct_fd, mask); + return (ct->ct_error.re_status); + } + if (reply_msg.rm_xid == x_id) + break; + } + + /* + * process header + */ + _seterr_reply(&reply_msg, &(ct->ct_error)); + if (ct->ct_error.re_status == RPC_SUCCESS) { + if (! AUTH_VALIDATE(cl->cl_auth, + &reply_msg.acpted_rply.ar_verf)) { + ct->ct_error.re_status = RPC_AUTHERROR; + ct->ct_error.re_why = AUTH_INVALIDRESP; + } else { + if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) { + reply_stat = (*xdr_results)(xdrs, results_ptr); + } else { + reply_stat = __rpc_gss_unwrap(cl->cl_auth, + xdrs, xdr_results, results_ptr); + } + if (! reply_stat) { + if (ct->ct_error.re_status == RPC_SUCCESS) + ct->ct_error.re_status = + RPC_CANTDECODERES; + } + } + /* free verifier ... */ + if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { + xdrs->x_op = XDR_FREE; + (void)xdr_opaque_auth(xdrs, + &(reply_msg.acpted_rply.ar_verf)); + } + } /* end successful completion */ + else { + /* maybe our credentials need to be refreshed ... */ + if (refreshes-- && AUTH_REFRESH(cl->cl_auth, &reply_msg)) + goto call_again; + } /* end of unsuccessful completion */ + release_fd_lock(ct->ct_fd, mask); + return (ct->ct_error.re_status); +} + +static void +clnt_vc_geterr(cl, errp) + CLIENT *cl; + struct rpc_err *errp; +{ + struct ct_data *ct; + + assert(cl != NULL); + assert(errp != NULL); + + ct = (struct ct_data *) cl->cl_private; + *errp = ct->ct_error; +} + +static bool_t +clnt_vc_freeres(cl, xdr_res, res_ptr) + CLIENT *cl; + xdrproc_t xdr_res; + void *res_ptr; +{ + struct ct_data *ct; + XDR *xdrs; + bool_t dummy; + sigset_t mask; + sigset_t newmask; + + assert(cl != NULL); + + ct = (struct ct_data *)cl->cl_private; + xdrs = &(ct->ct_xdrs); + + sigfillset(&newmask); + thr_sigsetmask(SIG_SETMASK, &newmask, &mask); + mutex_lock(&clnt_fd_lock); + while (vc_fd_locks[ct->ct_fd]) + cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock); + xdrs->x_op = XDR_FREE; + dummy = (*xdr_res)(xdrs, res_ptr); + mutex_unlock(&clnt_fd_lock); + thr_sigsetmask(SIG_SETMASK, &(mask), NULL); + cond_signal(&vc_cv[ct->ct_fd]); + + return dummy; +} + +/*ARGSUSED*/ +static void +clnt_vc_abort(cl) + CLIENT *cl; +{ +} + +static bool_t +clnt_vc_control(cl, request, info) + CLIENT *cl; + u_int request; + void *info; +{ + struct ct_data *ct; + void *infop = info; + sigset_t mask; + sigset_t newmask; + int rpc_lock_value; + + assert(cl != NULL); + + ct = (struct ct_data *)cl->cl_private; + + sigfillset(&newmask); + thr_sigsetmask(SIG_SETMASK, &newmask, &mask); + mutex_lock(&clnt_fd_lock); + while (vc_fd_locks[ct->ct_fd]) + cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock); + if (__isthreaded) + rpc_lock_value = 1; + else + rpc_lock_value = 0; + vc_fd_locks[ct->ct_fd] = rpc_lock_value; + mutex_unlock(&clnt_fd_lock); + + switch (request) { + case CLSET_FD_CLOSE: + ct->ct_closeit = TRUE; + release_fd_lock(ct->ct_fd, mask); + return (TRUE); + case CLSET_FD_NCLOSE: + ct->ct_closeit = FALSE; + release_fd_lock(ct->ct_fd, mask); + return (TRUE); + default: + break; + } + + /* for other requests which use info */ + if (info == NULL) { + release_fd_lock(ct->ct_fd, mask); + return (FALSE); + } + switch (request) { + case CLSET_TIMEOUT: + if (time_not_ok((struct timeval *)info)) { + release_fd_lock(ct->ct_fd, mask); + return (FALSE); + } + ct->ct_wait = *(struct timeval *)infop; + ct->ct_waitset = TRUE; + break; + case CLGET_TIMEOUT: + *(struct timeval *)infop = ct->ct_wait; + break; + case CLGET_SERVER_ADDR: + (void) memcpy(info, ct->ct_addr.buf, (size_t)ct->ct_addr.len); + break; + case CLGET_FD: + *(int *)info = ct->ct_fd; + break; + case CLGET_SVC_ADDR: + /* The caller should not free this memory area */ + *(struct netbuf *)info = ct->ct_addr; + break; + case CLSET_SVC_ADDR: /* set to new address */ + release_fd_lock(ct->ct_fd, mask); + return (FALSE); + case CLGET_XID: + /* + * use the knowledge that xid is the + * first element in the call structure + * This will get the xid of the PREVIOUS call + */ + *(u_int32_t *)info = + ntohl(*(u_int32_t *)(void *)&ct->ct_u.ct_mcalli); + break; + case CLSET_XID: + /* This will set the xid of the NEXT call */ + *(u_int32_t *)(void *)&ct->ct_u.ct_mcalli = + htonl(*((u_int32_t *)info) + 1); + /* increment by 1 as clnt_vc_call() decrements once */ + break; + case CLGET_VERS: + /* + * This RELIES on the information that, in the call body, + * the version number field is the fifth field from the + * begining of the RPC header. MUST be changed if the + * call_struct is changed + */ + *(u_int32_t *)info = + ntohl(*(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + + 4 * BYTES_PER_XDR_UNIT)); + break; + + case CLSET_VERS: + *(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + + 4 * BYTES_PER_XDR_UNIT) = + htonl(*(u_int32_t *)info); + break; + + case CLGET_PROG: + /* + * This RELIES on the information that, in the call body, + * the program number field is the fourth field from the + * begining of the RPC header. MUST be changed if the + * call_struct is changed + */ + *(u_int32_t *)info = + ntohl(*(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + + 3 * BYTES_PER_XDR_UNIT)); + break; + + case CLSET_PROG: + *(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + + 3 * BYTES_PER_XDR_UNIT) = + htonl(*(u_int32_t *)info); + break; + + default: + release_fd_lock(ct->ct_fd, mask); + return (FALSE); + } + release_fd_lock(ct->ct_fd, mask); + return (TRUE); +} + + +static void +clnt_vc_destroy(cl) + CLIENT *cl; +{ + struct ct_data *ct = (struct ct_data *) cl->cl_private; + int ct_fd = ct->ct_fd; + sigset_t mask; + sigset_t newmask; + + assert(cl != NULL); + + ct = (struct ct_data *) cl->cl_private; + + sigfillset(&newmask); + thr_sigsetmask(SIG_SETMASK, &newmask, &mask); + mutex_lock(&clnt_fd_lock); + while (vc_fd_locks[ct_fd]) + cond_wait(&vc_cv[ct_fd], &clnt_fd_lock); + if (ct->ct_closeit && ct->ct_fd != -1) { + (void)_close(ct->ct_fd); + } + XDR_DESTROY(&(ct->ct_xdrs)); + if (ct->ct_addr.buf) + free(ct->ct_addr.buf); + mem_free(ct, sizeof(struct ct_data)); + if (cl->cl_netid && cl->cl_netid[0]) + mem_free(cl->cl_netid, strlen(cl->cl_netid) +1); + if (cl->cl_tp && cl->cl_tp[0]) + mem_free(cl->cl_tp, strlen(cl->cl_tp) +1); + mem_free(cl, sizeof(CLIENT)); + mutex_unlock(&clnt_fd_lock); + thr_sigsetmask(SIG_SETMASK, &(mask), NULL); + cond_signal(&vc_cv[ct_fd]); +} + +/* + * Interface between xdr serializer and tcp connection. + * Behaves like the system calls, read & write, but keeps some error state + * around for the rpc level. + */ +static int +read_vc(ctp, buf, len) + void *ctp; + void *buf; + int len; +{ + struct sockaddr sa; + socklen_t sal; + struct ct_data *ct = (struct ct_data *)ctp; + struct pollfd fd; + int milliseconds = (int)((ct->ct_wait.tv_sec * 1000) + + (ct->ct_wait.tv_usec / 1000)); + + if (len == 0) + return (0); + fd.fd = ct->ct_fd; + fd.events = POLLIN; + for (;;) { + switch (_poll(&fd, 1, milliseconds)) { + case 0: + ct->ct_error.re_status = RPC_TIMEDOUT; + return (-1); + + case -1: + if (errno == EINTR) + continue; + ct->ct_error.re_status = RPC_CANTRECV; + ct->ct_error.re_errno = errno; + return (-1); + } + break; + } + + sal = sizeof(sa); + if ((_getpeername(ct->ct_fd, &sa, &sal) == 0) && + (sa.sa_family == AF_LOCAL)) { + len = __msgread(ct->ct_fd, buf, (size_t)len); + } else { + len = _read(ct->ct_fd, buf, (size_t)len); + } + + switch (len) { + case 0: + /* premature eof */ + ct->ct_error.re_errno = ECONNRESET; + ct->ct_error.re_status = RPC_CANTRECV; + len = -1; /* it's really an error */ + break; + + case -1: + ct->ct_error.re_errno = errno; + ct->ct_error.re_status = RPC_CANTRECV; + break; + } + return (len); +} + +static int +write_vc(ctp, buf, len) + void *ctp; + void *buf; + int len; +{ + struct sockaddr sa; + socklen_t sal; + struct ct_data *ct = (struct ct_data *)ctp; + int i, cnt; + + sal = sizeof(sa); + if ((_getpeername(ct->ct_fd, &sa, &sal) == 0) && + (sa.sa_family == AF_LOCAL)) { + for (cnt = len; cnt > 0; cnt -= i, buf = (char *)buf + i) { + if ((i = __msgwrite(ct->ct_fd, buf, + (size_t)cnt)) == -1) { + ct->ct_error.re_errno = errno; + ct->ct_error.re_status = RPC_CANTSEND; + return (-1); + } + } + } else { + for (cnt = len; cnt > 0; cnt -= i, buf = (char *)buf + i) { + if ((i = _write(ct->ct_fd, buf, (size_t)cnt)) == -1) { + ct->ct_error.re_errno = errno; + ct->ct_error.re_status = RPC_CANTSEND; + return (-1); + } + } + } + return (len); +} + +static struct clnt_ops * +clnt_vc_ops() +{ + static struct clnt_ops ops; + sigset_t mask, newmask; + + /* VARIABLES PROTECTED BY ops_lock: ops */ + + sigfillset(&newmask); + thr_sigsetmask(SIG_SETMASK, &newmask, &mask); + mutex_lock(&ops_lock); + if (ops.cl_call == NULL) { + ops.cl_call = clnt_vc_call; + ops.cl_abort = clnt_vc_abort; + ops.cl_geterr = clnt_vc_geterr; + ops.cl_freeres = clnt_vc_freeres; + ops.cl_destroy = clnt_vc_destroy; + ops.cl_control = clnt_vc_control; + } + mutex_unlock(&ops_lock); + thr_sigsetmask(SIG_SETMASK, &(mask), NULL); + return (&ops); +} + +/* + * Make sure that the time is not garbage. -1 value is disallowed. + * Note this is different from time_not_ok in clnt_dg.c + */ +static bool_t +time_not_ok(t) + struct timeval *t; +{ + return (t->tv_sec <= -1 || t->tv_sec > 100000000 || + t->tv_usec <= -1 || t->tv_usec > 1000000); +} + +static int +__msgread(sock, buf, cnt) + int sock; + void *buf; + size_t cnt; +{ + struct iovec iov[1]; + struct msghdr msg; + union { + struct cmsghdr cmsg; + char control[CMSG_SPACE(sizeof(struct cmsgcred))]; + } cm; + + bzero((char *)&cm, sizeof(cm)); + iov[0].iov_base = buf; + iov[0].iov_len = cnt; + + msg.msg_iov = iov; + msg.msg_iovlen = 1; + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_control = (caddr_t)&cm; + msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred)); + msg.msg_flags = 0; + + return(_recvmsg(sock, &msg, 0)); +} + +static int +__msgwrite(sock, buf, cnt) + int sock; + void *buf; + size_t cnt; +{ + struct iovec iov[1]; + struct msghdr msg; + union { + struct cmsghdr cmsg; + char control[CMSG_SPACE(sizeof(struct cmsgcred))]; + } cm; + + bzero((char *)&cm, sizeof(cm)); + iov[0].iov_base = buf; + iov[0].iov_len = cnt; + + cm.cmsg.cmsg_type = SCM_CREDS; + cm.cmsg.cmsg_level = SOL_SOCKET; + cm.cmsg.cmsg_len = CMSG_LEN(sizeof(struct cmsgcred)); + + msg.msg_iov = iov; + msg.msg_iovlen = 1; + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_control = (caddr_t)&cm; + msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred)); + msg.msg_flags = 0; + + return(_sendmsg(sock, &msg, 0)); +} diff --git a/freebsd/lib/libc/rpc/crypt_client.c b/freebsd/lib/libc/rpc/crypt_client.c new file mode 100644 index 00000000..9ce94157 --- /dev/null +++ b/freebsd/lib/libc/rpc/crypt_client.c @@ -0,0 +1,103 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * Copyright (c) 1996 + * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "namespace.h" +#include <err.h> +#include <sys/types.h> +#include <rpc/des_crypt.h> +#include <rpc/des.h> +#include <string.h> +#include <rpcsvc/crypt.h> +#include "un-namespace.h" + +int +_des_crypt_call(buf, len, dparms) + char *buf; + int len; + struct desparams *dparms; +{ + CLIENT *clnt; + desresp *result_1; + desargs des_crypt_1_arg; + struct netconfig *nconf; + void *localhandle; + int stat; + + nconf = NULL; + localhandle = setnetconfig(); + while ((nconf = getnetconfig(localhandle)) != NULL) { + if (nconf->nc_protofmly != NULL && + strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) + break; + } + if (nconf == NULL) { + warnx("getnetconfig: %s", nc_sperror()); + return(DESERR_HWERROR); + } + clnt = clnt_tp_create(NULL, CRYPT_PROG, CRYPT_VERS, nconf); + if (clnt == (CLIENT *) NULL) { + endnetconfig(localhandle); + return(DESERR_HWERROR); + } + endnetconfig(localhandle); + + des_crypt_1_arg.desbuf.desbuf_len = len; + des_crypt_1_arg.desbuf.desbuf_val = buf; + des_crypt_1_arg.des_dir = (dparms->des_dir == ENCRYPT) ? ENCRYPT_DES : DECRYPT_DES; + des_crypt_1_arg.des_mode = (dparms->des_mode == CBC) ? CBC_DES : ECB_DES; + bcopy(dparms->des_ivec, des_crypt_1_arg.des_ivec, 8); + bcopy(dparms->des_key, des_crypt_1_arg.des_key, 8); + + result_1 = des_crypt_1(&des_crypt_1_arg, clnt); + if (result_1 == (desresp *) NULL) { + clnt_destroy(clnt); + return(DESERR_HWERROR); + } + + stat = result_1->stat; + + if (result_1->stat == DESERR_NONE || + result_1->stat == DESERR_NOHWDEVICE) { + bcopy(result_1->desbuf.desbuf_val, buf, len); + bcopy(result_1->des_ivec, dparms->des_ivec, 8); + } + + clnt_freeres(clnt, (xdrproc_t)xdr_desresp, result_1); + clnt_destroy(clnt); + + return(stat); +} diff --git a/freebsd/lib/libc/rpc/des_crypt.c b/freebsd/lib/libc/rpc/des_crypt.c new file mode 100644 index 00000000..b5f14f82 --- /dev/null +++ b/freebsd/lib/libc/rpc/des_crypt.c @@ -0,0 +1,155 @@ +#include <machine/rtems-bsd-user-space.h> + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * des_crypt.c, DES encryption library routines + * Copyright (C) 1986, Sun Microsystems, Inc. + */ + +#include <sys/types.h> +#include <rpc/des_crypt.h> +#include <rpc/des.h> + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)des_crypt.c 2.2 88/08/10 4.0 RPCSRC; from 1.13 88/02/08 SMI"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +static int common_crypt( char *, char *, unsigned, unsigned, struct desparams * ); +int (*__des_crypt_LOCAL)() = 0; +extern int _des_crypt_call(char *, int, struct desparams *); +/* + * Copy 8 bytes + */ +#define COPY8(src, dst) { \ + char *a = (char *) dst; \ + char *b = (char *) src; \ + *a++ = *b++; *a++ = *b++; *a++ = *b++; *a++ = *b++; \ + *a++ = *b++; *a++ = *b++; *a++ = *b++; *a++ = *b++; \ +} + +/* + * Copy multiple of 8 bytes + */ +#define DESCOPY(src, dst, len) { \ + char *a = (char *) dst; \ + char *b = (char *) src; \ + int i; \ + for (i = (int) len; i > 0; i -= 8) { \ + *a++ = *b++; *a++ = *b++; *a++ = *b++; *a++ = *b++; \ + *a++ = *b++; *a++ = *b++; *a++ = *b++; *a++ = *b++; \ + } \ +} + +/* + * CBC mode encryption + */ +int +cbc_crypt(key, buf, len, mode, ivec) + char *key; + char *buf; + unsigned len; + unsigned mode; + char *ivec; +{ + int err; + struct desparams dp; + +#ifdef BROKEN_DES + dp.UDES.UDES_buf = buf; + dp.des_mode = ECB; +#else + dp.des_mode = CBC; +#endif + COPY8(ivec, dp.des_ivec); + err = common_crypt(key, buf, len, mode, &dp); + COPY8(dp.des_ivec, ivec); + return(err); +} + + +/* + * ECB mode encryption + */ +int +ecb_crypt(key, buf, len, mode) + char *key; + char *buf; + unsigned len; + unsigned mode; +{ + struct desparams dp; + +#ifdef BROKEN_DES + dp.UDES.UDES_buf = buf; + dp.des_mode = CBC; +#else + dp.des_mode = ECB; +#endif + return(common_crypt(key, buf, len, mode, &dp)); +} + + + +/* + * Common code to cbc_crypt() & ecb_crypt() + */ +static int +common_crypt(key, buf, len, mode, desp) + char *key; + char *buf; + unsigned len; + unsigned mode; + struct desparams *desp; +{ + int desdev; + + if ((len % 8) != 0 || len > DES_MAXDATA) { + return(DESERR_BADPARAM); + } + desp->des_dir = + ((mode & DES_DIRMASK) == DES_ENCRYPT) ? ENCRYPT : DECRYPT; + + desdev = mode & DES_DEVMASK; + COPY8(key, desp->des_key); + /* + * software + */ + if (__des_crypt_LOCAL != NULL) { + if (!__des_crypt_LOCAL(buf, len, desp)) { + return (DESERR_HWERROR); + } + } else { + if (!_des_crypt_call(buf, len, desp)) { + return (DESERR_HWERROR); + } + } + return(desdev == DES_SW ? DESERR_NONE : DESERR_NOHWDEVICE); +} diff --git a/freebsd/lib/libc/rpc/des_soft.c b/freebsd/lib/libc/rpc/des_soft.c new file mode 100644 index 00000000..e67f90d8 --- /dev/null +++ b/freebsd/lib/libc/rpc/des_soft.c @@ -0,0 +1,72 @@ +#include <machine/rtems-bsd-user-space.h> + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)des_soft.c 2.2 88/08/10 4.0 RPCSRC; from 1.13 88/02/08 SMI"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Table giving odd parity in the low bit for ASCII characters + */ +static char partab[128] = { + 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x07, 0x07, + 0x08, 0x08, 0x0b, 0x0b, 0x0d, 0x0d, 0x0e, 0x0e, + 0x10, 0x10, 0x13, 0x13, 0x15, 0x15, 0x16, 0x16, + 0x19, 0x19, 0x1a, 0x1a, 0x1c, 0x1c, 0x1f, 0x1f, + 0x20, 0x20, 0x23, 0x23, 0x25, 0x25, 0x26, 0x26, + 0x29, 0x29, 0x2a, 0x2a, 0x2c, 0x2c, 0x2f, 0x2f, + 0x31, 0x31, 0x32, 0x32, 0x34, 0x34, 0x37, 0x37, + 0x38, 0x38, 0x3b, 0x3b, 0x3d, 0x3d, 0x3e, 0x3e, + 0x40, 0x40, 0x43, 0x43, 0x45, 0x45, 0x46, 0x46, + 0x49, 0x49, 0x4a, 0x4a, 0x4c, 0x4c, 0x4f, 0x4f, + 0x51, 0x51, 0x52, 0x52, 0x54, 0x54, 0x57, 0x57, + 0x58, 0x58, 0x5b, 0x5b, 0x5d, 0x5d, 0x5e, 0x5e, + 0x61, 0x61, 0x62, 0x62, 0x64, 0x64, 0x67, 0x67, + 0x68, 0x68, 0x6b, 0x6b, 0x6d, 0x6d, 0x6e, 0x6e, + 0x70, 0x70, 0x73, 0x73, 0x75, 0x75, 0x76, 0x76, + 0x79, 0x79, 0x7a, 0x7a, 0x7c, 0x7c, 0x7f, 0x7f, +}; + +/* + * Add odd parity to low bit of 8 byte key + */ +void +des_setparity(p) + char *p; +{ + int i; + + for (i = 0; i < 8; i++) { + *p = partab[*p & 0x7f]; + p++; + } +} diff --git a/freebsd/lib/libc/rpc/getnetconfig.c b/freebsd/lib/libc/rpc/getnetconfig.c new file mode 100644 index 00000000..f6279e04 --- /dev/null +++ b/freebsd/lib/libc/rpc/getnetconfig.c @@ -0,0 +1,742 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: getnetconfig.c,v 1.3 2000/07/06 03:10:34 christos Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getnetconfig.c 1.12 91/12/19 SMI"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Copyright (c) 1989 by Sun Microsystems, Inc. + */ + +#include "namespace.h" +#include "reentrant.h" +#include <stdio.h> +#include <errno.h> +#include <netconfig.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <rpc/rpc.h> +#include <unistd.h> +#include "un-namespace.h" +#include "rpc_com.h" + +/* + * The five library routines in this file provide application access to the + * system network configuration database, /etc/netconfig. In addition to the + * netconfig database and the routines for accessing it, the environment + * variable NETPATH and its corresponding routines in getnetpath.c may also be + * used to specify the network transport to be used. + */ + + +/* + * netconfig errors + */ + +#define NC_NONETCONFIG ENOENT +#define NC_NOMEM ENOMEM +#define NC_NOTINIT EINVAL /* setnetconfig was not called first */ +#define NC_BADFILE EBADF /* format for netconfig file is bad */ +#define NC_NOTFOUND ENOPROTOOPT /* specified netid was not found */ + +/* + * semantics as strings (should be in netconfig.h) + */ +#define NC_TPI_CLTS_S "tpi_clts" +#define NC_TPI_COTS_S "tpi_cots" +#define NC_TPI_COTS_ORD_S "tpi_cots_ord" +#define NC_TPI_RAW_S "tpi_raw" + +/* + * flags as characters (also should be in netconfig.h) + */ +#define NC_NOFLAG_C '-' +#define NC_VISIBLE_C 'v' +#define NC_BROADCAST_C 'b' + +/* + * Character used to indicate there is no name-to-address lookup library + */ +#define NC_NOLOOKUP "-" + +static const char * const _nc_errors[] = { + "Netconfig database not found", + "Not enough memory", + "Not initialized", + "Netconfig database has invalid format", + "Netid not found in netconfig database" +}; + +struct netconfig_info { + int eof; /* all entries has been read */ + int ref; /* # of times setnetconfig() has been called */ + struct netconfig_list *head; /* head of the list */ + struct netconfig_list *tail; /* last of the list */ +}; + +struct netconfig_list { + char *linep; /* hold line read from netconfig */ + struct netconfig *ncp; + struct netconfig_list *next; +}; + +struct netconfig_vars { + int valid; /* token that indicates a valid netconfig_vars */ + int flag; /* first time flag */ + struct netconfig_list *nc_configs; /* pointer to the current netconfig entry */ +}; + +#define NC_VALID 0xfeed +#define NC_STORAGE 0xf00d +#define NC_INVALID 0 + + +static int *__nc_error(void); +static int parse_ncp(char *, struct netconfig *); +static struct netconfig *dup_ncp(struct netconfig *); + + +static FILE *nc_file; /* for netconfig db */ +static mutex_t nc_file_lock = MUTEX_INITIALIZER; + +static struct netconfig_info ni = { 0, 0, NULL, NULL}; +static mutex_t ni_lock = MUTEX_INITIALIZER; + +static thread_key_t nc_key; +static once_t nc_once = ONCE_INITIALIZER; +static int nc_key_error; + +static void +nc_key_init(void) +{ + + nc_key_error = thr_keycreate(&nc_key, free); +} + +#define MAXNETCONFIGLINE 1000 + +static int * +__nc_error() +{ + static int nc_error = 0; + int *nc_addr; + + /* + * Use the static `nc_error' if we are the main thread + * (including non-threaded programs), or if an allocation + * fails. + */ + if (thr_main()) + return (&nc_error); + if (thr_once(&nc_once, nc_key_init) != 0 || nc_key_error != 0) + return (&nc_error); + if ((nc_addr = (int *)thr_getspecific(nc_key)) == NULL) { + nc_addr = (int *)malloc(sizeof (int)); + if (thr_setspecific(nc_key, (void *) nc_addr) != 0) { + if (nc_addr) + free(nc_addr); + return (&nc_error); + } + *nc_addr = 0; + } + return (nc_addr); +} + +#define nc_error (*(__nc_error())) +/* + * A call to setnetconfig() establishes a /etc/netconfig "session". A session + * "handle" is returned on a successful call. At the start of a session (after + * a call to setnetconfig()) searches through the /etc/netconfig database will + * proceed from the start of the file. The session handle must be passed to + * getnetconfig() to parse the file. Each call to getnetconfig() using the + * current handle will process one subsequent entry in /etc/netconfig. + * setnetconfig() must be called before the first call to getnetconfig(). + * (Handles are used to allow for nested calls to setnetpath()). + * + * A new session is established with each call to setnetconfig(), with a new + * handle being returned on each call. Previously established sessions remain + * active until endnetconfig() is called with that session's handle as an + * argument. + * + * setnetconfig() need *not* be called before a call to getnetconfigent(). + * setnetconfig() returns a NULL pointer on failure (for example, if + * the netconfig database is not present). + */ +void * +setnetconfig() +{ + struct netconfig_vars *nc_vars; + + if ((nc_vars = (struct netconfig_vars *)malloc(sizeof + (struct netconfig_vars))) == NULL) { + return(NULL); + } + + /* + * For multiple calls, i.e. nc_file is not NULL, we just return the + * handle without reopening the netconfig db. + */ + mutex_lock(&ni_lock); + ni.ref++; + mutex_unlock(&ni_lock); + + mutex_lock(&nc_file_lock); + if ((nc_file != NULL) || (nc_file = fopen(NETCONFIG, "r")) != NULL) { + nc_vars->valid = NC_VALID; + nc_vars->flag = 0; + nc_vars->nc_configs = ni.head; + mutex_unlock(&nc_file_lock); + return ((void *)nc_vars); + } + mutex_unlock(&nc_file_lock); + + mutex_lock(&ni_lock); + ni.ref--; + mutex_unlock(&ni_lock); + + nc_error = NC_NONETCONFIG; + free(nc_vars); + return (NULL); +} + + +/* + * When first called, getnetconfig() returns a pointer to the first entry in + * the netconfig database, formatted as a struct netconfig. On each subsequent + * call, getnetconfig() returns a pointer to the next entry in the database. + * getnetconfig() can thus be used to search the entire netconfig file. + * getnetconfig() returns NULL at end of file. + */ + +struct netconfig * +getnetconfig(handlep) +void *handlep; +{ + struct netconfig_vars *ncp = (struct netconfig_vars *)handlep; + char *stringp; /* tmp string pointer */ + struct netconfig_list *list; + struct netconfig *np; + struct netconfig *result; + + /* + * Verify that handle is valid + */ + mutex_lock(&nc_file_lock); + if (ncp == NULL || nc_file == NULL) { + nc_error = NC_NOTINIT; + mutex_unlock(&nc_file_lock); + return (NULL); + } + mutex_unlock(&nc_file_lock); + + switch (ncp->valid) { + case NC_VALID: + /* + * If entry has already been read into the list, + * we return the entry in the linked list. + * If this is the first time call, check if there are any entries in + * linked list. If no entries, we need to read the netconfig db. + * If we have been here and the next entry is there, we just return + * it. + */ + if (ncp->flag == 0) { /* first time */ + ncp->flag = 1; + mutex_lock(&ni_lock); + ncp->nc_configs = ni.head; + mutex_unlock(&ni_lock); + if (ncp->nc_configs != NULL) /* entry already exist */ + return(ncp->nc_configs->ncp); + } + else if (ncp->nc_configs != NULL && ncp->nc_configs->next != NULL) { + ncp->nc_configs = ncp->nc_configs->next; + return(ncp->nc_configs->ncp); + } + + /* + * If we cannot find the entry in the list and is end of file, + * we give up. + */ + mutex_lock(&ni_lock); + if (ni.eof == 1) { + mutex_unlock(&ni_lock); + return(NULL); + } + mutex_unlock(&ni_lock); + + break; + default: + nc_error = NC_NOTINIT; + return (NULL); + } + + stringp = (char *) malloc(MAXNETCONFIGLINE); + if (stringp == NULL) + return (NULL); + +#ifdef MEM_CHK + if (malloc_verify() == 0) { + fprintf(stderr, "memory heap corrupted in getnetconfig\n"); + exit(1); + } +#endif + + /* + * Read a line from netconfig file. + */ + mutex_lock(&nc_file_lock); + do { + if (fgets(stringp, MAXNETCONFIGLINE, nc_file) == NULL) { + free(stringp); + mutex_lock(&ni_lock); + ni.eof = 1; + mutex_unlock(&ni_lock); + mutex_unlock(&nc_file_lock); + return (NULL); + } + } while (*stringp == '#'); + mutex_unlock(&nc_file_lock); + + list = (struct netconfig_list *) malloc(sizeof (struct netconfig_list)); + if (list == NULL) { + free(stringp); + return(NULL); + } + np = (struct netconfig *) malloc(sizeof (struct netconfig)); + if (np == NULL) { + free(stringp); + free(list); + return(NULL); + } + list->ncp = np; + list->next = NULL; + list->ncp->nc_lookups = NULL; + list->linep = stringp; + if (parse_ncp(stringp, list->ncp) == -1) { + free(stringp); + free(np); + free(list); + return (NULL); + } + else { + /* + * If this is the first entry that's been read, it is the head of + * the list. If not, put the entry at the end of the list. + * Reposition the current pointer of the handle to the last entry + * in the list. + */ + mutex_lock(&ni_lock); + if (ni.head == NULL) { /* first entry */ + ni.head = ni.tail = list; + } + else { + ni.tail->next = list; + ni.tail = ni.tail->next; + } + ncp->nc_configs = ni.tail; + result = ni.tail->ncp; + mutex_unlock(&ni_lock); + return(result); + } +} + +/* + * endnetconfig() may be called to "unbind" or "close" the netconfig database + * when processing is complete, releasing resources for reuse. endnetconfig() + * may not be called before setnetconfig(). endnetconfig() returns 0 on + * success and -1 on failure (for example, if setnetconfig() was not called + * previously). + */ +int +endnetconfig(handlep) +void *handlep; +{ + struct netconfig_vars *nc_handlep = (struct netconfig_vars *)handlep; + + struct netconfig_list *q, *p; + + /* + * Verify that handle is valid + */ + if (nc_handlep == NULL || (nc_handlep->valid != NC_VALID && + nc_handlep->valid != NC_STORAGE)) { + nc_error = NC_NOTINIT; + return (-1); + } + + /* + * Return 0 if anyone still needs it. + */ + nc_handlep->valid = NC_INVALID; + nc_handlep->flag = 0; + nc_handlep->nc_configs = NULL; + mutex_lock(&ni_lock); + if (--ni.ref > 0) { + mutex_unlock(&ni_lock); + free(nc_handlep); + return(0); + } + + /* + * Noone needs these entries anymore, then frees them. + * Make sure all info in netconfig_info structure has been reinitialized. + */ + q = ni.head; + ni.eof = ni.ref = 0; + ni.head = NULL; + ni.tail = NULL; + mutex_unlock(&ni_lock); + + while (q != NULL) { + p = q->next; + if (q->ncp->nc_lookups != NULL) free(q->ncp->nc_lookups); + free(q->ncp); + free(q->linep); + free(q); + q = p; + } + free(nc_handlep); + + mutex_lock(&nc_file_lock); + fclose(nc_file); + nc_file = NULL; + mutex_unlock(&nc_file_lock); + + return (0); +} + +/* + * getnetconfigent(netid) returns a pointer to the struct netconfig structure + * corresponding to netid. It returns NULL if netid is invalid (that is, does + * not name an entry in the netconfig database). It returns NULL and sets + * errno in case of failure (for example, if the netconfig database cannot be + * opened). + */ + +struct netconfig * +getnetconfigent(netid) + const char *netid; +{ + FILE *file; /* NETCONFIG db's file pointer */ + char *linep; /* holds current netconfig line */ + char *stringp; /* temporary string pointer */ + struct netconfig *ncp = NULL; /* returned value */ + struct netconfig_list *list; /* pointer to cache list */ + + nc_error = NC_NOTFOUND; /* default error. */ + if (netid == NULL || strlen(netid) == 0) { + return (NULL); + } + + /* + * Look up table if the entries have already been read and parsed in + * getnetconfig(), then copy this entry into a buffer and return it. + * If we cannot find the entry in the current list and there are more + * entries in the netconfig db that has not been read, we then read the + * db and try find the match netid. + * If all the netconfig db has been read and placed into the list and + * there is no match for the netid, return NULL. + */ + mutex_lock(&ni_lock); + if (ni.head != NULL) { + for (list = ni.head; list; list = list->next) { + if (strcmp(list->ncp->nc_netid, netid) == 0) { + mutex_unlock(&ni_lock); + return(dup_ncp(list->ncp)); + } + } + if (ni.eof == 1) { /* that's all the entries */ + mutex_unlock(&ni_lock); + return(NULL); + } + } + mutex_unlock(&ni_lock); + + + if ((file = fopen(NETCONFIG, "r")) == NULL) { + nc_error = NC_NONETCONFIG; + return (NULL); + } + + if ((linep = malloc(MAXNETCONFIGLINE)) == NULL) { + fclose(file); + nc_error = NC_NOMEM; + return (NULL); + } + do { + ptrdiff_t len; + char *tmpp; /* tmp string pointer */ + + do { + if ((stringp = fgets(linep, MAXNETCONFIGLINE, file)) == NULL) { + break; + } + } while (*stringp == '#'); + if (stringp == NULL) { /* eof */ + break; + } + if ((tmpp = strpbrk(stringp, "\t ")) == NULL) { /* can't parse file */ + nc_error = NC_BADFILE; + break; + } + if (strlen(netid) == (size_t) (len = tmpp - stringp) && /* a match */ + strncmp(stringp, netid, (size_t)len) == 0) { + if ((ncp = (struct netconfig *) + malloc(sizeof (struct netconfig))) == NULL) { + break; + } + ncp->nc_lookups = NULL; + if (parse_ncp(linep, ncp) == -1) { + free(ncp); + ncp = NULL; + } + break; + } + } while (stringp != NULL); + if (ncp == NULL) { + free(linep); + } + fclose(file); + return(ncp); +} + +/* + * freenetconfigent(netconfigp) frees the netconfig structure pointed to by + * netconfigp (previously returned by getnetconfigent()). + */ + +void +freenetconfigent(netconfigp) + struct netconfig *netconfigp; +{ + if (netconfigp != NULL) { + free(netconfigp->nc_netid); /* holds all netconfigp's strings */ + if (netconfigp->nc_lookups != NULL) + free(netconfigp->nc_lookups); + free(netconfigp); + } + return; +} + +/* + * Parse line and stuff it in a struct netconfig + * Typical line might look like: + * udp tpi_cots vb inet udp /dev/udp /usr/lib/ip.so,/usr/local/ip.so + * + * We return -1 if any of the tokens don't parse, or malloc fails. + * + * Note that we modify stringp (putting NULLs after tokens) and + * we set the ncp's string field pointers to point to these tokens within + * stringp. + */ + +static int +parse_ncp(stringp, ncp) +char *stringp; /* string to parse */ +struct netconfig *ncp; /* where to put results */ +{ + char *tokenp; /* for processing tokens */ + char *lasts; + char **nc_lookups; + + nc_error = NC_BADFILE; /* nearly anything that breaks is for this reason */ + stringp[strlen(stringp)-1] = '\0'; /* get rid of newline */ + /* netid */ + if ((ncp->nc_netid = strtok_r(stringp, "\t ", &lasts)) == NULL) { + return (-1); + } + + /* semantics */ + if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL) { + return (-1); + } + if (strcmp(tokenp, NC_TPI_COTS_ORD_S) == 0) + ncp->nc_semantics = NC_TPI_COTS_ORD; + else if (strcmp(tokenp, NC_TPI_COTS_S) == 0) + ncp->nc_semantics = NC_TPI_COTS; + else if (strcmp(tokenp, NC_TPI_CLTS_S) == 0) + ncp->nc_semantics = NC_TPI_CLTS; + else if (strcmp(tokenp, NC_TPI_RAW_S) == 0) + ncp->nc_semantics = NC_TPI_RAW; + else + return (-1); + + /* flags */ + if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL) { + return (-1); + } + for (ncp->nc_flag = NC_NOFLAG; *tokenp != '\0'; + tokenp++) { + switch (*tokenp) { + case NC_NOFLAG_C: + break; + case NC_VISIBLE_C: + ncp->nc_flag |= NC_VISIBLE; + break; + case NC_BROADCAST_C: + ncp->nc_flag |= NC_BROADCAST; + break; + default: + return (-1); + } + } + /* protocol family */ + if ((ncp->nc_protofmly = strtok_r(NULL, "\t ", &lasts)) == NULL) { + return (-1); + } + /* protocol name */ + if ((ncp->nc_proto = strtok_r(NULL, "\t ", &lasts)) == NULL) { + return (-1); + } + /* network device */ + if ((ncp->nc_device = strtok_r(NULL, "\t ", &lasts)) == NULL) { + return (-1); + } + if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL) { + return (-1); + } + if (strcmp(tokenp, NC_NOLOOKUP) == 0) { + ncp->nc_nlookups = 0; + ncp->nc_lookups = NULL; + } else { + char *cp; /* tmp string */ + + if (ncp->nc_lookups != NULL) /* from last visit */ + free(ncp->nc_lookups); + ncp->nc_lookups = NULL; + ncp->nc_nlookups = 0; + while ((cp = tokenp) != NULL) { + if ((nc_lookups = realloc(ncp->nc_lookups, + (ncp->nc_nlookups + 1) * sizeof *ncp->nc_lookups)) == NULL) { + free(ncp->nc_lookups); + ncp->nc_lookups = NULL; + return (-1); + } + tokenp = _get_next_token(cp, ','); + ncp->nc_lookups = nc_lookups; + ncp->nc_lookups[ncp->nc_nlookups++] = cp; + } + } + return (0); +} + + +/* + * Returns a string describing the reason for failure. + */ +char * +nc_sperror() +{ + const char *message; + + switch(nc_error) { + case NC_NONETCONFIG: + message = _nc_errors[0]; + break; + case NC_NOMEM: + message = _nc_errors[1]; + break; + case NC_NOTINIT: + message = _nc_errors[2]; + break; + case NC_BADFILE: + message = _nc_errors[3]; + break; + case NC_NOTFOUND: + message = _nc_errors[4]; + break; + default: + message = "Unknown network selection error"; + } + /* LINTED const castaway */ + return ((char *)message); +} + +/* + * Prints a message onto standard error describing the reason for failure. + */ +void +nc_perror(s) + const char *s; +{ + fprintf(stderr, "%s: %s\n", s, nc_sperror()); +} + +/* + * Duplicates the matched netconfig buffer. + */ +static struct netconfig * +dup_ncp(ncp) +struct netconfig *ncp; +{ + struct netconfig *p; + char *tmp; + u_int i; + + if ((tmp=malloc(MAXNETCONFIGLINE)) == NULL) + return(NULL); + if ((p=(struct netconfig *)malloc(sizeof(struct netconfig))) == NULL) { + free(tmp); + return(NULL); + } + /* + * First we dup all the data from matched netconfig buffer. Then we + * adjust some of the member pointer to a pre-allocated buffer where + * contains part of the data. + * To follow the convention used in parse_ncp(), we store all the + * necessary information in the pre-allocated buffer and let each + * of the netconfig char pointer member point to the right address + * in the buffer. + */ + *p = *ncp; + p->nc_netid = (char *)strcpy(tmp,ncp->nc_netid); + tmp = strchr(tmp, '\0') + 1; + p->nc_protofmly = (char *)strcpy(tmp,ncp->nc_protofmly); + tmp = strchr(tmp, '\0') + 1; + p->nc_proto = (char *)strcpy(tmp,ncp->nc_proto); + tmp = strchr(tmp, '\0') + 1; + p->nc_device = (char *)strcpy(tmp,ncp->nc_device); + p->nc_lookups = (char **)malloc((size_t)(p->nc_nlookups+1) * sizeof(char *)); + if (p->nc_lookups == NULL) { + free(p->nc_netid); + free(p); + return(NULL); + } + for (i=0; i < p->nc_nlookups; i++) { + tmp = strchr(tmp, '\0') + 1; + p->nc_lookups[i] = (char *)strcpy(tmp,ncp->nc_lookups[i]); + } + return(p); +} diff --git a/freebsd/lib/libc/rpc/getnetpath.c b/freebsd/lib/libc/rpc/getnetpath.c new file mode 100644 index 00000000..56493557 --- /dev/null +++ b/freebsd/lib/libc/rpc/getnetpath.c @@ -0,0 +1,276 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: getnetpath.c,v 1.3 2000/07/06 03:10:34 christos Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getnetpath.c 1.11 91/12/19 SMI"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Copyright (c) 1989 by Sun Microsystems, Inc. + */ + +#include "namespace.h" +#include <stdio.h> +#include <errno.h> +#include <netconfig.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include "un-namespace.h" + +/* + * internal structure to keep track of a netpath "session" + */ +struct netpath_chain { + struct netconfig *ncp; /* an nconf entry */ + struct netpath_chain *nchain_next; /* next nconf entry allocated */ +}; + + +struct netpath_vars { + int valid; /* token that indicates a valid netpath_vars */ + void *nc_handlep; /* handle for current netconfig "session" */ + char *netpath; /* pointer to current view-point in NETPATH */ + char *netpath_start; /* pointer to start of our copy of NETPATH */ + struct netpath_chain *ncp_list; /* list of nconfs allocated this session*/ +}; + +#define NP_VALID 0xf00d +#define NP_INVALID 0 + +char *_get_next_token(char *, int); + + +/* + * A call to setnetpath() establishes a NETPATH "session". setnetpath() + * must be called before the first call to getnetpath(). A "handle" is + * returned to distinguish the session; this handle should be passed + * subsequently to getnetpath(). (Handles are used to allow for nested calls + * to setnetpath()). + * If setnetpath() is unable to establish a session (due to lack of memory + * resources, or the absence of the /etc/netconfig file), a NULL pointer is + * returned. + */ + +void * +setnetpath() +{ + + struct netpath_vars *np_sessionp; /* this session's variables */ + char *npp; /* NETPATH env variable */ + +#ifdef MEM_CHK + malloc_debug(1); +#endif + + if ((np_sessionp = + (struct netpath_vars *)malloc(sizeof (struct netpath_vars))) == NULL) { + return (NULL); + } + if ((np_sessionp->nc_handlep = setnetconfig()) == NULL) { + free(np_sessionp); + syslog (LOG_ERR, "rpc: failed to open " NETCONFIG); + return (NULL); + } + np_sessionp->valid = NP_VALID; + np_sessionp->ncp_list = NULL; + if ((npp = getenv(NETPATH)) == NULL) { + np_sessionp->netpath = NULL; + } else { + (void) endnetconfig(np_sessionp->nc_handlep);/* won't need nc session*/ + np_sessionp->nc_handlep = NULL; + if ((np_sessionp->netpath = malloc(strlen(npp)+1)) == NULL) + goto failed; + else { + (void) strcpy(np_sessionp->netpath, npp); + } + } + np_sessionp->netpath_start = np_sessionp->netpath; + return ((void *)np_sessionp); + +failed: + free(np_sessionp); + return (NULL); +} + +/* + * When first called, getnetpath() returns a pointer to the netconfig + * database entry corresponding to the first valid NETPATH component. The + * netconfig entry is formatted as a struct netconfig. + * On each subsequent call, getnetpath returns a pointer to the netconfig + * entry that corresponds to the next valid NETPATH component. getnetpath + * can thus be used to search the netconfig database for all networks + * included in the NETPATH variable. + * When NETPATH has been exhausted, getnetpath() returns NULL. It returns + * NULL and sets errno in case of an error (e.g., setnetpath was not called + * previously). + * getnetpath() silently ignores invalid NETPATH components. A NETPATH + * compnent is invalid if there is no corresponding entry in the netconfig + * database. + * If the NETPATH variable is unset, getnetpath() behaves as if NETPATH + * were set to the sequence of default or visible networks in the netconfig + * database, in the order in which they are listed. + */ + +struct netconfig * +getnetpath(handlep) + void *handlep; +{ + struct netpath_vars *np_sessionp = (struct netpath_vars *)handlep; + struct netconfig *ncp = NULL; /* temp. holds a netconfig session */ + struct netpath_chain *chainp; /* holds chain of ncp's we alloc */ + char *npp; /* holds current NETPATH */ + + if (np_sessionp == NULL || np_sessionp->valid != NP_VALID) { + errno = EINVAL; + return (NULL); + } + if (np_sessionp->netpath_start == NULL) { /* NETPATH was not set */ + do { /* select next visible network */ + if (np_sessionp->nc_handlep == NULL) { + np_sessionp->nc_handlep = setnetconfig(); + if (np_sessionp->nc_handlep == NULL) + syslog (LOG_ERR, "rpc: failed to open " NETCONFIG); + } + if ((ncp = getnetconfig(np_sessionp->nc_handlep)) == NULL) { + return(NULL); + } + } while ((ncp->nc_flag & NC_VISIBLE) == 0); + return (ncp); + } + /* + * Find first valid network ID in netpath. + */ + while ((npp = np_sessionp->netpath) != NULL && strlen(npp) != 0) { + np_sessionp->netpath = _get_next_token(npp, ':'); + /* + * npp is a network identifier. + */ + if ((ncp = getnetconfigent(npp)) != NULL) { + chainp = (struct netpath_chain *) /* cobble alloc chain entry */ + malloc(sizeof (struct netpath_chain)); + chainp->ncp = ncp; + chainp->nchain_next = NULL; + if (np_sessionp->ncp_list == NULL) { + np_sessionp->ncp_list = chainp; + } else { + np_sessionp->ncp_list->nchain_next = chainp; + } + return (ncp); + } + /* couldn't find this token in the database; go to next one. */ + } + return (NULL); +} + +/* + * endnetpath() may be called to unbind NETPATH when processing is complete, + * releasing resources for reuse. It returns 0 on success and -1 on failure + * (e.g. if setnetpath() was not called previously. + */ +int +endnetpath(handlep) + void *handlep; +{ + struct netpath_vars *np_sessionp = (struct netpath_vars *)handlep; + struct netpath_chain *chainp, *lastp; + + if (np_sessionp == NULL || np_sessionp->valid != NP_VALID) { + errno = EINVAL; + return (-1); + } + if (np_sessionp->nc_handlep != NULL) + endnetconfig(np_sessionp->nc_handlep); + if (np_sessionp->netpath_start != NULL) + free(np_sessionp->netpath_start); + for (chainp = np_sessionp->ncp_list; chainp != NULL; + lastp=chainp, chainp=chainp->nchain_next, free(lastp)) { + freenetconfigent(chainp->ncp); + } + free(np_sessionp); +#ifdef MEM_CHK + if (malloc_verify() == 0) { + fprintf(stderr, "memory heap corrupted in endnetpath\n"); + exit(1); + } +#endif + return (0); +} + + + +/* + * Returns pointer to the rest-of-the-string after the current token. + * The token itself starts at arg, and we null terminate it. We return NULL + * if either the arg is empty, or if this is the last token. + */ + +char * +_get_next_token(npp, token) +char *npp; /* string */ +int token; /* char to parse string for */ +{ + char *cp; /* char pointer */ + char *np; /* netpath pointer */ + char *ep; /* escape pointer */ + + if ((cp = strchr(npp, token)) == NULL) { + return (NULL); + } + /* + * did find a token, but it might be escaped. + */ + if ((cp > npp) && (cp[-1] == '\\')) { + /* if slash was also escaped, carry on, otherwise find next token */ + if ((cp > npp + 1) && (cp[-2] != '\\')) { + /* shift r-o-s onto the escaped token */ + strcpy(&cp[-1], cp); /* XXX: overlapping string copy */ + /* + * Do a recursive call. + * We don't know how many escaped tokens there might be. + */ + return (_get_next_token(cp, token)); + } + } + + *cp++ = '\0'; /* null-terminate token */ + /* get rid of any backslash escapes */ + ep = npp; + while ((np = strchr(ep, '\\')) != 0) { + if (np[1] == '\\') + np++; + strcpy(np, (ep = &np[1])); /* XXX: overlapping string copy */ + } + return (cp); /* return ptr to r-o-s */ +} diff --git a/freebsd/lib/libc/rpc/getpublickey.c b/freebsd/lib/libc/rpc/getpublickey.c new file mode 100644 index 00000000..d7bac7c2 --- /dev/null +++ b/freebsd/lib/libc/rpc/getpublickey.c @@ -0,0 +1,179 @@ +#include <machine/rtems-bsd-user-space.h> + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)publickey.c 1.10 91/03/11 Copyr 1986 Sun Micro"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * publickey.c + * Copyright (C) 1986, Sun Microsystems, Inc. + */ + +/* + * Public key lookup routines + */ +#include "namespace.h" +#include <stdio.h> +#include <pwd.h> +#include <rpc/rpc.h> +#include <rpc/key_prot.h> +#include <rpcsvc/yp_prot.h> +#include <rpcsvc/ypclnt.h> +#include <string.h> +#include <stdlib.h> +#include "un-namespace.h" + +#define PKFILE "/etc/publickey" + +/* + * Hack to let ypserv/rpc.nisd use AUTH_DES. + */ +int (*__getpublickey_LOCAL)() = 0; + +/* + * Get somebody's public key + */ +static int +__getpublickey_real(netname, publickey) + const char *netname; + char *publickey; +{ + char lookup[3 * HEXKEYBYTES]; + char *p; + + if (publickey == NULL) + return (0); + if (!getpublicandprivatekey(netname, lookup)) + return (0); + p = strchr(lookup, ':'); + if (p == NULL) { + return (0); + } + *p = '\0'; + (void) strncpy(publickey, lookup, HEXKEYBYTES); + publickey[HEXKEYBYTES] = '\0'; + return (1); +} + +/* + * reads the file /etc/publickey looking for a + to optionally go to the + * yellow pages + */ + +int +getpublicandprivatekey(key, ret) + const char *key; + char *ret; +{ + char buf[1024]; /* big enough */ + char *res; + FILE *fd; + char *mkey; + char *mval; + + fd = fopen(PKFILE, "r"); + if (fd == NULL) + return (0); + for (;;) { + res = fgets(buf, sizeof(buf), fd); + if (res == NULL) { + fclose(fd); + return (0); + } + if (res[0] == '#') + continue; + else if (res[0] == '+') { +#ifdef YP + char *PKMAP = "publickey.byname"; + char *lookup; + char *domain; + int err; + int len; + + err = yp_get_default_domain(&domain); + if (err) { + continue; + } + lookup = NULL; + err = yp_match(domain, PKMAP, key, strlen(key), &lookup, &len); + if (err) { +#ifdef DEBUG + fprintf(stderr, "match failed error %d\n", err); +#endif + continue; + } + lookup[len] = 0; + strcpy(ret, lookup); + fclose(fd); + free(lookup); + return (2); +#else /* YP */ +#ifdef DEBUG + fprintf(stderr, +"Bad record in %s '+' -- NIS not supported in this library copy\n", PKFILE); +#endif /* DEBUG */ + continue; +#endif /* YP */ + } else { + mkey = strsep(&res, "\t "); + if (mkey == NULL) { + fprintf(stderr, + "Bad record in %s -- %s", PKFILE, buf); + continue; + } + do { + mval = strsep(&res, " \t#\n"); + } while (mval != NULL && !*mval); + if (mval == NULL) { + fprintf(stderr, + "Bad record in %s val problem - %s", PKFILE, buf); + continue; + } + if (strcmp(mkey, key) == 0) { + strcpy(ret, mval); + fclose(fd); + return (1); + } + } + } +} + +int getpublickey(netname, publickey) + const char *netname; + char *publickey; +{ + if (__getpublickey_LOCAL != NULL) + return(__getpublickey_LOCAL(netname, publickey)); + else + return(__getpublickey_real(netname, publickey)); +} diff --git a/freebsd/lib/libc/rpc/getrpcent.c b/freebsd/lib/libc/rpc/getrpcent.c new file mode 100644 index 00000000..b4d51e0d --- /dev/null +++ b/freebsd/lib/libc/rpc/getrpcent.c @@ -0,0 +1,1048 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: getrpcent.c,v 1.17 2000/01/22 22:19:17 mycroft Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *sccsid = "@(#)getrpcent.c 1.14 91/03/11 Copyr 1984 Sun Micro"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Copyright (c) 1984 by Sun Microsystems, Inc. + */ + +#include <rtems/bsd/sys/param.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <assert.h> +#include <errno.h> +#include <nsswitch.h> +#include <netinet/in.h> +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <stdlib.h> +#include <rpc/rpc.h> +#ifdef YP +#include <rpcsvc/yp_prot.h> +#include <rpcsvc/ypclnt.h> +#endif +#include <unistd.h> +#include "namespace.h" +#include "reentrant.h" +#include "un-namespace.h" +#include "libc_private.h" +#include "nss_tls.h" +#ifdef NS_CACHING +#include "nscache.h" +#endif + +#define RPCDB "/etc/rpc" + +/* nsswitch declarations */ +enum constants +{ + SETRPCENT = 1, + ENDRPCENT = 2, + RPCENT_STORAGE_INITIAL = 1 << 10, /* 1 KByte */ + RPCENT_STORAGE_MAX = 1 << 20, /* 1 MByte */ +}; + +static const ns_src defaultsrc[] = { + { NSSRC_FILES, NS_SUCCESS }, +#ifdef YP + { NSSRC_NIS, NS_SUCCESS }, +#endif + { NULL, 0 } +}; + +/* files backend declarations */ +struct files_state { + FILE *fp; + int stayopen; +}; + +static int files_rpcent(void *, void *, va_list); +static int files_setrpcent(void *, void *, va_list); + +static void files_endstate(void *); +NSS_TLS_HANDLING(files); + +/* nis backend declarations */ +#ifdef YP +struct nis_state { + char domain[MAXHOSTNAMELEN]; + char *current; + int currentlen; + int stepping; + int no_name_map; +}; + +static int nis_rpcent(void *, void *, va_list); +static int nis_setrpcent(void *, void *, va_list); + +static void nis_endstate(void *); +NSS_TLS_HANDLING(nis); +#endif + +/* get** wrappers for get**_r functions declarations */ +struct rpcent_state { + struct rpcent rpc; + char *buffer; + size_t bufsize; +}; +static void rpcent_endstate(void *); +NSS_TLS_HANDLING(rpcent); + +union key { + const char *name; + int number; +}; + +static int wrap_getrpcbyname_r(union key, struct rpcent *, char *, + size_t, struct rpcent **); +static int wrap_getrpcbynumber_r(union key, struct rpcent *, char *, + size_t, struct rpcent **); +static int wrap_getrpcent_r(union key, struct rpcent *, char *, + size_t, struct rpcent **); +static struct rpcent *getrpc(int (*fn)(union key, struct rpcent *, char *, + size_t, struct rpcent **), union key); + +#ifdef NS_CACHING +static int rpc_id_func(char *, size_t *, va_list, void *); +static int rpc_marshal_func(char *, size_t *, void *, va_list, void *); +static int rpc_unmarshal_func(char *, size_t, void *, va_list, void *); +#endif + +static int +rpcent_unpack(char *p, struct rpcent *rpc, char **r_aliases, + size_t aliases_size, int *errnop) +{ + char *cp, **q; + + assert(p != NULL); + + if (*p == '#') + return (-1); + cp = strpbrk(p, "#\n"); + if (cp == NULL) + return (-1); + *cp = '\0'; + cp = strpbrk(p, " \t"); + if (cp == NULL) + return (-1); + *cp++ = '\0'; + /* THIS STUFF IS INTERNET SPECIFIC */ + rpc->r_name = p; + while (*cp == ' ' || *cp == '\t') + cp++; + rpc->r_number = atoi(cp); + q = rpc->r_aliases = r_aliases; + cp = strpbrk(cp, " \t"); + if (cp != NULL) + *cp++ = '\0'; + while (cp && *cp) { + if (*cp == ' ' || *cp == '\t') { + cp++; + continue; + } + if (q < &(r_aliases[aliases_size - 1])) + *q++ = cp; + else { + *errnop = ERANGE; + return -1; + } + + cp = strpbrk(cp, " \t"); + if (cp != NULL) + *cp++ = '\0'; + } + *q = NULL; + return 0; +} + +/* files backend implementation */ +static void +files_endstate(void *p) +{ + FILE * f; + + if (p == NULL) + return; + + f = ((struct files_state *)p)->fp; + if (f != NULL) + fclose(f); + + free(p); +} + +static int +files_rpcent(void *retval, void *mdata, va_list ap) +{ + char *name; + int number; + struct rpcent *rpc; + char *buffer; + size_t bufsize; + int *errnop; + + char *line; + size_t linesize; + char **aliases; + int aliases_size; + char **rp; + + struct files_state *st; + int rv; + int stayopen; + enum nss_lookup_type how; + + how = (enum nss_lookup_type)mdata; + switch (how) + { + case nss_lt_name: + name = va_arg(ap, char *); + break; + case nss_lt_id: + number = va_arg(ap, int); + break; + case nss_lt_all: + break; + default: + return (NS_NOTFOUND); + } + + rpc = va_arg(ap, struct rpcent *); + buffer = va_arg(ap, char *); + bufsize = va_arg(ap, size_t); + errnop = va_arg(ap, int *); + + *errnop = files_getstate(&st); + if (*errnop != 0) + return (NS_UNAVAIL); + + if (st->fp == NULL && (st->fp = fopen(RPCDB, "r")) == NULL) { + *errnop = errno; + return (NS_UNAVAIL); + } + + if (how == nss_lt_all) + stayopen = 1; + else { + rewind(st->fp); + stayopen = st->stayopen; + } + + do { + if ((line = fgetln(st->fp, &linesize)) == NULL) { + *errnop = errno; + rv = NS_RETURN; + break; + } + + if (bufsize <= linesize + _ALIGNBYTES + sizeof(char *)) { + *errnop = ERANGE; + rv = NS_RETURN; + break; + } + + aliases = (char **)_ALIGN(&buffer[linesize+1]); + aliases_size = (buffer + bufsize - + (char *)aliases)/sizeof(char *); + if (aliases_size < 1) { + *errnop = ERANGE; + rv = NS_RETURN; + break; + } + + memcpy(buffer, line, linesize); + buffer[linesize] = '\0'; + + rv = rpcent_unpack(buffer, rpc, aliases, aliases_size, errnop); + if (rv != 0) { + if (*errnop == 0) { + rv = NS_NOTFOUND; + continue; + } + else { + rv = NS_RETURN; + break; + } + } + + switch (how) + { + case nss_lt_name: + if (strcmp(rpc->r_name, name) == 0) + goto done; + for (rp = rpc->r_aliases; *rp != NULL; rp++) { + if (strcmp(*rp, name) == 0) + goto done; + } + rv = NS_NOTFOUND; + continue; +done: + rv = NS_SUCCESS; + break; + case nss_lt_id: + rv = (rpc->r_number == number) ? NS_SUCCESS : + NS_NOTFOUND; + break; + case nss_lt_all: + rv = NS_SUCCESS; + break; + } + + } while (!(rv & NS_TERMINATE)); + + if (!stayopen && st->fp!=NULL) { + fclose(st->fp); + st->fp = NULL; + } + + if ((rv == NS_SUCCESS) && (retval != NULL)) + *((struct rpcent **)retval) = rpc; + + return (rv); +} + +static int +files_setrpcent(void *retval, void *mdata, va_list ap) +{ + struct files_state *st; + int rv; + int f; + + rv = files_getstate(&st); + if (rv != 0) + return (NS_UNAVAIL); + + switch ((enum constants)mdata) + { + case SETRPCENT: + f = va_arg(ap,int); + if (st->fp == NULL) + st->fp = fopen(RPCDB, "r"); + else + rewind(st->fp); + st->stayopen |= f; + break; + case ENDRPCENT: + if (st->fp != NULL) { + fclose(st->fp); + st->fp = NULL; + } + st->stayopen = 0; + break; + default: + break; + } + + return (NS_UNAVAIL); +} + +/* nis backend implementation */ +#ifdef YP +static void +nis_endstate(void *p) +{ + if (p == NULL) + return; + + free(((struct nis_state *)p)->current); + free(p); +} + +static int +nis_rpcent(void *retval, void *mdata, va_list ap) +{ + char *name; + int number; + struct rpcent *rpc; + char *buffer; + size_t bufsize; + int *errnop; + + char **rp; + char **aliases; + int aliases_size; + + char *lastkey; + char *resultbuf; + int resultbuflen; + char buf[YPMAXRECORD + 2]; + + struct nis_state *st; + int rv; + enum nss_lookup_type how; + int no_name_active; + + how = (enum nss_lookup_type)mdata; + switch (how) + { + case nss_lt_name: + name = va_arg(ap, char *); + break; + case nss_lt_id: + number = va_arg(ap, int); + break; + case nss_lt_all: + break; + default: + return (NS_NOTFOUND); + } + + rpc = va_arg(ap, struct rpcent *); + buffer = va_arg(ap, char *); + bufsize = va_arg(ap, size_t); + errnop = va_arg(ap, int *); + + *errnop = nis_getstate(&st); + if (*errnop != 0) + return (NS_UNAVAIL); + + if (st->domain[0] == '\0') { + if (getdomainname(st->domain, sizeof(st->domain)) != 0) { + *errnop = errno; + return (NS_UNAVAIL); + } + } + + no_name_active = 0; + do { + switch (how) + { + case nss_lt_name: + if (!st->no_name_map) + { + snprintf(buf, sizeof buf, "%s", name); + rv = yp_match(st->domain, "rpc.byname", buf, + strlen(buf), &resultbuf, &resultbuflen); + + switch (rv) { + case 0: + break; + case YPERR_MAP: + st->stepping = 0; + no_name_active = 1; + how = nss_lt_all; + + rv = NS_NOTFOUND; + continue; + default: + rv = NS_NOTFOUND; + goto fin; + } + } else { + st->stepping = 0; + no_name_active = 1; + how = nss_lt_all; + + rv = NS_NOTFOUND; + continue; + } + break; + case nss_lt_id: + snprintf(buf, sizeof buf, "%d", number); + if (yp_match(st->domain, "rpc.bynumber", buf, + strlen(buf), &resultbuf, &resultbuflen)) { + rv = NS_NOTFOUND; + goto fin; + } + break; + case nss_lt_all: + if (!st->stepping) { + rv = yp_first(st->domain, "rpc.bynumber", + &st->current, + &st->currentlen, &resultbuf, + &resultbuflen); + if (rv) { + rv = NS_NOTFOUND; + goto fin; + } + st->stepping = 1; + } else { + lastkey = st->current; + rv = yp_next(st->domain, "rpc.bynumber", + st->current, + st->currentlen, &st->current, + &st->currentlen, + &resultbuf, &resultbuflen); + free(lastkey); + if (rv) { + st->stepping = 0; + rv = NS_NOTFOUND; + goto fin; + } + } + break; + } + + /* we need a room for additional \n symbol */ + if (bufsize <= resultbuflen + 1 + _ALIGNBYTES + + sizeof(char *)) { + *errnop = ERANGE; + rv = NS_RETURN; + break; + } + + aliases=(char **)_ALIGN(&buffer[resultbuflen+2]); + aliases_size = (buffer + bufsize - (char *)aliases) / + sizeof(char *); + if (aliases_size < 1) { + *errnop = ERANGE; + rv = NS_RETURN; + break; + } + + /* + * rpcent_unpack expects lines terminated with \n -- make it happy + */ + memcpy(buffer, resultbuf, resultbuflen); + buffer[resultbuflen] = '\n'; + buffer[resultbuflen+1] = '\0'; + free(resultbuf); + + if (rpcent_unpack(buffer, rpc, aliases, aliases_size, + errnop) != 0) { + if (*errnop == 0) + rv = NS_NOTFOUND; + else + rv = NS_RETURN; + } else { + if ((how == nss_lt_all) && (no_name_active != 0)) { + if (strcmp(rpc->r_name, name) == 0) + goto done; + for (rp = rpc->r_aliases; *rp != NULL; rp++) { + if (strcmp(*rp, name) == 0) + goto done; + } + rv = NS_NOTFOUND; + continue; +done: + rv = NS_SUCCESS; + } else + rv = NS_SUCCESS; + } + + } while (!(rv & NS_TERMINATE) && (how == nss_lt_all)); + +fin: + if ((rv == NS_SUCCESS) && (retval != NULL)) + *((struct rpcent **)retval) = rpc; + + return (rv); +} + +static int +nis_setrpcent(void *retval, void *mdata, va_list ap) +{ + struct nis_state *st; + int rv; + + rv = nis_getstate(&st); + if (rv != 0) + return (NS_UNAVAIL); + + switch ((enum constants)mdata) + { + case SETRPCENT: + case ENDRPCENT: + free(st->current); + st->current = NULL; + st->stepping = 0; + break; + default: + break; + } + + return (NS_UNAVAIL); +} +#endif + +#ifdef NS_CACHING +static int +rpc_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata) +{ + char *name; + int rpc; + + size_t desired_size, size; + enum nss_lookup_type lookup_type; + int res = NS_UNAVAIL; + + lookup_type = (enum nss_lookup_type)cache_mdata; + switch (lookup_type) { + case nss_lt_name: + name = va_arg(ap, char *); + + size = strlen(name); + desired_size = sizeof(enum nss_lookup_type) + size + 1; + if (desired_size > *buffer_size) { + res = NS_RETURN; + goto fin; + } + + memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type)); + memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1); + + res = NS_SUCCESS; + break; + case nss_lt_id: + rpc = va_arg(ap, int); + + desired_size = sizeof(enum nss_lookup_type) + sizeof(int); + if (desired_size > *buffer_size) { + res = NS_RETURN; + goto fin; + } + + memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type)); + memcpy(buffer + sizeof(enum nss_lookup_type), &rpc, + sizeof(int)); + + res = NS_SUCCESS; + break; + default: + /* should be unreachable */ + return (NS_UNAVAIL); + } + +fin: + *buffer_size = desired_size; + return (res); +} + +static int +rpc_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap, + void *cache_mdata) +{ + char *name; + int num; + struct rpcent *rpc; + char *orig_buf; + size_t orig_buf_size; + + struct rpcent new_rpc; + size_t desired_size, size, aliases_size; + char *p; + char **alias; + + switch ((enum nss_lookup_type)cache_mdata) { + case nss_lt_name: + name = va_arg(ap, char *); + break; + case nss_lt_id: + num = va_arg(ap, int); + break; + case nss_lt_all: + break; + default: + /* should be unreachable */ + return (NS_UNAVAIL); + } + + rpc = va_arg(ap, struct rpcent *); + orig_buf = va_arg(ap, char *); + orig_buf_size = va_arg(ap, size_t); + + desired_size = _ALIGNBYTES + sizeof(struct rpcent) + sizeof(char *); + if (rpc->r_name != NULL) + desired_size += strlen(rpc->r_name) + 1; + + if (rpc->r_aliases != NULL) { + aliases_size = 0; + for (alias = rpc->r_aliases; *alias; ++alias) { + desired_size += strlen(*alias) + 1; + ++aliases_size; + } + + desired_size += _ALIGNBYTES + (aliases_size + 1) * + sizeof(char *); + } + + if (*buffer_size < desired_size) { + /* this assignment is here for future use */ + *buffer_size = desired_size; + return (NS_RETURN); + } + + new_rpc = *rpc; + + *buffer_size = desired_size; + memset(buffer, 0, desired_size); + p = buffer + sizeof(struct rpcent) + sizeof(char *); + memcpy(buffer + sizeof(struct rpcent), &p, sizeof(char *)); + p = (char *)_ALIGN(p); + + if (new_rpc.r_name != NULL) { + size = strlen(new_rpc.r_name); + memcpy(p, new_rpc.r_name, size); + new_rpc.r_name = p; + p += size + 1; + } + + if (new_rpc.r_aliases != NULL) { + p = (char *)_ALIGN(p); + memcpy(p, new_rpc.r_aliases, sizeof(char *) * aliases_size); + new_rpc.r_aliases = (char **)p; + p += sizeof(char *) * (aliases_size + 1); + + for (alias = new_rpc.r_aliases; *alias; ++alias) { + size = strlen(*alias); + memcpy(p, *alias, size); + *alias = p; + p += size + 1; + } + } + + memcpy(buffer, &new_rpc, sizeof(struct rpcent)); + return (NS_SUCCESS); +} + +static int +rpc_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap, + void *cache_mdata) +{ + char *name; + int num; + struct rpcent *rpc; + char *orig_buf; + size_t orig_buf_size; + int *ret_errno; + + char *p; + char **alias; + + switch ((enum nss_lookup_type)cache_mdata) { + case nss_lt_name: + name = va_arg(ap, char *); + break; + case nss_lt_id: + num = va_arg(ap, int); + break; + case nss_lt_all: + break; + default: + /* should be unreachable */ + return (NS_UNAVAIL); + } + + rpc = va_arg(ap, struct rpcent *); + orig_buf = va_arg(ap, char *); + orig_buf_size = va_arg(ap, size_t); + ret_errno = va_arg(ap, int *); + + if (orig_buf_size < + buffer_size - sizeof(struct rpcent) - sizeof(char *)) { + *ret_errno = ERANGE; + return (NS_RETURN); + } + + memcpy(rpc, buffer, sizeof(struct rpcent)); + memcpy(&p, buffer + sizeof(struct rpcent), sizeof(char *)); + + orig_buf = (char *)_ALIGN(orig_buf); + memcpy(orig_buf, buffer + sizeof(struct rpcent) + sizeof(char *) + + _ALIGN(p) - (size_t)p, + buffer_size - sizeof(struct rpcent) - sizeof(char *) - + _ALIGN(p) + (size_t)p); + p = (char *)_ALIGN(p); + + NS_APPLY_OFFSET(rpc->r_name, orig_buf, p, char *); + if (rpc->r_aliases != NULL) { + NS_APPLY_OFFSET(rpc->r_aliases, orig_buf, p, char **); + + for (alias = rpc->r_aliases ; *alias; ++alias) + NS_APPLY_OFFSET(*alias, orig_buf, p, char *); + } + + if (retval != NULL) + *((struct rpcent **)retval) = rpc; + + return (NS_SUCCESS); +} + +NSS_MP_CACHE_HANDLING(rpc); +#endif /* NS_CACHING */ + + +/* get**_r functions implementation */ +static int +getrpcbyname_r(const char *name, struct rpcent *rpc, char *buffer, + size_t bufsize, struct rpcent **result) +{ +#ifdef NS_CACHING + static const nss_cache_info cache_info = + NS_COMMON_CACHE_INFO_INITIALIZER( + rpc, (void *)nss_lt_name, + rpc_id_func, rpc_marshal_func, rpc_unmarshal_func); +#endif + static const ns_dtab dtab[] = { + { NSSRC_FILES, files_rpcent, (void *)nss_lt_name }, +#ifdef YP + { NSSRC_NIS, nis_rpcent, (void *)nss_lt_name }, +#endif +#ifdef NS_CACHING + NS_CACHE_CB(&cache_info) +#endif + { NULL, NULL, NULL } + }; + int rv, ret_errno; + + ret_errno = 0; + *result = NULL; + rv = nsdispatch(result, dtab, NSDB_RPC, "getrpcbyname_r", defaultsrc, + name, rpc, buffer, bufsize, &ret_errno); + + if (rv == NS_SUCCESS) + return (0); + else + return (ret_errno); +} + +static int +getrpcbynumber_r(int number, struct rpcent *rpc, char *buffer, + size_t bufsize, struct rpcent **result) +{ +#ifdef NS_CACHING + static const nss_cache_info cache_info = + NS_COMMON_CACHE_INFO_INITIALIZER( + rpc, (void *)nss_lt_id, + rpc_id_func, rpc_marshal_func, rpc_unmarshal_func); +#endif + static const ns_dtab dtab[] = { + { NSSRC_FILES, files_rpcent, (void *)nss_lt_id }, +#ifdef YP + { NSSRC_NIS, nis_rpcent, (void *)nss_lt_id }, +#endif +#ifdef NS_CACHING + NS_CACHE_CB(&cache_info) +#endif + { NULL, NULL, NULL } + }; + int rv, ret_errno; + + ret_errno = 0; + *result = NULL; + rv = nsdispatch(result, dtab, NSDB_RPC, "getrpcbynumber_r", defaultsrc, + number, rpc, buffer, bufsize, &ret_errno); + + if (rv == NS_SUCCESS) + return (0); + else + return (ret_errno); +} + +static int +getrpcent_r(struct rpcent *rpc, char *buffer, size_t bufsize, + struct rpcent **result) +{ +#ifdef NS_CACHING + static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER( + rpc, (void *)nss_lt_all, + rpc_marshal_func, rpc_unmarshal_func); +#endif + static const ns_dtab dtab[] = { + { NSSRC_FILES, files_rpcent, (void *)nss_lt_all }, +#ifdef YP + { NSSRC_NIS, nis_rpcent, (void *)nss_lt_all }, +#endif +#ifdef NS_CACHING + NS_CACHE_CB(&cache_info) +#endif + { NULL, NULL, NULL } + }; + int rv, ret_errno; + + ret_errno = 0; + *result = NULL; + rv = nsdispatch(result, dtab, NSDB_RPC, "getrpcent_r", defaultsrc, + rpc, buffer, bufsize, &ret_errno); + + if (rv == NS_SUCCESS) + return (0); + else + return (ret_errno); +} + +/* get** wrappers for get**_r functions implementation */ +static void +rpcent_endstate(void *p) +{ + if (p == NULL) + return; + + free(((struct rpcent_state *)p)->buffer); + free(p); +} + +static int +wrap_getrpcbyname_r(union key key, struct rpcent *rpc, char *buffer, + size_t bufsize, struct rpcent **res) +{ + return (getrpcbyname_r(key.name, rpc, buffer, bufsize, res)); +} + +static int +wrap_getrpcbynumber_r(union key key, struct rpcent *rpc, char *buffer, + size_t bufsize, struct rpcent **res) +{ + return (getrpcbynumber_r(key.number, rpc, buffer, bufsize, res)); +} + +static int +wrap_getrpcent_r(union key key __unused, struct rpcent *rpc, char *buffer, + size_t bufsize, struct rpcent **res) +{ + return (getrpcent_r(rpc, buffer, bufsize, res)); +} + +static struct rpcent * +getrpc(int (*fn)(union key, struct rpcent *, char *, size_t, struct rpcent **), + union key key) +{ + int rv; + struct rpcent *res; + struct rpcent_state * st; + + rv=rpcent_getstate(&st); + if (rv != 0) { + errno = rv; + return NULL; + } + + if (st->buffer == NULL) { + st->buffer = malloc(RPCENT_STORAGE_INITIAL); + if (st->buffer == NULL) + return (NULL); + st->bufsize = RPCENT_STORAGE_INITIAL; + } + do { + rv = fn(key, &st->rpc, st->buffer, st->bufsize, &res); + if (res == NULL && rv == ERANGE) { + free(st->buffer); + if ((st->bufsize << 1) > RPCENT_STORAGE_MAX) { + st->buffer = NULL; + errno = ERANGE; + return (NULL); + } + st->bufsize <<= 1; + st->buffer = malloc(st->bufsize); + if (st->buffer == NULL) + return (NULL); + } + } while (res == NULL && rv == ERANGE); + if (rv != 0) + errno = rv; + + return (res); +} + +struct rpcent * +getrpcbyname(char *name) +{ + union key key; + + key.name = name; + + return (getrpc(wrap_getrpcbyname_r, key)); +} + +struct rpcent * +getrpcbynumber(int number) +{ + union key key; + + key.number = number; + + return (getrpc(wrap_getrpcbynumber_r, key)); +} + +struct rpcent * +getrpcent() +{ + union key key; + + key.number = 0; /* not used */ + + return (getrpc(wrap_getrpcent_r, key)); +} + +void +setrpcent(int stayopen) +{ +#ifdef NS_CACHING + static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER( + rpc, (void *)nss_lt_all, + NULL, NULL); +#endif + + static const ns_dtab dtab[] = { + { NSSRC_FILES, files_setrpcent, (void *)SETRPCENT }, +#ifdef YP + { NSSRC_NIS, nis_setrpcent, (void *)SETRPCENT }, +#endif +#ifdef NS_CACHING + NS_CACHE_CB(&cache_info) +#endif + { NULL, NULL, NULL } + }; + + (void)nsdispatch(NULL, dtab, NSDB_RPC, "setrpcent", defaultsrc, + stayopen); +} + +void +endrpcent() +{ +#ifdef NS_CACHING + static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER( + rpc, (void *)nss_lt_all, + NULL, NULL); +#endif + + static const ns_dtab dtab[] = { + { NSSRC_FILES, files_setrpcent, (void *)ENDRPCENT }, +#ifdef YP + { NSSRC_NIS, nis_setrpcent, (void *)ENDRPCENT }, +#endif +#ifdef NS_CACHING + NS_CACHE_CB(&cache_info) +#endif + { NULL, NULL, NULL } + }; + + (void)nsdispatch(NULL, dtab, NSDB_RPC, "endrpcent", defaultsrc); +} diff --git a/freebsd/lib/libc/rpc/getrpcport.c b/freebsd/lib/libc/rpc/getrpcport.c new file mode 100644 index 00000000..161486dc --- /dev/null +++ b/freebsd/lib/libc/rpc/getrpcport.c @@ -0,0 +1,79 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: getrpcport.c,v 1.16 2000/01/22 22:19:18 mycroft Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *sccsid2 = "@(#)getrpcport.c 1.3 87/08/11 SMI"; +static char *sccsid = "@(#)getrpcport.c 2.1 88/07/29 4.0 RPCSRC"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Copyright (c) 1985 by Sun Microsystems, Inc. + */ + +#include "namespace.h" +#include <sys/types.h> +#include <sys/socket.h> + +#include <assert.h> +#include <netdb.h> +#include <stdio.h> +#include <string.h> + +#include <rpc/rpc.h> +#include <rpc/pmap_clnt.h> +#include "un-namespace.h" + +int +getrpcport(host, prognum, versnum, proto) + char *host; + int prognum, versnum, proto; +{ + struct sockaddr_in addr; + struct hostent *hp; + + assert(host != NULL); + + if ((hp = gethostbyname(host)) == NULL) + return (0); + memset(&addr, 0, sizeof(addr)); + addr.sin_len = sizeof(struct sockaddr_in); + addr.sin_family = AF_INET; + addr.sin_port = 0; + if (hp->h_length > addr.sin_len) + hp->h_length = addr.sin_len; + memcpy(&addr.sin_addr.s_addr, hp->h_addr, (size_t)hp->h_length); + /* Inconsistent interfaces need casts! :-( */ + return (pmap_getport(&addr, (u_long)prognum, (u_long)versnum, + (u_int)proto)); +} diff --git a/freebsd/lib/libc/rpc/key_call.c b/freebsd/lib/libc/rpc/key_call.c new file mode 100644 index 00000000..ba2a3835 --- /dev/null +++ b/freebsd/lib/libc/rpc/key_call.c @@ -0,0 +1,481 @@ +#include <machine/rtems-bsd-user-space.h> + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ + +#ident "@(#)key_call.c 1.25 94/04/24 SMI" +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * key_call.c, Interface to keyserver + * + * setsecretkey(key) - set your secret key + * encryptsessionkey(agent, deskey) - encrypt a session key to talk to agent + * decryptsessionkey(agent, deskey) - decrypt ditto + * gendeskey(deskey) - generate a secure des key + */ + +#include "namespace.h" +#include "reentrant.h" +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <rpc/rpc.h> +#include <rpc/auth.h> +#include <rpc/auth_unix.h> +#include <rpc/key_prot.h> +#include <string.h> +#include <netconfig.h> +#include <sys/utsname.h> +#include <stdlib.h> +#include <signal.h> +#include <sys/wait.h> +#include <sys/fcntl.h> +#include "un-namespace.h" +#include "mt_misc.h" + + +#define KEY_TIMEOUT 5 /* per-try timeout in seconds */ +#define KEY_NRETRY 12 /* number of retries */ + +#ifdef DEBUG +#define debug(msg) (void) fprintf(stderr, "%s\n", msg); +#else +#define debug(msg) +#endif /* DEBUG */ + +/* + * Hack to allow the keyserver to use AUTH_DES (for authenticated + * NIS+ calls, for example). The only functions that get called + * are key_encryptsession_pk, key_decryptsession_pk, and key_gendes. + * + * The approach is to have the keyserver fill in pointers to local + * implementations of these functions, and to call those in key_call(). + */ + +cryptkeyres *(*__key_encryptsession_pk_LOCAL)() = 0; +cryptkeyres *(*__key_decryptsession_pk_LOCAL)() = 0; +des_block *(*__key_gendes_LOCAL)() = 0; + +static int key_call( u_long, xdrproc_t, void *, xdrproc_t, void *); + +int +key_setsecret(secretkey) + const char *secretkey; +{ + keystatus status; + + if (!key_call((u_long) KEY_SET, (xdrproc_t)xdr_keybuf, + (void *)secretkey, + (xdrproc_t)xdr_keystatus, &status)) { + return (-1); + } + if (status != KEY_SUCCESS) { + debug("set status is nonzero"); + return (-1); + } + return (0); +} + + +/* key_secretkey_is_set() returns 1 if the keyserver has a secret key + * stored for the caller's effective uid; it returns 0 otherwise + * + * N.B.: The KEY_NET_GET key call is undocumented. Applications shouldn't + * be using it, because it allows them to get the user's secret key. + */ + +int +key_secretkey_is_set(void) +{ + struct key_netstres kres; + + memset((void*)&kres, 0, sizeof (kres)); + if (key_call((u_long) KEY_NET_GET, (xdrproc_t)xdr_void, NULL, + (xdrproc_t)xdr_key_netstres, &kres) && + (kres.status == KEY_SUCCESS) && + (kres.key_netstres_u.knet.st_priv_key[0] != 0)) { + /* avoid leaving secret key in memory */ + memset(kres.key_netstres_u.knet.st_priv_key, 0, HEXKEYBYTES); + return (1); + } + return (0); +} + +int +key_encryptsession_pk(remotename, remotekey, deskey) + char *remotename; + netobj *remotekey; + des_block *deskey; +{ + cryptkeyarg2 arg; + cryptkeyres res; + + arg.remotename = remotename; + arg.remotekey = *remotekey; + arg.deskey = *deskey; + if (!key_call((u_long)KEY_ENCRYPT_PK, (xdrproc_t)xdr_cryptkeyarg2, &arg, + (xdrproc_t)xdr_cryptkeyres, &res)) { + return (-1); + } + if (res.status != KEY_SUCCESS) { + debug("encrypt status is nonzero"); + return (-1); + } + *deskey = res.cryptkeyres_u.deskey; + return (0); +} + +int +key_decryptsession_pk(remotename, remotekey, deskey) + char *remotename; + netobj *remotekey; + des_block *deskey; +{ + cryptkeyarg2 arg; + cryptkeyres res; + + arg.remotename = remotename; + arg.remotekey = *remotekey; + arg.deskey = *deskey; + if (!key_call((u_long)KEY_DECRYPT_PK, (xdrproc_t)xdr_cryptkeyarg2, &arg, + (xdrproc_t)xdr_cryptkeyres, &res)) { + return (-1); + } + if (res.status != KEY_SUCCESS) { + debug("decrypt status is nonzero"); + return (-1); + } + *deskey = res.cryptkeyres_u.deskey; + return (0); +} + +int +key_encryptsession(remotename, deskey) + const char *remotename; + des_block *deskey; +{ + cryptkeyarg arg; + cryptkeyres res; + + arg.remotename = (char *) remotename; + arg.deskey = *deskey; + if (!key_call((u_long)KEY_ENCRYPT, (xdrproc_t)xdr_cryptkeyarg, &arg, + (xdrproc_t)xdr_cryptkeyres, &res)) { + return (-1); + } + if (res.status != KEY_SUCCESS) { + debug("encrypt status is nonzero"); + return (-1); + } + *deskey = res.cryptkeyres_u.deskey; + return (0); +} + +int +key_decryptsession(remotename, deskey) + const char *remotename; + des_block *deskey; +{ + cryptkeyarg arg; + cryptkeyres res; + + arg.remotename = (char *) remotename; + arg.deskey = *deskey; + if (!key_call((u_long)KEY_DECRYPT, (xdrproc_t)xdr_cryptkeyarg, &arg, + (xdrproc_t)xdr_cryptkeyres, &res)) { + return (-1); + } + if (res.status != KEY_SUCCESS) { + debug("decrypt status is nonzero"); + return (-1); + } + *deskey = res.cryptkeyres_u.deskey; + return (0); +} + +int +key_gendes(key) + des_block *key; +{ + if (!key_call((u_long)KEY_GEN, (xdrproc_t)xdr_void, NULL, + (xdrproc_t)xdr_des_block, key)) { + return (-1); + } + return (0); +} + +int +key_setnet(arg) +struct key_netstarg *arg; +{ + keystatus status; + + + if (!key_call((u_long) KEY_NET_PUT, (xdrproc_t)xdr_key_netstarg, arg, + (xdrproc_t)xdr_keystatus, &status)){ + return (-1); + } + + if (status != KEY_SUCCESS) { + debug("key_setnet status is nonzero"); + return (-1); + } + return (1); +} + + +int +key_get_conv(pkey, deskey) + char *pkey; + des_block *deskey; +{ + cryptkeyres res; + + if (!key_call((u_long) KEY_GET_CONV, (xdrproc_t)xdr_keybuf, pkey, + (xdrproc_t)xdr_cryptkeyres, &res)) { + return (-1); + } + if (res.status != KEY_SUCCESS) { + debug("get_conv status is nonzero"); + return (-1); + } + *deskey = res.cryptkeyres_u.deskey; + return (0); +} + +struct key_call_private { + CLIENT *client; /* Client handle */ + pid_t pid; /* process-id at moment of creation */ + uid_t uid; /* user-id at last authorization */ +}; +static struct key_call_private *key_call_private_main = NULL; +static thread_key_t key_call_key; +static once_t key_call_once = ONCE_INITIALIZER; +static int key_call_key_error; + +static void +key_call_destroy(void *vp) +{ + struct key_call_private *kcp = (struct key_call_private *)vp; + + if (kcp) { + if (kcp->client) + clnt_destroy(kcp->client); + free(kcp); + } +} + +static void +key_call_init(void) +{ + + key_call_key_error = thr_keycreate(&key_call_key, key_call_destroy); +} + +/* + * Keep the handle cached. This call may be made quite often. + */ +static CLIENT * +getkeyserv_handle(vers) +int vers; +{ + void *localhandle; + struct netconfig *nconf; + struct netconfig *tpconf; + struct key_call_private *kcp; + struct timeval wait_time; + struct utsname u; + int main_thread; + int fd; + +#define TOTAL_TIMEOUT 30 /* total timeout talking to keyserver */ +#define TOTAL_TRIES 5 /* Number of tries */ + + if ((main_thread = thr_main())) { + kcp = key_call_private_main; + } else { + if (thr_once(&key_call_once, key_call_init) != 0 || + key_call_key_error != 0) + return ((CLIENT *) NULL); + kcp = (struct key_call_private *)thr_getspecific(key_call_key); + } + if (kcp == (struct key_call_private *)NULL) { + kcp = (struct key_call_private *)malloc(sizeof (*kcp)); + if (kcp == (struct key_call_private *)NULL) { + return ((CLIENT *) NULL); + } + if (main_thread) + key_call_private_main = kcp; + else + thr_setspecific(key_call_key, (void *) kcp); + kcp->client = NULL; + } + + /* if pid has changed, destroy client and rebuild */ + if (kcp->client != NULL && kcp->pid != getpid()) { + clnt_destroy(kcp->client); + kcp->client = NULL; + } + + if (kcp->client != NULL) { + /* if uid has changed, build client handle again */ + if (kcp->uid != geteuid()) { + kcp->uid = geteuid(); + auth_destroy(kcp->client->cl_auth); + kcp->client->cl_auth = + authsys_create("", kcp->uid, 0, 0, NULL); + if (kcp->client->cl_auth == NULL) { + clnt_destroy(kcp->client); + kcp->client = NULL; + return ((CLIENT *) NULL); + } + } + /* Change the version number to the new one */ + clnt_control(kcp->client, CLSET_VERS, (void *)&vers); + return (kcp->client); + } + if (!(localhandle = setnetconfig())) { + return ((CLIENT *) NULL); + } + tpconf = NULL; +#if defined(__FreeBSD__) + if (uname(&u) == -1) +#else +#if defined(i386) + if (_nuname(&u) == -1) +#elif defined(sparc) + if (_uname(&u) == -1) +#else +#error Unknown architecture! +#endif +#endif + { + endnetconfig(localhandle); + return ((CLIENT *) NULL); + } + while ((nconf = getnetconfig(localhandle)) != NULL) { + if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) { + /* + * We use COTS_ORD here so that the caller can + * find out immediately if the server is dead. + */ + if (nconf->nc_semantics == NC_TPI_COTS_ORD) { + kcp->client = clnt_tp_create(u.nodename, + KEY_PROG, vers, nconf); + if (kcp->client) + break; + } else { + tpconf = nconf; + } + } + } + if ((kcp->client == (CLIENT *) NULL) && (tpconf)) + /* Now, try the CLTS or COTS loopback transport */ + kcp->client = clnt_tp_create(u.nodename, + KEY_PROG, vers, tpconf); + endnetconfig(localhandle); + + if (kcp->client == (CLIENT *) NULL) { + return ((CLIENT *) NULL); + } + kcp->uid = geteuid(); + kcp->pid = getpid(); + kcp->client->cl_auth = authsys_create("", kcp->uid, 0, 0, NULL); + if (kcp->client->cl_auth == NULL) { + clnt_destroy(kcp->client); + kcp->client = NULL; + return ((CLIENT *) NULL); + } + + wait_time.tv_sec = TOTAL_TIMEOUT/TOTAL_TRIES; + wait_time.tv_usec = 0; + (void) clnt_control(kcp->client, CLSET_RETRY_TIMEOUT, + (char *)&wait_time); + if (clnt_control(kcp->client, CLGET_FD, (char *)&fd)) + _fcntl(fd, F_SETFD, 1); /* make it "close on exec" */ + + return (kcp->client); +} + +/* returns 0 on failure, 1 on success */ + +static int +key_call(proc, xdr_arg, arg, xdr_rslt, rslt) + u_long proc; + xdrproc_t xdr_arg; + void *arg; + xdrproc_t xdr_rslt; + void *rslt; +{ + CLIENT *clnt; + struct timeval wait_time; + + if (proc == KEY_ENCRYPT_PK && __key_encryptsession_pk_LOCAL) { + cryptkeyres *res; + res = (*__key_encryptsession_pk_LOCAL)(geteuid(), arg); + *(cryptkeyres*)rslt = *res; + return (1); + } else if (proc == KEY_DECRYPT_PK && __key_decryptsession_pk_LOCAL) { + cryptkeyres *res; + res = (*__key_decryptsession_pk_LOCAL)(geteuid(), arg); + *(cryptkeyres*)rslt = *res; + return (1); + } else if (proc == KEY_GEN && __key_gendes_LOCAL) { + des_block *res; + res = (*__key_gendes_LOCAL)(geteuid(), 0); + *(des_block*)rslt = *res; + return (1); + } + + if ((proc == KEY_ENCRYPT_PK) || (proc == KEY_DECRYPT_PK) || + (proc == KEY_NET_GET) || (proc == KEY_NET_PUT) || + (proc == KEY_GET_CONV)) + clnt = getkeyserv_handle(2); /* talk to version 2 */ + else + clnt = getkeyserv_handle(1); /* talk to version 1 */ + + if (clnt == NULL) { + return (0); + } + + wait_time.tv_sec = TOTAL_TIMEOUT; + wait_time.tv_usec = 0; + + if (clnt_call(clnt, proc, xdr_arg, arg, xdr_rslt, rslt, + wait_time) == RPC_SUCCESS) { + return (1); + } else { + return (0); + } +} diff --git a/freebsd/lib/libc/rpc/key_prot_xdr.c b/freebsd/lib/libc/rpc/key_prot_xdr.c new file mode 100644 index 00000000..ee045587 --- /dev/null +++ b/freebsd/lib/libc/rpc/key_prot_xdr.c @@ -0,0 +1,179 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#include "namespace.h" +#include <rpc/key_prot.h> +#include "un-namespace.h" +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* Copyright (c) 1990, 1991 Sun Microsystems, Inc. */ + +/* #pragma ident "@(#)key_prot.x 1.7 94/04/29 SMI" */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Compiled from key_prot.x using rpcgen. + * DO NOT EDIT THIS FILE! + * This is NOT source code! + */ + +bool_t +xdr_keystatus(register XDR *xdrs, keystatus *objp) +{ + + if (!xdr_enum(xdrs, (enum_t *)objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_keybuf(register XDR *xdrs, keybuf objp) +{ + + if (!xdr_opaque(xdrs, objp, HEXKEYBYTES)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_netnamestr(register XDR *xdrs, netnamestr *objp) +{ + + if (!xdr_string(xdrs, objp, MAXNETNAMELEN)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_cryptkeyarg(register XDR *xdrs, cryptkeyarg *objp) +{ + + if (!xdr_netnamestr(xdrs, &objp->remotename)) + return (FALSE); + if (!xdr_des_block(xdrs, &objp->deskey)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_cryptkeyarg2(register XDR *xdrs, cryptkeyarg2 *objp) +{ + + if (!xdr_netnamestr(xdrs, &objp->remotename)) + return (FALSE); + if (!xdr_netobj(xdrs, &objp->remotekey)) + return (FALSE); + if (!xdr_des_block(xdrs, &objp->deskey)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_cryptkeyres(register XDR *xdrs, cryptkeyres *objp) +{ + + if (!xdr_keystatus(xdrs, &objp->status)) + return (FALSE); + switch (objp->status) { + case KEY_SUCCESS: + if (!xdr_des_block(xdrs, &objp->cryptkeyres_u.deskey)) + return (FALSE); + break; + default: + break; + } + return (TRUE); +} + +bool_t +xdr_unixcred(register XDR *xdrs, unixcred *objp) +{ + u_int **pgids_val; + + if (!xdr_u_int(xdrs, &objp->uid)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->gid)) + return (FALSE); + pgids_val = &objp->gids.gids_val; + if (!xdr_array(xdrs, (char **) pgids_val, (u_int *) &objp->gids.gids_len, MAXGIDS, + sizeof (u_int), (xdrproc_t) xdr_u_int)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_getcredres(register XDR *xdrs, getcredres *objp) +{ + + if (!xdr_keystatus(xdrs, &objp->status)) + return (FALSE); + switch (objp->status) { + case KEY_SUCCESS: + if (!xdr_unixcred(xdrs, &objp->getcredres_u.cred)) + return (FALSE); + break; + default: + break; + } + return (TRUE); +} + +bool_t +xdr_key_netstarg(register XDR *xdrs, key_netstarg *objp) +{ + + if (!xdr_keybuf(xdrs, objp->st_priv_key)) + return (FALSE); + if (!xdr_keybuf(xdrs, objp->st_pub_key)) + return (FALSE); + if (!xdr_netnamestr(xdrs, &objp->st_netname)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_key_netstres(register XDR *xdrs, key_netstres *objp) +{ + + if (!xdr_keystatus(xdrs, &objp->status)) + return (FALSE); + switch (objp->status) { + case KEY_SUCCESS: + if (!xdr_key_netstarg(xdrs, &objp->key_netstres_u.knet)) + return (FALSE); + break; + default: + break; + } + return (TRUE); +} diff --git a/freebsd/lib/libc/rpc/mt_misc.c b/freebsd/lib/libc/rpc/mt_misc.c new file mode 100644 index 00000000..b494bef7 --- /dev/null +++ b/freebsd/lib/libc/rpc/mt_misc.c @@ -0,0 +1,119 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: mt_misc.c,v 1.1 2000/06/02 23:11:11 fvdl Exp $ */ + +/* #pragma ident "@(#)mt_misc.c 1.24 93/04/29 SMI" */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "namespace.h" +#include "reentrant.h" +#include <rpc/rpc.h> +#include <sys/time.h> +#include <stdlib.h> +#include <string.h> +#include "un-namespace.h" +#include "mt_misc.h" + +/* Take these objects out of the application namespace. */ +#define svc_lock __svc_lock +#define svc_fd_lock __svc_fd_lock +#define rpcbaddr_cache_lock __rpcbaddr_cache_lock +#define authdes_ops_lock __authdes_ops_lock +#define authnone_lock __authnone_lock +#define authsvc_lock __authsvc_lock +#define clnt_fd_lock __clnt_fd_lock +#define clntraw_lock __clntraw_lock +#define dupreq_lock __dupreq_lock +#define loopnconf_lock __loopnconf_lock +#define ops_lock __ops_lock +#define proglst_lock __proglst_lock +#define rpcsoc_lock __rpcsoc_lock +#define svcraw_lock __svcraw_lock +#define xprtlist_lock __xprtlist_lock + +/* protects the services list (svc.c) */ +pthread_rwlock_t svc_lock = PTHREAD_RWLOCK_INITIALIZER; + +/* protects svc_fdset and the xports[] array */ +pthread_rwlock_t svc_fd_lock = PTHREAD_RWLOCK_INITIALIZER; + +/* protects the RPCBIND address cache */ +pthread_rwlock_t rpcbaddr_cache_lock = PTHREAD_RWLOCK_INITIALIZER; + +/* serializes authdes ops initializations */ +pthread_mutex_t authdes_ops_lock = PTHREAD_MUTEX_INITIALIZER; + +/* protects des stats list */ +pthread_mutex_t svcauthdesstats_lock = PTHREAD_MUTEX_INITIALIZER; + +/* auth_none.c serialization */ +pthread_mutex_t authnone_lock = PTHREAD_MUTEX_INITIALIZER; + +/* protects the Auths list (svc_auth.c) */ +pthread_mutex_t authsvc_lock = PTHREAD_MUTEX_INITIALIZER; + +/* protects client-side fd lock array */ +pthread_mutex_t clnt_fd_lock = PTHREAD_MUTEX_INITIALIZER; + +/* clnt_raw.c serialization */ +pthread_mutex_t clntraw_lock = PTHREAD_MUTEX_INITIALIZER; + +/* dupreq variables (svc_dg.c) */ +pthread_mutex_t dupreq_lock = PTHREAD_MUTEX_INITIALIZER; + +/* loopnconf (rpcb_clnt.c) */ +pthread_mutex_t loopnconf_lock = PTHREAD_MUTEX_INITIALIZER; + +/* serializes ops initializations */ +pthread_mutex_t ops_lock = PTHREAD_MUTEX_INITIALIZER; + +/* protects proglst list (svc_simple.c) */ +pthread_mutex_t proglst_lock = PTHREAD_MUTEX_INITIALIZER; + +/* serializes clnt_com_create() (rpc_soc.c) */ +pthread_mutex_t rpcsoc_lock = PTHREAD_MUTEX_INITIALIZER; + +/* svc_raw.c serialization */ +pthread_mutex_t svcraw_lock = PTHREAD_MUTEX_INITIALIZER; + +/* xprtlist (svc_generic.c) */ +pthread_mutex_t xprtlist_lock = PTHREAD_MUTEX_INITIALIZER; + +#undef rpc_createerr + +struct rpc_createerr rpc_createerr; +static thread_key_t rce_key; +static once_t rce_once = ONCE_INITIALIZER; +static int rce_key_error; + +static void +rce_key_init(void) +{ + + rce_key_error = thr_keycreate(&rce_key, free); +} + +struct rpc_createerr * +__rpc_createerr() +{ + struct rpc_createerr *rce_addr = 0; + + if (thr_main()) + return (&rpc_createerr); + if (thr_once(&rce_once, rce_key_init) != 0 || rce_key_error != 0) + return (&rpc_createerr); + rce_addr = (struct rpc_createerr *)thr_getspecific(rce_key); + if (!rce_addr) { + rce_addr = (struct rpc_createerr *) + malloc(sizeof (struct rpc_createerr)); + if (thr_setspecific(rce_key, (void *) rce_addr) != 0) { + if (rce_addr) + free(rce_addr); + return (&rpc_createerr); + } + memset(rce_addr, 0, sizeof (struct rpc_createerr)); + return (rce_addr); + } + return (rce_addr); +} diff --git a/freebsd/lib/libc/rpc/mt_misc.h b/freebsd/lib/libc/rpc/mt_misc.h new file mode 100644 index 00000000..9cc2349c --- /dev/null +++ b/freebsd/lib/libc/rpc/mt_misc.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2006 The FreeBSD Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ +#ifndef _MT_MISC_H +#define _MT_MISC_H + +/* Take these locks out of the application namespace. */ +#define svc_lock __svc_lock +#define svc_fd_lock __svc_fd_lock +#define rpcbaddr_cache_lock __rpcbaddr_cache_lock +#define authdes_ops_lock __authdes_ops_lock +#define authnone_lock __authnone_lock +#define authsvc_lock __authsvc_lock +#define clnt_fd_lock __clnt_fd_lock +#define clntraw_lock __clntraw_lock +#define dupreq_lock __dupreq_lock +#define loopnconf_lock __loopnconf_lock +#define ops_lock __ops_lock +#define proglst_lock __proglst_lock +#define rpcsoc_lock __rpcsoc_lock +#define svcraw_lock __svcraw_lock +#define xprtlist_lock __xprtlist_lock + +extern pthread_rwlock_t svc_lock; +extern pthread_rwlock_t svc_fd_lock; +extern pthread_rwlock_t rpcbaddr_cache_lock; +extern pthread_mutex_t authdes_ops_lock; +extern pthread_mutex_t svcauthdesstats_lock; +extern pthread_mutex_t authnone_lock; +extern pthread_mutex_t authsvc_lock; +extern pthread_mutex_t clnt_fd_lock; +extern pthread_mutex_t clntraw_lock; +extern pthread_mutex_t dupreq_lock; +extern pthread_mutex_t loopnconf_lock; +extern pthread_mutex_t ops_lock; +extern pthread_mutex_t proglst_lock; +extern pthread_mutex_t rpcsoc_lock; +extern pthread_mutex_t svcraw_lock; +extern pthread_mutex_t tsd_lock; +extern pthread_mutex_t xprtlist_lock; + +#endif diff --git a/freebsd/lib/libc/rpc/netname.c b/freebsd/lib/libc/rpc/netname.c new file mode 100644 index 00000000..d992c05d --- /dev/null +++ b/freebsd/lib/libc/rpc/netname.c @@ -0,0 +1,150 @@ +#include <machine/rtems-bsd-user-space.h> + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)netname.c 1.8 91/03/11 Copyr 1986 Sun Micro"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * netname utility routines + * convert from unix names to network names and vice-versa + * This module is operating system dependent! + * What we define here will work with any unix system that has adopted + * the sun NIS domain architecture. + */ + +#include "namespace.h" +#include <rtems/bsd/sys/param.h> +#include <rpc/rpc.h> +#include <rpc/rpc_com.h> +#ifdef YP +#include <rpcsvc/yp_prot.h> +#include <rpcsvc/ypclnt.h> +#endif +#include <ctype.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "un-namespace.h" + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 256 +#endif + +#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT) + +#define TYPE_SIGNED(type) (((type) -1) < 0) + +/* +** 302 / 1000 is log10(2.0) rounded up. +** Subtract one for the sign bit if the type is signed; +** add one for integer division truncation; +** add one more for a minus sign if the type is signed. +*/ +#define INT_STRLEN_MAXIMUM(type) \ + ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + 1 + TYPE_SIGNED(type)) + +static char *OPSYS = "unix"; + +/* + * Figure out my fully qualified network name + */ +int +getnetname(name) + char name[MAXNETNAMELEN+1]; +{ + uid_t uid; + + uid = geteuid(); + if (uid == 0) { + return (host2netname(name, (char *) NULL, (char *) NULL)); + } else { + return (user2netname(name, uid, (char *) NULL)); + } +} + + +/* + * Convert unix cred to network-name + */ +int +user2netname(netname, uid, domain) + char netname[MAXNETNAMELEN + 1]; + const uid_t uid; + const char *domain; +{ + char *dfltdom; + + if (domain == NULL) { + if (__rpc_get_default_domain(&dfltdom) != 0) { + return (0); + } + domain = dfltdom; + } + if (strlen(domain) + 1 + INT_STRLEN_MAXIMUM(u_long) + 1 + strlen(OPSYS) > MAXNETNAMELEN) { + return (0); + } + (void) sprintf(netname, "%s.%ld@%s", OPSYS, (u_long)uid, domain); + return (1); +} + + +/* + * Convert host to network-name + */ +int +host2netname(netname, host, domain) + char netname[MAXNETNAMELEN + 1]; + const char *host; + const char *domain; +{ + char *dfltdom; + char hostname[MAXHOSTNAMELEN+1]; + + if (domain == NULL) { + if (__rpc_get_default_domain(&dfltdom) != 0) { + return (0); + } + domain = dfltdom; + } + if (host == NULL) { + (void) gethostname(hostname, sizeof(hostname)); + host = hostname; + } + if (strlen(domain) + 1 + strlen(host) + 1 + strlen(OPSYS) > MAXNETNAMELEN) { + return (0); + } + (void) sprintf(netname, "%s.%s@%s", OPSYS, host, domain); + return (1); +} diff --git a/freebsd/lib/libc/rpc/netnamer.c b/freebsd/lib/libc/rpc/netnamer.c new file mode 100644 index 00000000..dd09c257 --- /dev/null +++ b/freebsd/lib/libc/rpc/netnamer.c @@ -0,0 +1,331 @@ +#include <machine/rtems-bsd-user-space.h> + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)netnamer.c 1.13 91/03/11 Copyr 1986 Sun Micro"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * netname utility routines convert from unix names to network names and + * vice-versa This module is operating system dependent! What we define here + * will work with any unix system that has adopted the sun NIS domain + * architecture. + */ +#include "namespace.h" +#include <rtems/bsd/sys/param.h> +#include <rpc/rpc.h> +#include <rpc/rpc_com.h> +#ifdef YP +#include <rpcsvc/yp_prot.h> +#include <rpcsvc/ypclnt.h> +#endif +#include <ctype.h> +#include <stdio.h> +#include <grp.h> +#include <pwd.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include "un-namespace.h" + +static char *OPSYS = "unix"; +#ifdef YP +static char *NETID = "netid.byname"; +#endif +static char *NETIDFILE = "/etc/netid"; + +static int getnetid( char *, char * ); +static int _getgroups( char *, gid_t * ); + +/* + * Convert network-name into unix credential + */ +int +netname2user(netname, uidp, gidp, gidlenp, gidlist) + char netname[MAXNETNAMELEN + 1]; + uid_t *uidp; + gid_t *gidp; + int *gidlenp; + gid_t *gidlist; +{ + char *p; + int gidlen; + uid_t uid; + long luid; + struct passwd *pwd; + char val[1024]; + char *val1, *val2; + char *domain; + int vallen; + int err; + + if (getnetid(netname, val)) { + char *res = val; + + p = strsep(&res, ":"); + if (p == NULL) + return (0); + *uidp = (uid_t) atol(p); + p = strsep(&res, "\n,"); + if (p == NULL) { + return (0); + } + *gidp = (gid_t) atol(p); + for (gidlen = 0; gidlen < NGRPS; gidlen++) { + p = strsep(&res, "\n,"); + if (p == NULL) + break; + gidlist[gidlen] = (gid_t) atol(p); + } + *gidlenp = gidlen; + + return (1); + } + val1 = strchr(netname, '.'); + if (val1 == NULL) + return (0); + if (strncmp(netname, OPSYS, (val1-netname))) + return (0); + val1++; + val2 = strchr(val1, '@'); + if (val2 == NULL) + return (0); + vallen = val2 - val1; + if (vallen > (1024 - 1)) + vallen = 1024 - 1; + (void) strncpy(val, val1, 1024); + val[vallen] = 0; + + err = __rpc_get_default_domain(&domain); /* change to rpc */ + if (err) + return (0); + + if (strcmp(val2 + 1, domain)) + return (0); /* wrong domain */ + + if (sscanf(val, "%ld", &luid) != 1) + return (0); + uid = luid; + + /* use initgroups method */ + pwd = getpwuid(uid); + if (pwd == NULL) + return (0); + *uidp = pwd->pw_uid; + *gidp = pwd->pw_gid; + *gidlenp = _getgroups(pwd->pw_name, gidlist); + return (1); +} + +/* + * initgroups + */ + +static int +_getgroups(uname, groups) + char *uname; + gid_t groups[NGRPS]; +{ + gid_t ngroups = 0; + struct group *grp; + int i; + int j; + int filter; + + setgrent(); + while ((grp = getgrent())) { + for (i = 0; grp->gr_mem[i]; i++) + if (!strcmp(grp->gr_mem[i], uname)) { + if (ngroups == NGRPS) { +#ifdef DEBUG + fprintf(stderr, + "initgroups: %s is in too many groups\n", uname); +#endif + goto toomany; + } + /* filter out duplicate group entries */ + filter = 0; + for (j = 0; j < ngroups; j++) + if (groups[j] == grp->gr_gid) { + filter++; + break; + } + if (!filter) + groups[ngroups++] = grp->gr_gid; + } + } +toomany: + endgrent(); + return (ngroups); +} + +/* + * Convert network-name to hostname + */ +int +netname2host(netname, hostname, hostlen) + char netname[MAXNETNAMELEN + 1]; + char *hostname; + int hostlen; +{ + int err; + char valbuf[1024]; + char *val; + char *val2; + int vallen; + char *domain; + + if (getnetid(netname, valbuf)) { + val = valbuf; + if ((*val == '0') && (val[1] == ':')) { + (void) strncpy(hostname, val + 2, hostlen); + return (1); + } + } + val = strchr(netname, '.'); + if (val == NULL) + return (0); + if (strncmp(netname, OPSYS, (val - netname))) + return (0); + val++; + val2 = strchr(val, '@'); + if (val2 == NULL) + return (0); + vallen = val2 - val; + if (vallen > (hostlen - 1)) + vallen = hostlen - 1; + (void) strncpy(hostname, val, vallen); + hostname[vallen] = 0; + + err = __rpc_get_default_domain(&domain); /* change to rpc */ + if (err) + return (0); + + if (strcmp(val2 + 1, domain)) + return (0); /* wrong domain */ + else + return (1); +} + +/* + * reads the file /etc/netid looking for a + to optionally go to the + * network information service. + */ +int +getnetid(key, ret) + char *key, *ret; +{ + char buf[1024]; /* big enough */ + char *res; + char *mkey; + char *mval; + FILE *fd; +#ifdef YP + char *domain; + int err; + char *lookup; + int len; +#endif + + fd = fopen(NETIDFILE, "r"); + if (fd == NULL) { +#ifdef YP + res = "+"; + goto getnetidyp; +#else + return (0); +#endif + } + for (;;) { + if (fd == NULL) + return (0); /* getnetidyp brings us here */ + res = fgets(buf, sizeof(buf), fd); + if (res == NULL) { + fclose(fd); + return (0); + } + if (res[0] == '#') + continue; + else if (res[0] == '+') { +#ifdef YP + getnetidyp: + err = yp_get_default_domain(&domain); + if (err) { + continue; + } + lookup = NULL; + err = yp_match(domain, NETID, key, + strlen(key), &lookup, &len); + if (err) { +#ifdef DEBUG + fprintf(stderr, "match failed error %d\n", err); +#endif + continue; + } + lookup[len] = 0; + strcpy(ret, lookup); + free(lookup); + if (fd != NULL) + fclose(fd); + return (2); +#else /* YP */ +#ifdef DEBUG + fprintf(stderr, +"Bad record in %s '+' -- NIS not supported in this library copy\n", + NETIDFILE); +#endif + continue; +#endif /* YP */ + } else { + mkey = strsep(&res, "\t "); + if (mkey == NULL) { + fprintf(stderr, + "Bad record in %s -- %s", NETIDFILE, buf); + continue; + } + do { + mval = strsep(&res, " \t#\n"); + } while (mval != NULL && !*mval); + if (mval == NULL) { + fprintf(stderr, + "Bad record in %s val problem - %s", NETIDFILE, buf); + continue; + } + if (strcmp(mkey, key) == 0) { + strcpy(ret, mval); + fclose(fd); + return (1); + + } + } + } +} diff --git a/freebsd/lib/libc/rpc/pmap_clnt.c b/freebsd/lib/libc/rpc/pmap_clnt.c new file mode 100644 index 00000000..c3eadbc2 --- /dev/null +++ b/freebsd/lib/libc/rpc/pmap_clnt.c @@ -0,0 +1,121 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: pmap_clnt.c,v 1.16 2000/07/06 03:10:34 christos Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *sccsid2 = "@(#)pmap_clnt.c 1.37 87/08/11 Copyr 1984 Sun Micro"; +static char *sccsid = "@(#)pmap_clnt.c 2.2 88/08/01 4.0 RPCSRC"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * pmap_clnt.c + * Client interface to pmap rpc service. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include "namespace.h" +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +#include <rpc/rpc.h> +#include <rpc/pmap_prot.h> +#include <rpc/pmap_clnt.h> +#include <rpc/nettype.h> +#include <netinet/in.h> +#include "un-namespace.h" + +#include <stdio.h> +#include <stdlib.h> + +#include "rpc_com.h" + +bool_t +pmap_set(u_long program, u_long version, int protocol, int port) +{ + bool_t rslt; + struct netbuf *na; + struct netconfig *nconf; + char buf[32]; + + if ((protocol != IPPROTO_UDP) && (protocol != IPPROTO_TCP)) { + return (FALSE); + } + nconf = __rpc_getconfip(protocol == IPPROTO_UDP ? "udp" : "tcp"); + if (nconf == NULL) { + return (FALSE); + } + snprintf(buf, sizeof buf, "0.0.0.0.%d.%d", + (((u_int32_t)port) >> 8) & 0xff, port & 0xff); + na = uaddr2taddr(nconf, buf); + if (na == NULL) { + freenetconfigent(nconf); + return (FALSE); + } + rslt = rpcb_set((rpcprog_t)program, (rpcvers_t)version, nconf, na); + free(na); + freenetconfigent(nconf); + return (rslt); +} + +/* + * Remove the mapping between program, version and port. + * Calls the pmap service remotely to do the un-mapping. + */ +bool_t +pmap_unset(u_long program, u_long version) +{ + struct netconfig *nconf; + bool_t udp_rslt = FALSE; + bool_t tcp_rslt = FALSE; + + nconf = __rpc_getconfip("udp"); + if (nconf != NULL) { + udp_rslt = rpcb_unset((rpcprog_t)program, (rpcvers_t)version, + nconf); + freenetconfigent(nconf); + } + nconf = __rpc_getconfip("tcp"); + if (nconf != NULL) { + tcp_rslt = rpcb_unset((rpcprog_t)program, (rpcvers_t)version, + nconf); + freenetconfigent(nconf); + } + /* + * XXX: The call may still succeed even if only one of the + * calls succeeded. This was the best that could be + * done for backward compatibility. + */ + return (tcp_rslt || udp_rslt); +} diff --git a/freebsd/lib/libc/rpc/pmap_getmaps.c b/freebsd/lib/libc/rpc/pmap_getmaps.c new file mode 100644 index 00000000..7c35ff26 --- /dev/null +++ b/freebsd/lib/libc/rpc/pmap_getmaps.c @@ -0,0 +1,101 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: pmap_getmaps.c,v 1.16 2000/07/06 03:10:34 christos Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *sccsid2 = "@(#)pmap_getmaps.c 1.10 87/08/11 Copyr 1984 Sun Micro"; +static char *sccsid = "@(#)pmap_getmaps.c 2.2 88/08/01 4.0 RPCSRC"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * 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 "namespace.h" +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/ioctl.h> + +#include <arpa/inet.h> +#include <net/if.h> + +#include <assert.h> +#include <errno.h> +#include <netdb.h> +#include <stdio.h> +#include <unistd.h> + +#include <rpc/rpc.h> +#include <rpc/pmap_prot.h> +#include <rpc/pmap_clnt.h> +#include "un-namespace.h" + +#define NAMELEN 255 +#define MAX_BROADCAST_SIZE 1400 + +/* + * Get a copy of the current port maps. + * Calls the pmap service remotely to do get the maps. + */ +struct pmaplist * +pmap_getmaps(address) + struct sockaddr_in *address; +{ + struct pmaplist *head = NULL; + int sock = -1; + struct timeval minutetimeout; + CLIENT *client; + + assert(address != NULL); + + minutetimeout.tv_sec = 60; + minutetimeout.tv_usec = 0; + address->sin_port = htons(PMAPPORT); + client = clnttcp_create(address, PMAPPROG, + PMAPVERS, &sock, 50, 500); + if (client != NULL) { + if (CLNT_CALL(client, (rpcproc_t)PMAPPROC_DUMP, + (xdrproc_t)xdr_void, NULL, + (xdrproc_t)xdr_pmaplist, &head, minutetimeout) != + RPC_SUCCESS) { + clnt_perror(client, "pmap_getmaps rpc problem"); + } + CLNT_DESTROY(client); + } + address->sin_port = 0; + return (head); +} diff --git a/freebsd/lib/libc/rpc/pmap_getport.c b/freebsd/lib/libc/rpc/pmap_getport.c new file mode 100644 index 00000000..7b6c4818 --- /dev/null +++ b/freebsd/lib/libc/rpc/pmap_getport.c @@ -0,0 +1,105 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: pmap_getport.c,v 1.16 2000/07/06 03:10:34 christos Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *sccsid2 = "from: @(#)pmap_getport.c 1.9 87/08/11 Copyr 1984 Sun Micro"; +static char *sccsid = "from: @(#)pmap_getport.c 2.2 88/08/01 4.0 RPCSRC"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * pmap_getport.c + * Client interface to pmap rpc service. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include "namespace.h" +#include <sys/types.h> +#include <sys/socket.h> + +#include <arpa/inet.h> +#include <net/if.h> + +#include <assert.h> +#include <unistd.h> + +#include <rpc/rpc.h> +#include <rpc/pmap_prot.h> +#include <rpc/pmap_clnt.h> +#include "un-namespace.h" + +static const struct timeval timeout = { 5, 0 }; +static const struct timeval tottimeout = { 60, 0 }; + +/* + * Find the mapped port for program,version. + * Calls the pmap service remotely to do the lookup. + * Returns 0 if no map exists. + */ +u_short +pmap_getport(address, program, version, protocol) + struct sockaddr_in *address; + u_long program; + u_long version; + u_int protocol; +{ + u_short port = 0; + int sock = -1; + CLIENT *client; + struct pmap parms; + + assert(address != NULL); + + address->sin_port = htons(PMAPPORT); + client = clntudp_bufcreate(address, PMAPPROG, + PMAPVERS, timeout, &sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE); + if (client != NULL) { + parms.pm_prog = program; + parms.pm_vers = version; + parms.pm_prot = protocol; + parms.pm_port = 0; /* not needed or used */ + if (CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT, + (xdrproc_t)xdr_pmap, + &parms, (xdrproc_t)xdr_u_short, &port, tottimeout) != + RPC_SUCCESS){ + rpc_createerr.cf_stat = RPC_PMAPFAILURE; + clnt_geterr(client, &rpc_createerr.cf_error); + } else if (port == 0) { + rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; + } + CLNT_DESTROY(client); + } + address->sin_port = 0; + return (port); +} diff --git a/freebsd/lib/libc/rpc/pmap_prot.c b/freebsd/lib/libc/rpc/pmap_prot.c new file mode 100644 index 00000000..121af17a --- /dev/null +++ b/freebsd/lib/libc/rpc/pmap_prot.c @@ -0,0 +1,70 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: pmap_prot.c,v 1.10 2000/01/22 22:19:18 mycroft Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *sccsid2 = "@(#)pmap_prot.c 1.17 87/08/11 Copyr 1984 Sun Micro"; +static char *sccsid = "@(#)pmap_prot.c 2.1 88/07/29 4.0 RPCSRC"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * pmap_prot.c + * Protocol for the local binder service, or pmap. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include "namespace.h" +#include <assert.h> + +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <rpc/pmap_prot.h> +#include "un-namespace.h" + + +bool_t +xdr_pmap(xdrs, regs) + XDR *xdrs; + struct pmap *regs; +{ + + assert(xdrs != NULL); + assert(regs != NULL); + + if (xdr_u_long(xdrs, ®s->pm_prog) && + xdr_u_long(xdrs, ®s->pm_vers) && + xdr_u_long(xdrs, ®s->pm_prot)) + return (xdr_u_long(xdrs, ®s->pm_port)); + return (FALSE); +} diff --git a/freebsd/lib/libc/rpc/pmap_prot2.c b/freebsd/lib/libc/rpc/pmap_prot2.c new file mode 100644 index 00000000..9a50dfa7 --- /dev/null +++ b/freebsd/lib/libc/rpc/pmap_prot2.c @@ -0,0 +1,144 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: pmap_prot2.c,v 1.14 2000/07/06 03:10:34 christos Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *sccsid2 = "@(#)pmap_prot2.c 1.3 87/08/11 Copyr 1984 Sun Micro"; +static char *sccsid = "@(#)pmap_prot2.c 2.1 88/07/29 4.0 RPCSRC"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * pmap_prot2.c + * Protocol for the local binder service, or pmap. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include "namespace.h" +#include <assert.h> + +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <rpc/pmap_prot.h> +#include "un-namespace.h" + + +/* + * What is going on with linked lists? (!) + * First recall the link list declaration from pmap_prot.h: + * + * struct pmaplist { + * struct pmap pml_map; + * struct pmaplist *pml_map; + * }; + * + * Compare that declaration with a corresponding xdr declaration that + * is (a) pointer-less, and (b) recursive: + * + * typedef union switch (bool_t) { + * + * case TRUE: struct { + * struct pmap; + * pmaplist_t foo; + * }; + * + * case FALSE: struct {}; + * } pmaplist_t; + * + * Notice that the xdr declaration has no nxt pointer while + * the C declaration has no bool_t variable. The bool_t can be + * interpreted as ``more data follows me''; if FALSE then nothing + * follows this bool_t; if TRUE then the bool_t is followed by + * an actual struct pmap, and then (recursively) by the + * xdr union, pamplist_t. + * + * This could be implemented via the xdr_union primitive, though this + * would cause a one recursive call per element in the list. Rather than do + * that we can ``unwind'' the recursion + * into a while loop and do the union arms in-place. + * + * The head of the list is what the C programmer wishes to past around + * the net, yet is the data that the pointer points to which is interesting; + * this sounds like a job for xdr_reference! + */ +bool_t +xdr_pmaplist(xdrs, rp) + XDR *xdrs; + struct pmaplist **rp; +{ + /* + * more_elements is pre-computed in case the direction is + * XDR_ENCODE or XDR_FREE. more_elements is overwritten by + * xdr_bool when the direction is XDR_DECODE. + */ + bool_t more_elements; + int freeing; + struct pmaplist **next = NULL; /* pacify gcc */ + + assert(xdrs != NULL); + assert(rp != NULL); + + freeing = (xdrs->x_op == XDR_FREE); + + for (;;) { + more_elements = (bool_t)(*rp != NULL); + if (! xdr_bool(xdrs, &more_elements)) + return (FALSE); + if (! more_elements) + return (TRUE); /* we are done */ + /* + * the unfortunate side effect of non-recursion is that in + * the case of freeing we must remember the next object + * before we free the current object ... + */ + if (freeing) + next = &((*rp)->pml_next); + if (! xdr_reference(xdrs, (caddr_t *)rp, + (u_int)sizeof(struct pmaplist), (xdrproc_t)xdr_pmap)) + return (FALSE); + rp = (freeing) ? next : &((*rp)->pml_next); + } +} + + +/* + * xdr_pmaplist_ptr() is specified to take a PMAPLIST *, but is identical in + * functionality to xdr_pmaplist(). + */ +bool_t +xdr_pmaplist_ptr(xdrs, rp) + XDR *xdrs; + struct pmaplist *rp; +{ + return xdr_pmaplist(xdrs, (struct pmaplist **)(void *)rp); +} diff --git a/freebsd/lib/libc/rpc/pmap_rmt.c b/freebsd/lib/libc/rpc/pmap_rmt.c new file mode 100644 index 00000000..e2d45608 --- /dev/null +++ b/freebsd/lib/libc/rpc/pmap_rmt.c @@ -0,0 +1,177 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: pmap_rmt.c,v 1.29 2000/07/06 03:10:34 christos Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *sccsid2 = "@(#)pmap_rmt.c 1.21 87/08/27 Copyr 1984 Sun Micro"; +static char *sccsid = "@(#)pmap_rmt.c 2.2 88/08/01 4.0 RPCSRC"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * pmap_rmt.c + * Client interface to pmap rpc service. + * remote call and broadcast service + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include "namespace.h" +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/poll.h> +#include <sys/socket.h> + +#include <net/if.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <assert.h> +#include <err.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include <rpc/rpc.h> +#include <rpc/pmap_prot.h> +#include <rpc/pmap_clnt.h> +#include <rpc/pmap_rmt.h> +#include "un-namespace.h" + +static const struct timeval timeout = { 3, 0 }; + +/* + * pmapper remote-call-service interface. + * This routine is used to call the pmapper remote call service + * which will look up a service program in the port maps, and then + * remotely call that routine with the given parameters. This allows + * programs to do a lookup and call in one step. +*/ +enum clnt_stat +pmap_rmtcall(addr, prog, vers, proc, xdrargs, argsp, xdrres, resp, tout, + port_ptr) + struct sockaddr_in *addr; + u_long prog, vers, proc; + xdrproc_t xdrargs, xdrres; + caddr_t argsp, resp; + struct timeval tout; + u_long *port_ptr; +{ + int sock = -1; + CLIENT *client; + struct rmtcallargs a; + struct rmtcallres r; + enum clnt_stat stat; + + assert(addr != NULL); + assert(port_ptr != NULL); + + addr->sin_port = htons(PMAPPORT); + client = clntudp_create(addr, PMAPPROG, PMAPVERS, timeout, &sock); + if (client != NULL) { + a.prog = prog; + a.vers = vers; + a.proc = proc; + a.args_ptr = argsp; + a.xdr_args = xdrargs; + r.port_ptr = port_ptr; + r.results_ptr = resp; + r.xdr_results = xdrres; + stat = CLNT_CALL(client, (rpcproc_t)PMAPPROC_CALLIT, + (xdrproc_t)xdr_rmtcall_args, &a, (xdrproc_t)xdr_rmtcallres, + &r, tout); + CLNT_DESTROY(client); + } else { + stat = RPC_FAILED; + } + addr->sin_port = 0; + return (stat); +} + + +/* + * XDR remote call arguments + * written for XDR_ENCODE direction only + */ +bool_t +xdr_rmtcall_args(xdrs, cap) + XDR *xdrs; + struct rmtcallargs *cap; +{ + u_int lenposition, argposition, position; + + assert(xdrs != NULL); + assert(cap != NULL); + + if (xdr_u_long(xdrs, &(cap->prog)) && + xdr_u_long(xdrs, &(cap->vers)) && + xdr_u_long(xdrs, &(cap->proc))) { + lenposition = XDR_GETPOS(xdrs); + if (! xdr_u_long(xdrs, &(cap->arglen))) + return (FALSE); + argposition = XDR_GETPOS(xdrs); + if (! (*(cap->xdr_args))(xdrs, cap->args_ptr)) + return (FALSE); + position = XDR_GETPOS(xdrs); + cap->arglen = (u_long)position - (u_long)argposition; + XDR_SETPOS(xdrs, lenposition); + if (! xdr_u_long(xdrs, &(cap->arglen))) + return (FALSE); + XDR_SETPOS(xdrs, position); + return (TRUE); + } + return (FALSE); +} + +/* + * XDR remote call results + * written for XDR_DECODE direction only + */ +bool_t +xdr_rmtcallres(xdrs, crp) + XDR *xdrs; + struct rmtcallres *crp; +{ + caddr_t port_ptr; + + assert(xdrs != NULL); + assert(crp != NULL); + + port_ptr = (caddr_t)(void *)crp->port_ptr; + if (xdr_reference(xdrs, &port_ptr, sizeof (u_long), + (xdrproc_t)xdr_u_long) && xdr_u_long(xdrs, &crp->resultslen)) { + crp->port_ptr = (u_long *)(void *)port_ptr; + return ((*(crp->xdr_results))(xdrs, crp->results_ptr)); + } + return (FALSE); +} diff --git a/freebsd/lib/libc/rpc/rpc_callmsg.c b/freebsd/lib/libc/rpc/rpc_callmsg.c new file mode 100644 index 00000000..7d236d5e --- /dev/null +++ b/freebsd/lib/libc/rpc/rpc_callmsg.c @@ -0,0 +1,208 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: rpc_callmsg.c,v 1.16 2000/07/14 08:40:42 fvdl Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *sccsid2 = "@(#)rpc_callmsg.c 1.4 87/08/11 Copyr 1984 Sun Micro"; +static char *sccsid = "@(#)rpc_callmsg.c 2.1 88/07/29 4.0 RPCSRC"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * rpc_callmsg.c + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + */ + +#include "namespace.h" +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#include <rpc/rpc.h> +#include "un-namespace.h" + +/* + * XDR a call message + */ +bool_t +xdr_callmsg(xdrs, cmsg) + XDR *xdrs; + struct rpc_msg *cmsg; +{ + enum msg_type *prm_direction; + int32_t *buf; + struct opaque_auth *oa; + + assert(xdrs != NULL); + assert(cmsg != NULL); + + if (xdrs->x_op == XDR_ENCODE) { + if (cmsg->rm_call.cb_cred.oa_length > MAX_AUTH_BYTES) { + return (FALSE); + } + if (cmsg->rm_call.cb_verf.oa_length > MAX_AUTH_BYTES) { + return (FALSE); + } + buf = XDR_INLINE(xdrs, 8 * BYTES_PER_XDR_UNIT + + RNDUP(cmsg->rm_call.cb_cred.oa_length) + + 2 * BYTES_PER_XDR_UNIT + + RNDUP(cmsg->rm_call.cb_verf.oa_length)); + if (buf != NULL) { + IXDR_PUT_INT32(buf, cmsg->rm_xid); + IXDR_PUT_ENUM(buf, cmsg->rm_direction); + if (cmsg->rm_direction != CALL) { + return (FALSE); + } + IXDR_PUT_INT32(buf, cmsg->rm_call.cb_rpcvers); + if (cmsg->rm_call.cb_rpcvers != RPC_MSG_VERSION) { + return (FALSE); + } + IXDR_PUT_INT32(buf, cmsg->rm_call.cb_prog); + IXDR_PUT_INT32(buf, cmsg->rm_call.cb_vers); + IXDR_PUT_INT32(buf, cmsg->rm_call.cb_proc); + oa = &cmsg->rm_call.cb_cred; + IXDR_PUT_ENUM(buf, oa->oa_flavor); + IXDR_PUT_INT32(buf, oa->oa_length); + if (oa->oa_length) { + memmove(buf, oa->oa_base, oa->oa_length); + buf += RNDUP(oa->oa_length) / sizeof (int32_t); + } + oa = &cmsg->rm_call.cb_verf; + IXDR_PUT_ENUM(buf, oa->oa_flavor); + IXDR_PUT_INT32(buf, oa->oa_length); + if (oa->oa_length) { + memmove(buf, oa->oa_base, oa->oa_length); + /* no real need.... + buf += RNDUP(oa->oa_length) / sizeof (int32_t); + */ + } + return (TRUE); + } + } + if (xdrs->x_op == XDR_DECODE) { + buf = XDR_INLINE(xdrs, 8 * BYTES_PER_XDR_UNIT); + if (buf != NULL) { + cmsg->rm_xid = IXDR_GET_U_INT32(buf); + cmsg->rm_direction = IXDR_GET_ENUM(buf, enum msg_type); + if (cmsg->rm_direction != CALL) { + return (FALSE); + } + cmsg->rm_call.cb_rpcvers = IXDR_GET_U_INT32(buf); + if (cmsg->rm_call.cb_rpcvers != RPC_MSG_VERSION) { + return (FALSE); + } + cmsg->rm_call.cb_prog = IXDR_GET_U_INT32(buf); + cmsg->rm_call.cb_vers = IXDR_GET_U_INT32(buf); + cmsg->rm_call.cb_proc = IXDR_GET_U_INT32(buf); + oa = &cmsg->rm_call.cb_cred; + oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t); + oa->oa_length = (u_int)IXDR_GET_U_INT32(buf); + if (oa->oa_length) { + if (oa->oa_length > MAX_AUTH_BYTES) { + return (FALSE); + } + if (oa->oa_base == NULL) { + oa->oa_base = (caddr_t) + mem_alloc(oa->oa_length); + if (oa->oa_base == NULL) + return (FALSE); + } + buf = XDR_INLINE(xdrs, RNDUP(oa->oa_length)); + if (buf == NULL) { + if (xdr_opaque(xdrs, oa->oa_base, + oa->oa_length) == FALSE) { + return (FALSE); + } + } else { + memmove(oa->oa_base, buf, + oa->oa_length); + /* no real need.... + buf += RNDUP(oa->oa_length) / + sizeof (int32_t); + */ + } + } + oa = &cmsg->rm_call.cb_verf; + buf = XDR_INLINE(xdrs, 2 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (xdr_enum(xdrs, &oa->oa_flavor) == FALSE || + xdr_u_int(xdrs, &oa->oa_length) == FALSE) { + return (FALSE); + } + } else { + oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t); + oa->oa_length = (u_int)IXDR_GET_U_INT32(buf); + } + if (oa->oa_length) { + if (oa->oa_length > MAX_AUTH_BYTES) { + return (FALSE); + } + if (oa->oa_base == NULL) { + oa->oa_base = (caddr_t) + mem_alloc(oa->oa_length); + if (oa->oa_base == NULL) + return (FALSE); + } + buf = XDR_INLINE(xdrs, RNDUP(oa->oa_length)); + if (buf == NULL) { + if (xdr_opaque(xdrs, oa->oa_base, + oa->oa_length) == FALSE) { + return (FALSE); + } + } else { + memmove(oa->oa_base, buf, + oa->oa_length); + /* no real need... + buf += RNDUP(oa->oa_length) / + sizeof (int32_t); + */ + } + } + return (TRUE); + } + } + prm_direction = &cmsg->rm_direction; + if ( + xdr_u_int32_t(xdrs, &(cmsg->rm_xid)) && + xdr_enum(xdrs, (enum_t *) prm_direction) && + (cmsg->rm_direction == CALL) && + xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_rpcvers)) && + (cmsg->rm_call.cb_rpcvers == RPC_MSG_VERSION) && + xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_prog)) && + xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_vers)) && + xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_proc)) && + xdr_opaque_auth(xdrs, &(cmsg->rm_call.cb_cred)) ) + return (xdr_opaque_auth(xdrs, &(cmsg->rm_call.cb_verf))); + return (FALSE); +} diff --git a/freebsd/lib/libc/rpc/rpc_com.h b/freebsd/lib/libc/rpc/rpc_com.h new file mode 100644 index 00000000..770faf91 --- /dev/null +++ b/freebsd/lib/libc/rpc/rpc_com.h @@ -0,0 +1,94 @@ +/* $NetBSD: rpc_com.h,v 1.3 2000/12/10 04:10:08 christos Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ +/* + * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. + */ + +/* + * rpc_com.h, Common definitions for both the server and client side. + * All for the topmost layer of rpc + * + * In Sun's tirpc distribution, this was installed as <rpc/rpc_com.h>, + * but as it contains only non-exported interfaces, it was moved here. + */ + +#ifndef _RPC_RPCCOM_H +#define _RPC_RPCCOM_H + +#include <sys/cdefs.h> + +/* #pragma ident "@(#)rpc_com.h 1.11 93/07/05 SMI" */ + +/* + * The max size of the transport, if the size cannot be determined + * by other means. + */ +#define RPC_MAXDATASIZE 9000 +#define RPC_MAXADDRSIZE 1024 + +#define __RPC_GETXID(now) ((u_int32_t)getpid() ^ (u_int32_t)(now)->tv_sec ^ \ + (u_int32_t)(now)->tv_usec) + +__BEGIN_DECLS +extern u_int __rpc_get_a_size(int); +extern int __rpc_dtbsize(void); +extern struct netconfig * __rpcgettp(int); +extern int __rpc_get_default_domain(char **); + +char *__rpc_taddr2uaddr_af(int, const struct netbuf *); +struct netbuf *__rpc_uaddr2taddr_af(int, const char *); +int __rpc_fixup_addr(struct netbuf *, const struct netbuf *); +int __rpc_sockinfo2netid(struct __rpc_sockinfo *, const char **); +int __rpc_seman2socktype(int); +int __rpc_socktype2seman(int); +void *rpc_nullproc(CLIENT *); +int __rpc_sockisbound(int); + +struct netbuf *__rpcb_findaddr_timed(rpcprog_t, rpcvers_t, + const struct netconfig *, const char *host, CLIENT **clpp, + struct timeval *tp); + +bool_t __rpc_control(int,void *); + +char *_get_next_token(char *, int); + +bool_t __svc_clean_idle(fd_set *, int, bool_t); +bool_t __xdrrec_setnonblock(XDR *, int); +bool_t __xdrrec_getrec(XDR *, enum xprt_stat *, bool_t); +void __xprt_unregister_unlocked(SVCXPRT *); + +SVCXPRT **__svc_xports; +int __svc_maxrec; + +__END_DECLS + +#endif /* _RPC_RPCCOM_H */ diff --git a/freebsd/lib/libc/rpc/rpc_commondata.c b/freebsd/lib/libc/rpc/rpc_commondata.c new file mode 100644 index 00000000..1afaee29 --- /dev/null +++ b/freebsd/lib/libc/rpc/rpc_commondata.c @@ -0,0 +1,49 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: rpc_commondata.c,v 1.7 2000/06/02 23:11:13 fvdl Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *sccsid = "@(#)rpc_commondata.c 2.1 88/07/29 4.0 RPCSRC"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "namespace.h" +#include <rpc/rpc.h> +#include "un-namespace.h" + +/* + * This file should only contain common data (global data) that is exported + * by public interfaces + */ +struct opaque_auth _null_auth; +fd_set svc_fdset; +int svc_maxfd = -1; diff --git a/freebsd/lib/libc/rpc/rpc_dtablesize.c b/freebsd/lib/libc/rpc/rpc_dtablesize.c new file mode 100644 index 00000000..69bea25e --- /dev/null +++ b/freebsd/lib/libc/rpc/rpc_dtablesize.c @@ -0,0 +1,68 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: rpc_dtablesize.c,v 1.14 1998/11/15 17:32:43 christos Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *sccsid2 = "@(#)rpc_dtablesize.c 1.2 87/08/11 Copyr 1987 Sun Micro"; +static char *sccsid = "@(#)rpc_dtablesize.c 2.1 88/07/29 4.0 RPCSRC"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "namespace.h" +#include <unistd.h> +#include "un-namespace.h" + +int _rpc_dtablesize(void); /* XXX */ + +/* + * Cache the result of getdtablesize(), so we don't have to do an + * expensive system call every time. + */ +/* + * XXX In FreeBSD 2.x, you can have the maximum number of open file + * descriptors be greater than FD_SETSIZE (which us 256 by default). + * + * Since old programs tend to use this call to determine the first arg + * for _select(), having this return > FD_SETSIZE is a Bad Idea(TM)! + */ +int +_rpc_dtablesize(void) +{ + static int size; + + if (size == 0) { + size = getdtablesize(); + if (size > FD_SETSIZE) + size = FD_SETSIZE; + } + return (size); +} diff --git a/freebsd/lib/libc/rpc/rpc_generic.c b/freebsd/lib/libc/rpc/rpc_generic.c new file mode 100644 index 00000000..d58bbfc0 --- /dev/null +++ b/freebsd/lib/libc/rpc/rpc_generic.c @@ -0,0 +1,848 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: rpc_generic.c,v 1.4 2000/09/28 09:07:04 kleink Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ + +/* #pragma ident "@(#)rpc_generic.c 1.17 94/04/24 SMI" */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * rpc_generic.c, Miscl routines for RPC. + * + */ + +#include "namespace.h" +#include "reentrant.h" +#include <sys/types.h> +#include <rtems/bsd/sys/param.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/un.h> +#include <rtems/bsd/sys/resource.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <rpc/rpc.h> +#include <ctype.h> +#include <stddef.h> +#include <stdio.h> +#include <netdb.h> +#include <netconfig.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <rpc/nettype.h> +#include "un-namespace.h" +#include "rpc_com.h" +#include "mt_misc.h" + +struct handle { + NCONF_HANDLE *nhandle; + int nflag; /* Whether NETPATH or NETCONFIG */ + int nettype; +}; + +static const struct _rpcnettype { + const char *name; + const int type; +} _rpctypelist[] = { + { "netpath", _RPC_NETPATH }, + { "visible", _RPC_VISIBLE }, + { "circuit_v", _RPC_CIRCUIT_V }, + { "datagram_v", _RPC_DATAGRAM_V }, + { "circuit_n", _RPC_CIRCUIT_N }, + { "datagram_n", _RPC_DATAGRAM_N }, + { "tcp", _RPC_TCP }, + { "udp", _RPC_UDP }, + { 0, _RPC_NONE } +}; + +struct netid_af { + const char *netid; + int af; + int protocol; +}; + +static const struct netid_af na_cvt[] = { + { "udp", AF_INET, IPPROTO_UDP }, + { "tcp", AF_INET, IPPROTO_TCP }, +#ifdef INET6 + { "udp6", AF_INET6, IPPROTO_UDP }, + { "tcp6", AF_INET6, IPPROTO_TCP }, +#endif + { "local", AF_LOCAL, 0 } +}; + +#if 0 +static char *strlocase(char *); +#endif +static int getnettype(const char *); + +/* + * Cache the result of getrlimit(), so we don't have to do an + * expensive call every time. + */ +int +__rpc_dtbsize() +{ + static int tbsize; + struct rlimit rl; + + if (tbsize) { + return (tbsize); + } + if (getrlimit(RLIMIT_NOFILE, &rl) == 0) { + return (tbsize = (int)rl.rlim_max); + } + /* + * Something wrong. I'll try to save face by returning a + * pessimistic number. + */ + return (32); +} + + +/* + * Find the appropriate buffer size + */ +u_int +/*ARGSUSED*/ +__rpc_get_t_size(af, proto, size) + int af, proto; + int size; /* Size requested */ +{ + int maxsize, defsize; + + maxsize = 256 * 1024; /* XXX */ + switch (proto) { + case IPPROTO_TCP: + defsize = 64 * 1024; /* XXX */ + break; + case IPPROTO_UDP: + defsize = UDPMSGSIZE; + break; + default: + defsize = RPC_MAXDATASIZE; + break; + } + if (size == 0) + return defsize; + + /* Check whether the value is within the upper max limit */ + return (size > maxsize ? (u_int)maxsize : (u_int)size); +} + +/* + * Find the appropriate address buffer size + */ +u_int +__rpc_get_a_size(af) + int af; +{ + switch (af) { + case AF_INET: + return sizeof (struct sockaddr_in); +#ifdef INET6 + case AF_INET6: + return sizeof (struct sockaddr_in6); +#endif + case AF_LOCAL: + return sizeof (struct sockaddr_un); + default: + break; + } + return ((u_int)RPC_MAXADDRSIZE); +} + +#if 0 +static char * +strlocase(p) + char *p; +{ + char *t = p; + + for (; *p; p++) + if (isupper(*p)) + *p = tolower(*p); + return (t); +} +#endif + +/* + * Returns the type of the network as defined in <rpc/nettype.h> + * If nettype is NULL, it defaults to NETPATH. + */ +static int +getnettype(nettype) + const char *nettype; +{ + int i; + + if ((nettype == NULL) || (nettype[0] == 0)) { + return (_RPC_NETPATH); /* Default */ + } + +#if 0 + nettype = strlocase(nettype); +#endif + for (i = 0; _rpctypelist[i].name; i++) + if (strcasecmp(nettype, _rpctypelist[i].name) == 0) { + return (_rpctypelist[i].type); + } + return (_rpctypelist[i].type); +} + +static thread_key_t tcp_key, udp_key; +static once_t keys_once = ONCE_INITIALIZER; +static int tcp_key_error, udp_key_error; + +static void +keys_init(void) +{ + + tcp_key_error = thr_keycreate(&tcp_key, free); + udp_key_error = thr_keycreate(&udp_key, free); +} + +/* + * For the given nettype (tcp or udp only), return the first structure found. + * This should be freed by calling freenetconfigent() + */ +struct netconfig * +__rpc_getconfip(nettype) + const char *nettype; +{ + char *netid; + char *netid_tcp = (char *) NULL; + char *netid_udp = (char *) NULL; + static char *netid_tcp_main; + static char *netid_udp_main; + struct netconfig *dummy; + int main_thread; + + if ((main_thread = thr_main())) { + netid_udp = netid_udp_main; + netid_tcp = netid_tcp_main; + } else { + if (thr_once(&keys_once, keys_init) != 0 || + tcp_key_error != 0 || udp_key_error != 0) + return (NULL); + netid_tcp = (char *)thr_getspecific(tcp_key); + netid_udp = (char *)thr_getspecific(udp_key); + } + if (!netid_udp && !netid_tcp) { + struct netconfig *nconf; + void *confighandle; + + if (!(confighandle = setnetconfig())) { + syslog (LOG_ERR, "rpc: failed to open " NETCONFIG); + return (NULL); + } + while ((nconf = getnetconfig(confighandle)) != NULL) { + if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { + if (strcmp(nconf->nc_proto, NC_TCP) == 0 && + netid_tcp == NULL) { + netid_tcp = strdup(nconf->nc_netid); + if (main_thread) + netid_tcp_main = netid_tcp; + else + thr_setspecific(tcp_key, + (void *) netid_tcp); + } else + if (strcmp(nconf->nc_proto, NC_UDP) == 0 && + netid_udp == NULL) { + netid_udp = strdup(nconf->nc_netid); + if (main_thread) + netid_udp_main = netid_udp; + else + thr_setspecific(udp_key, + (void *) netid_udp); + } + } + } + endnetconfig(confighandle); + } + if (strcmp(nettype, "udp") == 0) + netid = netid_udp; + else if (strcmp(nettype, "tcp") == 0) + netid = netid_tcp; + else { + return (NULL); + } + if ((netid == NULL) || (netid[0] == 0)) { + return (NULL); + } + dummy = getnetconfigent(netid); + return (dummy); +} + +/* + * Returns the type of the nettype, which should then be used with + * __rpc_getconf(). + */ +void * +__rpc_setconf(nettype) + const char *nettype; +{ + struct handle *handle; + + handle = (struct handle *) malloc(sizeof (struct handle)); + if (handle == NULL) { + return (NULL); + } + switch (handle->nettype = getnettype(nettype)) { + case _RPC_NETPATH: + case _RPC_CIRCUIT_N: + case _RPC_DATAGRAM_N: + if (!(handle->nhandle = setnetpath())) + goto failed; + handle->nflag = TRUE; + break; + case _RPC_VISIBLE: + case _RPC_CIRCUIT_V: + case _RPC_DATAGRAM_V: + case _RPC_TCP: + case _RPC_UDP: + if (!(handle->nhandle = setnetconfig())) { + syslog (LOG_ERR, "rpc: failed to open " NETCONFIG); + goto failed; + } + handle->nflag = FALSE; + break; + default: + goto failed; + } + + return (handle); + +failed: + free(handle); + return (NULL); +} + +/* + * Returns the next netconfig struct for the given "net" type. + * __rpc_setconf() should have been called previously. + */ +struct netconfig * +__rpc_getconf(vhandle) + void *vhandle; +{ + struct handle *handle; + struct netconfig *nconf; + + handle = (struct handle *)vhandle; + if (handle == NULL) { + return (NULL); + } + for (;;) { + if (handle->nflag) + nconf = getnetpath(handle->nhandle); + else + nconf = getnetconfig(handle->nhandle); + if (nconf == NULL) + break; + if ((nconf->nc_semantics != NC_TPI_CLTS) && + (nconf->nc_semantics != NC_TPI_COTS) && + (nconf->nc_semantics != NC_TPI_COTS_ORD)) + continue; + switch (handle->nettype) { + case _RPC_VISIBLE: + if (!(nconf->nc_flag & NC_VISIBLE)) + continue; + /* FALLTHROUGH */ + case _RPC_NETPATH: /* Be happy */ + break; + case _RPC_CIRCUIT_V: + if (!(nconf->nc_flag & NC_VISIBLE)) + continue; + /* FALLTHROUGH */ + case _RPC_CIRCUIT_N: + if ((nconf->nc_semantics != NC_TPI_COTS) && + (nconf->nc_semantics != NC_TPI_COTS_ORD)) + continue; + break; + case _RPC_DATAGRAM_V: + if (!(nconf->nc_flag & NC_VISIBLE)) + continue; + /* FALLTHROUGH */ + case _RPC_DATAGRAM_N: + if (nconf->nc_semantics != NC_TPI_CLTS) + continue; + break; + case _RPC_TCP: + if (((nconf->nc_semantics != NC_TPI_COTS) && + (nconf->nc_semantics != NC_TPI_COTS_ORD)) || + (strcmp(nconf->nc_protofmly, NC_INET) +#ifdef INET6 + && strcmp(nconf->nc_protofmly, NC_INET6)) +#else + ) +#endif + || + strcmp(nconf->nc_proto, NC_TCP)) + continue; + break; + case _RPC_UDP: + if ((nconf->nc_semantics != NC_TPI_CLTS) || + (strcmp(nconf->nc_protofmly, NC_INET) +#ifdef INET6 + && strcmp(nconf->nc_protofmly, NC_INET6)) +#else + ) +#endif + || + strcmp(nconf->nc_proto, NC_UDP)) + continue; + break; + } + break; + } + return (nconf); +} + +void +__rpc_endconf(vhandle) + void * vhandle; +{ + struct handle *handle; + + handle = (struct handle *) vhandle; + if (handle == NULL) { + return; + } + if (handle->nflag) { + endnetpath(handle->nhandle); + } else { + endnetconfig(handle->nhandle); + } + free(handle); +} + +/* + * Used to ping the NULL procedure for clnt handle. + * Returns NULL if fails, else a non-NULL pointer. + */ +void * +rpc_nullproc(clnt) + CLIENT *clnt; +{ + struct timeval TIMEOUT = {25, 0}; + + if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL, + (xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return ((void *) clnt); +} + +/* + * Try all possible transports until + * one succeeds in finding the netconf for the given fd. + */ +struct netconfig * +__rpcgettp(fd) + int fd; +{ + const char *netid; + struct __rpc_sockinfo si; + + if (!__rpc_fd2sockinfo(fd, &si)) + return NULL; + + if (!__rpc_sockinfo2netid(&si, &netid)) + return NULL; + + /*LINTED const castaway*/ + return getnetconfigent((char *)netid); +} + +int +__rpc_fd2sockinfo(int fd, struct __rpc_sockinfo *sip) +{ + socklen_t len; + int type, proto; + struct sockaddr_storage ss; + + len = sizeof ss; + if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &len) < 0) + return 0; + sip->si_alen = len; + + len = sizeof type; + if (_getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len) < 0) + return 0; + + /* XXX */ + if (ss.ss_family != AF_LOCAL) { + if (type == SOCK_STREAM) + proto = IPPROTO_TCP; + else if (type == SOCK_DGRAM) + proto = IPPROTO_UDP; + else + return 0; + } else + proto = 0; + + sip->si_af = ss.ss_family; + sip->si_proto = proto; + sip->si_socktype = type; + + return 1; +} + +/* + * Linear search, but the number of entries is small. + */ +int +__rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip) +{ + int i; + + for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) + if (strcmp(na_cvt[i].netid, nconf->nc_netid) == 0 || ( + strcmp(nconf->nc_netid, "unix") == 0 && + strcmp(na_cvt[i].netid, "local") == 0)) { + sip->si_af = na_cvt[i].af; + sip->si_proto = na_cvt[i].protocol; + sip->si_socktype = + __rpc_seman2socktype((int)nconf->nc_semantics); + if (sip->si_socktype == -1) + return 0; + sip->si_alen = __rpc_get_a_size(sip->si_af); + return 1; + } + + return 0; +} + +int +__rpc_nconf2fd(const struct netconfig *nconf) +{ + struct __rpc_sockinfo si; + + if (!__rpc_nconf2sockinfo(nconf, &si)) + return 0; + + return _socket(si.si_af, si.si_socktype, si.si_proto); +} + +int +__rpc_sockinfo2netid(struct __rpc_sockinfo *sip, const char **netid) +{ + int i; + struct netconfig *nconf; + + nconf = getnetconfigent("local"); + + for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) { + if (na_cvt[i].af == sip->si_af && + na_cvt[i].protocol == sip->si_proto) { + if (strcmp(na_cvt[i].netid, "local") == 0 && nconf == NULL) { + if (netid) + *netid = "unix"; + } else { + if (netid) + *netid = na_cvt[i].netid; + } + if (nconf != NULL) + freenetconfigent(nconf); + return 1; + } + } + if (nconf != NULL) + freenetconfigent(nconf); + + return 0; +} + +char * +taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf) +{ + struct __rpc_sockinfo si; + + if (!__rpc_nconf2sockinfo(nconf, &si)) + return NULL; + return __rpc_taddr2uaddr_af(si.si_af, nbuf); +} + +struct netbuf * +uaddr2taddr(const struct netconfig *nconf, const char *uaddr) +{ + struct __rpc_sockinfo si; + + if (!__rpc_nconf2sockinfo(nconf, &si)) + return NULL; + return __rpc_uaddr2taddr_af(si.si_af, uaddr); +} + +char * +__rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf) +{ + char *ret; + struct sockaddr_in *sin; + struct sockaddr_un *sun; + char namebuf[INET_ADDRSTRLEN]; +#ifdef INET6 + struct sockaddr_in6 *sin6; + char namebuf6[INET6_ADDRSTRLEN]; +#endif + u_int16_t port; + + switch (af) { + case AF_INET: + sin = nbuf->buf; + if (inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf) + == NULL) + return NULL; + port = ntohs(sin->sin_port); + if (asprintf(&ret, "%s.%u.%u", namebuf, ((u_int32_t)port) >> 8, + port & 0xff) < 0) + return NULL; + break; +#ifdef INET6 + case AF_INET6: + sin6 = nbuf->buf; + if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6) + == NULL) + return NULL; + port = ntohs(sin6->sin6_port); + if (asprintf(&ret, "%s.%u.%u", namebuf6, ((u_int32_t)port) >> 8, + port & 0xff) < 0) + return NULL; + break; +#endif + case AF_LOCAL: + sun = nbuf->buf; + if (asprintf(&ret, "%.*s", (int)(sun->sun_len - + offsetof(struct sockaddr_un, sun_path)), + sun->sun_path) < 0) + return (NULL); + break; + default: + return NULL; + } + + return ret; +} + +struct netbuf * +__rpc_uaddr2taddr_af(int af, const char *uaddr) +{ + struct netbuf *ret = NULL; + char *addrstr, *p; + unsigned port, portlo, porthi; + struct sockaddr_in *sin; +#ifdef INET6 + struct sockaddr_in6 *sin6; +#endif + struct sockaddr_un *sun; + + port = 0; + sin = NULL; + addrstr = strdup(uaddr); + if (addrstr == NULL) + return NULL; + + /* + * AF_LOCAL addresses are expected to be absolute + * pathnames, anything else will be AF_INET or AF_INET6. + */ + if (*addrstr != '/') { + p = strrchr(addrstr, '.'); + if (p == NULL) + goto out; + portlo = (unsigned)atoi(p + 1); + *p = '\0'; + + p = strrchr(addrstr, '.'); + if (p == NULL) + goto out; + porthi = (unsigned)atoi(p + 1); + *p = '\0'; + port = (porthi << 8) | portlo; + } + + ret = (struct netbuf *)malloc(sizeof *ret); + if (ret == NULL) + goto out; + + switch (af) { + case AF_INET: + sin = (struct sockaddr_in *)malloc(sizeof *sin); + if (sin == NULL) + goto out; + memset(sin, 0, sizeof *sin); + sin->sin_family = AF_INET; + sin->sin_port = htons(port); + if (inet_pton(AF_INET, addrstr, &sin->sin_addr) <= 0) { + free(sin); + free(ret); + ret = NULL; + goto out; + } + sin->sin_len = ret->maxlen = ret->len = sizeof *sin; + ret->buf = sin; + break; +#ifdef INET6 + case AF_INET6: + sin6 = (struct sockaddr_in6 *)malloc(sizeof *sin6); + if (sin6 == NULL) + goto out; + memset(sin6, 0, sizeof *sin6); + sin6->sin6_family = AF_INET6; + sin6->sin6_port = htons(port); + if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) { + free(sin6); + free(ret); + ret = NULL; + goto out; + } + sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6; + ret->buf = sin6; + break; +#endif + case AF_LOCAL: + sun = (struct sockaddr_un *)malloc(sizeof *sun); + if (sun == NULL) + goto out; + memset(sun, 0, sizeof *sun); + sun->sun_family = AF_LOCAL; + strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1); + ret->len = ret->maxlen = sun->sun_len = SUN_LEN(sun); + ret->buf = sun; + break; + default: + break; + } +out: + free(addrstr); + return ret; +} + +int +__rpc_seman2socktype(int semantics) +{ + switch (semantics) { + case NC_TPI_CLTS: + return SOCK_DGRAM; + case NC_TPI_COTS_ORD: + return SOCK_STREAM; + case NC_TPI_RAW: + return SOCK_RAW; + default: + break; + } + + return -1; +} + +int +__rpc_socktype2seman(int socktype) +{ + switch (socktype) { + case SOCK_DGRAM: + return NC_TPI_CLTS; + case SOCK_STREAM: + return NC_TPI_COTS_ORD; + case SOCK_RAW: + return NC_TPI_RAW; + default: + break; + } + + return -1; +} + +/* + * XXXX - IPv6 scope IDs can't be handled in universal addresses. + * Here, we compare the original server address to that of the RPC + * service we just received back from a call to rpcbind on the remote + * machine. If they are both "link local" or "site local", copy + * the scope id of the server address over to the service address. + */ +int +__rpc_fixup_addr(struct netbuf *new, const struct netbuf *svc) +{ +#ifdef INET6 + struct sockaddr *sa_new, *sa_svc; + struct sockaddr_in6 *sin6_new, *sin6_svc; + + sa_svc = (struct sockaddr *)svc->buf; + sa_new = (struct sockaddr *)new->buf; + + if (sa_new->sa_family == sa_svc->sa_family && + sa_new->sa_family == AF_INET6) { + sin6_new = (struct sockaddr_in6 *)new->buf; + sin6_svc = (struct sockaddr_in6 *)svc->buf; + + if ((IN6_IS_ADDR_LINKLOCAL(&sin6_new->sin6_addr) && + IN6_IS_ADDR_LINKLOCAL(&sin6_svc->sin6_addr)) || + (IN6_IS_ADDR_SITELOCAL(&sin6_new->sin6_addr) && + IN6_IS_ADDR_SITELOCAL(&sin6_svc->sin6_addr))) { + sin6_new->sin6_scope_id = sin6_svc->sin6_scope_id; + } + } +#endif + return 1; +} + +int +__rpc_sockisbound(int fd) +{ + struct sockaddr_storage ss; + socklen_t slen; + + slen = sizeof (struct sockaddr_storage); + if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) + return 0; + + switch (ss.ss_family) { + case AF_INET: + return (((struct sockaddr_in *) + (void *)&ss)->sin_port != 0); +#ifdef INET6 + case AF_INET6: + return (((struct sockaddr_in6 *) + (void *)&ss)->sin6_port != 0); +#endif + case AF_LOCAL: + /* XXX check this */ + return (((struct sockaddr_un *) + (void *)&ss)->sun_path[0] != '\0'); + default: + break; + } + + return 0; +} diff --git a/freebsd/lib/libc/rpc/rpc_prot.c b/freebsd/lib/libc/rpc/rpc_prot.c new file mode 100644 index 00000000..754f7cb9 --- /dev/null +++ b/freebsd/lib/libc/rpc/rpc_prot.c @@ -0,0 +1,373 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: rpc_prot.c,v 1.16 2000/06/02 23:11:13 fvdl Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *sccsid2 = "@(#)rpc_prot.c 1.36 87/08/11 Copyr 1984 Sun Micro"; +static char *sccsid = "@(#)rpc_prot.c 2.3 88/08/07 4.0 RPCSRC"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * 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 "namespace.h" +#include <rtems/bsd/sys/param.h> + +#include <assert.h> + +#include <rpc/rpc.h> +#include "un-namespace.h" + +static void accepted(enum accept_stat, struct rpc_err *); +static void rejected(enum reject_stat, struct rpc_err *); + +/* * * * * * * * * * * * * * XDR Authentication * * * * * * * * * * * */ + +extern struct opaque_auth _null_auth; + +/* + * XDR an opaque authentication struct + * (see auth.h) + */ +bool_t +xdr_opaque_auth(xdrs, ap) + XDR *xdrs; + struct opaque_auth *ap; +{ + + assert(xdrs != NULL); + assert(ap != NULL); + + if (xdr_enum(xdrs, &(ap->oa_flavor))) + return (xdr_bytes(xdrs, &ap->oa_base, + &ap->oa_length, MAX_AUTH_BYTES)); + return (FALSE); +} + +/* + * XDR a DES block + */ +bool_t +xdr_des_block(xdrs, blkp) + XDR *xdrs; + des_block *blkp; +{ + + assert(xdrs != NULL); + assert(blkp != NULL); + + return (xdr_opaque(xdrs, (caddr_t)(void *)blkp, sizeof(des_block))); +} + +/* * * * * * * * * * * * * * XDR RPC MESSAGE * * * * * * * * * * * * * * * */ + +/* + * XDR the MSG_ACCEPTED part of a reply message union + */ +bool_t +xdr_accepted_reply(xdrs, ar) + XDR *xdrs; + struct accepted_reply *ar; +{ + enum accept_stat *par_stat; + + assert(xdrs != NULL); + assert(ar != NULL); + + par_stat = &ar->ar_stat; + + /* personalized union, rather than calling xdr_union */ + if (! xdr_opaque_auth(xdrs, &(ar->ar_verf))) + return (FALSE); + if (! xdr_enum(xdrs, (enum_t *) par_stat)) + return (FALSE); + switch (ar->ar_stat) { + + case SUCCESS: + return ((*(ar->ar_results.proc))(xdrs, ar->ar_results.where)); + + case PROG_MISMATCH: + if (! xdr_u_int32_t(xdrs, &(ar->ar_vers.low))) + return (FALSE); + return (xdr_u_int32_t(xdrs, &(ar->ar_vers.high))); + + case GARBAGE_ARGS: + case SYSTEM_ERR: + case PROC_UNAVAIL: + case PROG_UNAVAIL: + break; + } + return (TRUE); /* TRUE => open ended set of problems */ +} + +/* + * XDR the MSG_DENIED part of a reply message union + */ +bool_t +xdr_rejected_reply(xdrs, rr) + XDR *xdrs; + struct rejected_reply *rr; +{ + enum reject_stat *prj_stat; + enum auth_stat *prj_why; + + assert(xdrs != NULL); + assert(rr != NULL); + + prj_stat = &rr->rj_stat; + + /* personalized union, rather than calling xdr_union */ + if (! xdr_enum(xdrs, (enum_t *) prj_stat)) + return (FALSE); + switch (rr->rj_stat) { + + case RPC_MISMATCH: + if (! xdr_u_int32_t(xdrs, &(rr->rj_vers.low))) + return (FALSE); + return (xdr_u_int32_t(xdrs, &(rr->rj_vers.high))); + + case AUTH_ERROR: + prj_why = &rr->rj_why; + return (xdr_enum(xdrs, (enum_t *) prj_why)); + } + /* NOTREACHED */ + assert(0); + return (FALSE); +} + +static const struct xdr_discrim reply_dscrm[3] = { + { (int)MSG_ACCEPTED, (xdrproc_t)xdr_accepted_reply }, + { (int)MSG_DENIED, (xdrproc_t)xdr_rejected_reply }, + { __dontcare__, NULL_xdrproc_t } }; + +/* + * XDR a reply message + */ +bool_t +xdr_replymsg(xdrs, rmsg) + XDR *xdrs; + struct rpc_msg *rmsg; +{ + enum msg_type *prm_direction; + enum reply_stat *prp_stat; + + assert(xdrs != NULL); + assert(rmsg != NULL); + + prm_direction = &rmsg->rm_direction; + prp_stat = &rmsg->rm_reply.rp_stat; + + if ( + xdr_u_int32_t(xdrs, &(rmsg->rm_xid)) && + xdr_enum(xdrs, (enum_t *) prm_direction) && + (rmsg->rm_direction == REPLY) ) + return (xdr_union(xdrs, (enum_t *) prp_stat, + (caddr_t)(void *)&(rmsg->rm_reply.ru), reply_dscrm, + NULL_xdrproc_t)); + return (FALSE); +} + + +/* + * Serializes the "static part" of a call message header. + * The fields include: rm_xid, rm_direction, rpcvers, prog, and vers. + * The rm_xid is not really static, but the user can easily munge on the fly. + */ +bool_t +xdr_callhdr(xdrs, cmsg) + XDR *xdrs; + struct rpc_msg *cmsg; +{ + enum msg_type *prm_direction; + + assert(xdrs != NULL); + assert(cmsg != NULL); + + prm_direction = &cmsg->rm_direction; + + cmsg->rm_direction = CALL; + cmsg->rm_call.cb_rpcvers = RPC_MSG_VERSION; + if ( + (xdrs->x_op == XDR_ENCODE) && + xdr_u_int32_t(xdrs, &(cmsg->rm_xid)) && + xdr_enum(xdrs, (enum_t *) prm_direction) && + xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_rpcvers)) && + xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_prog)) ) + return (xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_vers))); + return (FALSE); +} + +/* ************************** Client utility routine ************* */ + +static void +accepted(acpt_stat, error) + enum accept_stat acpt_stat; + struct rpc_err *error; +{ + + assert(error != NULL); + + switch (acpt_stat) { + + case PROG_UNAVAIL: + error->re_status = RPC_PROGUNAVAIL; + return; + + case PROG_MISMATCH: + error->re_status = RPC_PROGVERSMISMATCH; + return; + + case PROC_UNAVAIL: + error->re_status = RPC_PROCUNAVAIL; + return; + + case GARBAGE_ARGS: + error->re_status = RPC_CANTDECODEARGS; + return; + + case SYSTEM_ERR: + error->re_status = RPC_SYSTEMERROR; + return; + + case SUCCESS: + error->re_status = RPC_SUCCESS; + return; + } + /* NOTREACHED */ + /* something's wrong, but we don't know what ... */ + error->re_status = RPC_FAILED; + error->re_lb.s1 = (int32_t)MSG_ACCEPTED; + error->re_lb.s2 = (int32_t)acpt_stat; +} + +static void +rejected(rjct_stat, error) + enum reject_stat rjct_stat; + struct rpc_err *error; +{ + + assert(error != NULL); + + switch (rjct_stat) { + case RPC_MISMATCH: + error->re_status = RPC_VERSMISMATCH; + return; + + case AUTH_ERROR: + error->re_status = RPC_AUTHERROR; + return; + } + /* something's wrong, but we don't know what ... */ + /* NOTREACHED */ + error->re_status = RPC_FAILED; + error->re_lb.s1 = (int32_t)MSG_DENIED; + error->re_lb.s2 = (int32_t)rjct_stat; +} + +/* + * given a reply message, fills in the error + */ +void +_seterr_reply(msg, error) + struct rpc_msg *msg; + struct rpc_err *error; +{ + + assert(msg != NULL); + assert(error != NULL); + + /* optimized for normal, SUCCESSful case */ + switch (msg->rm_reply.rp_stat) { + + case MSG_ACCEPTED: + if (msg->acpted_rply.ar_stat == SUCCESS) { + error->re_status = RPC_SUCCESS; + return; + } + accepted(msg->acpted_rply.ar_stat, error); + break; + + case MSG_DENIED: + rejected(msg->rjcted_rply.rj_stat, error); + break; + + default: + error->re_status = RPC_FAILED; + error->re_lb.s1 = (int32_t)(msg->rm_reply.rp_stat); + break; + } + switch (error->re_status) { + + case RPC_VERSMISMATCH: + error->re_vers.low = msg->rjcted_rply.rj_vers.low; + error->re_vers.high = msg->rjcted_rply.rj_vers.high; + break; + + case RPC_AUTHERROR: + error->re_why = msg->rjcted_rply.rj_why; + break; + + case RPC_PROGVERSMISMATCH: + error->re_vers.low = msg->acpted_rply.ar_vers.low; + error->re_vers.high = msg->acpted_rply.ar_vers.high; + break; + + case RPC_FAILED: + case RPC_SUCCESS: + case RPC_PROGNOTREGISTERED: + case RPC_PMAPFAILURE: + case RPC_UNKNOWNPROTO: + case RPC_UNKNOWNHOST: + case RPC_SYSTEMERROR: + case RPC_CANTDECODEARGS: + case RPC_PROCUNAVAIL: + case RPC_PROGUNAVAIL: + case RPC_TIMEDOUT: + case RPC_CANTRECV: + case RPC_CANTSEND: + case RPC_CANTDECODERES: + case RPC_CANTENCODEARGS: + default: + break; + } +} diff --git a/freebsd/lib/libc/rpc/rpc_soc.c b/freebsd/lib/libc/rpc/rpc_soc.c new file mode 100644 index 00000000..6b4260c4 --- /dev/null +++ b/freebsd/lib/libc/rpc/rpc_soc.c @@ -0,0 +1,583 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: rpc_soc.c,v 1.6 2000/07/06 03:10:35 christos Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* #ident "@(#)rpc_soc.c 1.17 94/04/24 SMI" */ + +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + * In addition, portions of such source code were derived from Berkeley + * 4.3 BSD under license from the Regents of the University of + * California. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)rpc_soc.c 1.41 89/05/02 Copyr 1988 Sun Micro"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#ifdef PORTMAP +/* + * rpc_soc.c + * + * The backward compatibility routines for the earlier implementation + * of RPC, where the only transports supported were tcp/ip and udp/ip. + * Based on berkeley socket abstraction, now implemented on the top + * of TLI/Streams + */ + +#include "namespace.h" +#include "reentrant.h" +#include <sys/types.h> +#include <sys/socket.h> +#include <stdio.h> +#include <rpc/rpc.h> +#include <rpc/pmap_clnt.h> +#include <rpc/pmap_prot.h> +#include <rpc/nettype.h> +#include <syslog.h> +#include <netinet/in.h> +#include <netdb.h> +#include <errno.h> +#include <syslog.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "un-namespace.h" + +#include "rpc_com.h" +#include "mt_misc.h" + +static CLIENT *clnt_com_create(struct sockaddr_in *, rpcprog_t, rpcvers_t, + int *, u_int, u_int, char *); +static SVCXPRT *svc_com_create(int, u_int, u_int, char *); +static bool_t rpc_wrap_bcast(char *, struct netbuf *, struct netconfig *); + +/* XXX */ +#define IN4_LOCALHOST_STRING "127.0.0.1" +#define IN6_LOCALHOST_STRING "::1" + +/* + * A common clnt create routine + */ +static CLIENT * +clnt_com_create(raddr, prog, vers, sockp, sendsz, recvsz, tp) + struct sockaddr_in *raddr; + rpcprog_t prog; + rpcvers_t vers; + int *sockp; + u_int sendsz; + u_int recvsz; + char *tp; +{ + CLIENT *cl; + int madefd = FALSE; + int fd = *sockp; + struct netconfig *nconf; + struct netbuf bindaddr; + + mutex_lock(&rpcsoc_lock); + if ((nconf = __rpc_getconfip(tp)) == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + mutex_unlock(&rpcsoc_lock); + return (NULL); + } + if (fd == RPC_ANYSOCK) { + fd = __rpc_nconf2fd(nconf); + if (fd == -1) + goto syserror; + madefd = TRUE; + } + + if (raddr->sin_port == 0) { + u_int proto; + u_short sport; + + mutex_unlock(&rpcsoc_lock); /* pmap_getport is recursive */ + proto = strcmp(tp, "udp") == 0 ? IPPROTO_UDP : IPPROTO_TCP; + sport = pmap_getport(raddr, (u_long)prog, (u_long)vers, + proto); + if (sport == 0) { + goto err; + } + raddr->sin_port = htons(sport); + mutex_lock(&rpcsoc_lock); /* pmap_getport is recursive */ + } + + /* Transform sockaddr_in to netbuf */ + bindaddr.maxlen = bindaddr.len = sizeof (struct sockaddr_in); + bindaddr.buf = raddr; + + bindresvport(fd, NULL); + cl = clnt_tli_create(fd, nconf, &bindaddr, prog, vers, + sendsz, recvsz); + if (cl) { + if (madefd == TRUE) { + /* + * The fd should be closed while destroying the handle. + */ + (void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL); + *sockp = fd; + } + (void) freenetconfigent(nconf); + mutex_unlock(&rpcsoc_lock); + return (cl); + } + goto err; + +syserror: + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + +err: if (madefd == TRUE) + (void)_close(fd); + (void) freenetconfigent(nconf); + mutex_unlock(&rpcsoc_lock); + return (NULL); +} + +CLIENT * +clntudp_bufcreate(raddr, prog, vers, wait, sockp, sendsz, recvsz) + struct sockaddr_in *raddr; + u_long prog; + u_long vers; + struct timeval wait; + int *sockp; + u_int sendsz; + u_int recvsz; +{ + CLIENT *cl; + + cl = clnt_com_create(raddr, (rpcprog_t)prog, (rpcvers_t)vers, sockp, + sendsz, recvsz, "udp"); + if (cl == NULL) { + return (NULL); + } + (void) CLNT_CONTROL(cl, CLSET_RETRY_TIMEOUT, &wait); + return (cl); +} + +CLIENT * +clntudp_create(raddr, program, version, wait, sockp) + struct sockaddr_in *raddr; + u_long program; + u_long version; + struct timeval wait; + int *sockp; +{ + + return clntudp_bufcreate(raddr, program, version, wait, sockp, + UDPMSGSIZE, UDPMSGSIZE); +} + +CLIENT * +clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz) + struct sockaddr_in *raddr; + u_long prog; + u_long vers; + int *sockp; + u_int sendsz; + u_int recvsz; +{ + + return clnt_com_create(raddr, (rpcprog_t)prog, (rpcvers_t)vers, sockp, + sendsz, recvsz, "tcp"); +} + +CLIENT * +clntraw_create(prog, vers) + u_long prog; + u_long vers; +{ + + return clnt_raw_create((rpcprog_t)prog, (rpcvers_t)vers); +} + +/* + * A common server create routine + */ +static SVCXPRT * +svc_com_create(fd, sendsize, recvsize, netid) + int fd; + u_int sendsize; + u_int recvsize; + char *netid; +{ + struct netconfig *nconf; + SVCXPRT *svc; + int madefd = FALSE; + int port; + struct sockaddr_in sin; + + if ((nconf = __rpc_getconfip(netid)) == NULL) { + (void) syslog(LOG_ERR, "Could not get %s transport", netid); + return (NULL); + } + if (fd == RPC_ANYSOCK) { + fd = __rpc_nconf2fd(nconf); + if (fd == -1) { + (void) freenetconfigent(nconf); + (void) syslog(LOG_ERR, + "svc%s_create: could not open connection", netid); + return (NULL); + } + madefd = TRUE; + } + + memset(&sin, 0, sizeof sin); + sin.sin_family = AF_INET; + bindresvport(fd, &sin); + _listen(fd, SOMAXCONN); + svc = svc_tli_create(fd, nconf, NULL, sendsize, recvsize); + (void) freenetconfigent(nconf); + if (svc == NULL) { + if (madefd) + (void)_close(fd); + return (NULL); + } + port = (((struct sockaddr_in *)svc->xp_ltaddr.buf)->sin_port); + svc->xp_port = ntohs(port); + return (svc); +} + +SVCXPRT * +svctcp_create(fd, sendsize, recvsize) + int fd; + u_int sendsize; + u_int recvsize; +{ + + return svc_com_create(fd, sendsize, recvsize, "tcp"); +} + +SVCXPRT * +svcudp_bufcreate(fd, sendsz, recvsz) + int fd; + u_int sendsz, recvsz; +{ + + return svc_com_create(fd, sendsz, recvsz, "udp"); +} + +SVCXPRT * +svcfd_create(fd, sendsize, recvsize) + int fd; + u_int sendsize; + u_int recvsize; +{ + + return svc_fd_create(fd, sendsize, recvsize); +} + + +SVCXPRT * +svcudp_create(fd) + int fd; +{ + + return svc_com_create(fd, UDPMSGSIZE, UDPMSGSIZE, "udp"); +} + +SVCXPRT * +svcraw_create() +{ + + return svc_raw_create(); +} + +int +get_myaddress(addr) + struct sockaddr_in *addr; +{ + + memset((void *) addr, 0, sizeof(*addr)); + addr->sin_family = AF_INET; + addr->sin_port = htons(PMAPPORT); + addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK); + return (0); +} + +/* + * For connectionless "udp" transport. Obsoleted by rpc_call(). + */ +int +callrpc(host, prognum, versnum, procnum, inproc, in, outproc, out) + const char *host; + int prognum, versnum, procnum; + xdrproc_t inproc, outproc; + void *in, *out; +{ + + return (int)rpc_call(host, (rpcprog_t)prognum, (rpcvers_t)versnum, + (rpcproc_t)procnum, inproc, in, outproc, out, "udp"); +} + +/* + * For connectionless kind of transport. Obsoleted by rpc_reg() + */ +int +registerrpc(prognum, versnum, procnum, progname, inproc, outproc) + int prognum, versnum, procnum; + char *(*progname)(char [UDPMSGSIZE]); + xdrproc_t inproc, outproc; +{ + + return rpc_reg((rpcprog_t)prognum, (rpcvers_t)versnum, + (rpcproc_t)procnum, progname, inproc, outproc, "udp"); +} + +/* + * All the following clnt_broadcast stuff is convulated; it supports + * the earlier calling style of the callback function + */ +static thread_key_t clnt_broadcast_key; +static resultproc_t clnt_broadcast_result_main; +static once_t clnt_broadcast_once = ONCE_INITIALIZER; + +static void +clnt_broadcast_key_init(void) +{ + + thr_keycreate(&clnt_broadcast_key, free); +} + +/* + * Need to translate the netbuf address into sockaddr_in address. + * Dont care about netid here. + */ +/* ARGSUSED */ +static bool_t +rpc_wrap_bcast(resultp, addr, nconf) + char *resultp; /* results of the call */ + struct netbuf *addr; /* address of the guy who responded */ + struct netconfig *nconf; /* Netconf of the transport */ +{ + resultproc_t clnt_broadcast_result; + + if (strcmp(nconf->nc_netid, "udp")) + return (FALSE); + if (thr_main()) + clnt_broadcast_result = clnt_broadcast_result_main; + else + clnt_broadcast_result = (resultproc_t)thr_getspecific(clnt_broadcast_key); + return (*clnt_broadcast_result)(resultp, + (struct sockaddr_in *)addr->buf); +} + +/* + * Broadcasts on UDP transport. Obsoleted by rpc_broadcast(). + */ +enum clnt_stat +clnt_broadcast(prog, vers, proc, xargs, argsp, xresults, resultsp, eachresult) + u_long prog; /* program number */ + u_long vers; /* version number */ + u_long proc; /* procedure number */ + xdrproc_t xargs; /* xdr routine for args */ + void *argsp; /* pointer to args */ + xdrproc_t xresults; /* xdr routine for results */ + void *resultsp; /* pointer to results */ + resultproc_t eachresult; /* call with each result obtained */ +{ + + if (thr_main()) + clnt_broadcast_result_main = eachresult; + else { + thr_once(&clnt_broadcast_once, clnt_broadcast_key_init); + thr_setspecific(clnt_broadcast_key, (void *) eachresult); + } + return rpc_broadcast((rpcprog_t)prog, (rpcvers_t)vers, + (rpcproc_t)proc, xargs, argsp, xresults, resultsp, + (resultproc_t) rpc_wrap_bcast, "udp"); +} + +/* + * Create the client des authentication object. Obsoleted by + * authdes_seccreate(). + */ +AUTH * +authdes_create(servername, window, syncaddr, ckey) + char *servername; /* network name of server */ + u_int window; /* time to live */ + struct sockaddr *syncaddr; /* optional hostaddr to sync with */ + des_block *ckey; /* optional conversation key to use */ +{ + AUTH *dummy; + AUTH *nauth; + char hostname[NI_MAXHOST]; + + if (syncaddr) { + /* + * Change addr to hostname, because that is the way + * new interface takes it. + */ + if (getnameinfo(syncaddr, syncaddr->sa_len, hostname, + sizeof hostname, NULL, 0, 0) != 0) + goto fallback; + + nauth = authdes_seccreate(servername, window, hostname, ckey); + return (nauth); + } +fallback: + dummy = authdes_seccreate(servername, window, NULL, ckey); + return (dummy); +} + +/* + * Create a client handle for a unix connection. Obsoleted by clnt_vc_create() + */ +CLIENT * +clntunix_create(raddr, prog, vers, sockp, sendsz, recvsz) + struct sockaddr_un *raddr; + u_long prog; + u_long vers; + int *sockp; + u_int sendsz; + u_int recvsz; +{ + struct netbuf *svcaddr; + struct netconfig *nconf; + CLIENT *cl; + int len; + + cl = NULL; + nconf = NULL; + svcaddr = NULL; + if ((raddr->sun_len == 0) || + ((svcaddr = malloc(sizeof(struct netbuf))) == NULL ) || + ((svcaddr->buf = malloc(sizeof(struct sockaddr_un))) == NULL)) { + if (svcaddr != NULL) + free(svcaddr); + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + return(cl); + } + if (*sockp < 0) { + *sockp = _socket(AF_LOCAL, SOCK_STREAM, 0); + len = raddr->sun_len = SUN_LEN(raddr); + if ((*sockp < 0) || (_connect(*sockp, + (struct sockaddr *)raddr, len) < 0)) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + if (*sockp != -1) + (void)_close(*sockp); + goto done; + } + } + svcaddr->buf = raddr; + svcaddr->len = raddr->sun_len; + svcaddr->maxlen = sizeof (struct sockaddr_un); + cl = clnt_vc_create(*sockp, svcaddr, prog, + vers, sendsz, recvsz); +done: + free(svcaddr->buf); + free(svcaddr); + return(cl); +} + +/* + * Creates, registers, and returns a (rpc) unix based transporter. + * Obsoleted by svc_vc_create(). + */ +SVCXPRT * +svcunix_create(sock, sendsize, recvsize, path) + int sock; + u_int sendsize; + u_int recvsize; + char *path; +{ + struct netconfig *nconf; + void *localhandle; + struct sockaddr_un sun; + struct sockaddr *sa; + struct t_bind taddr; + SVCXPRT *xprt; + int addrlen; + + xprt = (SVCXPRT *)NULL; + localhandle = setnetconfig(); + while ((nconf = getnetconfig(localhandle)) != NULL) { + if (nconf->nc_protofmly != NULL && + strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) + break; + } + if (nconf == NULL) + return(xprt); + + if ((sock = __rpc_nconf2fd(nconf)) < 0) + goto done; + + memset(&sun, 0, sizeof sun); + sun.sun_family = AF_LOCAL; + if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >= + sizeof(sun.sun_path)) + goto done; + sun.sun_len = SUN_LEN(&sun); + addrlen = sizeof (struct sockaddr_un); + sa = (struct sockaddr *)&sun; + + if (_bind(sock, sa, addrlen) < 0) + goto done; + + taddr.addr.len = taddr.addr.maxlen = addrlen; + taddr.addr.buf = malloc(addrlen); + if (taddr.addr.buf == NULL) + goto done; + memcpy(taddr.addr.buf, sa, addrlen); + + if (nconf->nc_semantics != NC_TPI_CLTS) { + if (_listen(sock, SOMAXCONN) < 0) { + free(taddr.addr.buf); + goto done; + } + } + + xprt = (SVCXPRT *)svc_tli_create(sock, nconf, &taddr, sendsize, recvsize); + +done: + endnetconfig(localhandle); + return(xprt); +} + +/* + * Like svunix_create(), except the routine takes any *open* UNIX file + * descriptor as its first input. Obsoleted by svc_fd_create(); + */ +SVCXPRT * +svcunixfd_create(fd, sendsize, recvsize) + int fd; + u_int sendsize; + u_int recvsize; +{ + return (svc_fd_create(fd, sendsize, recvsize)); +} + +#endif /* PORTMAP */ diff --git a/freebsd/lib/libc/rpc/rpcb_clnt.c b/freebsd/lib/libc/rpc/rpcb_clnt.c new file mode 100644 index 00000000..120b792c --- /dev/null +++ b/freebsd/lib/libc/rpc/rpcb_clnt.c @@ -0,0 +1,1342 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: rpcb_clnt.c,v 1.6 2000/07/16 06:41:43 itojun Exp $ */ + +/*- + * Copyright (c) 2010, Oracle America, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of the "Oracle America, Inc." nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* #ident "@(#)rpcb_clnt.c 1.27 94/04/24 SMI" */ + + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)rpcb_clnt.c 1.30 89/06/21 Copyr 1988 Sun Micro"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * rpcb_clnt.c + * interface to rpcbind rpc service. + */ + +#include "namespace.h" +#include "reentrant.h" +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/utsname.h> +#include <rpc/rpc.h> +#include <rpc/rpcb_prot.h> +#include <rpc/nettype.h> +#include <netconfig.h> +#ifdef PORTMAP +#include <netinet/in.h> /* FOR IPPROTO_TCP/UDP definitions */ +#include <rpc/pmap_prot.h> +#endif /* PORTMAP */ +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <netdb.h> +#include <syslog.h> +#include "un-namespace.h" + +#include "rpc_com.h" +#include "mt_misc.h" + +static struct timeval tottimeout = { 60, 0 }; +static const struct timeval rmttimeout = { 3, 0 }; +static struct timeval rpcbrmttime = { 15, 0 }; + +extern bool_t xdr_wrapstring(XDR *, char **); + +static const char nullstring[] = "\000"; + +#define CACHESIZE 6 + +struct address_cache { + char *ac_host; + char *ac_netid; + char *ac_uaddr; + struct netbuf *ac_taddr; + struct address_cache *ac_next; +}; + +static struct address_cache *front; +static int cachesize; + +#define CLCR_GET_RPCB_TIMEOUT 1 +#define CLCR_SET_RPCB_TIMEOUT 2 + + +extern int __rpc_lowvers; + +static struct address_cache *check_cache(const char *, const char *); +static void delete_cache(struct netbuf *); +static void add_cache(const char *, const char *, struct netbuf *, char *); +static CLIENT *getclnthandle(const char *, const struct netconfig *, char **); +static CLIENT *local_rpcb(void); +static struct netbuf *got_entry(rpcb_entry_list_ptr, const struct netconfig *); + +/* + * This routine adjusts the timeout used for calls to the remote rpcbind. + * Also, this routine can be used to set the use of portmapper version 2 + * only when doing rpc_broadcasts + * These are private routines that may not be provided in future releases. + */ +bool_t +__rpc_control(request, info) + int request; + void *info; +{ + switch (request) { + case CLCR_GET_RPCB_TIMEOUT: + *(struct timeval *)info = tottimeout; + break; + case CLCR_SET_RPCB_TIMEOUT: + tottimeout = *(struct timeval *)info; + break; + case CLCR_SET_LOWVERS: + __rpc_lowvers = *(int *)info; + break; + case CLCR_GET_LOWVERS: + *(int *)info = __rpc_lowvers; + break; + default: + return (FALSE); + } + return (TRUE); +} + +/* + * It might seem that a reader/writer lock would be more reasonable here. + * However because getclnthandle(), the only user of the cache functions, + * may do a delete_cache() operation if a check_cache() fails to return an + * address useful to clnt_tli_create(), we may as well use a mutex. + */ +/* + * As it turns out, if the cache lock is *not* a reader/writer lock, we will + * block all clnt_create's if we are trying to connect to a host that's down, + * since the lock will be held all during that time. + */ + +/* + * The routines check_cache(), add_cache(), delete_cache() manage the + * cache of rpcbind addresses for (host, netid). + */ + +static struct address_cache * +check_cache(host, netid) + const char *host, *netid; +{ + struct address_cache *cptr; + + /* READ LOCK HELD ON ENTRY: rpcbaddr_cache_lock */ + + for (cptr = front; cptr != NULL; cptr = cptr->ac_next) { + if (!strcmp(cptr->ac_host, host) && + !strcmp(cptr->ac_netid, netid)) { +#ifdef ND_DEBUG + fprintf(stderr, "Found cache entry for %s: %s\n", + host, netid); +#endif + return (cptr); + } + } + return ((struct address_cache *) NULL); +} + +static void +delete_cache(addr) + struct netbuf *addr; +{ + struct address_cache *cptr, *prevptr = NULL; + + /* WRITE LOCK HELD ON ENTRY: rpcbaddr_cache_lock */ + for (cptr = front; cptr != NULL; cptr = cptr->ac_next) { + if (!memcmp(cptr->ac_taddr->buf, addr->buf, addr->len)) { + free(cptr->ac_host); + free(cptr->ac_netid); + free(cptr->ac_taddr->buf); + free(cptr->ac_taddr); + if (cptr->ac_uaddr) + free(cptr->ac_uaddr); + if (prevptr) + prevptr->ac_next = cptr->ac_next; + else + front = cptr->ac_next; + free(cptr); + cachesize--; + break; + } + prevptr = cptr; + } +} + +static void +add_cache(host, netid, taddr, uaddr) + const char *host, *netid; + char *uaddr; + struct netbuf *taddr; +{ + struct address_cache *ad_cache, *cptr, *prevptr; + + ad_cache = (struct address_cache *) + malloc(sizeof (struct address_cache)); + if (!ad_cache) { + return; + } + ad_cache->ac_host = strdup(host); + ad_cache->ac_netid = strdup(netid); + ad_cache->ac_uaddr = uaddr ? strdup(uaddr) : NULL; + ad_cache->ac_taddr = (struct netbuf *)malloc(sizeof (struct netbuf)); + if (!ad_cache->ac_host || !ad_cache->ac_netid || !ad_cache->ac_taddr || + (uaddr && !ad_cache->ac_uaddr)) { + goto out; + } + ad_cache->ac_taddr->len = ad_cache->ac_taddr->maxlen = taddr->len; + ad_cache->ac_taddr->buf = (char *) malloc(taddr->len); + if (ad_cache->ac_taddr->buf == NULL) { +out: + if (ad_cache->ac_host) + free(ad_cache->ac_host); + if (ad_cache->ac_netid) + free(ad_cache->ac_netid); + if (ad_cache->ac_uaddr) + free(ad_cache->ac_uaddr); + if (ad_cache->ac_taddr) + free(ad_cache->ac_taddr); + free(ad_cache); + return; + } + memcpy(ad_cache->ac_taddr->buf, taddr->buf, taddr->len); +#ifdef ND_DEBUG + fprintf(stderr, "Added to cache: %s : %s\n", host, netid); +#endif + +/* VARIABLES PROTECTED BY rpcbaddr_cache_lock: cptr */ + + rwlock_wrlock(&rpcbaddr_cache_lock); + if (cachesize < CACHESIZE) { + ad_cache->ac_next = front; + front = ad_cache; + cachesize++; + } else { + /* Free the last entry */ + cptr = front; + prevptr = NULL; + while (cptr->ac_next) { + prevptr = cptr; + cptr = cptr->ac_next; + } + +#ifdef ND_DEBUG + fprintf(stderr, "Deleted from cache: %s : %s\n", + cptr->ac_host, cptr->ac_netid); +#endif + free(cptr->ac_host); + free(cptr->ac_netid); + free(cptr->ac_taddr->buf); + free(cptr->ac_taddr); + if (cptr->ac_uaddr) + free(cptr->ac_uaddr); + + if (prevptr) { + prevptr->ac_next = NULL; + ad_cache->ac_next = front; + front = ad_cache; + } else { + front = ad_cache; + ad_cache->ac_next = NULL; + } + free(cptr); + } + rwlock_unlock(&rpcbaddr_cache_lock); +} + +/* + * This routine will return a client handle that is connected to the + * rpcbind. If targaddr is non-NULL, the "universal address" of the + * host will be stored in *targaddr; the caller is responsible for + * freeing this string. + * On error, returns NULL and free's everything. + */ +static CLIENT * +getclnthandle(host, nconf, targaddr) + const char *host; + const struct netconfig *nconf; + char **targaddr; +{ + CLIENT *client; + struct netbuf *addr, taddr; + struct netbuf addr_to_delete; + struct __rpc_sockinfo si; + struct addrinfo hints, *res, *tres; + struct address_cache *ad_cache; + char *tmpaddr; + +/* VARIABLES PROTECTED BY rpcbaddr_cache_lock: ad_cache */ + + /* Get the address of the rpcbind. Check cache first */ + client = NULL; + addr_to_delete.len = 0; + rwlock_rdlock(&rpcbaddr_cache_lock); + ad_cache = NULL; + if (host != NULL) + ad_cache = check_cache(host, nconf->nc_netid); + if (ad_cache != NULL) { + addr = ad_cache->ac_taddr; + client = clnt_tli_create(RPC_ANYFD, nconf, addr, + (rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS4, 0, 0); + if (client != NULL) { + if (targaddr) + *targaddr = strdup(ad_cache->ac_uaddr); + rwlock_unlock(&rpcbaddr_cache_lock); + return (client); + } + addr_to_delete.len = addr->len; + addr_to_delete.buf = (char *)malloc(addr->len); + if (addr_to_delete.buf == NULL) { + addr_to_delete.len = 0; + } else { + memcpy(addr_to_delete.buf, addr->buf, addr->len); + } + } + rwlock_unlock(&rpcbaddr_cache_lock); + if (addr_to_delete.len != 0) { + /* + * Assume this may be due to cache data being + * outdated + */ + rwlock_wrlock(&rpcbaddr_cache_lock); + delete_cache(&addr_to_delete); + rwlock_unlock(&rpcbaddr_cache_lock); + free(addr_to_delete.buf); + } + if (!__rpc_nconf2sockinfo(nconf, &si)) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return NULL; + } + + memset(&hints, 0, sizeof hints); + hints.ai_family = si.si_af; + hints.ai_socktype = si.si_socktype; + hints.ai_protocol = si.si_proto; + +#ifdef CLNT_DEBUG + printf("trying netid %s family %d proto %d socktype %d\n", + nconf->nc_netid, si.si_af, si.si_proto, si.si_socktype); +#endif + + if (nconf->nc_protofmly != NULL && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) { + client = local_rpcb(); + if (! client) { +#ifdef ND_DEBUG + clnt_pcreateerror("rpcbind clnt interface"); +#endif + return (NULL); + } else { + struct sockaddr_un sun; + if (targaddr) { + *targaddr = malloc(sizeof(sun.sun_path)); + if (*targaddr == NULL) { + CLNT_DESTROY(client); + return (NULL); + } + strncpy(*targaddr, _PATH_RPCBINDSOCK, + sizeof(sun.sun_path)); + } + return (client); + } + } else { + if (getaddrinfo(host, "sunrpc", &hints, &res) != 0) { + rpc_createerr.cf_stat = RPC_UNKNOWNHOST; + return NULL; + } + } + + for (tres = res; tres != NULL; tres = tres->ai_next) { + taddr.buf = tres->ai_addr; + taddr.len = taddr.maxlen = tres->ai_addrlen; + +#ifdef ND_DEBUG + { + char *ua; + + ua = taddr2uaddr(nconf, &taddr); + fprintf(stderr, "Got it [%s]\n", ua); + free(ua); + } +#endif + +#ifdef ND_DEBUG + { + int i; + + fprintf(stderr, "\tnetbuf len = %d, maxlen = %d\n", + taddr.len, taddr.maxlen); + fprintf(stderr, "\tAddress is "); + for (i = 0; i < taddr.len; i++) + fprintf(stderr, "%u.", ((char *)(taddr.buf))[i]); + fprintf(stderr, "\n"); + } +#endif + client = clnt_tli_create(RPC_ANYFD, nconf, &taddr, + (rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS4, 0, 0); +#ifdef ND_DEBUG + if (! client) { + clnt_pcreateerror("rpcbind clnt interface"); + } +#endif + + if (client) { + tmpaddr = targaddr ? taddr2uaddr(nconf, &taddr) : NULL; + add_cache(host, nconf->nc_netid, &taddr, tmpaddr); + if (targaddr) + *targaddr = tmpaddr; + break; + } + } + if (res) + freeaddrinfo(res); + return (client); +} + +/* XXX */ +#define IN4_LOCALHOST_STRING "127.0.0.1" +#define IN6_LOCALHOST_STRING "::1" + +/* + * This routine will return a client handle that is connected to the local + * rpcbind. Returns NULL on error and free's everything. + */ +static CLIENT * +local_rpcb() +{ + CLIENT *client; + static struct netconfig *loopnconf; + static char *hostname; + int sock; + size_t tsize; + struct netbuf nbuf; + struct sockaddr_un sun; + + /* + * Try connecting to the local rpcbind through a local socket + * first. If this doesn't work, try all transports defined in + * the netconfig file. + */ + memset(&sun, 0, sizeof sun); + sock = _socket(AF_LOCAL, SOCK_STREAM, 0); + if (sock < 0) + goto try_nconf; + sun.sun_family = AF_LOCAL; + strcpy(sun.sun_path, _PATH_RPCBINDSOCK); + nbuf.len = sun.sun_len = SUN_LEN(&sun); + nbuf.maxlen = sizeof (struct sockaddr_un); + nbuf.buf = &sun; + + tsize = __rpc_get_t_size(AF_LOCAL, 0, 0); + client = clnt_vc_create(sock, &nbuf, (rpcprog_t)RPCBPROG, + (rpcvers_t)RPCBVERS, tsize, tsize); + + if (client != NULL) { + /* Mark the socket to be closed in destructor */ + (void) CLNT_CONTROL(client, CLSET_FD_CLOSE, NULL); + return client; + } + + /* Nobody needs this socket anymore; free the descriptor. */ + _close(sock); + +try_nconf: + +/* VARIABLES PROTECTED BY loopnconf_lock: loopnconf */ + mutex_lock(&loopnconf_lock); + if (loopnconf == NULL) { + struct netconfig *nconf, *tmpnconf = NULL; + void *nc_handle; + int fd; + + nc_handle = setnetconfig(); + if (nc_handle == NULL) { + /* fails to open netconfig file */ + syslog (LOG_ERR, "rpc: failed to open " NETCONFIG); + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + mutex_unlock(&loopnconf_lock); + return (NULL); + } + while ((nconf = getnetconfig(nc_handle)) != NULL) { +#ifdef INET6 + if ((strcmp(nconf->nc_protofmly, NC_INET6) == 0 || +#else + if (( +#endif + strcmp(nconf->nc_protofmly, NC_INET) == 0) && + (nconf->nc_semantics == NC_TPI_COTS || + nconf->nc_semantics == NC_TPI_COTS_ORD)) { + fd = __rpc_nconf2fd(nconf); + /* + * Can't create a socket, assume that + * this family isn't configured in the kernel. + */ + if (fd < 0) + continue; + _close(fd); + tmpnconf = nconf; + if (!strcmp(nconf->nc_protofmly, NC_INET)) + hostname = IN4_LOCALHOST_STRING; + else + hostname = IN6_LOCALHOST_STRING; + } + } + if (tmpnconf == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + mutex_unlock(&loopnconf_lock); + return (NULL); + } + loopnconf = getnetconfigent(tmpnconf->nc_netid); + /* loopnconf is never freed */ + endnetconfig(nc_handle); + } + mutex_unlock(&loopnconf_lock); + client = getclnthandle(hostname, loopnconf, NULL); + return (client); +} + +/* + * Set a mapping between program, version and address. + * Calls the rpcbind service to do the mapping. + */ +bool_t +rpcb_set(program, version, nconf, address) + rpcprog_t program; + rpcvers_t version; + const struct netconfig *nconf; /* Network structure of transport */ + const struct netbuf *address; /* Services netconfig address */ +{ + CLIENT *client; + bool_t rslt = FALSE; + RPCB parms; + char uidbuf[32]; + + /* parameter checking */ + if (nconf == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return (FALSE); + } + if (address == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNADDR; + return (FALSE); + } + client = local_rpcb(); + if (! client) { + return (FALSE); + } + + /* convert to universal */ + /*LINTED const castaway*/ + parms.r_addr = taddr2uaddr((struct netconfig *) nconf, + (struct netbuf *)address); + if (!parms.r_addr) { + CLNT_DESTROY(client); + rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE; + return (FALSE); /* no universal address */ + } + parms.r_prog = program; + parms.r_vers = version; + parms.r_netid = nconf->nc_netid; + /* + * Though uid is not being used directly, we still send it for + * completeness. For non-unix platforms, perhaps some other + * string or an empty string can be sent. + */ + (void) snprintf(uidbuf, sizeof uidbuf, "%d", geteuid()); + parms.r_owner = uidbuf; + + CLNT_CALL(client, (rpcproc_t)RPCBPROC_SET, (xdrproc_t) xdr_rpcb, + (char *)(void *)&parms, (xdrproc_t) xdr_bool, + (char *)(void *)&rslt, tottimeout); + + CLNT_DESTROY(client); + free(parms.r_addr); + return (rslt); +} + +/* + * Remove the mapping between program, version and netbuf address. + * Calls the rpcbind service to do the un-mapping. + * If netbuf is NULL, unset for all the transports, otherwise unset + * only for the given transport. + */ +bool_t +rpcb_unset(program, version, nconf) + rpcprog_t program; + rpcvers_t version; + const struct netconfig *nconf; +{ + CLIENT *client; + bool_t rslt = FALSE; + RPCB parms; + char uidbuf[32]; + + client = local_rpcb(); + if (! client) { + return (FALSE); + } + + parms.r_prog = program; + parms.r_vers = version; + if (nconf) + parms.r_netid = nconf->nc_netid; + else { + /*LINTED const castaway*/ + parms.r_netid = (char *) &nullstring[0]; /* unsets all */ + } + /*LINTED const castaway*/ + parms.r_addr = (char *) &nullstring[0]; + (void) snprintf(uidbuf, sizeof uidbuf, "%d", geteuid()); + parms.r_owner = uidbuf; + + CLNT_CALL(client, (rpcproc_t)RPCBPROC_UNSET, (xdrproc_t) xdr_rpcb, + (char *)(void *)&parms, (xdrproc_t) xdr_bool, + (char *)(void *)&rslt, tottimeout); + + CLNT_DESTROY(client); + return (rslt); +} + +/* + * From the merged list, find the appropriate entry + */ +static struct netbuf * +got_entry(relp, nconf) + rpcb_entry_list_ptr relp; + const struct netconfig *nconf; +{ + struct netbuf *na = NULL; + rpcb_entry_list_ptr sp; + rpcb_entry *rmap; + + for (sp = relp; sp != NULL; sp = sp->rpcb_entry_next) { + rmap = &sp->rpcb_entry_map; + if ((strcmp(nconf->nc_proto, rmap->r_nc_proto) == 0) && + (strcmp(nconf->nc_protofmly, rmap->r_nc_protofmly) == 0) && + (nconf->nc_semantics == rmap->r_nc_semantics) && + (rmap->r_maddr != NULL) && (rmap->r_maddr[0] != 0)) { + na = uaddr2taddr(nconf, rmap->r_maddr); +#ifdef ND_DEBUG + fprintf(stderr, "\tRemote address is [%s].\n", + rmap->r_maddr); + if (!na) + fprintf(stderr, + "\tCouldn't resolve remote address!\n"); +#endif + break; + } + } + return (na); +} + +/* + * Quick check to see if rpcbind is up. Tries to connect over + * local transport. + */ +static bool_t +__rpcbind_is_up() +{ + struct netconfig *nconf; + struct sockaddr_un sun; + void *localhandle; + int sock; + + nconf = NULL; + localhandle = setnetconfig(); + while ((nconf = getnetconfig(localhandle)) != NULL) { + if (nconf->nc_protofmly != NULL && + strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) + break; + } + if (nconf == NULL) + return (FALSE); + + endnetconfig(localhandle); + + memset(&sun, 0, sizeof sun); + sock = _socket(AF_LOCAL, SOCK_STREAM, 0); + if (sock < 0) + return (FALSE); + sun.sun_family = AF_LOCAL; + strncpy(sun.sun_path, _PATH_RPCBINDSOCK, sizeof(sun.sun_path)); + sun.sun_len = SUN_LEN(&sun); + + if (_connect(sock, (struct sockaddr *)&sun, sun.sun_len) < 0) { + _close(sock); + return (FALSE); + } + + _close(sock); + return (TRUE); +} + +/* + * An internal function which optimizes rpcb_getaddr function. It also + * returns the client handle that it uses to contact the remote rpcbind. + * + * The algorithm used: If the transports is TCP or UDP, it first tries + * version 2 (portmap), 4 and then 3 (svr4). This order should be + * changed in the next OS release to 4, 2 and 3. We are assuming that by + * that time, version 4 would be available on many machines on the network. + * With this algorithm, we get performance as well as a plan for + * obsoleting version 2. + * + * For all other transports, the algorithm remains as 4 and then 3. + * + * XXX: Due to some problems with t_connect(), we do not reuse the same client + * handle for COTS cases and hence in these cases we do not return the + * client handle. This code will change if t_connect() ever + * starts working properly. Also look under clnt_vc.c. + */ +struct netbuf * +__rpcb_findaddr_timed(program, version, nconf, host, clpp, tp) + rpcprog_t program; + rpcvers_t version; + const struct netconfig *nconf; + const char *host; + CLIENT **clpp; + struct timeval *tp; +{ + static bool_t check_rpcbind = TRUE; + CLIENT *client = NULL; + RPCB parms; + enum clnt_stat clnt_st; + char *ua = NULL; + rpcvers_t vers; + struct netbuf *address = NULL; + rpcvers_t start_vers = RPCBVERS4; + struct netbuf servaddr; + + /* parameter checking */ + if (nconf == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return (NULL); + } + + parms.r_addr = NULL; + + /* + * Use default total timeout if no timeout is specified. + */ + if (tp == NULL) + tp = &tottimeout; + +#ifdef PORTMAP + /* Try version 2 for TCP or UDP */ + if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { + u_short port = 0; + struct netbuf remote; + rpcvers_t pmapvers = 2; + struct pmap pmapparms; + + /* + * Try UDP only - there are some portmappers out + * there that use UDP only. + */ + if (strcmp(nconf->nc_proto, NC_TCP) == 0) { + struct netconfig *newnconf; + + if ((newnconf = getnetconfigent("udp")) == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return (NULL); + } + client = getclnthandle(host, newnconf, &parms.r_addr); + freenetconfigent(newnconf); + } else { + client = getclnthandle(host, nconf, &parms.r_addr); + } + if (client == NULL) + return (NULL); + + /* + * Set version and retry timeout. + */ + CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime); + CLNT_CONTROL(client, CLSET_VERS, (char *)&pmapvers); + + pmapparms.pm_prog = program; + pmapparms.pm_vers = version; + pmapparms.pm_prot = strcmp(nconf->nc_proto, NC_TCP) ? + IPPROTO_UDP : IPPROTO_TCP; + pmapparms.pm_port = 0; /* not needed */ + clnt_st = CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT, + (xdrproc_t) xdr_pmap, (caddr_t)(void *)&pmapparms, + (xdrproc_t) xdr_u_short, (caddr_t)(void *)&port, + *tp); + if (clnt_st != RPC_SUCCESS) { + if ((clnt_st == RPC_PROGVERSMISMATCH) || + (clnt_st == RPC_PROGUNAVAIL)) + goto try_rpcbind; /* Try different versions */ + rpc_createerr.cf_stat = RPC_PMAPFAILURE; + clnt_geterr(client, &rpc_createerr.cf_error); + goto error; + } else if (port == 0) { + address = NULL; + rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; + goto error; + } + port = htons(port); + CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)&remote); + if (((address = (struct netbuf *) + malloc(sizeof (struct netbuf))) == NULL) || + ((address->buf = (char *) + malloc(remote.len)) == NULL)) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + clnt_geterr(client, &rpc_createerr.cf_error); + if (address) { + free(address); + address = NULL; + } + goto error; + } + memcpy(address->buf, remote.buf, remote.len); + memcpy(&((char *)address->buf)[sizeof (short)], + (char *)(void *)&port, sizeof (short)); + address->len = address->maxlen = remote.len; + goto done; + } +#endif /* PORTMAP */ + +try_rpcbind: + /* + * Check if rpcbind is up. This prevents needless delays when + * accessing applications such as the keyserver while booting + * disklessly. + */ + if (check_rpcbind && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) { + if (!__rpcbind_is_up()) { + rpc_createerr.cf_stat = RPC_PMAPFAILURE; + rpc_createerr.cf_error.re_errno = 0; + goto error; + } + check_rpcbind = FALSE; + } + + /* + * Now we try version 4 and then 3. + * We also send the remote system the address we used to + * contact it in case it can help to connect back with us + */ + parms.r_prog = program; + parms.r_vers = version; + /*LINTED const castaway*/ + parms.r_owner = (char *) &nullstring[0]; /* not needed; */ + /* just for xdring */ + parms.r_netid = nconf->nc_netid; /* not really needed */ + + /* + * If a COTS transport is being used, try getting address via CLTS + * transport. This works only with version 4. + */ + if (nconf->nc_semantics == NC_TPI_COTS_ORD || + nconf->nc_semantics == NC_TPI_COTS) { + + void *handle; + struct netconfig *nconf_clts; + rpcb_entry_list_ptr relp = NULL; + + if (client == NULL) { + /* This did not go through the above PORTMAP/TCP code */ + if ((handle = __rpc_setconf("datagram_v")) != NULL) { + while ((nconf_clts = __rpc_getconf(handle)) + != NULL) { + if (strcmp(nconf_clts->nc_protofmly, + nconf->nc_protofmly) != 0) { + continue; + } + client = getclnthandle(host, nconf_clts, + &parms.r_addr); + break; + } + __rpc_endconf(handle); + } + if (client == NULL) + goto regular_rpcbind; /* Go the regular way */ + } else { + /* This is a UDP PORTMAP handle. Change to version 4 */ + vers = RPCBVERS4; + CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); + } + /* + * We also send the remote system the address we used to + * contact it in case it can help it connect back with us + */ + if (parms.r_addr == NULL) { + /*LINTED const castaway*/ + parms.r_addr = (char *) &nullstring[0]; /* for XDRing */ + } + + CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime); + + clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDRLIST, + (xdrproc_t) xdr_rpcb, (char *)(void *)&parms, + (xdrproc_t) xdr_rpcb_entry_list_ptr, + (char *)(void *)&relp, *tp); + if (clnt_st == RPC_SUCCESS) { + if ((address = got_entry(relp, nconf)) != NULL) { + xdr_free((xdrproc_t) xdr_rpcb_entry_list_ptr, + (char *)(void *)&relp); + CLNT_CONTROL(client, CLGET_SVC_ADDR, + (char *)(void *)&servaddr); + __rpc_fixup_addr(address, &servaddr); + goto done; + } + /* Entry not found for this transport */ + xdr_free((xdrproc_t) xdr_rpcb_entry_list_ptr, + (char *)(void *)&relp); + /* + * XXX: should have perhaps returned with error but + * since the remote machine might not always be able + * to send the address on all transports, we try the + * regular way with regular_rpcbind + */ + goto regular_rpcbind; + } else if ((clnt_st == RPC_PROGVERSMISMATCH) || + (clnt_st == RPC_PROGUNAVAIL)) { + start_vers = RPCBVERS; /* Try version 3 now */ + goto regular_rpcbind; /* Try different versions */ + } else { + rpc_createerr.cf_stat = RPC_PMAPFAILURE; + clnt_geterr(client, &rpc_createerr.cf_error); + goto error; + } + } + +regular_rpcbind: + + /* Now the same transport is to be used to get the address */ + if (client && ((nconf->nc_semantics == NC_TPI_COTS_ORD) || + (nconf->nc_semantics == NC_TPI_COTS))) { + /* A CLTS type of client - destroy it */ + CLNT_DESTROY(client); + client = NULL; + } + + if (client == NULL) { + client = getclnthandle(host, nconf, &parms.r_addr); + if (client == NULL) { + goto error; + } + } + if (parms.r_addr == NULL) { + /*LINTED const castaway*/ + parms.r_addr = (char *) &nullstring[0]; + } + + /* First try from start_vers and then version 3 (RPCBVERS) */ + + CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *) &rpcbrmttime); + for (vers = start_vers; vers >= RPCBVERS; vers--) { + /* Set the version */ + CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); + clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDR, + (xdrproc_t) xdr_rpcb, (char *)(void *)&parms, + (xdrproc_t) xdr_wrapstring, (char *)(void *) &ua, *tp); + if (clnt_st == RPC_SUCCESS) { + if ((ua == NULL) || (ua[0] == 0)) { + /* address unknown */ + rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; + goto error; + } + address = uaddr2taddr(nconf, ua); +#ifdef ND_DEBUG + fprintf(stderr, "\tRemote address is [%s]\n", ua); + if (!address) + fprintf(stderr, + "\tCouldn't resolve remote address!\n"); +#endif + xdr_free((xdrproc_t)xdr_wrapstring, + (char *)(void *)&ua); + + if (! address) { + /* We don't know about your universal address */ + rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE; + goto error; + } + CLNT_CONTROL(client, CLGET_SVC_ADDR, + (char *)(void *)&servaddr); + __rpc_fixup_addr(address, &servaddr); + goto done; + } else if (clnt_st == RPC_PROGVERSMISMATCH) { + struct rpc_err rpcerr; + + clnt_geterr(client, &rpcerr); + if (rpcerr.re_vers.low > RPCBVERS4) + goto error; /* a new version, can't handle */ + } else if (clnt_st != RPC_PROGUNAVAIL) { + /* Cant handle this error */ + rpc_createerr.cf_stat = clnt_st; + clnt_geterr(client, &rpc_createerr.cf_error); + goto error; + } + } + +error: + if (client) { + CLNT_DESTROY(client); + client = NULL; + } +done: + if (nconf->nc_semantics != NC_TPI_CLTS) { + /* This client is the connectionless one */ + if (client) { + CLNT_DESTROY(client); + client = NULL; + } + } + if (clpp) { + *clpp = client; + } else if (client) { + CLNT_DESTROY(client); + } + if (parms.r_addr != NULL && parms.r_addr != nullstring) + free(parms.r_addr); + return (address); +} + + +/* + * Find the mapped address for program, version. + * Calls the rpcbind service remotely to do the lookup. + * Uses the transport specified in nconf. + * Returns FALSE (0) if no map exists, else returns 1. + * + * Assuming that the address is all properly allocated + */ +int +rpcb_getaddr(program, version, nconf, address, host) + rpcprog_t program; + rpcvers_t version; + const struct netconfig *nconf; + struct netbuf *address; + const char *host; +{ + struct netbuf *na; + + if ((na = __rpcb_findaddr_timed(program, version, + (struct netconfig *) nconf, (char *) host, + (CLIENT **) NULL, (struct timeval *) NULL)) == NULL) + return (FALSE); + + if (na->len > address->maxlen) { + /* Too long address */ + free(na->buf); + free(na); + rpc_createerr.cf_stat = RPC_FAILED; + return (FALSE); + } + memcpy(address->buf, na->buf, (size_t)na->len); + address->len = na->len; + free(na->buf); + free(na); + return (TRUE); +} + +/* + * Get a copy of the current maps. + * Calls the rpcbind service remotely to get the maps. + * + * It returns only a list of the services + * It returns NULL on failure. + */ +rpcblist * +rpcb_getmaps(nconf, host) + const struct netconfig *nconf; + const char *host; +{ + rpcblist_ptr head = NULL; + CLIENT *client; + enum clnt_stat clnt_st; + rpcvers_t vers = 0; + + client = getclnthandle(host, nconf, NULL); + if (client == NULL) { + return (head); + } + clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_DUMP, + (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_rpcblist_ptr, + (char *)(void *)&head, tottimeout); + if (clnt_st == RPC_SUCCESS) + goto done; + + if ((clnt_st != RPC_PROGVERSMISMATCH) && + (clnt_st != RPC_PROGUNAVAIL)) { + rpc_createerr.cf_stat = RPC_RPCBFAILURE; + clnt_geterr(client, &rpc_createerr.cf_error); + goto done; + } + + /* fall back to earlier version */ + CLNT_CONTROL(client, CLGET_VERS, (char *)(void *)&vers); + if (vers == RPCBVERS4) { + vers = RPCBVERS; + CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); + if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_DUMP, + (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_rpcblist_ptr, + (char *)(void *)&head, tottimeout) == RPC_SUCCESS) + goto done; + } + rpc_createerr.cf_stat = RPC_RPCBFAILURE; + clnt_geterr(client, &rpc_createerr.cf_error); + +done: + CLNT_DESTROY(client); + return (head); +} + +/* + * rpcbinder remote-call-service interface. + * This routine is used to call the rpcbind remote call service + * which will look up a service program in the address maps, and then + * remotely call that routine with the given parameters. This allows + * programs to do a lookup and call in one step. +*/ +enum clnt_stat +rpcb_rmtcall(nconf, host, prog, vers, proc, xdrargs, argsp, + xdrres, resp, tout, addr_ptr) + const struct netconfig *nconf; /* Netconfig structure */ + const char *host; /* Remote host name */ + rpcprog_t prog; + rpcvers_t vers; + rpcproc_t proc; /* Remote proc identifiers */ + xdrproc_t xdrargs, xdrres; /* XDR routines */ + caddr_t argsp, resp; /* Argument and Result */ + struct timeval tout; /* Timeout value for this call */ + const struct netbuf *addr_ptr; /* Preallocated netbuf address */ +{ + CLIENT *client; + enum clnt_stat stat; + struct r_rpcb_rmtcallargs a; + struct r_rpcb_rmtcallres r; + rpcvers_t rpcb_vers; + + stat = 0; + client = getclnthandle(host, nconf, NULL); + if (client == NULL) { + return (RPC_FAILED); + } + /*LINTED const castaway*/ + CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)(void *)&rmttimeout); + a.prog = prog; + a.vers = vers; + a.proc = proc; + a.args.args_val = argsp; + a.xdr_args = xdrargs; + r.addr = NULL; + r.results.results_val = resp; + r.xdr_res = xdrres; + + for (rpcb_vers = RPCBVERS4; rpcb_vers >= RPCBVERS; rpcb_vers--) { + CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&rpcb_vers); + stat = CLNT_CALL(client, (rpcproc_t)RPCBPROC_CALLIT, + (xdrproc_t) xdr_rpcb_rmtcallargs, (char *)(void *)&a, + (xdrproc_t) xdr_rpcb_rmtcallres, (char *)(void *)&r, tout); + if ((stat == RPC_SUCCESS) && (addr_ptr != NULL)) { + struct netbuf *na; + /*LINTED const castaway*/ + na = uaddr2taddr((struct netconfig *) nconf, r.addr); + if (!na) { + stat = RPC_N2AXLATEFAILURE; + /*LINTED const castaway*/ + ((struct netbuf *) addr_ptr)->len = 0; + goto error; + } + if (na->len > addr_ptr->maxlen) { + /* Too long address */ + stat = RPC_FAILED; /* XXX A better error no */ + free(na->buf); + free(na); + /*LINTED const castaway*/ + ((struct netbuf *) addr_ptr)->len = 0; + goto error; + } + memcpy(addr_ptr->buf, na->buf, (size_t)na->len); + /*LINTED const castaway*/ + ((struct netbuf *)addr_ptr)->len = na->len; + free(na->buf); + free(na); + break; + } else if ((stat != RPC_PROGVERSMISMATCH) && + (stat != RPC_PROGUNAVAIL)) { + goto error; + } + } +error: + CLNT_DESTROY(client); + if (r.addr) + xdr_free((xdrproc_t) xdr_wrapstring, (char *)(void *)&r.addr); + return (stat); +} + +/* + * Gets the time on the remote host. + * Returns 1 if succeeds else 0. + */ +bool_t +rpcb_gettime(host, timep) + const char *host; + time_t *timep; +{ + CLIENT *client = NULL; + void *handle; + struct netconfig *nconf; + rpcvers_t vers; + enum clnt_stat st; + + + if ((host == NULL) || (host[0] == 0)) { + time(timep); + return (TRUE); + } + + if ((handle = __rpc_setconf("netpath")) == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return (FALSE); + } + rpc_createerr.cf_stat = RPC_SUCCESS; + while (client == NULL) { + if ((nconf = __rpc_getconf(handle)) == NULL) { + if (rpc_createerr.cf_stat == RPC_SUCCESS) + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + break; + } + client = getclnthandle(host, nconf, NULL); + if (client) + break; + } + __rpc_endconf(handle); + if (client == (CLIENT *) NULL) { + return (FALSE); + } + + st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETTIME, + (xdrproc_t) xdr_void, NULL, + (xdrproc_t) xdr_int, (char *)(void *)timep, tottimeout); + + if ((st == RPC_PROGVERSMISMATCH) || (st == RPC_PROGUNAVAIL)) { + CLNT_CONTROL(client, CLGET_VERS, (char *)(void *)&vers); + if (vers == RPCBVERS4) { + /* fall back to earlier version */ + vers = RPCBVERS; + CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); + st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETTIME, + (xdrproc_t) xdr_void, NULL, + (xdrproc_t) xdr_int, (char *)(void *)timep, + tottimeout); + } + } + CLNT_DESTROY(client); + return (st == RPC_SUCCESS? TRUE: FALSE); +} + +/* + * Converts taddr to universal address. This routine should never + * really be called because local n2a libraries are always provided. + */ +char * +rpcb_taddr2uaddr(nconf, taddr) + struct netconfig *nconf; + struct netbuf *taddr; +{ + CLIENT *client; + char *uaddr = NULL; + + + /* parameter checking */ + if (nconf == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return (NULL); + } + if (taddr == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNADDR; + return (NULL); + } + client = local_rpcb(); + if (! client) { + return (NULL); + } + + CLNT_CALL(client, (rpcproc_t)RPCBPROC_TADDR2UADDR, + (xdrproc_t) xdr_netbuf, (char *)(void *)taddr, + (xdrproc_t) xdr_wrapstring, (char *)(void *)&uaddr, tottimeout); + CLNT_DESTROY(client); + return (uaddr); +} + +/* + * Converts universal address to netbuf. This routine should never + * really be called because local n2a libraries are always provided. + */ +struct netbuf * +rpcb_uaddr2taddr(nconf, uaddr) + struct netconfig *nconf; + char *uaddr; +{ + CLIENT *client; + struct netbuf *taddr; + + + /* parameter checking */ + if (nconf == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return (NULL); + } + if (uaddr == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNADDR; + return (NULL); + } + client = local_rpcb(); + if (! client) { + return (NULL); + } + + taddr = (struct netbuf *)calloc(1, sizeof (struct netbuf)); + if (taddr == NULL) { + CLNT_DESTROY(client); + return (NULL); + } + if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_UADDR2TADDR, + (xdrproc_t) xdr_wrapstring, (char *)(void *)&uaddr, + (xdrproc_t) xdr_netbuf, (char *)(void *)taddr, + tottimeout) != RPC_SUCCESS) { + free(taddr); + taddr = NULL; + } + CLNT_DESTROY(client); + return (taddr); +} diff --git a/freebsd/lib/libc/rpc/rpcb_prot.c b/freebsd/lib/libc/rpc/rpcb_prot.c new file mode 100644 index 00000000..c3a7ea8e --- /dev/null +++ b/freebsd/lib/libc/rpc/rpcb_prot.c @@ -0,0 +1,333 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: rpcb_prot.c,v 1.3 2000/07/14 08:40:42 fvdl Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ + +/* #ident "@(#)rpcb_prot.c 1.13 94/04/24 SMI" */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)rpcb_prot.c 1.9 89/04/21 Copyr 1984 Sun Micro"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * rpcb_prot.c + * XDR routines for the rpcbinder version 3. + * + * Copyright (C) 1984, 1988, Sun Microsystems, Inc. + */ + +#include "namespace.h" +#include <rpc/rpc.h> +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <rpc/rpcb_prot.h> +#include "un-namespace.h" + +bool_t +xdr_rpcb(xdrs, objp) + XDR *xdrs; + RPCB *objp; +{ + if (!xdr_u_int32_t(xdrs, &objp->r_prog)) { + return (FALSE); + } + if (!xdr_u_int32_t(xdrs, &objp->r_vers)) { + return (FALSE); + } + if (!xdr_string(xdrs, &objp->r_netid, (u_int)~0)) { + return (FALSE); + } + if (!xdr_string(xdrs, &objp->r_addr, (u_int)~0)) { + return (FALSE); + } + if (!xdr_string(xdrs, &objp->r_owner, (u_int)~0)) { + return (FALSE); + } + return (TRUE); +} + +/* + * rpcblist_ptr implements a linked list. The RPCL definition from + * rpcb_prot.x is: + * + * struct rpcblist { + * rpcb rpcb_map; + * struct rpcblist *rpcb_next; + * }; + * typedef rpcblist *rpcblist_ptr; + * + * Recall that "pointers" in XDR are encoded as a boolean, indicating whether + * there's any data behind the pointer, followed by the data (if any exists). + * The boolean can be interpreted as ``more data follows me''; if FALSE then + * nothing follows the boolean; if TRUE then the boolean is followed by an + * actual struct rpcb, and another rpcblist_ptr (declared in RPCL as "struct + * rpcblist *"). + * + * This could be implemented via the xdr_pointer type, though this would + * result in one recursive call per element in the list. Rather than do that + * we can ``unwind'' the recursion into a while loop and use xdr_reference to + * serialize the rpcb elements. + */ + +bool_t +xdr_rpcblist_ptr(xdrs, rp) + XDR *xdrs; + rpcblist_ptr *rp; +{ + /* + * more_elements is pre-computed in case the direction is + * XDR_ENCODE or XDR_FREE. more_elements is overwritten by + * xdr_bool when the direction is XDR_DECODE. + */ + bool_t more_elements; + int freeing = (xdrs->x_op == XDR_FREE); + rpcblist_ptr next; + rpcblist_ptr next_copy; + + next = NULL; + for (;;) { + more_elements = (bool_t)(*rp != NULL); + if (! xdr_bool(xdrs, &more_elements)) { + return (FALSE); + } + if (! more_elements) { + return (TRUE); /* we are done */ + } + /* + * the unfortunate side effect of non-recursion is that in + * the case of freeing we must remember the next object + * before we free the current object ... + */ + if (freeing && *rp) + next = (*rp)->rpcb_next; + if (! xdr_reference(xdrs, (caddr_t *)rp, + (u_int)sizeof (rpcblist), (xdrproc_t)xdr_rpcb)) { + return (FALSE); + } + if (freeing) { + next_copy = next; + rp = &next_copy; + /* + * Note that in the subsequent iteration, next_copy + * gets nulled out by the xdr_reference + * but next itself survives. + */ + } else if (*rp) { + rp = &((*rp)->rpcb_next); + } + } + /*NOTREACHED*/ +} + +/* + * xdr_rpcblist() is specified to take a RPCBLIST **, but is identical in + * functionality to xdr_rpcblist_ptr(). + */ +bool_t +xdr_rpcblist(xdrs, rp) + XDR *xdrs; + RPCBLIST **rp; +{ + bool_t dummy; + + dummy = xdr_rpcblist_ptr(xdrs, (rpcblist_ptr *)rp); + return (dummy); +} + + +bool_t +xdr_rpcb_entry(xdrs, objp) + XDR *xdrs; + rpcb_entry *objp; +{ + if (!xdr_string(xdrs, &objp->r_maddr, (u_int)~0)) { + return (FALSE); + } + if (!xdr_string(xdrs, &objp->r_nc_netid, (u_int)~0)) { + return (FALSE); + } + if (!xdr_u_int32_t(xdrs, &objp->r_nc_semantics)) { + return (FALSE); + } + if (!xdr_string(xdrs, &objp->r_nc_protofmly, (u_int)~0)) { + return (FALSE); + } + if (!xdr_string(xdrs, &objp->r_nc_proto, (u_int)~0)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_rpcb_entry_list_ptr(xdrs, rp) + XDR *xdrs; + rpcb_entry_list_ptr *rp; +{ + /* + * more_elements is pre-computed in case the direction is + * XDR_ENCODE or XDR_FREE. more_elements is overwritten by + * xdr_bool when the direction is XDR_DECODE. + */ + bool_t more_elements; + int freeing = (xdrs->x_op == XDR_FREE); + rpcb_entry_list_ptr next; + rpcb_entry_list_ptr next_copy; + + next = NULL; + for (;;) { + more_elements = (bool_t)(*rp != NULL); + if (! xdr_bool(xdrs, &more_elements)) { + return (FALSE); + } + if (! more_elements) { + return (TRUE); /* we are done */ + } + /* + * the unfortunate side effect of non-recursion is that in + * the case of freeing we must remember the next object + * before we free the current object ... + */ + if (freeing) + next = (*rp)->rpcb_entry_next; + if (! xdr_reference(xdrs, (caddr_t *)rp, + (u_int)sizeof (rpcb_entry_list), + (xdrproc_t)xdr_rpcb_entry)) { + return (FALSE); + } + if (freeing && *rp) { + next_copy = next; + rp = &next_copy; + /* + * Note that in the subsequent iteration, next_copy + * gets nulled out by the xdr_reference + * but next itself survives. + */ + } else if (*rp) { + rp = &((*rp)->rpcb_entry_next); + } + } + /*NOTREACHED*/ +} + +/* + * XDR remote call arguments + * written for XDR_ENCODE direction only + */ +bool_t +xdr_rpcb_rmtcallargs(xdrs, p) + XDR *xdrs; + struct rpcb_rmtcallargs *p; +{ + struct r_rpcb_rmtcallargs *objp = + (struct r_rpcb_rmtcallargs *)(void *)p; + u_int lenposition, argposition, position; + int32_t *buf; + + buf = XDR_INLINE(xdrs, 3 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_u_int32_t(xdrs, &objp->prog)) { + return (FALSE); + } + if (!xdr_u_int32_t(xdrs, &objp->vers)) { + return (FALSE); + } + if (!xdr_u_int32_t(xdrs, &objp->proc)) { + return (FALSE); + } + } else { + IXDR_PUT_U_INT32(buf, objp->prog); + IXDR_PUT_U_INT32(buf, objp->vers); + IXDR_PUT_U_INT32(buf, objp->proc); + } + + /* + * All the jugglery for just getting the size of the arguments + */ + lenposition = XDR_GETPOS(xdrs); + if (! xdr_u_int(xdrs, &(objp->args.args_len))) { + return (FALSE); + } + argposition = XDR_GETPOS(xdrs); + if (! (*objp->xdr_args)(xdrs, objp->args.args_val)) { + return (FALSE); + } + position = XDR_GETPOS(xdrs); + objp->args.args_len = (u_int)((u_long)position - (u_long)argposition); + XDR_SETPOS(xdrs, lenposition); + if (! xdr_u_int(xdrs, &(objp->args.args_len))) { + return (FALSE); + } + XDR_SETPOS(xdrs, position); + return (TRUE); +} + +/* + * XDR remote call results + * written for XDR_DECODE direction only + */ +bool_t +xdr_rpcb_rmtcallres(xdrs, p) + XDR *xdrs; + struct rpcb_rmtcallres *p; +{ + bool_t dummy; + struct r_rpcb_rmtcallres *objp = (struct r_rpcb_rmtcallres *)(void *)p; + + if (!xdr_string(xdrs, &objp->addr, (u_int)~0)) { + return (FALSE); + } + if (!xdr_u_int(xdrs, &objp->results.results_len)) { + return (FALSE); + } + dummy = (*(objp->xdr_res))(xdrs, objp->results.results_val); + return (dummy); +} + +bool_t +xdr_netbuf(xdrs, objp) + XDR *xdrs; + struct netbuf *objp; +{ + bool_t dummy; + void **pp; + + if (!xdr_u_int32_t(xdrs, (u_int32_t *) &objp->maxlen)) { + return (FALSE); + } + pp = &objp->buf; + dummy = xdr_bytes(xdrs, (char **) pp, + (u_int *)&(objp->len), objp->maxlen); + return (dummy); +} diff --git a/freebsd/lib/libc/rpc/rpcb_st_xdr.c b/freebsd/lib/libc/rpc/rpcb_st_xdr.c new file mode 100644 index 00000000..375f06cd --- /dev/null +++ b/freebsd/lib/libc/rpc/rpcb_st_xdr.c @@ -0,0 +1,276 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: rpcb_st_xdr.c,v 1.3 2000/07/14 08:40:42 fvdl Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright 1991 Sun Microsystems, Inc. + * rpcb_stat_xdr.c + */ + +/* + * This file was generated from rpcb_prot.x, but includes only those + * routines used with the rpcbind stats facility. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "namespace.h" +#include <rpc/rpc.h> +#include "un-namespace.h" + +/* Link list of all the stats about getport and getaddr */ + +bool_t +xdr_rpcbs_addrlist(xdrs, objp) + XDR *xdrs; + rpcbs_addrlist *objp; +{ + struct rpcbs_addrlist **pnext; + + if (!xdr_u_int32_t(xdrs, &objp->prog)) { + return (FALSE); + } + if (!xdr_u_int32_t(xdrs, &objp->vers)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->success)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->failure)) { + return (FALSE); + } + if (!xdr_string(xdrs, &objp->netid, (u_int)~0)) { + return (FALSE); + } + + pnext = &objp->next; + + if (!xdr_pointer(xdrs, (char **) pnext, + sizeof (rpcbs_addrlist), + (xdrproc_t)xdr_rpcbs_addrlist)) { + return (FALSE); + } + + return (TRUE); +} + +/* Link list of all the stats about rmtcall */ + +bool_t +xdr_rpcbs_rmtcalllist(xdrs, objp) + XDR *xdrs; + rpcbs_rmtcalllist *objp; +{ + int32_t *buf; + struct rpcbs_rmtcalllist **pnext; + + if (xdrs->x_op == XDR_ENCODE) { + buf = XDR_INLINE(xdrs, 6 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_u_int32_t(xdrs, &objp->prog)) { + return (FALSE); + } + if (!xdr_u_int32_t(xdrs, &objp->vers)) { + return (FALSE); + } + if (!xdr_u_int32_t(xdrs, &objp->proc)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->success)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->failure)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->indirect)) { + return (FALSE); + } + } else { + IXDR_PUT_U_INT32(buf, objp->prog); + IXDR_PUT_U_INT32(buf, objp->vers); + IXDR_PUT_U_INT32(buf, objp->proc); + IXDR_PUT_INT32(buf, objp->success); + IXDR_PUT_INT32(buf, objp->failure); + IXDR_PUT_INT32(buf, objp->indirect); + } + if (!xdr_string(xdrs, &objp->netid, (u_int)~0)) { + return (FALSE); + } + pnext = &objp->next; + if (!xdr_pointer(xdrs, (char **) pnext, + sizeof (rpcbs_rmtcalllist), + (xdrproc_t)xdr_rpcbs_rmtcalllist)) { + return (FALSE); + } + return (TRUE); + } else if (xdrs->x_op == XDR_DECODE) { + buf = XDR_INLINE(xdrs, 6 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_u_int32_t(xdrs, &objp->prog)) { + return (FALSE); + } + if (!xdr_u_int32_t(xdrs, &objp->vers)) { + return (FALSE); + } + if (!xdr_u_int32_t(xdrs, &objp->proc)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->success)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->failure)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->indirect)) { + return (FALSE); + } + } else { + objp->prog = (rpcprog_t)IXDR_GET_U_INT32(buf); + objp->vers = (rpcvers_t)IXDR_GET_U_INT32(buf); + objp->proc = (rpcproc_t)IXDR_GET_U_INT32(buf); + objp->success = (int)IXDR_GET_INT32(buf); + objp->failure = (int)IXDR_GET_INT32(buf); + objp->indirect = (int)IXDR_GET_INT32(buf); + } + if (!xdr_string(xdrs, &objp->netid, (u_int)~0)) { + return (FALSE); + } + if (!xdr_pointer(xdrs, (char **) pnext, + sizeof (rpcbs_rmtcalllist), + (xdrproc_t)xdr_rpcbs_rmtcalllist)) { + return (FALSE); + } + return (TRUE); + } + if (!xdr_u_int32_t(xdrs, &objp->prog)) { + return (FALSE); + } + if (!xdr_u_int32_t(xdrs, &objp->vers)) { + return (FALSE); + } + if (!xdr_u_int32_t(xdrs, &objp->proc)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->success)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->failure)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->indirect)) { + return (FALSE); + } + if (!xdr_string(xdrs, &objp->netid, (u_int)~0)) { + return (FALSE); + } + if (!xdr_pointer(xdrs, (char **) pnext, + sizeof (rpcbs_rmtcalllist), + (xdrproc_t)xdr_rpcbs_rmtcalllist)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_rpcbs_proc(xdrs, objp) + XDR *xdrs; + rpcbs_proc objp; +{ + if (!xdr_vector(xdrs, (char *)(void *)objp, RPCBSTAT_HIGHPROC, + sizeof (int), (xdrproc_t)xdr_int)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_rpcbs_addrlist_ptr(xdrs, objp) + XDR *xdrs; + rpcbs_addrlist_ptr *objp; +{ + if (!xdr_pointer(xdrs, (char **)objp, sizeof (rpcbs_addrlist), + (xdrproc_t)xdr_rpcbs_addrlist)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_rpcbs_rmtcalllist_ptr(xdrs, objp) + XDR *xdrs; + rpcbs_rmtcalllist_ptr *objp; +{ + if (!xdr_pointer(xdrs, (char **)objp, sizeof (rpcbs_rmtcalllist), + (xdrproc_t)xdr_rpcbs_rmtcalllist)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_rpcb_stat(xdrs, objp) + XDR *xdrs; + rpcb_stat *objp; +{ + + if (!xdr_rpcbs_proc(xdrs, objp->info)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->setinfo)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->unsetinfo)) { + return (FALSE); + } + if (!xdr_rpcbs_addrlist_ptr(xdrs, &objp->addrinfo)) { + return (FALSE); + } + if (!xdr_rpcbs_rmtcalllist_ptr(xdrs, &objp->rmtinfo)) { + return (FALSE); + } + return (TRUE); +} + +/* + * One rpcb_stat structure is returned for each version of rpcbind + * being monitored. + */ +bool_t +xdr_rpcb_stat_byvers(xdrs, objp) + XDR *xdrs; + rpcb_stat_byvers objp; +{ + if (!xdr_vector(xdrs, (char *)(void *)objp, RPCBVERS_STAT, + sizeof (rpcb_stat), (xdrproc_t)xdr_rpcb_stat)) { + return (FALSE); + } + return (TRUE); +} diff --git a/freebsd/lib/libc/rpc/rpcdname.c b/freebsd/lib/libc/rpc/rpcdname.c new file mode 100644 index 00000000..1805da80 --- /dev/null +++ b/freebsd/lib/libc/rpc/rpcdname.c @@ -0,0 +1,82 @@ +#include <machine/rtems-bsd-user-space.h> + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)rpcdname.c 1.7 91/03/11 Copyr 1989 Sun Micro"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * rpcdname.c + * Gets the default domain name + */ + +#include "namespace.h" +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include "un-namespace.h" + +static char *default_domain = 0; + +static char * +get_default_domain() +{ + char temp[256]; + + if (default_domain) + return (default_domain); + if (getdomainname(temp, sizeof(temp)) < 0) + return (0); + if ((int) strlen(temp) > 0) { + default_domain = (char *)malloc((strlen(temp)+(unsigned)1)); + if (default_domain == 0) + return (0); + (void) strcpy(default_domain, temp); + return (default_domain); + } + return (0); +} + +/* + * This is a wrapper for the system call getdomainname which returns a + * ypclnt.h error code in the failure case. It also checks to see that + * the domain name is non-null, knowing that the null string is going to + * get rejected elsewhere in the NIS client package. + */ +int +__rpc_get_default_domain(domain) + char **domain; +{ + if ((*domain = get_default_domain()) != 0) + return (0); + return (-1); +} diff --git a/freebsd/lib/libc/rpc/rpcsec_gss_stub.c b/freebsd/lib/libc/rpc/rpcsec_gss_stub.c new file mode 100644 index 00000000..2c82dba7 --- /dev/null +++ b/freebsd/lib/libc/rpc/rpcsec_gss_stub.c @@ -0,0 +1,50 @@ +#include <machine/rtems-bsd-user-space.h> + +/*- + * Copyright (c) 2006 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <rpc/rpc.h> +#include <rpc/rpcsec_gss.h> + +bool_t +__rpc_gss_wrap_stub(AUTH *auth, void *header, size_t headerlen, XDR* xdrs, + xdrproc_t xdr_args, void *args_ptr) +{ + + return (FALSE); +} + +bool_t +__rpc_gss_unwrap_stub(AUTH *auth, XDR* xdrs, xdrproc_t xdr_args, void *args_ptr) +{ + + return (FALSE); +} + +__weak_reference(__rpc_gss_wrap_stub, __rpc_gss_wrap); +__weak_reference(__rpc_gss_unwrap_stub, __rpc_gss_unwrap); diff --git a/freebsd/lib/libc/rpc/rtime.c b/freebsd/lib/libc/rpc/rtime.c new file mode 100644 index 00000000..b8f783e9 --- /dev/null +++ b/freebsd/lib/libc/rpc/rtime.c @@ -0,0 +1,161 @@ +#include <machine/rtems-bsd-user-space.h> + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 1988 by Sun Microsystems, Inc. + + */ + +/* + * rtime - get time from remote machine + * + * gets time, obtaining value from host + * on the udp/time socket. Since timeserver returns + * with time of day in seconds since Jan 1, 1900, must + * subtract seconds before Jan 1, 1970 to get + * what unix uses. + */ +#include "namespace.h" +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <netinet/in.h> +#include <stdio.h> +#include <netdb.h> +#include "un-namespace.h" + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)rtime.c 2.2 88/08/10 4.0 RPCSRC; from 1.8 88/02/08 SMI"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +extern int _rpc_dtablesize( void ); + +#define NYEARS (unsigned long)(1970 - 1900) +#define TOFFSET (unsigned long)(60*60*24*(365*NYEARS + (NYEARS/4))) + +static void do_close( int ); + +int +rtime(addrp, timep, timeout) + struct sockaddr_in *addrp; + struct timeval *timep; + struct timeval *timeout; +{ + int s; + fd_set readfds; + int res; + unsigned long thetime; + struct sockaddr_in from; + socklen_t fromlen; + int type; + struct servent *serv; + + if (timeout == NULL) { + type = SOCK_STREAM; + } else { + type = SOCK_DGRAM; + } + s = _socket(AF_INET, type, 0); + if (s < 0) { + return(-1); + } + addrp->sin_family = AF_INET; + + /* TCP and UDP port are the same in this case */ + if ((serv = getservbyname("time", "tcp")) == NULL) { + return(-1); + } + + addrp->sin_port = serv->s_port; + + if (type == SOCK_DGRAM) { + res = _sendto(s, (char *)&thetime, sizeof(thetime), 0, + (struct sockaddr *)addrp, sizeof(*addrp)); + if (res < 0) { + do_close(s); + return(-1); + } + do { + FD_ZERO(&readfds); + FD_SET(s, &readfds); + res = _select(_rpc_dtablesize(), &readfds, + (fd_set *)NULL, (fd_set *)NULL, timeout); + } while (res < 0 && errno == EINTR); + if (res <= 0) { + if (res == 0) { + errno = ETIMEDOUT; + } + do_close(s); + return(-1); + } + fromlen = sizeof(from); + res = _recvfrom(s, (char *)&thetime, sizeof(thetime), 0, + (struct sockaddr *)&from, &fromlen); + do_close(s); + if (res < 0) { + return(-1); + } + } else { + if (_connect(s, (struct sockaddr *)addrp, sizeof(*addrp)) < 0) { + do_close(s); + return(-1); + } + res = _read(s, (char *)&thetime, sizeof(thetime)); + do_close(s); + if (res < 0) { + return(-1); + } + } + if (res != sizeof(thetime)) { + errno = EIO; + return(-1); + } + thetime = ntohl(thetime); + timep->tv_sec = thetime - TOFFSET; + timep->tv_usec = 0; + return(0); +} + +static void +do_close(s) + int s; +{ + int save; + + save = errno; + (void)_close(s); + errno = save; +} diff --git a/freebsd/lib/libc/rpc/svc.c b/freebsd/lib/libc/rpc/svc.c new file mode 100644 index 00000000..709bfffa --- /dev/null +++ b/freebsd/lib/libc/rpc/svc.c @@ -0,0 +1,798 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: svc.c,v 1.21 2000/07/06 03:10:35 christos Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *sccsid2 = "@(#)svc.c 1.44 88/02/08 Copyr 1984 Sun Micro"; +static char *sccsid = "@(#)svc.c 2.4 88/08/11 4.0 RPCSRC"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * 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 "namespace.h" +#include "reentrant.h" +#include <sys/types.h> +#include <sys/poll.h> +#include <assert.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include <rpc/rpc.h> +#ifdef PORTMAP +#include <rpc/pmap_clnt.h> +#endif /* PORTMAP */ +#include "un-namespace.h" + +#include "rpc_com.h" +#include "mt_misc.h" + +#define RQCRED_SIZE 400 /* this size is excessive */ + +#define SVC_VERSQUIET 0x0001 /* keep quiet about vers mismatch */ +#define version_keepquiet(xp) (SVC_EXT(xp)->xp_flags & SVC_VERSQUIET) + +#define max(a, b) (a > b ? a : b) + +/* + * The services list + * Each entry represents a set of procedures (an rpc program). + * The dispatch routine takes request structs and runs the + * apropriate procedure. + */ +static struct svc_callout { + struct svc_callout *sc_next; + rpcprog_t sc_prog; + rpcvers_t sc_vers; + char *sc_netid; + void (*sc_dispatch)(struct svc_req *, SVCXPRT *); +} *svc_head; + +static struct svc_callout *svc_find(rpcprog_t, rpcvers_t, + struct svc_callout **, char *); +static void __xprt_do_unregister (SVCXPRT *xprt, bool_t dolock); + +/* *************** SVCXPRT related stuff **************** */ + +/* + * Activate a transport handle. + */ +void +xprt_register(xprt) + SVCXPRT *xprt; +{ + int sock; + + assert(xprt != NULL); + + sock = xprt->xp_fd; + + rwlock_wrlock(&svc_fd_lock); + if (__svc_xports == NULL) { + __svc_xports = (SVCXPRT **) + mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *)); + if (__svc_xports == NULL) { + rwlock_unlock(&svc_fd_lock); + return; + } + memset(__svc_xports, '\0', FD_SETSIZE * sizeof(SVCXPRT *)); + } + if (sock < FD_SETSIZE) { + __svc_xports[sock] = xprt; + FD_SET(sock, &svc_fdset); + svc_maxfd = max(svc_maxfd, sock); + } + rwlock_unlock(&svc_fd_lock); +} + +void +xprt_unregister(SVCXPRT *xprt) +{ + __xprt_do_unregister(xprt, TRUE); +} + +void +__xprt_unregister_unlocked(SVCXPRT *xprt) +{ + __xprt_do_unregister(xprt, FALSE); +} + +/* + * De-activate a transport handle. + */ +static void +__xprt_do_unregister(xprt, dolock) + SVCXPRT *xprt; + bool_t dolock; +{ + int sock; + + assert(xprt != NULL); + + sock = xprt->xp_fd; + + if (dolock) + rwlock_wrlock(&svc_fd_lock); + if ((sock < FD_SETSIZE) && (__svc_xports[sock] == xprt)) { + __svc_xports[sock] = NULL; + FD_CLR(sock, &svc_fdset); + if (sock >= svc_maxfd) { + for (svc_maxfd--; svc_maxfd>=0; svc_maxfd--) + if (__svc_xports[svc_maxfd]) + break; + } + } + if (dolock) + rwlock_unlock(&svc_fd_lock); +} + +/* + * Add a service program to the callout list. + * The dispatch routine will be called when a rpc request for this + * program number comes in. + */ +bool_t +svc_reg(xprt, prog, vers, dispatch, nconf) + SVCXPRT *xprt; + const rpcprog_t prog; + const rpcvers_t vers; + void (*dispatch)(struct svc_req *, SVCXPRT *); + const struct netconfig *nconf; +{ + bool_t dummy; + struct svc_callout *prev; + struct svc_callout *s; + struct netconfig *tnconf; + char *netid = NULL; + int flag = 0; + +/* VARIABLES PROTECTED BY svc_lock: s, prev, svc_head */ + + if (xprt->xp_netid) { + netid = strdup(xprt->xp_netid); + flag = 1; + } else if (nconf && nconf->nc_netid) { + netid = strdup(nconf->nc_netid); + flag = 1; + } else if ((tnconf = __rpcgettp(xprt->xp_fd)) != NULL) { + netid = strdup(tnconf->nc_netid); + flag = 1; + freenetconfigent(tnconf); + } /* must have been created with svc_raw_create */ + if ((netid == NULL) && (flag == 1)) { + return (FALSE); + } + + rwlock_wrlock(&svc_lock); + if ((s = svc_find(prog, vers, &prev, netid)) != NULL) { + if (netid) + free(netid); + if (s->sc_dispatch == dispatch) + goto rpcb_it; /* he is registering another xptr */ + rwlock_unlock(&svc_lock); + return (FALSE); + } + s = mem_alloc(sizeof (struct svc_callout)); + if (s == NULL) { + if (netid) + free(netid); + rwlock_unlock(&svc_lock); + return (FALSE); + } + + s->sc_prog = prog; + s->sc_vers = vers; + s->sc_dispatch = dispatch; + s->sc_netid = netid; + s->sc_next = svc_head; + svc_head = s; + + if ((xprt->xp_netid == NULL) && (flag == 1) && netid) + ((SVCXPRT *) xprt)->xp_netid = strdup(netid); + +rpcb_it: + rwlock_unlock(&svc_lock); + /* now register the information with the local binder service */ + if (nconf) { + /*LINTED const castaway*/ + dummy = rpcb_set(prog, vers, (struct netconfig *) nconf, + &((SVCXPRT *) xprt)->xp_ltaddr); + return (dummy); + } + return (TRUE); +} + +/* + * Remove a service program from the callout list. + */ +void +svc_unreg(prog, vers) + const rpcprog_t prog; + const rpcvers_t vers; +{ + struct svc_callout *prev; + struct svc_callout *s; + + /* unregister the information anyway */ + (void) rpcb_unset(prog, vers, NULL); + rwlock_wrlock(&svc_lock); + while ((s = svc_find(prog, vers, &prev, NULL)) != NULL) { + if (prev == NULL) { + svc_head = s->sc_next; + } else { + prev->sc_next = s->sc_next; + } + s->sc_next = NULL; + if (s->sc_netid) + mem_free(s->sc_netid, sizeof (s->sc_netid) + 1); + mem_free(s, sizeof (struct svc_callout)); + } + rwlock_unlock(&svc_lock); +} + +/* ********************** CALLOUT list related stuff ************* */ + +#ifdef PORTMAP +/* + * Add a service program to the callout list. + * The dispatch routine will be called when a rpc request for this + * program number comes in. + */ +bool_t +svc_register(xprt, prog, vers, dispatch, protocol) + SVCXPRT *xprt; + u_long prog; + u_long vers; + void (*dispatch)(struct svc_req *, SVCXPRT *); + int protocol; +{ + struct svc_callout *prev; + struct svc_callout *s; + + assert(xprt != NULL); + assert(dispatch != NULL); + + if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) != + NULL) { + if (s->sc_dispatch == dispatch) + goto pmap_it; /* he is registering another xptr */ + return (FALSE); + } + s = mem_alloc(sizeof(struct svc_callout)); + if (s == NULL) { + return (FALSE); + } + s->sc_prog = (rpcprog_t)prog; + s->sc_vers = (rpcvers_t)vers; + s->sc_dispatch = dispatch; + s->sc_next = svc_head; + svc_head = s; +pmap_it: + /* now register the information with the local binder service */ + if (protocol) { + return (pmap_set(prog, vers, protocol, xprt->xp_port)); + } + return (TRUE); +} + +/* + * Remove a service program from the callout list. + */ +void +svc_unregister(prog, vers) + u_long prog; + u_long vers; +{ + struct svc_callout *prev; + struct svc_callout *s; + + if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) == + NULL) + return; + if (prev == NULL) { + svc_head = s->sc_next; + } else { + prev->sc_next = s->sc_next; + } + s->sc_next = NULL; + mem_free(s, sizeof(struct svc_callout)); + /* now unregister the information with the local binder service */ + (void)pmap_unset(prog, vers); +} +#endif /* PORTMAP */ + +/* + * Search the callout list for a program number, return the callout + * struct. + */ +static struct svc_callout * +svc_find(prog, vers, prev, netid) + rpcprog_t prog; + rpcvers_t vers; + struct svc_callout **prev; + char *netid; +{ + struct svc_callout *s, *p; + + assert(prev != NULL); + + p = NULL; + for (s = svc_head; s != NULL; s = s->sc_next) { + if (((s->sc_prog == prog) && (s->sc_vers == vers)) && + ((netid == NULL) || (s->sc_netid == NULL) || + (strcmp(netid, s->sc_netid) == 0))) + break; + p = s; + } + *prev = p; + return (s); +} + +/* ******************* REPLY GENERATION ROUTINES ************ */ + +/* + * Send a reply to an rpc request + */ +bool_t +svc_sendreply(xprt, xdr_results, xdr_location) + SVCXPRT *xprt; + xdrproc_t xdr_results; + void * xdr_location; +{ + struct rpc_msg rply; + + assert(xprt != NULL); + + rply.rm_direction = REPLY; + rply.rm_reply.rp_stat = MSG_ACCEPTED; + rply.acpted_rply.ar_verf = xprt->xp_verf; + rply.acpted_rply.ar_stat = SUCCESS; + rply.acpted_rply.ar_results.where = xdr_location; + rply.acpted_rply.ar_results.proc = xdr_results; + return (SVC_REPLY(xprt, &rply)); +} + +/* + * No procedure error reply + */ +void +svcerr_noproc(xprt) + SVCXPRT *xprt; +{ + struct rpc_msg rply; + + assert(xprt != NULL); + + rply.rm_direction = REPLY; + rply.rm_reply.rp_stat = MSG_ACCEPTED; + rply.acpted_rply.ar_verf = xprt->xp_verf; + rply.acpted_rply.ar_stat = PROC_UNAVAIL; + SVC_REPLY(xprt, &rply); +} + +/* + * Can't decode args error reply + */ +void +svcerr_decode(xprt) + SVCXPRT *xprt; +{ + struct rpc_msg rply; + + assert(xprt != NULL); + + rply.rm_direction = REPLY; + rply.rm_reply.rp_stat = MSG_ACCEPTED; + rply.acpted_rply.ar_verf = xprt->xp_verf; + rply.acpted_rply.ar_stat = GARBAGE_ARGS; + SVC_REPLY(xprt, &rply); +} + +/* + * Some system error + */ +void +svcerr_systemerr(xprt) + SVCXPRT *xprt; +{ + struct rpc_msg rply; + + assert(xprt != NULL); + + rply.rm_direction = REPLY; + rply.rm_reply.rp_stat = MSG_ACCEPTED; + rply.acpted_rply.ar_verf = xprt->xp_verf; + rply.acpted_rply.ar_stat = SYSTEM_ERR; + SVC_REPLY(xprt, &rply); +} + +#if 0 +/* + * Tell RPC package to not complain about version errors to the client. This + * is useful when revving broadcast protocols that sit on a fixed address. + * There is really one (or should be only one) example of this kind of + * protocol: the portmapper (or rpc binder). + */ +void +__svc_versquiet_on(xprt) + SVCXPRT *xprt; +{ + + SVC_EXT(xprt)->xp_flags |= SVC_VERSQUIET; +} + +void +__svc_versquiet_off(xprt) + SVCXPRT *xprt; +{ + + SVC_EXT(xprt)->xp_flags &= ~SVC_VERSQUIET; +} + +void +svc_versquiet(xprt) + SVCXPRT *xprt; +{ + __svc_versquiet_on(xprt); +} + +int +__svc_versquiet_get(xprt) + SVCXPRT *xprt; +{ + + return (SVC_EXT(xprt)->xp_flags & SVC_VERSQUIET); +} +#endif + +/* + * Authentication error reply + */ +void +svcerr_auth(xprt, why) + SVCXPRT *xprt; + enum auth_stat why; +{ + struct rpc_msg rply; + + assert(xprt != NULL); + + rply.rm_direction = REPLY; + rply.rm_reply.rp_stat = MSG_DENIED; + rply.rjcted_rply.rj_stat = AUTH_ERROR; + rply.rjcted_rply.rj_why = why; + SVC_REPLY(xprt, &rply); +} + +/* + * Auth too weak error reply + */ +void +svcerr_weakauth(xprt) + SVCXPRT *xprt; +{ + + assert(xprt != NULL); + + svcerr_auth(xprt, AUTH_TOOWEAK); +} + +/* + * Program unavailable error reply + */ +void +svcerr_noprog(xprt) + SVCXPRT *xprt; +{ + struct rpc_msg rply; + + assert(xprt != NULL); + + rply.rm_direction = REPLY; + rply.rm_reply.rp_stat = MSG_ACCEPTED; + rply.acpted_rply.ar_verf = xprt->xp_verf; + rply.acpted_rply.ar_stat = PROG_UNAVAIL; + SVC_REPLY(xprt, &rply); +} + +/* + * Program version mismatch error reply + */ +void +svcerr_progvers(xprt, low_vers, high_vers) + SVCXPRT *xprt; + rpcvers_t low_vers; + rpcvers_t high_vers; +{ + struct rpc_msg rply; + + assert(xprt != NULL); + + rply.rm_direction = REPLY; + rply.rm_reply.rp_stat = MSG_ACCEPTED; + rply.acpted_rply.ar_verf = xprt->xp_verf; + rply.acpted_rply.ar_stat = PROG_MISMATCH; + rply.acpted_rply.ar_vers.low = (u_int32_t)low_vers; + rply.acpted_rply.ar_vers.high = (u_int32_t)high_vers; + SVC_REPLY(xprt, &rply); +} + +/* + * Allocate a new server transport structure. All fields are + * initialized to zero and xp_p3 is initialized to point at an + * extension structure to hold various flags and authentication + * parameters. + */ +SVCXPRT * +svc_xprt_alloc() +{ + SVCXPRT *xprt; + SVCXPRT_EXT *ext; + + xprt = mem_alloc(sizeof(SVCXPRT)); + if (xprt == NULL) + return (NULL); + memset(xprt, 0, sizeof(SVCXPRT)); + ext = mem_alloc(sizeof(SVCXPRT_EXT)); + if (ext == NULL) { + mem_free(xprt, sizeof(SVCXPRT)); + return (NULL); + } + memset(ext, 0, sizeof(SVCXPRT_EXT)); + xprt->xp_p3 = ext; + ext->xp_auth.svc_ah_ops = &svc_auth_null_ops; + + return (xprt); +} + +/* + * Free a server transport structure. + */ +void +svc_xprt_free(xprt) + SVCXPRT *xprt; +{ + + mem_free(xprt->xp_p3, sizeof(SVCXPRT_EXT)); + mem_free(xprt, sizeof(SVCXPRT)); +} + +/* ******************* SERVER INPUT STUFF ******************* */ + +/* + * Get server side input from some transport. + * + * Statement of authentication parameters management: + * This function owns and manages all authentication parameters, specifically + * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and + * the "cooked" credentials (rqst->rq_clntcred). + * However, this function does not know the structure of the cooked + * credentials, so it make the following assumptions: + * a) the structure is contiguous (no pointers), and + * b) the cred structure size does not exceed RQCRED_SIZE bytes. + * In all events, all three parameters are freed upon exit from this routine. + * The storage is trivially management on the call stack in user land, but + * is mallocated in kernel land. + */ + +void +svc_getreq(rdfds) + int rdfds; +{ + fd_set readfds; + + FD_ZERO(&readfds); + readfds.fds_bits[0] = rdfds; + svc_getreqset(&readfds); +} + +void +svc_getreqset(readfds) + fd_set *readfds; +{ + int bit, fd; + fd_mask mask, *maskp; + int sock; + + assert(readfds != NULL); + + maskp = readfds->fds_bits; + for (sock = 0; sock < FD_SETSIZE; sock += NFDBITS) { + for (mask = *maskp++; (bit = ffsl(mask)) != 0; + mask ^= (1ul << (bit - 1))) { + /* sock has input waiting */ + fd = sock + bit - 1; + svc_getreq_common(fd); + } + } +} + +void +svc_getreq_common(fd) + int fd; +{ + SVCXPRT *xprt; + struct svc_req r; + struct rpc_msg msg; + int prog_found; + rpcvers_t low_vers; + rpcvers_t high_vers; + enum xprt_stat stat; + char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE]; + + msg.rm_call.cb_cred.oa_base = cred_area; + msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]); + r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]); + + rwlock_rdlock(&svc_fd_lock); + xprt = __svc_xports[fd]; + rwlock_unlock(&svc_fd_lock); + if (xprt == NULL) + /* But do we control sock? */ + return; + /* now receive msgs from xprtprt (support batch calls) */ + do { + if (SVC_RECV(xprt, &msg)) { + + /* now find the exported program and call it */ + struct svc_callout *s; + enum auth_stat why; + + r.rq_xprt = xprt; + r.rq_prog = msg.rm_call.cb_prog; + r.rq_vers = msg.rm_call.cb_vers; + r.rq_proc = msg.rm_call.cb_proc; + r.rq_cred = msg.rm_call.cb_cred; + /* first authenticate the message */ + if ((why = _authenticate(&r, &msg)) != AUTH_OK) { + /* + * RPCSEC_GSS uses this return code + * for requests that form part of its + * context establishment protocol and + * should not be dispatched to the + * application. + */ + if (why != RPCSEC_GSS_NODISPATCH) + svcerr_auth(xprt, why); + goto call_done; + } + /* now match message with a registered service*/ + prog_found = FALSE; + low_vers = (rpcvers_t) -1L; + high_vers = (rpcvers_t) 0L; + for (s = svc_head; s != NULL; s = s->sc_next) { + if (s->sc_prog == r.rq_prog) { + if (s->sc_vers == r.rq_vers) { + (*s->sc_dispatch)(&r, xprt); + goto call_done; + } /* found correct version */ + prog_found = TRUE; + if (s->sc_vers < low_vers) + low_vers = s->sc_vers; + if (s->sc_vers > high_vers) + high_vers = s->sc_vers; + } /* found correct program */ + } + /* + * if we got here, the program or version + * is not served ... + */ + if (prog_found) + svcerr_progvers(xprt, low_vers, high_vers); + else + svcerr_noprog(xprt); + /* Fall through to ... */ + } + /* + * Check if the xprt has been disconnected in a + * recursive call in the service dispatch routine. + * If so, then break. + */ + rwlock_rdlock(&svc_fd_lock); + if (xprt != __svc_xports[fd]) { + rwlock_unlock(&svc_fd_lock); + break; + } + rwlock_unlock(&svc_fd_lock); +call_done: + if ((stat = SVC_STAT(xprt)) == XPRT_DIED){ + SVC_DESTROY(xprt); + break; + } + } while (stat == XPRT_MOREREQS); +} + + +void +svc_getreq_poll(pfdp, pollretval) + struct pollfd *pfdp; + int pollretval; +{ + int i; + int fds_found; + + for (i = fds_found = 0; fds_found < pollretval; i++) { + struct pollfd *p = &pfdp[i]; + + if (p->revents) { + /* fd has input waiting */ + fds_found++; + /* + * We assume that this function is only called + * via someone _select()ing from svc_fdset or + * _poll()ing from svc_pollset[]. Thus it's safe + * to handle the POLLNVAL event by simply turning + * the corresponding bit off in svc_fdset. The + * svc_pollset[] array is derived from svc_fdset + * and so will also be updated eventually. + * + * XXX Should we do an xprt_unregister() instead? + */ + if (p->revents & POLLNVAL) { + rwlock_wrlock(&svc_fd_lock); + FD_CLR(p->fd, &svc_fdset); + rwlock_unlock(&svc_fd_lock); + } else + svc_getreq_common(p->fd); + } + } +} + +bool_t +rpc_control(int what, void *arg) +{ + int val; + + switch (what) { + case RPC_SVC_CONNMAXREC_SET: + val = *(int *)arg; + if (val <= 0) + return FALSE; + __svc_maxrec = val; + return TRUE; + case RPC_SVC_CONNMAXREC_GET: + *(int *)arg = __svc_maxrec; + return TRUE; + default: + break; + } + return FALSE; +} diff --git a/freebsd/lib/libc/rpc/svc_auth.c b/freebsd/lib/libc/rpc/svc_auth.c new file mode 100644 index 00000000..917e5e81 --- /dev/null +++ b/freebsd/lib/libc/rpc/svc_auth.c @@ -0,0 +1,235 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: svc_auth.c,v 1.12 2000/07/06 03:10:35 christos Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +#ident "@(#)svc_auth.c 1.16 94/04/24 SMI" +static char sccsid[] = "@(#)svc_auth.c 1.26 89/02/07 Copyr 1984 Sun Micro"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * svc_auth.c, Server-side rpc authenticator interface. + * + */ + +#include "namespace.h" +#include "reentrant.h" +#include <sys/types.h> +#include <rpc/rpc.h> +#include <stdlib.h> +#include "un-namespace.h" +#include "mt_misc.h" + +/* + * svcauthsw is the bdevsw of server side authentication. + * + * Server side authenticators are called from authenticate by + * using the client auth struct flavor field to index into svcauthsw. + * The server auth flavors must implement a routine that looks + * like: + * + * enum auth_stat + * flavorx_auth(rqst, msg) + * struct svc_req *rqst; + * struct rpc_msg *msg; + * + */ + +/* declarations to allow servers to specify new authentication flavors */ +struct authsvc { + int flavor; + enum auth_stat (*handler)(struct svc_req *, struct rpc_msg *); + struct authsvc *next; +}; +static struct authsvc *Auths = NULL; + +struct svc_auth_ops svc_auth_null_ops; + +/* + * The call rpc message, msg has been obtained from the wire. The msg contains + * the raw form of credentials and verifiers. authenticate returns AUTH_OK + * if the msg is successfully authenticated. If AUTH_OK then the routine also + * does the following things: + * set rqst->rq_xprt->verf to the appropriate response verifier; + * sets rqst->rq_client_cred to the "cooked" form of the credentials. + * + * NB: rqst->rq_cxprt->verf must be pre-alloctaed; + * its length is set appropriately. + * + * The caller still owns and is responsible for msg->u.cmb.cred and + * msg->u.cmb.verf. The authentication system retains ownership of + * rqst->rq_client_cred, the cooked credentials. + * + * There is an assumption that any flavour less than AUTH_NULL is + * invalid. + */ +enum auth_stat +_authenticate(rqst, msg) + struct svc_req *rqst; + struct rpc_msg *msg; +{ + int cred_flavor; + struct authsvc *asp; + enum auth_stat dummy; + +/* VARIABLES PROTECTED BY authsvc_lock: asp, Auths */ + + rqst->rq_cred = msg->rm_call.cb_cred; + SVC_AUTH(rqst->rq_xprt).svc_ah_ops = &svc_auth_null_ops; + SVC_AUTH(rqst->rq_xprt).svc_ah_private = NULL; + rqst->rq_xprt->xp_verf.oa_flavor = _null_auth.oa_flavor; + rqst->rq_xprt->xp_verf.oa_length = 0; + cred_flavor = rqst->rq_cred.oa_flavor; + switch (cred_flavor) { + case AUTH_NULL: + dummy = _svcauth_null(rqst, msg); + return (dummy); + case AUTH_SYS: + dummy = _svcauth_unix(rqst, msg); + return (dummy); + case AUTH_SHORT: + dummy = _svcauth_short(rqst, msg); + return (dummy); +#ifdef DES_BUILTIN + case AUTH_DES: + dummy = _svcauth_des(rqst, msg); + return (dummy); +#endif + default: + break; + } + + /* flavor doesn't match any of the builtin types, so try new ones */ + mutex_lock(&authsvc_lock); + for (asp = Auths; asp; asp = asp->next) { + if (asp->flavor == cred_flavor) { + enum auth_stat as; + + as = (*asp->handler)(rqst, msg); + mutex_unlock(&authsvc_lock); + return (as); + } + } + mutex_unlock(&authsvc_lock); + + return (AUTH_REJECTEDCRED); +} + +/* + * A set of null auth methods used by any authentication protocols + * that don't need to inspect or modify the message body. + */ +static bool_t +svcauth_null_wrap(auth, xdrs, xdr_func, xdr_ptr) + SVCAUTH *auth; + XDR *xdrs; + xdrproc_t xdr_func; + caddr_t xdr_ptr; +{ + + return (xdr_func(xdrs, xdr_ptr)); +} + +struct svc_auth_ops svc_auth_null_ops = { + svcauth_null_wrap, + svcauth_null_wrap, +}; + +/*ARGSUSED*/ +enum auth_stat +_svcauth_null(rqst, msg) + struct svc_req *rqst; + struct rpc_msg *msg; +{ + return (AUTH_OK); +} + +/* + * Allow the rpc service to register new authentication types that it is + * prepared to handle. When an authentication flavor is registered, + * the flavor is checked against already registered values. If not + * registered, then a new Auths entry is added on the list. + * + * There is no provision to delete a registration once registered. + * + * This routine returns: + * 0 if registration successful + * 1 if flavor already registered + * -1 if can't register (errno set) + */ + +int +svc_auth_reg(cred_flavor, handler) + int cred_flavor; + enum auth_stat (*handler)(struct svc_req *, struct rpc_msg *); +{ + struct authsvc *asp; + + switch (cred_flavor) { + case AUTH_NULL: + case AUTH_SYS: + case AUTH_SHORT: +#ifdef DES_BUILTIN + case AUTH_DES: +#endif + /* already registered */ + return (1); + + default: + mutex_lock(&authsvc_lock); + for (asp = Auths; asp; asp = asp->next) { + if (asp->flavor == cred_flavor) { + /* already registered */ + mutex_unlock(&authsvc_lock); + return (1); + } + } + + /* this is a new one, so go ahead and register it */ + asp = mem_alloc(sizeof (*asp)); + if (asp == NULL) { + mutex_unlock(&authsvc_lock); + return (-1); + } + asp->flavor = cred_flavor; + asp->handler = handler; + asp->next = Auths; + Auths = asp; + mutex_unlock(&authsvc_lock); + break; + } + return (0); +} diff --git a/freebsd/lib/libc/rpc/svc_auth_des.c b/freebsd/lib/libc/rpc/svc_auth_des.c new file mode 100644 index 00000000..a9408019 --- /dev/null +++ b/freebsd/lib/libc/rpc/svc_auth_des.c @@ -0,0 +1,539 @@ +#include <machine/rtems-bsd-user-space.h> + + +/* + * Copyright (c) 1988 by Sun Microsystems, Inc. + */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * svcauth_des.c, server-side des authentication + * + * We insure for the service the following: + * (1) The timestamp microseconds do not exceed 1 million. + * (2) The timestamp plus the window is less than the current time. + * (3) The timestamp is not less than the one previously + * seen in the current session. + * + * It is up to the server to determine if the window size is + * too small . + * + */ + +#include "namespace.h" +#include "reentrant.h" +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <rpc/des_crypt.h> +#include <rtems/bsd/sys/param.h> +#include <netinet/in.h> +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <rpc/auth.h> +#include <rpc/auth_des.h> +#include <rpc/svc.h> +#include <rpc/rpc_msg.h> +#include <rpc/svc_auth.h> +#include "libc_private.h" + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)svcauth_des.c 2.3 89/07/11 4.0 RPCSRC; from 1.15 88/02/08 SMI"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +extern int key_decryptsession_pk(const char *, netobj *, des_block *); + +#define debug(msg) printf("svcauth_des: %s\n", msg) + +#define USEC_PER_SEC ((u_long) 1000000L) +#define BEFORE(t1, t2) timercmp(t1, t2, <) + +/* + * LRU cache of conversation keys and some other useful items. + */ +#define AUTHDES_CACHESZ 64 +struct cache_entry { + des_block key; /* conversation key */ + char *rname; /* client's name */ + u_int window; /* credential lifetime window */ + struct timeval laststamp; /* detect replays of creds */ + char *localcred; /* generic local credential */ +}; +static struct cache_entry *authdes_cache/* [AUTHDES_CACHESZ] */; +static short *authdes_lru/* [AUTHDES_CACHESZ] */; + +static void cache_init(); /* initialize the cache */ +static short cache_spot(); /* find an entry in the cache */ +static void cache_ref(/*short sid*/); /* note that sid was ref'd */ + +static void invalidate(); /* invalidate entry in cache */ + +/* + * cache statistics + */ +static struct { + u_long ncachehits; /* times cache hit, and is not replay */ + u_long ncachereplays; /* times cache hit, and is replay */ + u_long ncachemisses; /* times cache missed */ +} svcauthdes_stats; + +/* + * Service side authenticator for AUTH_DES + */ +enum auth_stat +_svcauth_des(rqst, msg) + struct svc_req *rqst; + struct rpc_msg *msg; +{ + + long *ixdr; + des_block cryptbuf[2]; + struct authdes_cred *cred; + struct authdes_verf verf; + int status; + struct cache_entry *entry; + short sid = 0; + des_block *sessionkey; + des_block ivec; + u_int window; + struct timeval timestamp; + u_long namelen; + struct area { + struct authdes_cred area_cred; + char area_netname[MAXNETNAMELEN+1]; + } *area; + + if (authdes_cache == NULL) { + cache_init(); + } + + area = (struct area *)rqst->rq_clntcred; + cred = (struct authdes_cred *)&area->area_cred; + + /* + * Get the credential + */ + ixdr = (long *)msg->rm_call.cb_cred.oa_base; + cred->adc_namekind = IXDR_GET_ENUM(ixdr, enum authdes_namekind); + switch (cred->adc_namekind) { + case ADN_FULLNAME: + namelen = IXDR_GET_U_LONG(ixdr); + if (namelen > MAXNETNAMELEN) { + return (AUTH_BADCRED); + } + cred->adc_fullname.name = area->area_netname; + bcopy((char *)ixdr, cred->adc_fullname.name, + (u_int)namelen); + cred->adc_fullname.name[namelen] = 0; + ixdr += (RNDUP(namelen) / BYTES_PER_XDR_UNIT); + cred->adc_fullname.key.key.high = (u_long)*ixdr++; + cred->adc_fullname.key.key.low = (u_long)*ixdr++; + cred->adc_fullname.window = (u_long)*ixdr++; + break; + case ADN_NICKNAME: + cred->adc_nickname = (u_long)*ixdr++; + break; + default: + return (AUTH_BADCRED); + } + + /* + * Get the verifier + */ + ixdr = (long *)msg->rm_call.cb_verf.oa_base; + verf.adv_xtimestamp.key.high = (u_long)*ixdr++; + verf.adv_xtimestamp.key.low = (u_long)*ixdr++; + verf.adv_int_u = (u_long)*ixdr++; + + + /* + * Get the conversation key + */ + if (cred->adc_namekind == ADN_FULLNAME) { + netobj pkey; + char pkey_data[1024]; + + sessionkey = &cred->adc_fullname.key; + if (! getpublickey(cred->adc_fullname.name, pkey_data)) { + debug("getpublickey"); + return(AUTH_BADCRED); + } + pkey.n_bytes = pkey_data; + pkey.n_len = strlen(pkey_data) + 1; + if (key_decryptsession_pk(cred->adc_fullname.name, &pkey, + sessionkey) < 0) { + debug("decryptsessionkey"); + return (AUTH_BADCRED); /* key not found */ + } + } else { /* ADN_NICKNAME */ + sid = (short)cred->adc_nickname; + if (sid < 0 || sid >= AUTHDES_CACHESZ) { + debug("bad nickname"); + return (AUTH_BADCRED); /* garbled credential */ + } + sessionkey = &authdes_cache[sid].key; + } + + + /* + * Decrypt the timestamp + */ + cryptbuf[0] = verf.adv_xtimestamp; + if (cred->adc_namekind == ADN_FULLNAME) { + cryptbuf[1].key.high = cred->adc_fullname.window; + cryptbuf[1].key.low = verf.adv_winverf; + ivec.key.high = ivec.key.low = 0; + status = cbc_crypt((char *)sessionkey, (char *)cryptbuf, + 2*sizeof(des_block), DES_DECRYPT | DES_HW, + (char *)&ivec); + } else { + status = ecb_crypt((char *)sessionkey, (char *)cryptbuf, + sizeof(des_block), DES_DECRYPT | DES_HW); + } + if (DES_FAILED(status)) { + debug("decryption failure"); + return (AUTH_FAILED); /* system error */ + } + + /* + * XDR the decrypted timestamp + */ + ixdr = (long *)cryptbuf; + timestamp.tv_sec = IXDR_GET_LONG(ixdr); + timestamp.tv_usec = IXDR_GET_LONG(ixdr); + + /* + * Check for valid credentials and verifiers. + * They could be invalid because the key was flushed + * out of the cache, and so a new session should begin. + * Be sure and send AUTH_REJECTED{CRED, VERF} if this is the case. + */ + { + struct timeval current; + int nick; + int winverf; + + if (cred->adc_namekind == ADN_FULLNAME) { + window = IXDR_GET_U_LONG(ixdr); + winverf = IXDR_GET_U_LONG(ixdr); + if (winverf != window - 1) { + debug("window verifier mismatch"); + return (AUTH_BADCRED); /* garbled credential */ + } + sid = cache_spot(sessionkey, cred->adc_fullname.name, + ×tamp); + if (sid < 0) { + debug("replayed credential"); + return (AUTH_REJECTEDCRED); /* replay */ + } + nick = 0; + } else { /* ADN_NICKNAME */ + window = authdes_cache[sid].window; + nick = 1; + } + + if ((u_long)timestamp.tv_usec >= USEC_PER_SEC) { + debug("invalid usecs"); + /* cached out (bad key), or garbled verifier */ + return (nick ? AUTH_REJECTEDVERF : AUTH_BADVERF); + } + if (nick && BEFORE(×tamp, + &authdes_cache[sid].laststamp)) { + debug("timestamp before last seen"); + return (AUTH_REJECTEDVERF); /* replay */ + } + (void) gettimeofday(¤t, (struct timezone *)NULL); + current.tv_sec -= window; /* allow for expiration */ + if (!BEFORE(¤t, ×tamp)) { + debug("timestamp expired"); + /* replay, or garbled credential */ + return (nick ? AUTH_REJECTEDVERF : AUTH_BADCRED); + } + } + + /* + * Set up the reply verifier + */ + verf.adv_nickname = (u_long)sid; + + /* + * xdr the timestamp before encrypting + */ + ixdr = (long *)cryptbuf; + IXDR_PUT_LONG(ixdr, timestamp.tv_sec - 1); + IXDR_PUT_LONG(ixdr, timestamp.tv_usec); + + /* + * encrypt the timestamp + */ + status = ecb_crypt((char *)sessionkey, (char *)cryptbuf, + sizeof(des_block), DES_ENCRYPT | DES_HW); + if (DES_FAILED(status)) { + debug("encryption failure"); + return (AUTH_FAILED); /* system error */ + } + verf.adv_xtimestamp = cryptbuf[0]; + + /* + * Serialize the reply verifier, and update rqst + */ + ixdr = (long *)msg->rm_call.cb_verf.oa_base; + *ixdr++ = (long)verf.adv_xtimestamp.key.high; + *ixdr++ = (long)verf.adv_xtimestamp.key.low; + *ixdr++ = (long)verf.adv_int_u; + + rqst->rq_xprt->xp_verf.oa_flavor = AUTH_DES; + rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base; + rqst->rq_xprt->xp_verf.oa_length = + (char *)ixdr - msg->rm_call.cb_verf.oa_base; + + /* + * We succeeded, commit the data to the cache now and + * finish cooking the credential. + */ + entry = &authdes_cache[sid]; + entry->laststamp = timestamp; + cache_ref(sid); + if (cred->adc_namekind == ADN_FULLNAME) { + cred->adc_fullname.window = window; + cred->adc_nickname = (u_long)sid; /* save nickname */ + if (entry->rname != NULL) { + mem_free(entry->rname, strlen(entry->rname) + 1); + } + entry->rname = (char *)mem_alloc((u_int)strlen(cred->adc_fullname.name) + + 1); + if (entry->rname != NULL) { + (void) strcpy(entry->rname, cred->adc_fullname.name); + } else { + debug("out of memory"); + } + entry->key = *sessionkey; + entry->window = window; + invalidate(entry->localcred); /* mark any cached cred invalid */ + } else { /* ADN_NICKNAME */ + /* + * nicknames are cooked into fullnames + */ + cred->adc_namekind = ADN_FULLNAME; + cred->adc_fullname.name = entry->rname; + cred->adc_fullname.key = entry->key; + cred->adc_fullname.window = entry->window; + } + return (AUTH_OK); /* we made it!*/ +} + + +/* + * Initialize the cache + */ +static void +cache_init() +{ + int i; + + authdes_cache = (struct cache_entry *) + mem_alloc(sizeof(struct cache_entry) * AUTHDES_CACHESZ); + bzero((char *)authdes_cache, + sizeof(struct cache_entry) * AUTHDES_CACHESZ); + + authdes_lru = (short *)mem_alloc(sizeof(short) * AUTHDES_CACHESZ); + /* + * Initialize the lru list + */ + for (i = 0; i < AUTHDES_CACHESZ; i++) { + authdes_lru[i] = i; + } +} + + +/* + * Find the lru victim + */ +static short +cache_victim() +{ + return (authdes_lru[AUTHDES_CACHESZ-1]); +} + +/* + * Note that sid was referenced + */ +static void +cache_ref(sid) + short sid; +{ + int i; + short curr; + short prev; + + prev = authdes_lru[0]; + authdes_lru[0] = sid; + for (i = 1; prev != sid; i++) { + curr = authdes_lru[i]; + authdes_lru[i] = prev; + prev = curr; + } +} + + +/* + * Find a spot in the cache for a credential containing + * the items given. Return -1 if a replay is detected, otherwise + * return the spot in the cache. + */ +static short +cache_spot(key, name, timestamp) + des_block *key; + char *name; + struct timeval *timestamp; +{ + struct cache_entry *cp; + int i; + u_long hi; + + hi = key->key.high; + for (cp = authdes_cache, i = 0; i < AUTHDES_CACHESZ; i++, cp++) { + if (cp->key.key.high == hi && + cp->key.key.low == key->key.low && + cp->rname != NULL && + bcmp(cp->rname, name, strlen(name) + 1) == 0) { + if (BEFORE(timestamp, &cp->laststamp)) { + svcauthdes_stats.ncachereplays++; + return (-1); /* replay */ + } + svcauthdes_stats.ncachehits++; + return (i); /* refresh */ + } + } + svcauthdes_stats.ncachemisses++; + return (cache_victim()); /* new credential */ +} + + +#if (defined(sun) || defined(vax) || defined(__FreeBSD__)) +/* + * Local credential handling stuff. + * NOTE: bsd unix dependent. + * Other operating systems should put something else here. + */ +#define UNKNOWN -2 /* grouplen, if cached cred is unknown user */ +#define INVALID -1 /* grouplen, if cache entry is invalid */ + +struct bsdcred { + uid_t uid; /* cached uid */ + gid_t gid; /* cached gid */ + int grouplen; /* length of cached groups */ + gid_t groups[NGRPS]; /* cached groups */ +}; + +/* + * Map a des credential into a unix cred. + * We cache the credential here so the application does + * not have to make an rpc call every time to interpret + * the credential. + */ +int +authdes_getucred(adc, uid, gid, grouplen, groups) + struct authdes_cred *adc; + uid_t *uid; + gid_t *gid; + int *grouplen; + gid_t *groups; +{ + unsigned sid; + int i; + uid_t i_uid; + gid_t i_gid; + int i_grouplen; + struct bsdcred *cred; + + sid = adc->adc_nickname; + if (sid >= AUTHDES_CACHESZ) { + debug("invalid nickname"); + return (0); + } + cred = (struct bsdcred *)authdes_cache[sid].localcred; + if (cred == NULL) { + cred = (struct bsdcred *)mem_alloc(sizeof(struct bsdcred)); + authdes_cache[sid].localcred = (char *)cred; + cred->grouplen = INVALID; + } + if (cred->grouplen == INVALID) { + /* + * not in cache: lookup + */ + if (!netname2user(adc->adc_fullname.name, &i_uid, &i_gid, + &i_grouplen, groups)) + { + debug("unknown netname"); + cred->grouplen = UNKNOWN; /* mark as lookup up, but not found */ + return (0); + } + debug("missed ucred cache"); + *uid = cred->uid = i_uid; + *gid = cred->gid = i_gid; + *grouplen = cred->grouplen = i_grouplen; + for (i = i_grouplen - 1; i >= 0; i--) { + cred->groups[i] = groups[i]; /* int to short */ + } + return (1); + } else if (cred->grouplen == UNKNOWN) { + /* + * Already lookup up, but no match found + */ + return (0); + } + + /* + * cached credentials + */ + *uid = cred->uid; + *gid = cred->gid; + *grouplen = cred->grouplen; + for (i = cred->grouplen - 1; i >= 0; i--) { + groups[i] = cred->groups[i]; /* short to int */ + } + return (1); +} + +static void +invalidate(cred) + char *cred; +{ + if (cred == NULL) { + return; + } + ((struct bsdcred *)cred)->grouplen = INVALID; +} +#endif + diff --git a/freebsd/lib/libc/rpc/svc_auth_unix.c b/freebsd/lib/libc/rpc/svc_auth_unix.c new file mode 100644 index 00000000..bd052b77 --- /dev/null +++ b/freebsd/lib/libc/rpc/svc_auth_unix.c @@ -0,0 +1,157 @@ +#include <machine/rtems-bsd-user-space.h> + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *sccsid2 = "@(#)svc_auth_unix.c 1.28 88/02/08 Copyr 1984 Sun Micro"; +static char *sccsid = "@(#)svc_auth_unix.c 2.3 88/08/01 4.0 RPCSRC"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * 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 "namespace.h" +#include <assert.h> +#include <stdio.h> +#include <string.h> + +#include <rpc/rpc.h> +#include "un-namespace.h" + +/* + * Unix longhand authenticator + */ +enum auth_stat +_svcauth_unix(rqst, msg) + struct svc_req *rqst; + struct rpc_msg *msg; +{ + enum auth_stat stat; + XDR xdrs; + struct authunix_parms *aup; + int32_t *buf; + struct area { + struct authunix_parms area_aup; + char area_machname[MAX_MACHINE_NAME+1]; + u_int area_gids[NGRPS]; + } *area; + u_int auth_len; + size_t str_len, gid_len; + u_int i; + + assert(rqst != NULL); + assert(msg != NULL); + + area = (struct area *) rqst->rq_clntcred; + aup = &area->area_aup; + aup->aup_machname = area->area_machname; + aup->aup_gids = area->area_gids; + auth_len = (u_int)msg->rm_call.cb_cred.oa_length; + xdrmem_create(&xdrs, msg->rm_call.cb_cred.oa_base, auth_len,XDR_DECODE); + buf = XDR_INLINE(&xdrs, auth_len); + if (buf != NULL) { + aup->aup_time = IXDR_GET_INT32(buf); + str_len = (size_t)IXDR_GET_U_INT32(buf); + if (str_len > MAX_MACHINE_NAME) { + stat = AUTH_BADCRED; + goto done; + } + memmove(aup->aup_machname, buf, str_len); + aup->aup_machname[str_len] = 0; + str_len = RNDUP(str_len); + buf += str_len / sizeof (int32_t); + aup->aup_uid = (int)IXDR_GET_INT32(buf); + aup->aup_gid = (int)IXDR_GET_INT32(buf); + gid_len = (size_t)IXDR_GET_U_INT32(buf); + if (gid_len > NGRPS) { + stat = AUTH_BADCRED; + goto done; + } + aup->aup_len = gid_len; + for (i = 0; i < gid_len; i++) { + aup->aup_gids[i] = (int)IXDR_GET_INT32(buf); + } + /* + * five is the smallest unix credentials structure - + * timestamp, hostname len (0), uid, gid, and gids len (0). + */ + if ((5 + gid_len) * BYTES_PER_XDR_UNIT + str_len > auth_len) { + (void) printf("bad auth_len gid %ld str %ld auth %u\n", + (long)gid_len, (long)str_len, auth_len); + stat = AUTH_BADCRED; + goto done; + } + } else if (! xdr_authunix_parms(&xdrs, aup)) { + xdrs.x_op = XDR_FREE; + (void)xdr_authunix_parms(&xdrs, aup); + stat = AUTH_BADCRED; + goto done; + } + + /* get the verifier */ + if ((u_int)msg->rm_call.cb_verf.oa_length) { + rqst->rq_xprt->xp_verf.oa_flavor = + msg->rm_call.cb_verf.oa_flavor; + rqst->rq_xprt->xp_verf.oa_base = + msg->rm_call.cb_verf.oa_base; + rqst->rq_xprt->xp_verf.oa_length = + msg->rm_call.cb_verf.oa_length; + } else { + rqst->rq_xprt->xp_verf.oa_flavor = AUTH_NULL; + rqst->rq_xprt->xp_verf.oa_length = 0; + } + stat = AUTH_OK; +done: + XDR_DESTROY(&xdrs); + return (stat); +} + + +/* + * Shorthand unix authenticator + * Looks up longhand in a cache. + */ +/*ARGSUSED*/ +enum auth_stat +_svcauth_short(rqst, msg) + struct svc_req *rqst; + struct rpc_msg *msg; +{ + return (AUTH_REJECTEDCRED); +} diff --git a/freebsd/lib/libc/rpc/svc_dg.c b/freebsd/lib/libc/rpc/svc_dg.c new file mode 100644 index 00000000..0d75191c --- /dev/null +++ b/freebsd/lib/libc/rpc/svc_dg.c @@ -0,0 +1,740 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: svc_dg.c,v 1.4 2000/07/06 03:10:35 christos Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +#ident "@(#)svc_dg.c 1.17 94/04/24 SMI" +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * svc_dg.c, Server side for connectionless RPC. + * + * Does some caching in the hopes of achieving execute-at-most-once semantics. + */ + +#include "namespace.h" +#include "reentrant.h" +#include <sys/types.h> +#include <sys/socket.h> +#include <rpc/rpc.h> +#include <rpc/svc_dg.h> +#include <assert.h> +#include <errno.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#ifdef RPC_CACHE_DEBUG +#include <netconfig.h> +#include <netdir.h> +#endif +#include <err.h> +#include "un-namespace.h" + +#include "rpc_com.h" +#include "mt_misc.h" + +#define su_data(xprt) ((struct svc_dg_data *)(xprt->xp_p2)) +#define rpc_buffer(xprt) ((xprt)->xp_p1) + +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +static void svc_dg_ops(SVCXPRT *); +static enum xprt_stat svc_dg_stat(SVCXPRT *); +static bool_t svc_dg_recv(SVCXPRT *, struct rpc_msg *); +static bool_t svc_dg_reply(SVCXPRT *, struct rpc_msg *); +static bool_t svc_dg_getargs(SVCXPRT *, xdrproc_t, void *); +static bool_t svc_dg_freeargs(SVCXPRT *, xdrproc_t, void *); +static void svc_dg_destroy(SVCXPRT *); +static bool_t svc_dg_control(SVCXPRT *, const u_int, void *); +static int cache_get(SVCXPRT *, struct rpc_msg *, char **, size_t *); +static void cache_set(SVCXPRT *, size_t); +int svc_dg_enablecache(SVCXPRT *, u_int); + +/* + * Usage: + * xprt = svc_dg_create(sock, sendsize, recvsize); + * Does other connectionless specific initializations. + * Once *xprt is initialized, it is registered. + * see (svc.h, xprt_register). If recvsize or sendsize are 0 suitable + * system defaults are chosen. + * The routines returns NULL if a problem occurred. + */ +static const char svc_dg_str[] = "svc_dg_create: %s"; +static const char svc_dg_err1[] = "could not get transport information"; +static const char svc_dg_err2[] = "transport does not support data transfer"; +static const char svc_dg_err3[] = "getsockname failed"; +static const char svc_dg_err4[] = "cannot set IP_RECVDSTADDR"; +static const char __no_mem_str[] = "out of memory"; + +SVCXPRT * +svc_dg_create(fd, sendsize, recvsize) + int fd; + u_int sendsize; + u_int recvsize; +{ + SVCXPRT *xprt; + struct svc_dg_data *su = NULL; + struct __rpc_sockinfo si; + struct sockaddr_storage ss; + socklen_t slen; + + if (!__rpc_fd2sockinfo(fd, &si)) { + warnx(svc_dg_str, svc_dg_err1); + return (NULL); + } + /* + * Find the receive and the send size + */ + sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize); + recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize); + if ((sendsize == 0) || (recvsize == 0)) { + warnx(svc_dg_str, svc_dg_err2); + return (NULL); + } + + xprt = svc_xprt_alloc(); + if (xprt == NULL) + goto freedata; + + su = mem_alloc(sizeof (*su)); + if (su == NULL) + goto freedata; + su->su_iosz = ((MAX(sendsize, recvsize) + 3) / 4) * 4; + if ((rpc_buffer(xprt) = mem_alloc(su->su_iosz)) == NULL) + goto freedata; + xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, + XDR_DECODE); + su->su_cache = NULL; + xprt->xp_fd = fd; + xprt->xp_p2 = su; + xprt->xp_verf.oa_base = su->su_verfbody; + svc_dg_ops(xprt); + xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage); + + slen = sizeof ss; + if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { + warnx(svc_dg_str, svc_dg_err3); + goto freedata_nowarn; + } + xprt->xp_ltaddr.buf = mem_alloc(sizeof (struct sockaddr_storage)); + xprt->xp_ltaddr.maxlen = sizeof (struct sockaddr_storage); + xprt->xp_ltaddr.len = slen; + memcpy(xprt->xp_ltaddr.buf, &ss, slen); + + if (ss.ss_family == AF_INET) { + struct sockaddr_in *sin; + static const int true_value = 1; + + sin = (struct sockaddr_in *)(void *)&ss; + if (sin->sin_addr.s_addr == INADDR_ANY) { + su->su_srcaddr.buf = mem_alloc(sizeof (ss)); + su->su_srcaddr.maxlen = sizeof (ss); + + if (_setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, + &true_value, sizeof(true_value))) { + warnx(svc_dg_str, svc_dg_err4); + goto freedata_nowarn; + } + } + } + + xprt_register(xprt); + return (xprt); +freedata: + (void) warnx(svc_dg_str, __no_mem_str); +freedata_nowarn: + if (xprt) { + if (su) + (void) mem_free(su, sizeof (*su)); + svc_xprt_free(xprt); + } + return (NULL); +} + +/*ARGSUSED*/ +static enum xprt_stat +svc_dg_stat(xprt) + SVCXPRT *xprt; +{ + return (XPRT_IDLE); +} + +static int +svc_dg_recvfrom(int fd, char *buf, int buflen, + struct sockaddr *raddr, socklen_t *raddrlen, + struct sockaddr *laddr, socklen_t *laddrlen) +{ + struct msghdr msg; + struct iovec msg_iov[1]; + struct sockaddr_in *lin = (struct sockaddr_in *)laddr; + int rlen; + bool_t have_lin = FALSE; + char tmp[CMSG_LEN(sizeof(*lin))]; + struct cmsghdr *cmsg; + + memset((char *)&msg, 0, sizeof(msg)); + msg_iov[0].iov_base = buf; + msg_iov[0].iov_len = buflen; + msg.msg_iov = msg_iov; + msg.msg_iovlen = 1; + msg.msg_namelen = *raddrlen; + msg.msg_name = (char *)raddr; + if (laddr != NULL) { + msg.msg_control = (caddr_t)tmp; + msg.msg_controllen = CMSG_LEN(sizeof(*lin)); + } + rlen = _recvmsg(fd, &msg, 0); + if (rlen >= 0) + *raddrlen = msg.msg_namelen; + + if (rlen == -1 || laddr == NULL || + msg.msg_controllen < sizeof(struct cmsghdr) || + msg.msg_flags & MSG_CTRUNC) + return rlen; + + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; + cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level == IPPROTO_IP && + cmsg->cmsg_type == IP_RECVDSTADDR) { + have_lin = TRUE; + memcpy(&lin->sin_addr, + (struct in_addr *)CMSG_DATA(cmsg), + sizeof(struct in_addr)); + break; + } + } + + lin->sin_family = AF_INET; + lin->sin_port = 0; + *laddrlen = sizeof(struct sockaddr_in); + + if (!have_lin) + lin->sin_addr.s_addr = INADDR_ANY; + + return rlen; +} + +static bool_t +svc_dg_recv(xprt, msg) + SVCXPRT *xprt; + struct rpc_msg *msg; +{ + struct svc_dg_data *su = su_data(xprt); + XDR *xdrs = &(su->su_xdrs); + char *reply; + struct sockaddr_storage ss; + socklen_t alen; + size_t replylen; + ssize_t rlen; + +again: + alen = sizeof (struct sockaddr_storage); + rlen = svc_dg_recvfrom(xprt->xp_fd, rpc_buffer(xprt), su->su_iosz, + (struct sockaddr *)(void *)&ss, &alen, + (struct sockaddr *)su->su_srcaddr.buf, &su->su_srcaddr.len); + if (rlen == -1 && errno == EINTR) + goto again; + if (rlen == -1 || (rlen < (ssize_t)(4 * sizeof (u_int32_t)))) + return (FALSE); + if (xprt->xp_rtaddr.len < alen) { + if (xprt->xp_rtaddr.len != 0) + mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.len); + xprt->xp_rtaddr.buf = mem_alloc(alen); + xprt->xp_rtaddr.len = alen; + } + memcpy(xprt->xp_rtaddr.buf, &ss, alen); +#ifdef PORTMAP + if (ss.ss_family == AF_INET) { + xprt->xp_raddr = *(struct sockaddr_in *)xprt->xp_rtaddr.buf; + xprt->xp_addrlen = sizeof (struct sockaddr_in); + } +#endif /* PORTMAP */ + xdrs->x_op = XDR_DECODE; + XDR_SETPOS(xdrs, 0); + if (! xdr_callmsg(xdrs, msg)) { + return (FALSE); + } + su->su_xid = msg->rm_xid; + if (su->su_cache != NULL) { + if (cache_get(xprt, msg, &reply, &replylen)) { + (void)_sendto(xprt->xp_fd, reply, replylen, 0, + (struct sockaddr *)(void *)&ss, alen); + return (FALSE); + } + } + return (TRUE); +} + +static int +svc_dg_sendto(int fd, char *buf, int buflen, + const struct sockaddr *raddr, socklen_t raddrlen, + const struct sockaddr *laddr, socklen_t laddrlen) +{ + struct msghdr msg; + struct iovec msg_iov[1]; + struct sockaddr_in *laddr_in = (struct sockaddr_in *)laddr; + struct in_addr *lin = &laddr_in->sin_addr; + char tmp[CMSG_SPACE(sizeof(*lin))]; + struct cmsghdr *cmsg; + + memset((char *)&msg, 0, sizeof(msg)); + msg_iov[0].iov_base = buf; + msg_iov[0].iov_len = buflen; + msg.msg_iov = msg_iov; + msg.msg_iovlen = 1; + msg.msg_namelen = raddrlen; + msg.msg_name = (char *)raddr; + + if (laddr != NULL && laddr->sa_family == AF_INET && + lin->s_addr != INADDR_ANY) { + msg.msg_control = (caddr_t)tmp; + msg.msg_controllen = CMSG_LEN(sizeof(*lin)); + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_len = CMSG_LEN(sizeof(*lin)); + cmsg->cmsg_level = IPPROTO_IP; + cmsg->cmsg_type = IP_SENDSRCADDR; + memcpy(CMSG_DATA(cmsg), lin, sizeof(*lin)); + } + + return _sendmsg(fd, &msg, 0); +} + +static bool_t +svc_dg_reply(xprt, msg) + SVCXPRT *xprt; + struct rpc_msg *msg; +{ + struct svc_dg_data *su = su_data(xprt); + XDR *xdrs = &(su->su_xdrs); + bool_t stat = TRUE; + size_t slen; + xdrproc_t xdr_proc; + caddr_t xdr_where; + + xdrs->x_op = XDR_ENCODE; + XDR_SETPOS(xdrs, 0); + msg->rm_xid = su->su_xid; + if (msg->rm_reply.rp_stat == MSG_ACCEPTED && + msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { + xdr_proc = msg->acpted_rply.ar_results.proc; + xdr_where = msg->acpted_rply.ar_results.where; + msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void; + msg->acpted_rply.ar_results.where = NULL; + + if (!xdr_replymsg(xdrs, msg) || + !SVCAUTH_WRAP(&SVC_AUTH(xprt), xdrs, xdr_proc, xdr_where)) + stat = FALSE; + } else { + stat = xdr_replymsg(xdrs, msg); + } + if (stat) { + slen = XDR_GETPOS(xdrs); + if (svc_dg_sendto(xprt->xp_fd, rpc_buffer(xprt), slen, + (struct sockaddr *)xprt->xp_rtaddr.buf, + (socklen_t)xprt->xp_rtaddr.len, + (struct sockaddr *)su->su_srcaddr.buf, + (socklen_t)su->su_srcaddr.len) == (ssize_t) slen) { + stat = TRUE; + if (su->su_cache) + cache_set(xprt, slen); + } + } + return (stat); +} + +static bool_t +svc_dg_getargs(xprt, xdr_args, args_ptr) + SVCXPRT *xprt; + xdrproc_t xdr_args; + void *args_ptr; +{ + struct svc_dg_data *su; + + assert(xprt != NULL); + su = su_data(xprt); + return (SVCAUTH_UNWRAP(&SVC_AUTH(xprt), + &su->su_xdrs, xdr_args, args_ptr)); +} + +static bool_t +svc_dg_freeargs(xprt, xdr_args, args_ptr) + SVCXPRT *xprt; + xdrproc_t xdr_args; + void *args_ptr; +{ + XDR *xdrs = &(su_data(xprt)->su_xdrs); + + xdrs->x_op = XDR_FREE; + return (*xdr_args)(xdrs, args_ptr); +} + +static void +svc_dg_destroy(xprt) + SVCXPRT *xprt; +{ + struct svc_dg_data *su = su_data(xprt); + + xprt_unregister(xprt); + if (xprt->xp_fd != -1) + (void)_close(xprt->xp_fd); + XDR_DESTROY(&(su->su_xdrs)); + (void) mem_free(rpc_buffer(xprt), su->su_iosz); + if (su->su_srcaddr.buf) + (void) mem_free(su->su_srcaddr.buf, su->su_srcaddr.maxlen); + (void) mem_free(su, sizeof (*su)); + if (xprt->xp_rtaddr.buf) + (void) mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen); + if (xprt->xp_ltaddr.buf) + (void) mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen); + if (xprt->xp_tp) + (void) free(xprt->xp_tp); + svc_xprt_free(xprt); +} + +static bool_t +/*ARGSUSED*/ +svc_dg_control(xprt, rq, in) + SVCXPRT *xprt; + const u_int rq; + void *in; +{ + return (FALSE); +} + +static void +svc_dg_ops(xprt) + SVCXPRT *xprt; +{ + static struct xp_ops ops; + static struct xp_ops2 ops2; + +/* VARIABLES PROTECTED BY ops_lock: ops */ + + mutex_lock(&ops_lock); + if (ops.xp_recv == NULL) { + ops.xp_recv = svc_dg_recv; + ops.xp_stat = svc_dg_stat; + ops.xp_getargs = svc_dg_getargs; + ops.xp_reply = svc_dg_reply; + ops.xp_freeargs = svc_dg_freeargs; + ops.xp_destroy = svc_dg_destroy; + ops2.xp_control = svc_dg_control; + } + xprt->xp_ops = &ops; + xprt->xp_ops2 = &ops2; + mutex_unlock(&ops_lock); +} + +/* The CACHING COMPONENT */ + +/* + * Could have been a separate file, but some part of it depends upon the + * private structure of the client handle. + * + * Fifo cache for cl server + * Copies pointers to reply buffers into fifo cache + * Buffers are sent again if retransmissions are detected. + */ + +#define SPARSENESS 4 /* 75% sparse */ + +#define ALLOC(type, size) \ + (type *) mem_alloc((sizeof (type) * (size))) + +#define MEMZERO(addr, type, size) \ + (void) memset((void *) (addr), 0, sizeof (type) * (int) (size)) + +#define FREE(addr, type, size) \ + mem_free((addr), (sizeof (type) * (size))) + +/* + * An entry in the cache + */ +typedef struct cache_node *cache_ptr; +struct cache_node { + /* + * Index into cache is xid, proc, vers, prog and address + */ + u_int32_t cache_xid; + rpcproc_t cache_proc; + rpcvers_t cache_vers; + rpcprog_t cache_prog; + struct netbuf cache_addr; + /* + * The cached reply and length + */ + char *cache_reply; + size_t cache_replylen; + /* + * Next node on the list, if there is a collision + */ + cache_ptr cache_next; +}; + +/* + * The entire cache + */ +struct cl_cache { + u_int uc_size; /* size of cache */ + cache_ptr *uc_entries; /* hash table of entries in cache */ + cache_ptr *uc_fifo; /* fifo list of entries in cache */ + u_int uc_nextvictim; /* points to next victim in fifo list */ + rpcprog_t uc_prog; /* saved program number */ + rpcvers_t uc_vers; /* saved version number */ + rpcproc_t uc_proc; /* saved procedure number */ +}; + + +/* + * the hashing function + */ +#define CACHE_LOC(transp, xid) \ + (xid % (SPARSENESS * ((struct cl_cache *) \ + su_data(transp)->su_cache)->uc_size)) + +/* + * Enable use of the cache. Returns 1 on success, 0 on failure. + * Note: there is no disable. + */ +static const char cache_enable_str[] = "svc_enablecache: %s %s"; +static const char alloc_err[] = "could not allocate cache "; +static const char enable_err[] = "cache already enabled"; + +int +svc_dg_enablecache(transp, size) + SVCXPRT *transp; + u_int size; +{ + struct svc_dg_data *su = su_data(transp); + struct cl_cache *uc; + + mutex_lock(&dupreq_lock); + if (su->su_cache != NULL) { + (void) warnx(cache_enable_str, enable_err, " "); + mutex_unlock(&dupreq_lock); + return (0); + } + uc = ALLOC(struct cl_cache, 1); + if (uc == NULL) { + warnx(cache_enable_str, alloc_err, " "); + mutex_unlock(&dupreq_lock); + return (0); + } + uc->uc_size = size; + uc->uc_nextvictim = 0; + uc->uc_entries = ALLOC(cache_ptr, size * SPARSENESS); + if (uc->uc_entries == NULL) { + warnx(cache_enable_str, alloc_err, "data"); + FREE(uc, struct cl_cache, 1); + mutex_unlock(&dupreq_lock); + return (0); + } + MEMZERO(uc->uc_entries, cache_ptr, size * SPARSENESS); + uc->uc_fifo = ALLOC(cache_ptr, size); + if (uc->uc_fifo == NULL) { + warnx(cache_enable_str, alloc_err, "fifo"); + FREE(uc->uc_entries, cache_ptr, size * SPARSENESS); + FREE(uc, struct cl_cache, 1); + mutex_unlock(&dupreq_lock); + return (0); + } + MEMZERO(uc->uc_fifo, cache_ptr, size); + su->su_cache = (char *)(void *)uc; + mutex_unlock(&dupreq_lock); + return (1); +} + +/* + * Set an entry in the cache. It assumes that the uc entry is set from + * the earlier call to cache_get() for the same procedure. This will always + * happen because cache_get() is calle by svc_dg_recv and cache_set() is called + * by svc_dg_reply(). All this hoopla because the right RPC parameters are + * not available at svc_dg_reply time. + */ + +static const char cache_set_str[] = "cache_set: %s"; +static const char cache_set_err1[] = "victim not found"; +static const char cache_set_err2[] = "victim alloc failed"; +static const char cache_set_err3[] = "could not allocate new rpc buffer"; + +static void +cache_set(xprt, replylen) + SVCXPRT *xprt; + size_t replylen; +{ + cache_ptr victim; + cache_ptr *vicp; + struct svc_dg_data *su = su_data(xprt); + struct cl_cache *uc = (struct cl_cache *) su->su_cache; + u_int loc; + char *newbuf; +#ifdef RPC_CACHE_DEBUG + struct netconfig *nconf; + char *uaddr; +#endif + + mutex_lock(&dupreq_lock); + /* + * Find space for the new entry, either by + * reusing an old entry, or by mallocing a new one + */ + victim = uc->uc_fifo[uc->uc_nextvictim]; + if (victim != NULL) { + loc = CACHE_LOC(xprt, victim->cache_xid); + for (vicp = &uc->uc_entries[loc]; + *vicp != NULL && *vicp != victim; + vicp = &(*vicp)->cache_next) + ; + if (*vicp == NULL) { + warnx(cache_set_str, cache_set_err1); + mutex_unlock(&dupreq_lock); + return; + } + *vicp = victim->cache_next; /* remove from cache */ + newbuf = victim->cache_reply; + } else { + victim = ALLOC(struct cache_node, 1); + if (victim == NULL) { + warnx(cache_set_str, cache_set_err2); + mutex_unlock(&dupreq_lock); + return; + } + newbuf = mem_alloc(su->su_iosz); + if (newbuf == NULL) { + warnx(cache_set_str, cache_set_err3); + FREE(victim, struct cache_node, 1); + mutex_unlock(&dupreq_lock); + return; + } + } + + /* + * Store it away + */ +#ifdef RPC_CACHE_DEBUG + if (nconf = getnetconfigent(xprt->xp_netid)) { + uaddr = taddr2uaddr(nconf, &xprt->xp_rtaddr); + freenetconfigent(nconf); + printf( + "cache set for xid= %x prog=%d vers=%d proc=%d for rmtaddr=%s\n", + su->su_xid, uc->uc_prog, uc->uc_vers, + uc->uc_proc, uaddr); + free(uaddr); + } +#endif + victim->cache_replylen = replylen; + victim->cache_reply = rpc_buffer(xprt); + rpc_buffer(xprt) = newbuf; + xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), + su->su_iosz, XDR_ENCODE); + victim->cache_xid = su->su_xid; + victim->cache_proc = uc->uc_proc; + victim->cache_vers = uc->uc_vers; + victim->cache_prog = uc->uc_prog; + victim->cache_addr = xprt->xp_rtaddr; + victim->cache_addr.buf = ALLOC(char, xprt->xp_rtaddr.len); + (void) memcpy(victim->cache_addr.buf, xprt->xp_rtaddr.buf, + (size_t)xprt->xp_rtaddr.len); + loc = CACHE_LOC(xprt, victim->cache_xid); + victim->cache_next = uc->uc_entries[loc]; + uc->uc_entries[loc] = victim; + uc->uc_fifo[uc->uc_nextvictim++] = victim; + uc->uc_nextvictim %= uc->uc_size; + mutex_unlock(&dupreq_lock); +} + +/* + * Try to get an entry from the cache + * return 1 if found, 0 if not found and set the stage for cache_set() + */ +static int +cache_get(xprt, msg, replyp, replylenp) + SVCXPRT *xprt; + struct rpc_msg *msg; + char **replyp; + size_t *replylenp; +{ + u_int loc; + cache_ptr ent; + struct svc_dg_data *su = su_data(xprt); + struct cl_cache *uc = (struct cl_cache *) su->su_cache; +#ifdef RPC_CACHE_DEBUG + struct netconfig *nconf; + char *uaddr; +#endif + + mutex_lock(&dupreq_lock); + loc = CACHE_LOC(xprt, su->su_xid); + for (ent = uc->uc_entries[loc]; ent != NULL; ent = ent->cache_next) { + if (ent->cache_xid == su->su_xid && + ent->cache_proc == msg->rm_call.cb_proc && + ent->cache_vers == msg->rm_call.cb_vers && + ent->cache_prog == msg->rm_call.cb_prog && + ent->cache_addr.len == xprt->xp_rtaddr.len && + (memcmp(ent->cache_addr.buf, xprt->xp_rtaddr.buf, + xprt->xp_rtaddr.len) == 0)) { +#ifdef RPC_CACHE_DEBUG + if (nconf = getnetconfigent(xprt->xp_netid)) { + uaddr = taddr2uaddr(nconf, &xprt->xp_rtaddr); + freenetconfigent(nconf); + printf( + "cache entry found for xid=%x prog=%d vers=%d proc=%d for rmtaddr=%s\n", + su->su_xid, msg->rm_call.cb_prog, + msg->rm_call.cb_vers, + msg->rm_call.cb_proc, uaddr); + free(uaddr); + } +#endif + *replyp = ent->cache_reply; + *replylenp = ent->cache_replylen; + mutex_unlock(&dupreq_lock); + return (1); + } + } + /* + * Failed to find entry + * Remember a few things so we can do a set later + */ + uc->uc_proc = msg->rm_call.cb_proc; + uc->uc_vers = msg->rm_call.cb_vers; + uc->uc_prog = msg->rm_call.cb_prog; + mutex_unlock(&dupreq_lock); + return (0); +} diff --git a/freebsd/lib/libc/rpc/svc_generic.c b/freebsd/lib/libc/rpc/svc_generic.c new file mode 100644 index 00000000..4d7a23a4 --- /dev/null +++ b/freebsd/lib/libc/rpc/svc_generic.c @@ -0,0 +1,312 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: svc_generic.c,v 1.3 2000/07/06 03:10:35 christos Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +#ident "@(#)svc_generic.c 1.19 94/04/24 SMI" +static char sccsid[] = "@(#)svc_generic.c 1.21 89/02/28 Copyr 1988 Sun Micro"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * svc_generic.c, Server side for RPC. + * + */ + +#include "namespace.h" +#include "reentrant.h" +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <rpc/rpc.h> +#include <rpc/nettype.h> +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <err.h> +#include "un-namespace.h" + +#include "rpc_com.h" +#include "mt_misc.h" + +extern int __svc_vc_setflag(SVCXPRT *, int); + +/* + * The highest level interface for server creation. + * It tries for all the nettokens in that particular class of token + * and returns the number of handles it can create and/or find. + * + * It creates a link list of all the handles it could create. + * If svc_create() is called multiple times, it uses the handle + * created earlier instead of creating a new handle every time. + */ +int +svc_create(dispatch, prognum, versnum, nettype) + void (*dispatch)(struct svc_req *, SVCXPRT *); + rpcprog_t prognum; /* Program number */ + rpcvers_t versnum; /* Version number */ + const char *nettype; /* Networktype token */ +{ + struct xlist { + SVCXPRT *xprt; /* Server handle */ + struct xlist *next; /* Next item */ + } *l; + static struct xlist *xprtlist; /* A link list of all the handles */ + int num = 0; + SVCXPRT *xprt; + struct netconfig *nconf; + void *handle; + +/* VARIABLES PROTECTED BY xprtlist_lock: xprtlist */ + + if ((handle = __rpc_setconf(nettype)) == NULL) { + warnx("svc_create: unknown protocol"); + return (0); + } + while ((nconf = __rpc_getconf(handle)) != NULL) { + mutex_lock(&xprtlist_lock); + for (l = xprtlist; l; l = l->next) { + if (strcmp(l->xprt->xp_netid, nconf->nc_netid) == 0) { + /* Found an old one, use it */ + (void) rpcb_unset(prognum, versnum, nconf); + if (svc_reg(l->xprt, prognum, versnum, + dispatch, nconf) == FALSE) + warnx( + "svc_create: could not register prog %u vers %u on %s", + (unsigned)prognum, (unsigned)versnum, + nconf->nc_netid); + else + num++; + break; + } + } + if (l == NULL) { + /* It was not found. Now create a new one */ + xprt = svc_tp_create(dispatch, prognum, versnum, nconf); + if (xprt) { + l = (struct xlist *)malloc(sizeof (*l)); + if (l == NULL) { + warnx("svc_create: no memory"); + mutex_unlock(&xprtlist_lock); + return (0); + } + l->xprt = xprt; + l->next = xprtlist; + xprtlist = l; + num++; + } + } + mutex_unlock(&xprtlist_lock); + } + __rpc_endconf(handle); + /* + * In case of num == 0; the error messages are generated by the + * underlying layers; and hence not needed here. + */ + return (num); +} + +/* + * The high level interface to svc_tli_create(). + * It tries to create a server for "nconf" and registers the service + * with the rpcbind. It calls svc_tli_create(); + */ +SVCXPRT * +svc_tp_create(dispatch, prognum, versnum, nconf) + void (*dispatch)(struct svc_req *, SVCXPRT *); + rpcprog_t prognum; /* Program number */ + rpcvers_t versnum; /* Version number */ + const struct netconfig *nconf; /* Netconfig structure for the network */ +{ + SVCXPRT *xprt; + + if (nconf == NULL) { + warnx( + "svc_tp_create: invalid netconfig structure for prog %u vers %u", + (unsigned)prognum, (unsigned)versnum); + return (NULL); + } + xprt = svc_tli_create(RPC_ANYFD, nconf, NULL, 0, 0); + if (xprt == NULL) { + return (NULL); + } + /*LINTED const castaway*/ + (void) rpcb_unset(prognum, versnum, (struct netconfig *) nconf); + if (svc_reg(xprt, prognum, versnum, dispatch, nconf) == FALSE) { + warnx( + "svc_tp_create: Could not register prog %u vers %u on %s", + (unsigned)prognum, (unsigned)versnum, + nconf->nc_netid); + SVC_DESTROY(xprt); + return (NULL); + } + return (xprt); +} + +/* + * If fd is RPC_ANYFD, then it opens a fd for the given transport + * provider (nconf cannot be NULL then). If the t_state is T_UNBND and + * bindaddr is NON-NULL, it performs a t_bind using the bindaddr. For + * NULL bindadr and Connection oriented transports, the value of qlen + * is set to 8. + * + * If sendsz or recvsz are zero, their default values are chosen. + */ +SVCXPRT * +svc_tli_create(fd, nconf, bindaddr, sendsz, recvsz) + int fd; /* Connection end point */ + const struct netconfig *nconf; /* Netconfig struct for nettoken */ + const struct t_bind *bindaddr; /* Local bind address */ + u_int sendsz; /* Max sendsize */ + u_int recvsz; /* Max recvsize */ +{ + SVCXPRT *xprt = NULL; /* service handle */ + bool_t madefd = FALSE; /* whether fd opened here */ + struct __rpc_sockinfo si; + struct sockaddr_storage ss; + socklen_t slen; + + if (fd == RPC_ANYFD) { + if (nconf == NULL) { + warnx("svc_tli_create: invalid netconfig"); + return (NULL); + } + fd = __rpc_nconf2fd(nconf); + if (fd == -1) { + warnx( + "svc_tli_create: could not open connection for %s", + nconf->nc_netid); + return (NULL); + } + __rpc_nconf2sockinfo(nconf, &si); + madefd = TRUE; + } else { + /* + * It is an open descriptor. Get the transport info. + */ + if (!__rpc_fd2sockinfo(fd, &si)) { + warnx( + "svc_tli_create: could not get transport information"); + return (NULL); + } + } + + /* + * If the fd is unbound, try to bind it. + */ + if (madefd || !__rpc_sockisbound(fd)) { + if (bindaddr == NULL) { + if (bindresvport(fd, NULL) < 0) { + memset(&ss, 0, sizeof ss); + ss.ss_family = si.si_af; + ss.ss_len = si.si_alen; + if (_bind(fd, (struct sockaddr *)(void *)&ss, + (socklen_t)si.si_alen) < 0) { + warnx( + "svc_tli_create: could not bind to anonymous port"); + goto freedata; + } + } + _listen(fd, SOMAXCONN); + } else { + if (_bind(fd, + (struct sockaddr *)bindaddr->addr.buf, + (socklen_t)si.si_alen) < 0) { + warnx( + "svc_tli_create: could not bind to requested address"); + goto freedata; + } + _listen(fd, (int)bindaddr->qlen); + } + + } + /* + * call transport specific function. + */ + switch (si.si_socktype) { + case SOCK_STREAM: + slen = sizeof ss; + if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) + == 0) { + /* accepted socket */ + xprt = svc_fd_create(fd, sendsz, recvsz); + } else + xprt = svc_vc_create(fd, sendsz, recvsz); + if (!nconf || !xprt) + break; +#if 0 + /* XXX fvdl */ + if (strcmp(nconf->nc_protofmly, "inet") == 0 || + strcmp(nconf->nc_protofmly, "inet6") == 0) + (void) __svc_vc_setflag(xprt, TRUE); +#endif + break; + case SOCK_DGRAM: + xprt = svc_dg_create(fd, sendsz, recvsz); + break; + default: + warnx("svc_tli_create: bad service type"); + goto freedata; + } + + if (xprt == NULL) + /* + * The error messages here are spitted out by the lower layers: + * svc_vc_create(), svc_fd_create() and svc_dg_create(). + */ + goto freedata; + + /* Fill in type of service */ + xprt->xp_type = __rpc_socktype2seman(si.si_socktype); + + if (nconf) { + xprt->xp_netid = strdup(nconf->nc_netid); + xprt->xp_tp = strdup(nconf->nc_device); + } + return (xprt); + +freedata: + if (madefd) + (void)_close(fd); + if (xprt) { + if (!madefd) /* so that svc_destroy doesnt close fd */ + xprt->xp_fd = RPC_ANYFD; + SVC_DESTROY(xprt); + } + return (NULL); +} diff --git a/freebsd/lib/libc/rpc/svc_raw.c b/freebsd/lib/libc/rpc/svc_raw.c new file mode 100644 index 00000000..7f9c4eb4 --- /dev/null +++ b/freebsd/lib/libc/rpc/svc_raw.c @@ -0,0 +1,287 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: svc_raw.c,v 1.14 2000/07/06 03:10:35 christos Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ + +/* #ident "@(#)svc_raw.c 1.16 94/04/24 SMI" */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)svc_raw.c 1.25 89/01/31 Copyr 1984 Sun Micro"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * svc_raw.c, This a toy for simple testing and timing. + * Interface to create an rpc client and server in the same UNIX process. + * This lets us similate rpc and get rpc (round trip) overhead, without + * any interference from the kernel. + * + */ + +#include "namespace.h" +#include "reentrant.h" +#include <rpc/rpc.h> +#include <sys/types.h> +#include <rpc/raw.h> +#include <stdlib.h> +#include "un-namespace.h" +#include "mt_misc.h" + +#ifndef UDPMSGSIZE +#define UDPMSGSIZE 8800 +#endif + +/* + * This is the "network" that we will be moving data over + */ +static struct svc_raw_private { + char *raw_buf; /* should be shared with the cl handle */ + SVCXPRT *server; + XDR xdr_stream; + char verf_body[MAX_AUTH_BYTES]; +} *svc_raw_private; + +static enum xprt_stat svc_raw_stat(SVCXPRT *); +static bool_t svc_raw_recv(SVCXPRT *, struct rpc_msg *); +static bool_t svc_raw_reply(SVCXPRT *, struct rpc_msg *); +static bool_t svc_raw_getargs(SVCXPRT *, xdrproc_t, void *); +static bool_t svc_raw_freeargs(SVCXPRT *, xdrproc_t, void *); +static void svc_raw_destroy(SVCXPRT *); +static void svc_raw_ops(SVCXPRT *); +static bool_t svc_raw_control(SVCXPRT *, const u_int, void *); + +char *__rpc_rawcombuf = NULL; + +SVCXPRT * +svc_raw_create() +{ + struct svc_raw_private *srp; +/* VARIABLES PROTECTED BY svcraw_lock: svc_raw_private, srp */ + + mutex_lock(&svcraw_lock); + srp = svc_raw_private; + if (srp == NULL) { + srp = (struct svc_raw_private *)calloc(1, sizeof (*srp)); + if (srp == NULL) { + mutex_unlock(&svcraw_lock); + return (NULL); + } + if (__rpc_rawcombuf == NULL) { + __rpc_rawcombuf = calloc(UDPMSGSIZE, sizeof (char)); + if (__rpc_rawcombuf == NULL) { + free(srp); + mutex_unlock(&svcraw_lock); + return (NULL); + } + } + srp->raw_buf = __rpc_rawcombuf; /* Share it with the client */ + srp->server = svc_xprt_alloc(); + if (srp->server == NULL) { + free(__rpc_rawcombuf); + free(srp); + mutex_unlock(&svcraw_lock); + return (NULL); + } + svc_raw_private = srp; + } + srp->server->xp_fd = FD_SETSIZE; + srp->server->xp_port = 0; + svc_raw_ops(srp->server); + srp->server->xp_verf.oa_base = srp->verf_body; + xdrmem_create(&srp->xdr_stream, srp->raw_buf, UDPMSGSIZE, XDR_DECODE); + xprt_register(srp->server); + mutex_unlock(&svcraw_lock); + return (srp->server); +} + +/*ARGSUSED*/ +static enum xprt_stat +svc_raw_stat(xprt) +SVCXPRT *xprt; /* args needed to satisfy ANSI-C typechecking */ +{ + return (XPRT_IDLE); +} + +/*ARGSUSED*/ +static bool_t +svc_raw_recv(xprt, msg) + SVCXPRT *xprt; + struct rpc_msg *msg; +{ + struct svc_raw_private *srp; + XDR *xdrs; + + mutex_lock(&svcraw_lock); + srp = svc_raw_private; + if (srp == NULL) { + mutex_unlock(&svcraw_lock); + return (FALSE); + } + mutex_unlock(&svcraw_lock); + + xdrs = &srp->xdr_stream; + xdrs->x_op = XDR_DECODE; + (void) XDR_SETPOS(xdrs, 0); + if (! xdr_callmsg(xdrs, msg)) { + return (FALSE); + } + return (TRUE); +} + +/*ARGSUSED*/ +static bool_t +svc_raw_reply(xprt, msg) + SVCXPRT *xprt; + struct rpc_msg *msg; +{ + struct svc_raw_private *srp; + XDR *xdrs; + bool_t stat; + xdrproc_t xdr_proc; + caddr_t xdr_where; + + mutex_lock(&svcraw_lock); + srp = svc_raw_private; + if (srp == NULL) { + mutex_unlock(&svcraw_lock); + return (FALSE); + } + mutex_unlock(&svcraw_lock); + + xdrs = &srp->xdr_stream; + xdrs->x_op = XDR_ENCODE; + (void) XDR_SETPOS(xdrs, 0); + if (msg->rm_reply.rp_stat == MSG_ACCEPTED && + msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { + xdr_proc = msg->acpted_rply.ar_results.proc; + xdr_where = msg->acpted_rply.ar_results.where; + msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void; + msg->acpted_rply.ar_results.where = NULL; + + stat = xdr_replymsg(xdrs, msg) && + SVCAUTH_WRAP(&SVC_AUTH(xprt), xdrs, xdr_proc, xdr_where); + } else { + stat = xdr_replymsg(xdrs, msg); + } + if (!stat) { + return (FALSE); + } + (void) XDR_GETPOS(xdrs); /* called just for overhead */ + return (TRUE); +} + +/*ARGSUSED*/ +static bool_t +svc_raw_getargs(xprt, xdr_args, args_ptr) + SVCXPRT *xprt; + xdrproc_t xdr_args; + void *args_ptr; +{ + struct svc_raw_private *srp; + + mutex_lock(&svcraw_lock); + srp = svc_raw_private; + if (srp == NULL) { + mutex_unlock(&svcraw_lock); + return (FALSE); + } + mutex_unlock(&svcraw_lock); + + return (SVCAUTH_UNWRAP(&SVC_AUTH(xprt), &srp->xdr_stream, + xdr_args, args_ptr)); +} + +/*ARGSUSED*/ +static bool_t +svc_raw_freeargs(xprt, xdr_args, args_ptr) + SVCXPRT *xprt; + xdrproc_t xdr_args; + void *args_ptr; +{ + struct svc_raw_private *srp; + XDR *xdrs; + + mutex_lock(&svcraw_lock); + srp = svc_raw_private; + if (srp == NULL) { + mutex_unlock(&svcraw_lock); + return (FALSE); + } + mutex_unlock(&svcraw_lock); + + xdrs = &srp->xdr_stream; + xdrs->x_op = XDR_FREE; + return (*xdr_args)(xdrs, args_ptr); +} + +/*ARGSUSED*/ +static void +svc_raw_destroy(xprt) +SVCXPRT *xprt; +{ +} + +/*ARGSUSED*/ +static bool_t +svc_raw_control(xprt, rq, in) + SVCXPRT *xprt; + const u_int rq; + void *in; +{ + return (FALSE); +} + +static void +svc_raw_ops(xprt) + SVCXPRT *xprt; +{ + static struct xp_ops ops; + static struct xp_ops2 ops2; + +/* VARIABLES PROTECTED BY ops_lock: ops */ + + mutex_lock(&ops_lock); + if (ops.xp_recv == NULL) { + ops.xp_recv = svc_raw_recv; + ops.xp_stat = svc_raw_stat; + ops.xp_getargs = svc_raw_getargs; + ops.xp_reply = svc_raw_reply; + ops.xp_freeargs = svc_raw_freeargs; + ops.xp_destroy = svc_raw_destroy; + ops2.xp_control = svc_raw_control; + } + xprt->xp_ops = &ops; + xprt->xp_ops2 = &ops2; + mutex_unlock(&ops_lock); +} diff --git a/freebsd/lib/libc/rpc/svc_run.c b/freebsd/lib/libc/rpc/svc_run.c new file mode 100644 index 00000000..85506c5c --- /dev/null +++ b/freebsd/lib/libc/rpc/svc_run.c @@ -0,0 +1,99 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: svc_run.c,v 1.17 2000/07/06 03:10:35 christos Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *sccsid2 = "from: @(#)svc_run.c 1.1 87/10/13 Copyr 1984 Sun Micro"; +static char *sccsid = "from: @(#)svc_run.c 2.1 88/07/29 4.0 RPCSRC"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * This is the rpc server side idle loop + * Wait for input, call server program. + */ +#include "namespace.h" +#include "reentrant.h" +#include <err.h> +#include <errno.h> +#include <rpc/rpc.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include "un-namespace.h" + +#include <rpc/rpc.h> +#include "rpc_com.h" +#include "mt_misc.h" + +void +svc_run() +{ + fd_set readfds, cleanfds; + struct timeval timeout; + + timeout.tv_sec = 30; + timeout.tv_usec = 0; + + for (;;) { + rwlock_rdlock(&svc_fd_lock); + readfds = svc_fdset; + cleanfds = svc_fdset; + rwlock_unlock(&svc_fd_lock); + switch (_select(svc_maxfd+1, &readfds, NULL, NULL, &timeout)) { + case -1: + FD_ZERO(&readfds); + if (errno == EINTR) { + continue; + } + _warn("svc_run: - select failed"); + return; + case 0: + __svc_clean_idle(&cleanfds, 30, FALSE); + continue; + default: + svc_getreqset(&readfds); + } + } +} + +/* + * This function causes svc_run() to exit by telling it that it has no + * more work to do. + */ +void +svc_exit() +{ + rwlock_wrlock(&svc_fd_lock); + FD_ZERO(&svc_fdset); + rwlock_unlock(&svc_fd_lock); +} diff --git a/freebsd/lib/libc/rpc/svc_simple.c b/freebsd/lib/libc/rpc/svc_simple.c new file mode 100644 index 00000000..da3f1ebf --- /dev/null +++ b/freebsd/lib/libc/rpc/svc_simple.c @@ -0,0 +1,314 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: svc_simple.c,v 1.20 2000/07/06 03:10:35 christos Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ + +/* #pragma ident "@(#)svc_simple.c 1.18 94/04/24 SMI" */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * svc_simple.c + * Simplified front end to rpc. + */ + +/* + * This interface creates a virtual listener for all the services + * started thru rpc_reg(). It listens on the same endpoint for + * all the services and then executes the corresponding service + * for the given prognum and procnum. + */ + +#include "namespace.h" +#include "reentrant.h" +#include <sys/types.h> +#include <rpc/rpc.h> +#include <rpc/nettype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <err.h> +#include "un-namespace.h" + +#include "rpc_com.h" +#include "mt_misc.h" + +static void universal(struct svc_req *, SVCXPRT *); + +static struct proglst { + char *(*p_progname)(char *); + rpcprog_t p_prognum; + rpcvers_t p_versnum; + rpcproc_t p_procnum; + SVCXPRT *p_transp; + char *p_netid; + char *p_xdrbuf; + int p_recvsz; + xdrproc_t p_inproc, p_outproc; + struct proglst *p_nxt; +} *proglst; + +static const char rpc_reg_err[] = "%s: %s"; +static const char rpc_reg_msg[] = "rpc_reg: "; +static const char __reg_err1[] = "can't find appropriate transport"; +static const char __reg_err2[] = "can't get protocol info"; +static const char __reg_err3[] = "unsupported transport size"; +static const char __no_mem_str[] = "out of memory"; + +/* + * For simplified, easy to use kind of rpc interfaces. + * nettype indicates the type of transport on which the service will be + * listening. Used for conservation of the system resource. Only one + * handle is created for all the services (actually one of each netid) + * and same xdrbuf is used for same netid. The size of the arguments + * is also limited by the recvsize for that transport, even if it is + * a COTS transport. This may be wrong, but for cases like these, they + * should not use the simplified interfaces like this. + */ + +int +rpc_reg(prognum, versnum, procnum, progname, inproc, outproc, nettype) + rpcprog_t prognum; /* program number */ + rpcvers_t versnum; /* version number */ + rpcproc_t procnum; /* procedure number */ + char *(*progname)(char *); /* Server routine */ + xdrproc_t inproc, outproc; /* in/out XDR procedures */ + char *nettype; /* nettype */ +{ + struct netconfig *nconf; + int done = FALSE; + void *handle; + + + if (procnum == NULLPROC) { + warnx("%s can't reassign procedure number %u", rpc_reg_msg, + NULLPROC); + return (-1); + } + + if (nettype == NULL) + nettype = "netpath"; /* The default behavior */ + if ((handle = __rpc_setconf(nettype)) == NULL) { + warnx(rpc_reg_err, rpc_reg_msg, __reg_err1); + return (-1); + } +/* VARIABLES PROTECTED BY proglst_lock: proglst */ + mutex_lock(&proglst_lock); + while ((nconf = __rpc_getconf(handle)) != NULL) { + struct proglst *pl; + SVCXPRT *svcxprt; + int madenow; + u_int recvsz; + char *xdrbuf; + char *netid; + + madenow = FALSE; + svcxprt = NULL; + recvsz = 0; + xdrbuf = netid = NULL; + for (pl = proglst; pl; pl = pl->p_nxt) { + if (strcmp(pl->p_netid, nconf->nc_netid) == 0) { + svcxprt = pl->p_transp; + xdrbuf = pl->p_xdrbuf; + recvsz = pl->p_recvsz; + netid = pl->p_netid; + break; + } + } + + if (svcxprt == NULL) { + struct __rpc_sockinfo si; + + svcxprt = svc_tli_create(RPC_ANYFD, nconf, NULL, 0, 0); + if (svcxprt == NULL) + continue; + if (!__rpc_fd2sockinfo(svcxprt->xp_fd, &si)) { + warnx(rpc_reg_err, rpc_reg_msg, __reg_err2); + SVC_DESTROY(svcxprt); + continue; + } + recvsz = __rpc_get_t_size(si.si_af, si.si_proto, 0); + if (recvsz == 0) { + warnx(rpc_reg_err, rpc_reg_msg, __reg_err3); + SVC_DESTROY(svcxprt); + continue; + } + if (((xdrbuf = malloc((unsigned)recvsz)) == NULL) || + ((netid = strdup(nconf->nc_netid)) == NULL)) { + warnx(rpc_reg_err, rpc_reg_msg, __no_mem_str); + if (xdrbuf != NULL) + free(xdrbuf); + if (netid != NULL) + free(netid); + SVC_DESTROY(svcxprt); + break; + } + madenow = TRUE; + } + /* + * Check if this (program, version, netid) had already been + * registered. The check may save a few RPC calls to rpcbind + */ + for (pl = proglst; pl; pl = pl->p_nxt) + if ((pl->p_prognum == prognum) && + (pl->p_versnum == versnum) && + (strcmp(pl->p_netid, netid) == 0)) + break; + if (pl == NULL) { /* Not yet */ + (void) rpcb_unset(prognum, versnum, nconf); + } else { + /* so that svc_reg does not call rpcb_set() */ + nconf = NULL; + } + + if (!svc_reg(svcxprt, prognum, versnum, universal, nconf)) { + warnx("%s couldn't register prog %u vers %u for %s", + rpc_reg_msg, (unsigned)prognum, + (unsigned)versnum, netid); + if (madenow) { + SVC_DESTROY(svcxprt); + free(xdrbuf); + free(netid); + } + continue; + } + + pl = malloc(sizeof (struct proglst)); + if (pl == NULL) { + warnx(rpc_reg_err, rpc_reg_msg, __no_mem_str); + if (madenow) { + SVC_DESTROY(svcxprt); + free(xdrbuf); + free(netid); + } + break; + } + pl->p_progname = progname; + pl->p_prognum = prognum; + pl->p_versnum = versnum; + pl->p_procnum = procnum; + pl->p_inproc = inproc; + pl->p_outproc = outproc; + pl->p_transp = svcxprt; + pl->p_xdrbuf = xdrbuf; + pl->p_recvsz = recvsz; + pl->p_netid = netid; + pl->p_nxt = proglst; + proglst = pl; + done = TRUE; + } + __rpc_endconf(handle); + mutex_unlock(&proglst_lock); + + if (done == FALSE) { + warnx("%s cant find suitable transport for %s", + rpc_reg_msg, nettype); + return (-1); + } + return (0); +} + +/* + * The universal handler for the services registered using registerrpc. + * It handles both the connectionless and the connection oriented cases. + */ + +static void +universal(rqstp, transp) + struct svc_req *rqstp; + SVCXPRT *transp; +{ + rpcprog_t prog; + rpcvers_t vers; + rpcproc_t proc; + char *outdata; + char *xdrbuf; + struct proglst *pl; + + /* + * enforce "procnum 0 is echo" convention + */ + if (rqstp->rq_proc == NULLPROC) { + if (svc_sendreply(transp, (xdrproc_t) xdr_void, NULL) == + FALSE) { + warnx("svc_sendreply failed"); + } + return; + } + prog = rqstp->rq_prog; + vers = rqstp->rq_vers; + proc = rqstp->rq_proc; + mutex_lock(&proglst_lock); + for (pl = proglst; pl; pl = pl->p_nxt) + if (pl->p_prognum == prog && pl->p_procnum == proc && + pl->p_versnum == vers && + (strcmp(pl->p_netid, transp->xp_netid) == 0)) { + /* decode arguments into a CLEAN buffer */ + xdrbuf = pl->p_xdrbuf; + /* Zero the arguments: reqd ! */ + (void) memset(xdrbuf, 0, sizeof (pl->p_recvsz)); + /* + * Assuming that sizeof (xdrbuf) would be enough + * for the arguments; if not then the program + * may bomb. BEWARE! + */ + if (!svc_getargs(transp, pl->p_inproc, xdrbuf)) { + svcerr_decode(transp); + mutex_unlock(&proglst_lock); + return; + } + outdata = (*(pl->p_progname))(xdrbuf); + if (outdata == NULL && + pl->p_outproc != (xdrproc_t) xdr_void){ + /* there was an error */ + mutex_unlock(&proglst_lock); + return; + } + if (!svc_sendreply(transp, pl->p_outproc, outdata)) { + warnx( + "rpc: rpc_reg trouble replying to prog %u vers %u", + (unsigned)prog, (unsigned)vers); + mutex_unlock(&proglst_lock); + return; + } + /* free the decoded arguments */ + (void)svc_freeargs(transp, pl->p_inproc, xdrbuf); + mutex_unlock(&proglst_lock); + return; + } + mutex_unlock(&proglst_lock); + /* This should never happen */ + warnx("rpc: rpc_reg: never registered prog %u vers %u", + (unsigned)prog, (unsigned)vers); + return; +} diff --git a/freebsd/lib/libc/rpc/svc_vc.c b/freebsd/lib/libc/rpc/svc_vc.c new file mode 100644 index 00000000..5b17ca4b --- /dev/null +++ b/freebsd/lib/libc/rpc/svc_vc.c @@ -0,0 +1,812 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $ */ + +/*- + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *sccsid2 = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro"; +static char *sccsid = "@(#)svc_tcp.c 2.2 88/08/01 4.0 RPCSRC"; +#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * svc_vc.c, Server side for Connection Oriented based RPC. + * + * Actually implements two flavors of transporter - + * a tcp rendezvouser (a listner and connection establisher) + * and a record/tcp stream. + */ + +#include "namespace.h" +#include "reentrant.h" +#include <sys/types.h> +#include <rtems/bsd/sys/param.h> +#include <sys/poll.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/time.h> +#include <sys/uio.h> +#include <netinet/in.h> +#include <netinet/tcp.h> + +#include <assert.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <rpc/rpc.h> + +#include "rpc_com.h" +#include "mt_misc.h" +#include "un-namespace.h" + +static SVCXPRT *makefd_xprt(int, u_int, u_int); +static bool_t rendezvous_request(SVCXPRT *, struct rpc_msg *); +static enum xprt_stat rendezvous_stat(SVCXPRT *); +static void svc_vc_destroy(SVCXPRT *); +static void __svc_vc_dodestroy (SVCXPRT *); +static int read_vc(void *, void *, int); +static int write_vc(void *, void *, int); +static enum xprt_stat svc_vc_stat(SVCXPRT *); +static bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *); +static bool_t svc_vc_getargs(SVCXPRT *, xdrproc_t, void *); +static bool_t svc_vc_freeargs(SVCXPRT *, xdrproc_t, void *); +static bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *); +static void svc_vc_rendezvous_ops(SVCXPRT *); +static void svc_vc_ops(SVCXPRT *); +static bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in); +static bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq, + void *in); + +struct cf_rendezvous { /* kept in xprt->xp_p1 for rendezvouser */ + u_int sendsize; + u_int recvsize; + int maxrec; +}; + +struct cf_conn { /* kept in xprt->xp_p1 for actual connection */ + enum xprt_stat strm_stat; + u_int32_t x_id; + XDR xdrs; + char verf_body[MAX_AUTH_BYTES]; + u_int sendsize; + u_int recvsize; + int maxrec; + bool_t nonblock; + struct timeval last_recv_time; +}; + +/* + * Usage: + * xprt = svc_vc_create(sock, send_buf_size, recv_buf_size); + * + * Creates, registers, and returns a (rpc) tcp based transporter. + * Once *xprt is initialized, it is registered as a transporter + * see (svc.h, xprt_register). This routine returns + * a NULL if a problem occurred. + * + * The filedescriptor passed in is expected to refer to a bound, but + * not yet connected socket. + * + * Since streams do buffered io similar to stdio, the caller can specify + * how big the send and receive buffers are via the second and third parms; + * 0 => use the system default. + */ +SVCXPRT * +svc_vc_create(fd, sendsize, recvsize) + int fd; + u_int sendsize; + u_int recvsize; +{ + SVCXPRT *xprt; + struct cf_rendezvous *r = NULL; + struct __rpc_sockinfo si; + struct sockaddr_storage sslocal; + socklen_t slen; + + if (!__rpc_fd2sockinfo(fd, &si)) + return NULL; + + r = mem_alloc(sizeof(*r)); + if (r == NULL) { + warnx("svc_vc_create: out of memory"); + goto cleanup_svc_vc_create; + } + r->sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize); + r->recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize); + r->maxrec = __svc_maxrec; + xprt = svc_xprt_alloc(); + if (xprt == NULL) { + warnx("svc_vc_create: out of memory"); + goto cleanup_svc_vc_create; + } + xprt->xp_p1 = r; + xprt->xp_verf = _null_auth; + svc_vc_rendezvous_ops(xprt); + xprt->xp_port = (u_short)-1; /* It is the rendezvouser */ + xprt->xp_fd = fd; + + slen = sizeof (struct sockaddr_storage); + if (_getsockname(fd, (struct sockaddr *)(void *)&sslocal, &slen) < 0) { + warnx("svc_vc_create: could not retrieve local addr"); + goto cleanup_svc_vc_create; + } + + xprt->xp_ltaddr.maxlen = xprt->xp_ltaddr.len = sslocal.ss_len; + xprt->xp_ltaddr.buf = mem_alloc((size_t)sslocal.ss_len); + if (xprt->xp_ltaddr.buf == NULL) { + warnx("svc_vc_create: no mem for local addr"); + goto cleanup_svc_vc_create; + } + memcpy(xprt->xp_ltaddr.buf, &sslocal, (size_t)sslocal.ss_len); + + xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage); + xprt_register(xprt); + return (xprt); +cleanup_svc_vc_create: + if (xprt) + mem_free(xprt, sizeof(*xprt)); + if (r != NULL) + mem_free(r, sizeof(*r)); + return (NULL); +} + +/* + * Like svtcp_create(), except the routine takes any *open* UNIX file + * descriptor as its first input. + */ +SVCXPRT * +svc_fd_create(fd, sendsize, recvsize) + int fd; + u_int sendsize; + u_int recvsize; +{ + struct sockaddr_storage ss; + socklen_t slen; + SVCXPRT *ret; + + assert(fd != -1); + + ret = makefd_xprt(fd, sendsize, recvsize); + if (ret == NULL) + return NULL; + + slen = sizeof (struct sockaddr_storage); + if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { + warnx("svc_fd_create: could not retrieve local addr"); + goto freedata; + } + ret->xp_ltaddr.maxlen = ret->xp_ltaddr.len = ss.ss_len; + ret->xp_ltaddr.buf = mem_alloc((size_t)ss.ss_len); + if (ret->xp_ltaddr.buf == NULL) { + warnx("svc_fd_create: no mem for local addr"); + goto freedata; + } + memcpy(ret->xp_ltaddr.buf, &ss, (size_t)ss.ss_len); + + slen = sizeof (struct sockaddr_storage); + if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { + warnx("svc_fd_create: could not retrieve remote addr"); + goto freedata; + } + ret->xp_rtaddr.maxlen = ret->xp_rtaddr.len = ss.ss_len; + ret->xp_rtaddr.buf = mem_alloc((size_t)ss.ss_len); + if (ret->xp_rtaddr.buf == NULL) { + warnx("svc_fd_create: no mem for local addr"); + goto freedata; + } + memcpy(ret->xp_rtaddr.buf, &ss, (size_t)ss.ss_len); +#ifdef PORTMAP + if (ss.ss_family == AF_INET || ss.ss_family == AF_LOCAL) { + ret->xp_raddr = *(struct sockaddr_in *)ret->xp_rtaddr.buf; + ret->xp_addrlen = sizeof (struct sockaddr_in); + } +#endif /* PORTMAP */ + + return ret; + +freedata: + if (ret->xp_ltaddr.buf != NULL) + mem_free(ret->xp_ltaddr.buf, rep->xp_ltaddr.maxlen); + + return NULL; +} + +static SVCXPRT * +makefd_xprt(fd, sendsize, recvsize) + int fd; + u_int sendsize; + u_int recvsize; +{ + SVCXPRT *xprt; + struct cf_conn *cd; + const char *netid; + struct __rpc_sockinfo si; + + assert(fd != -1); + + xprt = svc_xprt_alloc(); + if (xprt == NULL) { + warnx("svc_vc: makefd_xprt: out of memory"); + goto done; + } + cd = mem_alloc(sizeof(struct cf_conn)); + if (cd == NULL) { + warnx("svc_tcp: makefd_xprt: out of memory"); + svc_xprt_free(xprt); + xprt = NULL; + goto done; + } + cd->strm_stat = XPRT_IDLE; + xdrrec_create(&(cd->xdrs), sendsize, recvsize, + xprt, read_vc, write_vc); + xprt->xp_p1 = cd; + xprt->xp_verf.oa_base = cd->verf_body; + svc_vc_ops(xprt); /* truely deals with calls */ + xprt->xp_port = 0; /* this is a connection, not a rendezvouser */ + xprt->xp_fd = fd; + if (__rpc_fd2sockinfo(fd, &si) && __rpc_sockinfo2netid(&si, &netid)) + xprt->xp_netid = strdup(netid); + + xprt_register(xprt); +done: + return (xprt); +} + +/*ARGSUSED*/ +static bool_t +rendezvous_request(xprt, msg) + SVCXPRT *xprt; + struct rpc_msg *msg; +{ + int sock, flags; + struct cf_rendezvous *r; + struct cf_conn *cd; + struct sockaddr_storage addr; + socklen_t len; + struct __rpc_sockinfo si; + SVCXPRT *newxprt; + fd_set cleanfds; + + assert(xprt != NULL); + assert(msg != NULL); + + r = (struct cf_rendezvous *)xprt->xp_p1; +again: + len = sizeof addr; + if ((sock = _accept(xprt->xp_fd, (struct sockaddr *)(void *)&addr, + &len)) < 0) { + if (errno == EINTR) + goto again; + /* + * Clean out the most idle file descriptor when we're + * running out. + */ + if (errno == EMFILE || errno == ENFILE) { + cleanfds = svc_fdset; + __svc_clean_idle(&cleanfds, 0, FALSE); + goto again; + } + return (FALSE); + } + /* + * make a new transporter (re-uses xprt) + */ + newxprt = makefd_xprt(sock, r->sendsize, r->recvsize); + newxprt->xp_rtaddr.buf = mem_alloc(len); + if (newxprt->xp_rtaddr.buf == NULL) + return (FALSE); + memcpy(newxprt->xp_rtaddr.buf, &addr, len); + newxprt->xp_rtaddr.len = len; +#ifdef PORTMAP + if (addr.ss_family == AF_INET || addr.ss_family == AF_LOCAL) { + newxprt->xp_raddr = *(struct sockaddr_in *)newxprt->xp_rtaddr.buf; + newxprt->xp_addrlen = sizeof (struct sockaddr_in); + } +#endif /* PORTMAP */ + if (__rpc_fd2sockinfo(sock, &si) && si.si_proto == IPPROTO_TCP) { + len = 1; + /* XXX fvdl - is this useful? */ + _setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &len, sizeof (len)); + } + + cd = (struct cf_conn *)newxprt->xp_p1; + + cd->recvsize = r->recvsize; + cd->sendsize = r->sendsize; + cd->maxrec = r->maxrec; + + if (cd->maxrec != 0) { + flags = _fcntl(sock, F_GETFL, 0); + if (flags == -1) + return (FALSE); + if (_fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) + return (FALSE); + if (cd->recvsize > cd->maxrec) + cd->recvsize = cd->maxrec; + cd->nonblock = TRUE; + __xdrrec_setnonblock(&cd->xdrs, cd->maxrec); + } else + cd->nonblock = FALSE; + + gettimeofday(&cd->last_recv_time, NULL); + + return (FALSE); /* there is never an rpc msg to be processed */ +} + +/*ARGSUSED*/ +static enum xprt_stat +rendezvous_stat(xprt) + SVCXPRT *xprt; +{ + + return (XPRT_IDLE); +} + +static void +svc_vc_destroy(xprt) + SVCXPRT *xprt; +{ + assert(xprt != NULL); + + xprt_unregister(xprt); + __svc_vc_dodestroy(xprt); +} + +static void +__svc_vc_dodestroy(xprt) + SVCXPRT *xprt; +{ + struct cf_conn *cd; + struct cf_rendezvous *r; + + cd = (struct cf_conn *)xprt->xp_p1; + + if (xprt->xp_fd != RPC_ANYFD) + (void)_close(xprt->xp_fd); + if (xprt->xp_port != 0) { + /* a rendezvouser socket */ + r = (struct cf_rendezvous *)xprt->xp_p1; + mem_free(r, sizeof (struct cf_rendezvous)); + xprt->xp_port = 0; + } else { + /* an actual connection socket */ + XDR_DESTROY(&(cd->xdrs)); + mem_free(cd, sizeof(struct cf_conn)); + } + if (xprt->xp_rtaddr.buf) + mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen); + if (xprt->xp_ltaddr.buf) + mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen); + if (xprt->xp_tp) + free(xprt->xp_tp); + if (xprt->xp_netid) + free(xprt->xp_netid); + svc_xprt_free(xprt); +} + +/*ARGSUSED*/ +static bool_t +svc_vc_control(xprt, rq, in) + SVCXPRT *xprt; + const u_int rq; + void *in; +{ + return (FALSE); +} + +static bool_t +svc_vc_rendezvous_control(xprt, rq, in) + SVCXPRT *xprt; + const u_int rq; + void *in; +{ + struct cf_rendezvous *cfp; + + cfp = (struct cf_rendezvous *)xprt->xp_p1; + if (cfp == NULL) + return (FALSE); + switch (rq) { + case SVCGET_CONNMAXREC: + *(int *)in = cfp->maxrec; + break; + case SVCSET_CONNMAXREC: + cfp->maxrec = *(int *)in; + break; + default: + return (FALSE); + } + return (TRUE); +} + +/* + * reads data from the tcp or uip connection. + * any error is fatal and the connection is closed. + * (And a read of zero bytes is a half closed stream => error.) + * All read operations timeout after 35 seconds. A timeout is + * fatal for the connection. + */ +static int +read_vc(xprtp, buf, len) + void *xprtp; + void *buf; + int len; +{ + SVCXPRT *xprt; + int sock; + int milliseconds = 35 * 1000; + struct pollfd pollfd; + struct cf_conn *cfp; + + xprt = (SVCXPRT *)xprtp; + assert(xprt != NULL); + + sock = xprt->xp_fd; + + cfp = (struct cf_conn *)xprt->xp_p1; + + if (cfp->nonblock) { + len = _read(sock, buf, (size_t)len); + if (len < 0) { + if (errno == EAGAIN) + len = 0; + else + goto fatal_err; + } + if (len != 0) + gettimeofday(&cfp->last_recv_time, NULL); + return len; + } + + do { + pollfd.fd = sock; + pollfd.events = POLLIN; + pollfd.revents = 0; + switch (_poll(&pollfd, 1, milliseconds)) { + case -1: + if (errno == EINTR) + continue; + /*FALLTHROUGH*/ + case 0: + goto fatal_err; + + default: + break; + } + } while ((pollfd.revents & POLLIN) == 0); + + if ((len = _read(sock, buf, (size_t)len)) > 0) { + gettimeofday(&cfp->last_recv_time, NULL); + return (len); + } + +fatal_err: + ((struct cf_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED; + return (-1); +} + +/* + * writes data to the tcp connection. + * Any error is fatal and the connection is closed. + */ +static int +write_vc(xprtp, buf, len) + void *xprtp; + void *buf; + int len; +{ + SVCXPRT *xprt; + int i, cnt; + struct cf_conn *cd; + struct timeval tv0, tv1; + + xprt = (SVCXPRT *)xprtp; + assert(xprt != NULL); + + cd = (struct cf_conn *)xprt->xp_p1; + + if (cd->nonblock) + gettimeofday(&tv0, NULL); + + for (cnt = len; cnt > 0; cnt -= i, buf = (char *)buf + i) { + i = _write(xprt->xp_fd, buf, (size_t)cnt); + if (i < 0) { + if (errno != EAGAIN || !cd->nonblock) { + cd->strm_stat = XPRT_DIED; + return (-1); + } + if (cd->nonblock) { + /* + * For non-blocking connections, do not + * take more than 2 seconds writing the + * data out. + * + * XXX 2 is an arbitrary amount. + */ + gettimeofday(&tv1, NULL); + if (tv1.tv_sec - tv0.tv_sec >= 2) { + cd->strm_stat = XPRT_DIED; + return (-1); + } + } + i = 0; + } + } + + return (len); +} + +static enum xprt_stat +svc_vc_stat(xprt) + SVCXPRT *xprt; +{ + struct cf_conn *cd; + + assert(xprt != NULL); + + cd = (struct cf_conn *)(xprt->xp_p1); + + if (cd->strm_stat == XPRT_DIED) + return (XPRT_DIED); + if (! xdrrec_eof(&(cd->xdrs))) + return (XPRT_MOREREQS); + return (XPRT_IDLE); +} + +static bool_t +svc_vc_recv(xprt, msg) + SVCXPRT *xprt; + struct rpc_msg *msg; +{ + struct cf_conn *cd; + XDR *xdrs; + + assert(xprt != NULL); + assert(msg != NULL); + + cd = (struct cf_conn *)(xprt->xp_p1); + xdrs = &(cd->xdrs); + + if (cd->nonblock) { + if (!__xdrrec_getrec(xdrs, &cd->strm_stat, TRUE)) + return FALSE; + } else { + (void)xdrrec_skiprecord(xdrs); + } + + xdrs->x_op = XDR_DECODE; + if (xdr_callmsg(xdrs, msg)) { + cd->x_id = msg->rm_xid; + return (TRUE); + } + cd->strm_stat = XPRT_DIED; + return (FALSE); +} + +static bool_t +svc_vc_getargs(xprt, xdr_args, args_ptr) + SVCXPRT *xprt; + xdrproc_t xdr_args; + void *args_ptr; +{ + struct cf_conn *cd; + + assert(xprt != NULL); + cd = (struct cf_conn *)(xprt->xp_p1); + return (SVCAUTH_UNWRAP(&SVC_AUTH(xprt), + &cd->xdrs, xdr_args, args_ptr)); +} + +static bool_t +svc_vc_freeargs(xprt, xdr_args, args_ptr) + SVCXPRT *xprt; + xdrproc_t xdr_args; + void *args_ptr; +{ + XDR *xdrs; + + assert(xprt != NULL); + /* args_ptr may be NULL */ + + xdrs = &(((struct cf_conn *)(xprt->xp_p1))->xdrs); + + xdrs->x_op = XDR_FREE; + return ((*xdr_args)(xdrs, args_ptr)); +} + +static bool_t +svc_vc_reply(xprt, msg) + SVCXPRT *xprt; + struct rpc_msg *msg; +{ + struct cf_conn *cd; + XDR *xdrs; + bool_t rstat; + xdrproc_t xdr_proc; + caddr_t xdr_where; + u_int pos; + + assert(xprt != NULL); + assert(msg != NULL); + + cd = (struct cf_conn *)(xprt->xp_p1); + xdrs = &(cd->xdrs); + + xdrs->x_op = XDR_ENCODE; + msg->rm_xid = cd->x_id; + rstat = TRUE; + if (msg->rm_reply.rp_stat == MSG_ACCEPTED && + msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { + xdr_proc = msg->acpted_rply.ar_results.proc; + xdr_where = msg->acpted_rply.ar_results.where; + msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void; + msg->acpted_rply.ar_results.where = NULL; + + pos = XDR_GETPOS(xdrs); + if (!xdr_replymsg(xdrs, msg) || + !SVCAUTH_WRAP(&SVC_AUTH(xprt), xdrs, xdr_proc, xdr_where)) { + XDR_SETPOS(xdrs, pos); + rstat = FALSE; + } + } else { + rstat = xdr_replymsg(xdrs, msg); + } + + if (rstat) + (void)xdrrec_endofrecord(xdrs, TRUE); + + return (rstat); +} + +static void +svc_vc_ops(xprt) + SVCXPRT *xprt; +{ + static struct xp_ops ops; + static struct xp_ops2 ops2; + +/* VARIABLES PROTECTED BY ops_lock: ops, ops2 */ + + mutex_lock(&ops_lock); + if (ops.xp_recv == NULL) { + ops.xp_recv = svc_vc_recv; + ops.xp_stat = svc_vc_stat; + ops.xp_getargs = svc_vc_getargs; + ops.xp_reply = svc_vc_reply; + ops.xp_freeargs = svc_vc_freeargs; + ops.xp_destroy = svc_vc_destroy; + ops2.xp_control = svc_vc_control; + } + xprt->xp_ops = &ops; + xprt->xp_ops2 = &ops2; + mutex_unlock(&ops_lock); +} + +static void +svc_vc_rendezvous_ops(xprt) + SVCXPRT *xprt; +{ + static struct xp_ops ops; + static struct xp_ops2 ops2; + + mutex_lock(&ops_lock); + if (ops.xp_recv == NULL) { + ops.xp_recv = rendezvous_request; + ops.xp_stat = rendezvous_stat; + ops.xp_getargs = + (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort; + ops.xp_reply = + (bool_t (*)(SVCXPRT *, struct rpc_msg *))abort; + ops.xp_freeargs = + (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort, + ops.xp_destroy = svc_vc_destroy; + ops2.xp_control = svc_vc_rendezvous_control; + } + xprt->xp_ops = &ops; + xprt->xp_ops2 = &ops2; + mutex_unlock(&ops_lock); +} + +/* + * Get the effective UID of the sending process. Used by rpcbind, keyserv + * and rpc.yppasswdd on AF_LOCAL. + */ +int +__rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) { + int sock, ret; + gid_t egid; + uid_t euid; + struct sockaddr *sa; + + sock = transp->xp_fd; + sa = (struct sockaddr *)transp->xp_rtaddr.buf; + if (sa->sa_family == AF_LOCAL) { + ret = getpeereid(sock, &euid, &egid); + if (ret == 0) + *uid = euid; + return (ret); + } else + return (-1); +} + +/* + * Destroy xprts that have not have had any activity in 'timeout' seconds. + * If 'cleanblock' is true, blocking connections (the default) are also + * cleaned. If timeout is 0, the least active connection is picked. + */ +bool_t +__svc_clean_idle(fd_set *fds, int timeout, bool_t cleanblock) +{ + int i, ncleaned; + SVCXPRT *xprt, *least_active; + struct timeval tv, tdiff, tmax; + struct cf_conn *cd; + + gettimeofday(&tv, NULL); + tmax.tv_sec = tmax.tv_usec = 0; + least_active = NULL; + rwlock_wrlock(&svc_fd_lock); + for (i = ncleaned = 0; i <= svc_maxfd; i++) { + if (FD_ISSET(i, fds)) { + xprt = __svc_xports[i]; + if (xprt == NULL || xprt->xp_ops == NULL || + xprt->xp_ops->xp_recv != svc_vc_recv) + continue; + cd = (struct cf_conn *)xprt->xp_p1; + if (!cleanblock && !cd->nonblock) + continue; + if (timeout == 0) { + timersub(&tv, &cd->last_recv_time, &tdiff); + if (timercmp(&tdiff, &tmax, >)) { + tmax = tdiff; + least_active = xprt; + } + continue; + } + if (tv.tv_sec - cd->last_recv_time.tv_sec > timeout) { + __xprt_unregister_unlocked(xprt); + __svc_vc_dodestroy(xprt); + ncleaned++; + } + } + } + if (timeout == 0 && least_active != NULL) { + __xprt_unregister_unlocked(least_active); + __svc_vc_dodestroy(least_active); + ncleaned++; + } + rwlock_unlock(&svc_fd_lock); + return ncleaned > 0 ? TRUE : FALSE; +} |