diff options
| author | Bill Paul <wpaul@FreeBSD.org> | 1997-05-28 05:00:11 +0000 | 
|---|---|---|
| committer | Bill Paul <wpaul@FreeBSD.org> | 1997-05-28 05:00:11 +0000 | 
| commit | 9f3e964560d322bc8a33edb034336f199371ad5e (patch) | |
| tree | a6665af98aea23a2ff353b57f6154253f511ee31 /lib | |
| parent | 58041b5396a38b243a00b6c27c4387588bc21d4c (diff) | |
| parent | e8636dfd57b1bc6a19328606214e847c0d9eb1aa (diff) | |
Notes
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/libc/rpc/auth_des.c | 554 | ||||
| -rw-r--r-- | lib/libc/rpc/auth_time.c | 500 | ||||
| -rw-r--r-- | lib/libc/rpc/authdes_prot.c | 82 | ||||
| -rw-r--r-- | lib/libc/rpc/clnt_unix.c | 635 | ||||
| -rw-r--r-- | lib/libc/rpc/crypt_client.c | 89 | ||||
| -rw-r--r-- | lib/libc/rpc/des_crypt.3 | 126 | ||||
| -rw-r--r-- | lib/libc/rpc/des_crypt.c | 153 | ||||
| -rw-r--r-- | lib/libc/rpc/des_soft.c | 67 | ||||
| -rw-r--r-- | lib/libc/rpc/key_call.c | 425 | ||||
| -rw-r--r-- | lib/libc/rpc/key_prot_xdr.c | 166 | ||||
| -rw-r--r-- | lib/libc/rpc/netname.c | 136 | ||||
| -rw-r--r-- | lib/libc/rpc/netnamer.c | 326 | ||||
| -rw-r--r-- | lib/libc/rpc/publickey.3 | 44 | ||||
| -rw-r--r-- | lib/libc/rpc/publickey.5 | 37 | ||||
| -rw-r--r-- | lib/libc/rpc/rpc_secure.3 | 330 | ||||
| -rw-r--r-- | lib/libc/rpc/rpcdname.c | 77 | ||||
| -rw-r--r-- | lib/libc/rpc/rtime.3 | 43 | ||||
| -rw-r--r-- | lib/libc/rpc/rtime.c | 157 | ||||
| -rw-r--r-- | lib/libc/rpc/svc_auth_des.c | 531 | ||||
| -rw-r--r-- | lib/libc/rpc/svc_unix.c | 511 | 
20 files changed, 4989 insertions, 0 deletions
| diff --git a/lib/libc/rpc/auth_des.c b/lib/libc/rpc/auth_des.c new file mode 100644 index 000000000000..3fd2bfe8f4a0 --- /dev/null +++ b/lib/libc/rpc/auth_des.c @@ -0,0 +1,554 @@ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +/* + * Copyright (c) 1988 by Sun Microsystems, Inc. + */ +/* + * auth_des.c, client-side implementation of DES authentication + */ +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/cdefs.h> +#include <rpc/des_crypt.h> +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <rpc/auth.h> +#include <rpc/auth_des.h> +#include <netinet/in.h>	/* XXX: just to get htonl() and ntohl() */ +#include <sys/socket.h> +#undef NIS +#include <rpcsvc/nis.h> + +#if defined(LIBC_SCCS) && !defined(lint) +/* from: static char sccsid[] = 	"@(#)auth_des.c	2.2 88/07/29 4.0 RPCSRC; from 1.9 88/02/08 SMI"; */ +static const char rcsid[] = "$Id$"; +#endif + +extern bool_t __rpc_get_time_offset __P(( struct timeval *, nis_server *, +						char *, char **, struct sockaddr_in * )); +extern int rtime __P(( struct sockaddr_in *, struct timeval *, struct timeval *)); +extern bool_t xdr_authdes_cred __P(( XDR *, struct authdes_cred * )); +extern bool_t xdr_authdes_verf __P(( XDR *, struct authdes_verf * )); + +#define MILLION		1000000L +#define RTIME_TIMEOUT 5		/* seconds to wait for sync */ + +#define AUTH_PRIVATE(auth)	(struct ad_private *) auth->ah_private +#define ALLOC(object_type)	(object_type *) mem_alloc(sizeof(object_type)) +#define FREE(ptr, size)		mem_free((char *)(ptr), (int) size) +#define ATTEMPT(xdr_op)		if (!(xdr_op)) return (FALSE) + +#define debug(msg)		 /*printf("%s\n", msg) */ + +/*  + * DES authenticator operations vector + */ +static void	authdes_nextverf(); +static bool_t	authdes_marshal(); +static bool_t	authdes_validate(); +static bool_t	authdes_refresh(); +static void	authdes_destroy(); +static struct auth_ops authdes_ops = { +	authdes_nextverf, +	authdes_marshal, +	authdes_validate, +	authdes_refresh, +	authdes_destroy +}; +#ifdef foo +static bool_t	synchronize __P(( struct sockaddr *, struct timeval *)); +#endif +/* + * 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 sockaddr ad_syncaddr;	/* remote host to synch with */ +	char *ad_timehost;		/* remote host to synch with */ +	struct timeval ad_timediff;	/* server's time - client's time */ +	u_long ad_nickname;		/* server's nickname for client */ +	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 */ +}; +	 + +/* + * Create the client des authentication object + */	 +AUTH * +authdes_create(servername, window, syncaddr, ckey) +	char *servername;		/* network name of server */ +	u_int window;			/* time to live */ +	struct sockaddr *syncaddr;	/* optional addr of host to sync with */ +	des_block *ckey;		/* optional conversation key to use*/ +{ + +	AUTH *auth; +	struct ad_private *ad; +	char namebuf[MAXNETNAMELEN+1]; +	u_char	pkey_data[1024]; + +	if (!getpublickey(servername, pkey_data)) +		return(NULL); + +	/* + 	 * Allocate everything now +	 */ +	auth = ALLOC(AUTH); +	ad = ALLOC(struct ad_private); +	(void) getnetname(namebuf); + +	ad->ad_fullnamelen = RNDUP(strlen(namebuf)); +	ad->ad_fullname = (char *)mem_alloc(ad->ad_fullnamelen + 1); + +	ad->ad_servernamelen = strlen(servername); +	ad->ad_servername = (char *)mem_alloc(ad->ad_servernamelen + 1); + +	if (auth == NULL || ad == NULL || ad->ad_fullname == NULL || +	    ad->ad_servername == NULL) { +		debug("authdes_create: out of memory"); +		goto failed; +	} + +	/*  +	 * Set up private data +	 */ +	bcopy(namebuf, ad->ad_fullname, ad->ad_fullnamelen + 1); +	bcopy(servername, ad->ad_servername, ad->ad_servernamelen + 1); +	bcopy(pkey_data, ad->ad_pkey, strlen(pkey_data) + 1); +	if (syncaddr != NULL) { +		ad->ad_syncaddr = *syncaddr; +		ad->ad_dosync = TRUE; +	} else { +		ad->ad_dosync = FALSE; +	} +	ad->ad_window = window; +	if (ckey == NULL) { +		if (key_gendes(&auth->ah_key) < 0) { +			debug("authdes_create: unable to gen conversation key"); +			return (NULL); +		} +	} else { +		auth->ah_key = *ckey; +	} + +	/* +	 * Set up auth handle +	 */  +	auth->ah_cred.oa_flavor = AUTH_DES; +	auth->ah_verf.oa_flavor = AUTH_DES; +	auth->ah_ops = &authdes_ops; +	auth->ah_private = (caddr_t)ad; + +	if (!authdes_refresh(auth)) { +		goto failed; +	}	 +	return (auth); + +failed: +	if (auth != NULL)  +		FREE(auth, sizeof(AUTH));  +	if (ad != NULL)  +		FREE(ad, sizeof(struct ad_private)); +	if (ad->ad_fullname != NULL)  +		FREE(ad->ad_fullname, ad->ad_fullnamelen + 1); +	if (ad->ad_servername != NULL)  +		FREE(ad->ad_servername, ad->ad_servernamelen + 1); +	return (NULL); +} + +/* + * Slightly modified version of authdes_create which takes the public key + * of the server principal as an argument. This spares us a call to + * getpublickey() which in the nameserver context can cause a deadlock. + */ +AUTH * +authdes_pk_create(servername, pkey, window, timehost, ckey, srvr) +	char *servername;		/* network name of server */ +	netobj *pkey;			/* public key of server */ +	u_int window;			/* time to live */ +	char *timehost;			/* optional hostname to sync with */ +	des_block *ckey;		/* optional conversation key to use */ +	nis_server *srvr;		/* optional NIS+ server struct */ +{ +	AUTH *auth; +	struct ad_private *ad; +	char namebuf[MAXNETNAMELEN+1]; + +	/* +	 * Allocate everything now +	 */ +	auth = ALLOC(AUTH); +	if (auth == NULL) { +		debug("authdes_pk_create: out of memory"); +		return (NULL); +	} +	ad = ALLOC(struct ad_private); +	if (ad == NULL) { +		debug("authdes_pk_create: 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) { +		debug("authdes_pk_create: out of memory"); +		goto failed; +	} +	if (timehost != NULL) { +		ad->ad_timehost = (char *)mem_alloc(strlen(timehost) + 1); +		if (ad->ad_timehost == NULL) { +			debug("authdes_pk_create: out of memory"); +			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) { +			debug("authdes_pk_create: unable to gen conversation 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)) { +		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); +		if (ad->ad_uaddr) +			free(ad->ad_uaddr); +		FREE(ad, sizeof (struct ad_private)); +	} +	return (NULL); +} +/* + * Implement the five authentication operations + */ + + +/* + * 1. Next Verifier + */	 +/*ARGSUSED*/ +static void +authdes_nextverf(auth) +	AUTH *auth; +{ +	/* what the heck am I supposed to do??? */ +} +		 + + +/* + * 2. Marshal + */ +static bool_t +authdes_marshal(auth, xdrs) +	AUTH *auth; +	XDR *xdrs; +{ +	struct ad_private *ad = AUTH_PRIVATE(auth); +	struct authdes_cred *cred = &ad->ad_cred; +	struct authdes_verf *verf = &ad->ad_verf; +	des_block cryptbuf[2];	 +	des_block ivec; +	int status; +	long len; +	int32_t *ixdr; + +	/* +	 * 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; +	if (ad->ad_timestamp.tv_usec >= MILLION) { +		ad->ad_timestamp.tv_usec -= MILLION; +		ad->ad_timestamp.tv_sec += 1; +	} + +	/* +	 * XDR the timestamp and possibly some other things, then +	 * encrypt them. +	 */ +	ixdr = (int32_t *)cryptbuf; +	IXDR_PUT_LONG(ixdr, ad->ad_timestamp.tv_sec); +	IXDR_PUT_LONG(ixdr, ad->ad_timestamp.tv_usec); +	if (ad->ad_cred.adc_namekind == ADN_FULLNAME) { +		IXDR_PUT_U_LONG(ixdr, ad->ad_window); +		IXDR_PUT_U_LONG(ixdr, ad->ad_window - 1); +		ivec.key.high = ivec.key.low = 0;	 +		status = cbc_crypt((char *)&auth->ah_key, (char *)cryptbuf,  +			2*sizeof(des_block), DES_ENCRYPT | DES_HW, (char *)&ivec); +	} else { +		status = ecb_crypt((char *)&auth->ah_key, (char *)cryptbuf,  +			sizeof(des_block), DES_ENCRYPT | DES_HW); +	} +	if (DES_FAILED(status)) { +		debug("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_LONG(ixdr, AUTH_DES); +		IXDR_PUT_LONG(ixdr, len); +	} else { +		ATTEMPT(xdr_putlong(xdrs, (long *)&auth->ah_cred.oa_flavor));  +		ATTEMPT(xdr_putlong(xdrs, &len));  +	} +	ATTEMPT(xdr_authdes_cred(xdrs, cred)); + +	len = (2 + 1)*BYTES_PER_XDR_UNIT;  +	if ((ixdr = xdr_inline(xdrs, 2*BYTES_PER_XDR_UNIT))) { +		IXDR_PUT_LONG(ixdr, AUTH_DES); +		IXDR_PUT_LONG(ixdr, len); +	} else { +		ATTEMPT(xdr_putlong(xdrs, (long *)&auth->ah_verf.oa_flavor));  +		ATTEMPT(xdr_putlong(xdrs, &len));  +	} +	ATTEMPT(xdr_authdes_verf(xdrs, verf)); +	return (TRUE); +} + + +/* + * 3. Validate + */ +static bool_t +authdes_validate(auth, rverf) +	AUTH *auth; +	struct opaque_auth *rverf; +{ +	struct ad_private *ad = AUTH_PRIVATE(auth); +	struct authdes_verf verf; +	int status; +	register u_long *ixdr; + +	if (rverf->oa_length != (2 + 1) * BYTES_PER_XDR_UNIT) { +		return (FALSE); +	} +	ixdr = (u_long *)rverf->oa_base; +	verf.adv_xtimestamp.key.high = (u_long)*ixdr++; +	verf.adv_xtimestamp.key.low = (u_long)*ixdr++; +	verf.adv_int_u = (u_long)*ixdr++;	/* nickname not XDR'd ! */ + +	/* +	 * Decrypt the timestamp +	 */ +	status = ecb_crypt((char *)&auth->ah_key, (char *)&verf.adv_xtimestamp, +		sizeof(des_block), DES_DECRYPT | DES_HW); + +	if (DES_FAILED(status)) { +		debug("authdes_validate: DES decryption failure"); +		return (FALSE); +	} + +	/* +	 * xdr the decrypted timestamp  +	 */ +	ixdr = (u_long *)verf.adv_xtimestamp.c; +	verf.adv_timestamp.tv_sec = IXDR_GET_LONG(ixdr) + 1; +	verf.adv_timestamp.tv_usec = IXDR_GET_LONG(ixdr); + +	/* +	 * validate +	 */ +	if (bcmp((char *)&ad->ad_timestamp, (char *)&verf.adv_timestamp, +		 sizeof(struct timeval)) != 0) { +		debug("authdes_validate: verifier mismatch\n"); +		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 + */ +static bool_t +authdes_refresh(auth) +	AUTH *auth; +{ +	struct ad_private *ad = AUTH_PRIVATE(auth); +	struct authdes_cred *cred = &ad->ad_cred; +	netobj		pkey; + +	if (ad->ad_dosync && +#ifdef old +			!synchronize(&ad->ad_syncaddr, &ad->ad_timediff)) { +#else +			!__rpc_get_time_offset(&ad->ad_timediff,ad->ad_nis_srvr, +					       ad->ad_timehost, &(ad->ad_uaddr), +				(struct sockaddr_in *)&(ad->ad_syncaddr))) { +#endif +		/* +		 * Hope the clocks are synced! +		 */ +		ad->ad_timediff.tv_sec = ad->ad_timediff.tv_usec = 0; +		ad->ad_dosync = 0; +		debug("authdes_refresh: unable to synchronize with server"); +	} +	ad->ad_xkey = auth->ah_key; +	pkey.n_bytes = (char *)(ad->ad_pkey); +	pkey.n_len = strlen((char *)ad->ad_pkey) + 1; +	if (key_encryptsession_pk(ad->ad_servername, &pkey, &ad->ad_xkey) < 0) { +		debug("authdes_create: unable to encrypt conversation key"); +		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 *auth; +{ +	struct ad_private *ad = AUTH_PRIVATE(auth); + +	FREE(ad->ad_fullname, ad->ad_fullnamelen + 1); +	FREE(ad->ad_servername, ad->ad_servernamelen + 1); +	FREE(ad, sizeof(struct ad_private)); +	FREE(auth, sizeof(AUTH)); +} +	 + +#ifdef old +/* + * Synchronize with the server at the given address, that is, + * adjust timep to reflect the delta between our clocks + */ +static bool_t +synchronize(syncaddr, timep) +	struct sockaddr *syncaddr; +	struct timeval *timep; +{ +	struct timeval mytime; +	struct timeval timeout; + +	timeout.tv_sec = RTIME_TIMEOUT; +	timeout.tv_usec = 0; +	if (rtime((struct sockaddr_in *)syncaddr, timep, NULL /*&timeout*/) < 0) { +		return (FALSE); +	} +	(void) gettimeofday(&mytime, (struct timezone *)NULL); +	timep->tv_sec -= mytime.tv_sec; +	if (mytime.tv_usec > timep->tv_usec) { +		timep->tv_sec -= 1; +		timep->tv_usec += MILLION; +	} +	timep->tv_usec -= mytime.tv_usec; +	return (TRUE); +} +#endif diff --git a/lib/libc/rpc/auth_time.c b/lib/libc/rpc/auth_time.c new file mode 100644 index 000000000000..2b9a5a929e41 --- /dev/null +++ b/lib/libc/rpc/auth_time.c @@ -0,0 +1,500 @@ +#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. + * + * NOTE: This code has had the crap beaten out it in order to convert + *       it from TI-RPC back to TD-RPC for use on FreeBSD. + */ +#include <stdio.h> +#include <syslog.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <netdb.h> +#include <sys/signal.h> +#include <sys/errno.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <rpc/rpc.h> +#include <rpc/rpc_com.h> +#undef NIS +#include <rpcsvc/nis.h> + +/* + * FreeBSD currently uses RPC 4.0, which uses portmap rather than + * rpcbind. Consequently, we need to fake up these values here. + * Luckily, the RPCB_GETTIME procedure uses only base XDR data types + * so we don't need anything besides these magic numbers. + */ +#define RPCBPROG (u_long)100000 +#define RPCBVERS (u_long)3 +#define RPCBPROC_GETTIME (u_long)6 + +#ifdef TESTING +#define	msg(x)	printf("ERROR: %s\n", x) +/* #define msg(x) syslog(LOG_ERR, "%s", x) */ +#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]; + +	if (host == NULL && sin == NULL) +		return (NULL); + +	if (sin == NULL) { +		he = gethostbyname(host); +		if (he == NULL) +			return(NULL); +	} else { +		he = &dummy; +		ptr[0] = (char *)&sin->sin_addr.s_addr; +		ptr[1] = NULL; +		dummy.h_addr_list = ptr; +	} + +	/* +	 * This is lame. We go around once for TCP, then again +	 * for UDP. +	 */ +	for (i = 0; (he->h_addr_list[i] != NULL) && (num_ep < maxep); +						i++, num_ep++) { +		struct in_addr *a; + +		a = (struct in_addr *)he->h_addr_list[i]; +		snprintf(hname, sizeof(hname), "%s.0.111", inet_ntoa(*a)); +		eps[num_ep].uaddr = strdup(hname); +		eps[num_ep].family = strdup("inet"); +		eps[num_ep].proto =  strdup("tcp"); +	} + +	for (i = 0; (he->h_addr_list[i] != NULL) && (num_ep < maxep); +						i++, num_ep++) { +		struct in_addr *a; + +		a = (struct in_addr *)he->h_addr_list[i]; +		snprintf(hname, sizeof(hname), "%s.0.111", inet_ntoa(*a)); +		eps[num_ep].uaddr = strdup(hname); +		eps[num_ep].family = strdup("inet"); +		eps[num_ep].proto =  strdup("udp"); +	} + +	srv->name = (nis_name) host; +	srv->ep.ep_len = num_ep; +	srv->ep.ep_val = eps; +	srv->key_type = NIS_PK_NONE; +	srv->pkey.n_bytes = NULL; +	srv->pkey.n_len = 0; +	return (srv); +} + +/* + * __rpc_get_time_offset() + * + * This function uses a nis_server structure to contact the a remote + * machine (as named in that structure) and returns the offset in time + * between that machine and this one. This offset is returned in seconds + * and may be positive or negative. + * + * The first time through, a lot of fiddling is done with the netconfig + * stuff to find a suitable transport. The function is very aggressive + * about choosing UDP or at worst TCP if it can. This is because + * those transports support both the RCPBIND call and the internet + * time service. + * + * Once through, *uaddr is set to the universal address of + * the machine and *netid is set to the local netid for the transport + * that uaddr goes with. On the second call, the netconfig stuff + * is skipped and the uaddr/netid pair are used to fetch the netconfig + * structure and to then contact the machine for the time. + * + * td = "server" - "client" + */ +int +__rpc_get_time_offset(td, srv, thost, uaddr, netid) +	struct timeval	*td;	 /* Time difference			*/ +	nis_server	*srv;	 /* NIS Server description 		*/ +	char		*thost;	 /* if no server, this is the timehost	*/ +	char		**uaddr; /* known universal address		*/ +	struct sockaddr_in *netid; /* known network identifier		*/ +{ +	CLIENT			*clnt; 		/* Client handle 	*/ +	endpoint		*ep,		/* useful endpoints	*/ +				*useep = NULL;	/* endpoint of xp	*/ +	char			*useua = NULL;	/* uaddr of selected xp	*/ +	int			epl, i;		/* counters		*/ +	enum clnt_stat		status;		/* result of clnt_call	*/ +	u_long			thetime, delta; +	int			needfree = 0; +	struct timeval		tv; +	int			time_valid; +	int			udp_ep = -1, tcp_ep = -1; +	int			a1, a2, a3, a4; +	char			ut[64], ipuaddr[64]; +	endpoint		teps[32]; +	nis_server		tsrv; +	void			(*oldsig)() = NULL; /* old alarm handler */ +	struct sockaddr_in	sin; +	int			s = RPC_ANYSOCK, len; +	int			type = 0; + +	td->tv_sec = 0; +	td->tv_usec = 0; + +	/* +	 * First check to see if we need to find and address for this +	 * server. +	 */ +	if (*uaddr == NULL) { +		if ((srv != NULL) && (thost != NULL)) { +			msg("both timehost and srv pointer used!"); +			return (0); +		} +		if (! srv) { +			srv = get_server(netid, thost, &tsrv, teps, 32); +			if (srv == NULL) { +				msg("unable to contruct server data."); +				return (0); +			} +			needfree = 1;	/* need to free data in endpoints */ +		} + +		ep = srv->ep.ep_val; +		epl = srv->ep.ep_len; + +		/* Identify the TCP and UDP endpoints */ +		for (i = 0; +			(i < epl) && ((udp_ep == -1) || (tcp_ep == -1)); i++) { +			if (strcasecmp(ep[i].proto, "udp") == 0) +				udp_ep = i; +			if (strcasecmp(ep[i].proto, "tcp") == 0) +				tcp_ep = i; +		} + +		/* Check to see if it is UDP or TCP */ +		if (tcp_ep > -1) { +			useep = &ep[tcp_ep]; +			useua = ep[tcp_ep].uaddr; +			type = SOCK_STREAM; +		} else if (udp_ep > -1) { +			useep = &ep[udp_ep]; +			useua = ep[udp_ep].uaddr; +			type = SOCK_DGRAM; +		} + +		if (useep == NULL) { +			msg("no acceptable transport endpoints."); +			if (needfree) +				free_eps(teps, tsrv.ep.ep_len); +			return (0); +		} +	} + +	/* +	 * Create a sockaddr from the uaddr. +	 */ +	if (*uaddr != NULL) +		useua = *uaddr; + +	/* Fixup test for NIS+ */ +	sscanf(useua, "%d.%d.%d.%d.", &a1, &a2, &a3, &a4); +	sprintf(ipuaddr, "%d.%d.%d.%d.0.111", a1, a2, a3, a4); +	useua = &ipuaddr[0]; + +	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, xdr_void, NULL, +					xdr_u_long, (char *)&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/lib/libc/rpc/authdes_prot.c b/lib/libc/rpc/authdes_prot.c new file mode 100644 index 000000000000..14679c00a9cc --- /dev/null +++ b/lib/libc/rpc/authdes_prot.c @@ -0,0 +1,82 @@ +#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 +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +/* + * Copyright (c) 1988 by Sun Microsystems, Inc. + */ + +/* + * authdes_prot.c, XDR routines for DES authentication + */ + +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <rpc/auth.h> +#include <rpc/auth_des.h> + +#define ATTEMPT(xdr_op) if (!(xdr_op)) return (FALSE) + +bool_t +xdr_authdes_cred(xdrs, cred) +	XDR *xdrs; +	struct authdes_cred *cred; +{ +	/* +	 * Unrolled xdr +	 */ +	ATTEMPT(xdr_enum(xdrs, (enum_t *)&cred->adc_namekind)); +	switch (cred->adc_namekind) { +	case ADN_FULLNAME: +		ATTEMPT(xdr_string(xdrs, &cred->adc_fullname.name, MAXNETNAMELEN)); +		ATTEMPT(xdr_opaque(xdrs, (caddr_t)&cred->adc_fullname.key, sizeof(des_block))); +		ATTEMPT(xdr_opaque(xdrs, (caddr_t)&cred->adc_fullname.window, sizeof(cred->adc_fullname.window))); +		return (TRUE); +	case ADN_NICKNAME: +		ATTEMPT(xdr_opaque(xdrs, (caddr_t)&cred->adc_nickname, sizeof(cred->adc_nickname))); +		return (TRUE); +	default: +		return (FALSE); +	} +} + + +bool_t +xdr_authdes_verf(xdrs, verf) +	register XDR *xdrs; +	register 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/lib/libc/rpc/clnt_unix.c b/lib/libc/rpc/clnt_unix.c new file mode 100644 index 000000000000..e4c43094bc9c --- /dev/null +++ b/lib/libc/rpc/clnt_unix.c @@ -0,0 +1,635 @@ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +#if defined(LIBC_SCCS) && !defined(lint) +/*static char *sccsid = "from: @(#)clnt_unix.c 1.37 87/10/05 Copyr 1984 Sun Micro";*/ +/*static char *sccsid = "from: @(#)clnt_unix.c	2.2 88/08/01 4.0 RPCSRC";*/ +static char *rcsid = "$Id: clnt_unix.c,v 1.7 1996/12/30 14:36:17 peter Exp $"; +#endif + +/* + * clnt_unix.c, Implements a AF_UNIX based, client side RPC. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * AF_UNIX based RPC supports 'batched calls'. + * A sequence of calls may be batched-up in a send buffer.  The rpc call + * return immediately to the client even though the call was not necessarily + * sent.  The batching occurs if the results' xdr routine is NULL (0) AND + * the rpc timeout value is zero (see clnt.h, rpc). + * + * Clients should NOT casually batch calls that in fact return results; that is, + * the server side should be aware that a call is batched and not produce any + * return message.  Batched calls that produce many result messages can + * deadlock (netlock) the client and the server.... + * + * Now go hang yourself. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <rpc/rpc.h> +#include <sys/uio.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <netdb.h> +#include <errno.h> +#include <rpc/pmap_clnt.h> + +#define MCALL_MSG_SIZE 24 + +static int	readunix(); +static int	writeunix(); + +static enum clnt_stat	clntunix_call(); +static void		clntunix_abort(); +static void		clntunix_geterr(); +static bool_t		clntunix_freeres(); +static bool_t           clntunix_control(); +static void		clntunix_destroy(); + +static struct clnt_ops unix_ops = { +	clntunix_call, +	clntunix_abort, +	clntunix_geterr, +	clntunix_freeres, +	clntunix_destroy, +	clntunix_control +}; + +struct ct_data { +	int		ct_sock; +	bool_t		ct_closeit; +	struct timeval	ct_wait; +	bool_t          ct_waitset;       /* wait set by clnt_control? */ +	struct sockaddr_un ct_addr; +	struct rpc_err	ct_error; +	char		ct_mcall[MCALL_MSG_SIZE];	/* marshalled callmsg */ +	u_int		ct_mpos;			/* pos after marshal */ +	XDR		ct_xdrs; +}; + +/* + * Create a client handle for a unix/ip connection. + * If *sockp<0, *sockp is set to a newly created TCP socket and it is + * connected to raddr.  If *sockp non-negative then + * raddr is ignored.  The rpc/unix package does buffering + * similar to stdio, so the client must pick send and receive buffer sizes,]; + * 0 => use the default. + * If raddr->sin_port is 0, then a binder on the remote machine is + * consulted for the right port number. + * NB: *sockp is copied into a private area. + * NB: It is the clients responsibility to close *sockp. + * NB: The rpch->cl_auth is set null authentication.  Caller may wish to set this + * something more useful. + */ +CLIENT * +clntunix_create(raddr, prog, vers, sockp, sendsz, recvsz) +	struct sockaddr_un *raddr; +	u_long prog; +	u_long vers; +	register int *sockp; +	u_int sendsz; +	u_int recvsz; +{ +	CLIENT *h; +	register struct ct_data *ct = NULL; +	struct timeval now; +	struct rpc_msg call_msg; +	static u_int32_t disrupt; +	int len; + +	if (disrupt == 0) +		disrupt = (u_int32_t)(long)raddr; + +	h  = (CLIENT *)mem_alloc(sizeof(*h)); +	if (h == NULL) { +		(void)fprintf(stderr, "clntunix_create: out of memory\n"); +		rpc_createerr.cf_stat = RPC_SYSTEMERROR; +		rpc_createerr.cf_error.re_errno = errno; +		goto fooy; +	} +	ct = (struct ct_data *)mem_alloc(sizeof(*ct)); +	if (ct == NULL) { +		(void)fprintf(stderr, "clntunix_create: out of memory\n"); +		rpc_createerr.cf_stat = RPC_SYSTEMERROR; +		rpc_createerr.cf_error.re_errno = errno; +		goto fooy; +	} + +	/* +	 * If no socket given, open one +	 */ +	if (*sockp < 0) { +		*sockp = socket(AF_UNIX, SOCK_STREAM, 0); +		len = strlen(raddr->sun_path) + sizeof(raddr->sun_family) + +			sizeof(raddr->sun_len) + 1; +		raddr->sun_len = len; +		if ((*sockp < 0) +		    || (connect(*sockp, (struct sockaddr *)raddr, len) < 0)) { +			rpc_createerr.cf_stat = RPC_SYSTEMERROR; +			rpc_createerr.cf_error.re_errno = errno; +			if (*sockp != -1) +				(void)close(*sockp); +			goto fooy; +		} +		ct->ct_closeit = TRUE; +	} else { +		ct->ct_closeit = FALSE; +	} + +	/* +	 * Set up private data struct +	 */ +	ct->ct_sock = *sockp; +	ct->ct_wait.tv_usec = 0; +	ct->ct_waitset = FALSE; +	ct->ct_addr = *raddr; + +	/* +	 * Initialize call message +	 */ +	(void)gettimeofday(&now, (struct timezone *)0); +	call_msg.rm_xid = (++disrupt) ^ getpid() ^ now.tv_sec ^ now.tv_usec; +	call_msg.rm_direction = CALL; +	call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; +	call_msg.rm_call.cb_prog = prog; +	call_msg.rm_call.cb_vers = vers; + +	/* +	 * pre-serialize the static part of the call msg and stash it away +	 */ +	xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, +	    XDR_ENCODE); +	if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { +		if (ct->ct_closeit) { +			(void)close(*sockp); +		} +		goto fooy; +	} +	ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs)); +	XDR_DESTROY(&(ct->ct_xdrs)); + +	/* +	 * Create a client handle which uses xdrrec for serialization +	 * and authnone for authentication. +	 */ +	xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, +	    (caddr_t)ct, readunix, writeunix); +	h->cl_ops = &unix_ops; +	h->cl_private = (caddr_t) ct; +	h->cl_auth = authnone_create(); +	return (h); + +fooy: +	/* +	 * Something goofed, free stuff and barf +	 */ +	if (ct) +		mem_free((caddr_t)ct, sizeof(struct ct_data)); +	if (h) +		mem_free((caddr_t)h, sizeof(CLIENT)); +	return ((CLIENT *)NULL); +} + +static enum clnt_stat +clntunix_call(h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout) +	register CLIENT *h; +	u_long proc; +	xdrproc_t xdr_args; +	caddr_t args_ptr; +	xdrproc_t xdr_results; +	caddr_t results_ptr; +	struct timeval timeout; +{ +	register struct ct_data *ct = (struct ct_data *) h->cl_private; +	register XDR *xdrs = &(ct->ct_xdrs); +	struct rpc_msg reply_msg; +	u_long x_id; +	u_int32_t *msg_x_id = (u_int32_t *)(ct->ct_mcall);	/* yuk */ +	register bool_t shipnow; +	int refreshes = 2; + +	if (!ct->ct_waitset) { +		ct->ct_wait = timeout; +	} + +	shipnow = +	    (xdr_results == (xdrproc_t)0 && timeout.tv_sec == 0 +	    && timeout.tv_usec == 0) ? FALSE : TRUE; + +call_again: +	xdrs->x_op = XDR_ENCODE; +	ct->ct_error.re_status = RPC_SUCCESS; +	x_id = ntohl(--(*msg_x_id)); +	if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) || +	    (! XDR_PUTLONG(xdrs, (long *)&proc)) || +	    (! AUTH_MARSHALL(h->cl_auth, xdrs)) || +	    (! (*xdr_args)(xdrs, args_ptr))) { +		if (ct->ct_error.re_status == RPC_SUCCESS) +			ct->ct_error.re_status = RPC_CANTENCODEARGS; +		(void)xdrrec_endofrecord(xdrs, TRUE); +		return (ct->ct_error.re_status); +	} +	if (! xdrrec_endofrecord(xdrs, shipnow)) +		return (ct->ct_error.re_status = RPC_CANTSEND); +	if (! shipnow) +		return (RPC_SUCCESS); +	/* +	 * Hack to provide rpc-based message passing +	 */ +	if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { +		return(ct->ct_error.re_status = RPC_TIMEDOUT); +	} + + +	/* +	 * Keep receiving until we get a valid transaction id +	 */ +	xdrs->x_op = XDR_DECODE; +	while (TRUE) { +		reply_msg.acpted_rply.ar_verf = _null_auth; +		reply_msg.acpted_rply.ar_results.where = NULL; +		reply_msg.acpted_rply.ar_results.proc = xdr_void; +		if (! xdrrec_skiprecord(xdrs)) +			return (ct->ct_error.re_status); +		/* now decode and validate the response header */ +		if (! xdr_replymsg(xdrs, &reply_msg)) { +			if (ct->ct_error.re_status == RPC_SUCCESS) +				continue; +			return (ct->ct_error.re_status); +		} +		if (reply_msg.rm_xid == x_id) +			break; +	} + +	/* +	 * process header +	 */ +	_seterr_reply(&reply_msg, &(ct->ct_error)); +	if (ct->ct_error.re_status == RPC_SUCCESS) { +		if (! AUTH_VALIDATE(h->cl_auth, &reply_msg.acpted_rply.ar_verf)) { +			ct->ct_error.re_status = RPC_AUTHERROR; +			ct->ct_error.re_why = AUTH_INVALIDRESP; +		} else if (! (*xdr_results)(xdrs, results_ptr)) { +			if (ct->ct_error.re_status == RPC_SUCCESS) +				ct->ct_error.re_status = RPC_CANTDECODERES; +		} +		/* free verifier ... */ +		if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { +			xdrs->x_op = XDR_FREE; +			(void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf)); +		} +	}  /* end successful completion */ +	else { +		/* maybe our credentials need to be refreshed ... */ +		if (refreshes-- && AUTH_REFRESH(h->cl_auth)) +			goto call_again; +	}  /* end of unsuccessful completion */ +	return (ct->ct_error.re_status); +} + +static void +clntunix_geterr(h, errp) +	CLIENT *h; +	struct rpc_err *errp; +{ +	register struct ct_data *ct = +	    (struct ct_data *) h->cl_private; + +	*errp = ct->ct_error; +} + +static bool_t +clntunix_freeres(cl, xdr_res, res_ptr) +	CLIENT *cl; +	xdrproc_t xdr_res; +	caddr_t res_ptr; +{ +	register struct ct_data *ct = (struct ct_data *)cl->cl_private; +	register XDR *xdrs = &(ct->ct_xdrs); + +	xdrs->x_op = XDR_FREE; +	return ((*xdr_res)(xdrs, res_ptr)); +} + +static void +clntunix_abort() +{ +} + + +static bool_t +clntunix_control(cl, request, info) +	CLIENT *cl; +	int request; +	char *info; +{ +	register struct ct_data *ct = (struct ct_data *)cl->cl_private; +	register struct timeval *tv; +	int len; + +	switch (request) { +	case CLSET_FD_CLOSE: +		ct->ct_closeit = TRUE; +		break; +	case CLSET_FD_NCLOSE: +		ct->ct_closeit = FALSE; +		break; +	case CLSET_TIMEOUT: +		if (info == NULL) +			return(FALSE); +		tv = (struct timeval *)info; +		ct->ct_wait.tv_sec = tv->tv_sec; +		ct->ct_wait.tv_usec = tv->tv_usec; +		ct->ct_waitset = TRUE; +		break; +	case CLGET_TIMEOUT: +		if (info == NULL) +			return(FALSE); +		*(struct timeval *)info = ct->ct_wait; +		break; +	case CLGET_SERVER_ADDR: +		if (info == NULL) +			return(FALSE); +		*(struct sockaddr_un *)info = ct->ct_addr; +		break; +	case CLGET_FD: +		if (info == NULL) +			return(FALSE); +		*(int *)info = ct->ct_sock; +		break; +	case CLGET_XID: +		/* +		 * use the knowledge that xid is the +		 * first element in the call structure *. +		 * This will get the xid of the PREVIOUS call +		 */ +		if (info == NULL) +			return(FALSE); +		*(u_long *)info = ntohl(*(u_long *)ct->ct_mcall); +		break; +	case CLSET_XID: +		/* This will set the xid of the NEXT call */ +		if (info == NULL) +			return(FALSE); +		*(u_long *)ct->ct_mcall =  htonl(*(u_long *)info - 1); +		/* decrement by 1 as clntunix_call() increments once */ +	case CLGET_VERS: +		/* +		 * This RELIES on the information that, in the call body, +		 * the version number field is the fifth field from the +		 * begining of the RPC header. MUST be changed if the +		 * call_struct is changed +		 */ +		if (info == NULL) +			return(FALSE); +		*(u_long *)info = ntohl(*(u_long *)(ct->ct_mcall + +						4 * BYTES_PER_XDR_UNIT)); +		break; +	case CLSET_VERS: +		if (info == NULL) +			return(FALSE); +		*(u_long *)(ct->ct_mcall + 4 * BYTES_PER_XDR_UNIT) +				= htonl(*(u_long *)info); +		break; +	case CLGET_PROG: +		/* +		 * This RELIES on the information that, in the call body, +		 * the program number field is the  field from the +		 * begining of the RPC header. MUST be changed if the +		 * call_struct is changed +		 */ +		if (info == NULL) +			return(FALSE); +		*(u_long *)info = ntohl(*(u_long *)(ct->ct_mcall + +						3 * BYTES_PER_XDR_UNIT)); +		break; +	case CLSET_PROG: +		if (info == NULL) +			return(FALSE); +		*(u_long *)(ct->ct_mcall + 3 * BYTES_PER_XDR_UNIT) +				= htonl(*(u_long *)info); +		break; +	case CLGET_LOCAL_ADDR: +		len = sizeof(struct sockaddr); +		if (getsockname(ct->ct_sock, (struct sockaddr *)info, &len) <0) +			return(FALSE); +		break; +	case CLGET_RETRY_TIMEOUT: +	case CLSET_RETRY_TIMEOUT: +	case CLGET_SVC_ADDR: +	case CLSET_SVC_ADDR: +	case CLSET_PUSH_TIMOD: +	case CLSET_POP_TIMOD: +	default: +		return (FALSE); +	} +	return (TRUE); +} + + +static void +clntunix_destroy(h) +	CLIENT *h; +{ +	register struct ct_data *ct = +	    (struct ct_data *) h->cl_private; + +	if (ct->ct_closeit) { +		(void)close(ct->ct_sock); +	} +	XDR_DESTROY(&(ct->ct_xdrs)); +	mem_free((caddr_t)ct, sizeof(struct ct_data)); +	mem_free((caddr_t)h, sizeof(CLIENT)); +} + +/* + * read() and write() are replaced with recvmsg()/sendmsg() so that + * we can pass ancillary control data. In this case, the data constists + * of credential information which the kernel will fill in for us. + * XXX: This code is specific to FreeBSD and will not work on other + * platforms without the requisite kernel modifications. + */ +struct cmessage { +	struct cmsghdr cmsg; +	struct cmsgcred cmcred; +}; + +static int __msgread(sock, buf, cnt) +	int sock; +	void *buf; +	size_t cnt; +{ +	struct iovec iov[1]; +	struct msghdr msg; +	struct cmessage cm; + +	bzero((char *)&cm, sizeof(cm)); +	iov[0].iov_base = buf; +	iov[0].iov_len = cnt; + +	msg.msg_iov = iov; +	msg.msg_iovlen = 1; +	msg.msg_name = NULL; +	msg.msg_namelen = 0; +	msg.msg_control = (caddr_t)&cm; +	msg.msg_controllen = sizeof(struct cmessage); +	msg.msg_flags = 0; + +	return(recvmsg(sock, &msg, 0)); +} + +static int __msgwrite(sock, buf, cnt) +	int sock; +	void *buf; +	size_t cnt; +{ +	struct iovec iov[1]; +	struct msghdr msg; +	struct cmessage cm; + +	bzero((char *)&cm, sizeof(cm)); +	iov[0].iov_base = buf; +	iov[0].iov_len = cnt; + +	cm.cmsg.cmsg_type = SCM_CREDS; +	cm.cmsg.cmsg_level = SOL_SOCKET; +	cm.cmsg.cmsg_len = sizeof(struct cmessage); + +	msg.msg_iov = iov; +	msg.msg_iovlen = 1; +	msg.msg_name = NULL; +	msg.msg_namelen = 0; +	msg.msg_control = (caddr_t)&cm; +	msg.msg_controllen = sizeof(struct cmessage); +	msg.msg_flags = 0; + +	return(sendmsg(sock, &msg, 0)); +} + +/* + * Interface between xdr serializer and unix connection. + * Behaves like the system calls, read & write, but keeps some error state + * around for the rpc level. + */ +static int +readunix(ct, buf, len) +	register struct ct_data *ct; +	caddr_t buf; +	register int len; +{ +	fd_set *fds, readfds; +	struct timeval start, after, duration, delta, tmp, tv; +	int r, save_errno; + +	if (len == 0) +		return (0); + +	if (ct->ct_sock + 1 > FD_SETSIZE) { +		int bytes = howmany(ct->ct_sock + 1, NFDBITS) * sizeof(fd_mask); +		fds = (fd_set *)malloc(bytes); +		if (fds == NULL) +			return (-1); +		memset(fds, 0, bytes); +	} else { +		fds = &readfds; +		FD_ZERO(fds); +	} + +	gettimeofday(&start, NULL); +	delta = ct->ct_wait; +	while (TRUE) { +		/* XXX we know the other bits are still clear */ +		FD_SET(ct->ct_sock, fds); +		tv = delta;	/* in case select writes back */ +		r = select(ct->ct_sock+1, fds, NULL, NULL, &tv); +		save_errno = errno; + +		gettimeofday(&after, NULL); +		timersub(&start, &after, &duration); +		timersub(&delta, &duration, &tmp); +		delta = tmp; +		if (delta.tv_sec < 0 || !timerisset(&delta)) +			r = 0; + +		switch (r) { +		case 0: +			if (fds != &readfds) +				free(fds); +			ct->ct_error.re_status = RPC_TIMEDOUT; +			return (-1); + +		case -1: +			if (errno == EINTR) +				continue; +			if (fds != &readfds) +				free(fds); +			ct->ct_error.re_status = RPC_CANTRECV; +			ct->ct_error.re_errno = save_errno; +			return (-1); +		} +		break; +	} +	switch (len = __msgread(ct->ct_sock, buf, len)) { + +	case 0: +		/* premature eof */ +		ct->ct_error.re_errno = ECONNRESET; +		ct->ct_error.re_status = RPC_CANTRECV; +		len = -1;  /* it's really an error */ +		break; + +	case -1: +		ct->ct_error.re_errno = errno; +		ct->ct_error.re_status = RPC_CANTRECV; +		break; +	} +	return (len); +} + +static int +writeunix(ct, buf, len) +	struct ct_data *ct; +	caddr_t buf; +	int len; +{ +	register int i, cnt; + +	for (cnt = len; cnt > 0; cnt -= i, buf += i) { +		if ((i = __msgwrite(ct->ct_sock, buf, cnt)) == -1) { +			ct->ct_error.re_errno = errno; +			ct->ct_error.re_status = RPC_CANTSEND; +			return (-1); +		} +	} +	return (len); +} diff --git a/lib/libc/rpc/crypt_client.c b/lib/libc/rpc/crypt_client.c new file mode 100644 index 000000000000..cdc0c061d8b3 --- /dev/null +++ b/lib/libc/rpc/crypt_client.c @@ -0,0 +1,89 @@ +/* + * 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. + * + *	$Id$ + */ + +#include <sys/types.h> +#include <rpc/des_crypt.h> +#include <rpc/des.h> +#include <string.h> +#include <rpcsvc/crypt.h> + +#ifndef lint +static const char rcsid[] = "$Id$"; +#endif + +#ifndef KEYSERVSOCK +#define KEYSERVSOCK "/var/run/keyservsock" +#endif + +int +_des_crypt_call(buf, len, dparms) +	char *buf; +	int len; +	struct desparams *dparms; +{ +	CLIENT *clnt; +	desresp  *result_1; +	desargs  des_crypt_1_arg; +	int	stat; + +	clnt = clnt_create(KEYSERVSOCK, CRYPT_PROG, CRYPT_VERS, "unix"); +	if (clnt == (CLIENT *) NULL) { +		return(DESERR_HWERROR); +	} + +	des_crypt_1_arg.desbuf.desbuf_len = len; +	des_crypt_1_arg.desbuf.desbuf_val = buf; +	des_crypt_1_arg.des_dir = dparms->des_dir; +	des_crypt_1_arg.des_mode = dparms->des_mode; +	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) { +		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, xdr_desresp, (char *)result_1); +	clnt_destroy(clnt); + +	return(stat); +} diff --git a/lib/libc/rpc/des_crypt.3 b/lib/libc/rpc/des_crypt.3 new file mode 100644 index 000000000000..ca0a33e1c27d --- /dev/null +++ b/lib/libc/rpc/des_crypt.3 @@ -0,0 +1,126 @@ +.\" @(#)des_crypt.3	2.1 88/08/11 4.0 RPCSRC; from 1.16 88/03/02 SMI; +.TH DES_CRYPT 3  "6 October 1987" +.SH NAME +des_crypt, ecb_crypt, cbc_crypt, des_setparity \- fast DES encryption +.SH SYNOPSIS +.nf +.B #include <des_crypt.h> +.LP +.B int ecb_crypt(key, data, datalen, mode) +.B char *key; +.B char *data; +.B unsigned datalen; +.B unsigned mode; +.LP +.B int cbc_crypt(key, data, datalen, mode, ivec) +.B char *key; +.B char *data; +.B unsigned datalen; +.B unsigned mode; +.B char *ivec; +.LP +.B void des_setparity(key) +.B char *key; +.fi +.SH DESCRIPTION +.IX encryption cbc_crypt "" \fLcbc_crypt\fP +.IX "des encryption" cbc_crypt "DES encryption" \fLcbc_crypt\fP +.IX encryption des_setparity "" \fLdes_setparity\fP +.IX "des encryption" des_setparity "DES encryption" \fLdes_setparity\fP +.B ecb_crypt(\|) +and +.B cbc_crypt(\|) +implement the +.SM NBS +.SM DES +(Data Encryption Standard). +These routines are faster and more general purpose than +.BR crypt (3). +They also are able to utilize +.SM DES +hardware if it is available. +.B ecb_crypt(\|) +encrypts in +.SM ECB +(Electronic Code Book) +mode, which encrypts blocks of data independently. +.B cbc_crypt(\|) +encrypts in +.SM CBC +(Cipher Block Chaining) +mode, which chains together +successive blocks. +.SM CBC +mode protects against insertions, deletions and +substitutions of blocks. Also, regularities in the clear text will +not appear in the cipher text. +.LP +Here is how to use these routines.  The first parameter, +.IR key , +is the 8-byte encryption key with parity. +To set the key's parity, which for +.SM DES +is in the low bit of each byte, use +.IR des_setparity . +The second parameter, +.IR data , +contains the data to be encrypted or decrypted. The +third parameter, +.IR datalen , +is the length in bytes of +.IR data , +which must be a multiple of 8. The fourth parameter, +.IR mode , +is formed by +.SM OR\s0'ing +together some things.  For the encryption direction 'or' in either +.SM DES_ENCRYPT +or +.SM DES_DECRYPT\s0. +For software versus hardware +encryption, 'or' in either +.SM DES_HW +or +.SM DES_SW\s0. +If +.SM DES_HW +is specified, and there is no hardware, then the encryption is performed +in software and the routine returns +.SM DESERR_NOHWDEVICE\s0. +For +.IR cbc_crypt , +the parameter +.I ivec +is the the 8-byte initialization +vector for the chaining.  It is updated to the next initialization +vector upon return. +.LP +.SH "SEE ALSO" +.BR des (1), +.BR crypt (3) +.SH DIAGNOSTICS +.PD 0 +.TP 20 +.SM DESERR_NONE +No error. +.TP +.SM DESERR_NOHWDEVICE +Encryption succeeded, but done in software instead of the requested hardware. +.TP +.SM DESERR_HWERR +An error occurred in the hardware or driver. +.TP +.SM DESERR_BADPARAM +Bad parameter to routine. +.PD +.LP +Given a result status +.IR stat , +the macro +.SM DES_FAILED\c +.BR ( stat ) +is false only for the first two statuses. +.SH RESTRICTIONS +These routines are not available in RPCSRC 4.0. +This information is provided to describe the DES interface expected by +Secure RPC. diff --git a/lib/libc/rpc/des_crypt.c b/lib/libc/rpc/des_crypt.c new file mode 100644 index 000000000000..18c99724d3ea --- /dev/null +++ b/lib/libc/rpc/des_crypt.c @@ -0,0 +1,153 @@ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +/* + * 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> + +#ifndef lint +/* from: static char sccsid[] = "@(#)des_crypt.c	2.2 88/08/10 4.0 RPCSRC; from 1.13 88/02/08 SMI"; */ +static const char rcsid[] = "$Id$"; +#endif + +static int common_crypt	__P(( char *, char *, register unsigned, unsigned, struct desparams * )); +int (*__des_crypt_LOCAL)() = 0; +extern _des_crypt_call __P(( char *, int, struct desparams * )); +/* + * Copy 8 bytes + */ +#define COPY8(src, dst) { \ +	register char *a = (char *) dst; \ +	register 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) { \ +	register char *a = (char *) dst; \ +	register char *b = (char *) src; \ +	register 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; +	register unsigned len; +	unsigned mode; +	register struct desparams *desp; +{ +	register 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/lib/libc/rpc/des_soft.c b/lib/libc/rpc/des_soft.c new file mode 100644 index 000000000000..01dd7f280b2f --- /dev/null +++ b/lib/libc/rpc/des_soft.c @@ -0,0 +1,67 @@ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)des_soft.c	2.2 88/08/10 4.0 RPCSRC; from 1.13 88/02/08 SMI"; +#endif +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +/* + * 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/lib/libc/rpc/key_call.c b/lib/libc/rpc/key_call.c new file mode 100644 index 000000000000..bcef22ed8b72 --- /dev/null +++ b/lib/libc/rpc/key_call.c @@ -0,0 +1,425 @@ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc.  + */ + +#ident	"@(#)key_call.c	1.25	94/04/24 SMI" + +/* + * 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 <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 <sys/utsname.h> +#include <stdlib.h> +#include <signal.h> +#include <sys/wait.h> +#include <sys/fcntl.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 __P(( u_long, xdrproc_t, char *, xdrproc_t, char * )); + +int +key_setsecret(secretkey) +	const char *secretkey; +{ +	keystatus status; + +	if (!key_call((u_long) KEY_SET, xdr_keybuf, (char *) secretkey, +			xdr_keystatus, (char *)&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, xdr_void, (char *)NULL, +			xdr_key_netstres, (char *) &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, xdr_cryptkeyarg2, (char *)&arg, +			xdr_cryptkeyres, (char *)&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, xdr_cryptkeyarg2, (char *)&arg, +			xdr_cryptkeyres, (char *)&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, xdr_cryptkeyarg, (char *)&arg, +			xdr_cryptkeyres, (char *)&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, xdr_cryptkeyarg, (char *)&arg, +			xdr_cryptkeyres, (char *)&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, xdr_void, (char *)NULL, +			xdr_des_block, (char *)key)) { +		return (-1); +	} +	return (0); +} + +int +key_setnet(arg) +struct netstarg *arg; +{ +	keystatus status; + + +	if (!key_call((u_long) KEY_NET_PUT, xdr_key_netstarg, (char *) arg, +		xdr_keystatus, (char *) &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, xdr_keybuf, pkey, +		xdr_cryptkeyres, (char *)&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; + +#ifdef foo +static void +key_call_destroy(void *vp) +{ +	register struct key_call_private *kcp = (struct key_call_private *)vp; + +	if (kcp) { +		if (kcp->client) +			clnt_destroy(kcp->client); +		free(kcp); +	} +} +#endif + +/* + * Keep the handle cached.  This call may be made quite often. + */ +static CLIENT * +getkeyserv_handle(vers) +int	vers; +{ +	struct key_call_private *kcp = key_call_private_main; +	struct timeval wait_time; +	int fd; +	struct sockaddr_un name; +	int namelen = sizeof(struct sockaddr_un); + +#define	TOTAL_TIMEOUT	30	/* total timeout talking to keyserver */ +#define	TOTAL_TRIES	5	/* Number of tries */ + +	if (kcp == (struct key_call_private *)NULL) { +		kcp = (struct key_call_private *)malloc(sizeof (*kcp)); +		if (kcp == (struct key_call_private *)NULL) { +			return ((CLIENT *) NULL); +		} +		key_call_private_main = kcp; +		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 other side closed socket, build handle again */ +		clnt_control(kcp->client, CLGET_FD, (char *)&fd); +		if (getpeername(fd,(struct sockaddr *)&name,&namelen) == -1) { +			auth_destroy(kcp->client->cl_auth); +			clnt_destroy(kcp->client); +			kcp->client = NULL; +		} +	} + +	if (kcp->client != NULL) { +		/* if uid has changed, build client handle again */ +		if (kcp->uid != geteuid()) { +			kcp->uid = geteuid(); +			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 ((kcp->client == (CLIENT *) NULL)) +		/* Use the AF_UNIX transport */ +		kcp->client = clnt_create("/var/run/keyservsock", KEY_PROG, +							vers, "unix"); + +	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; +	char *arg; +	xdrproc_t xdr_rslt; +	char *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/lib/libc/rpc/key_prot_xdr.c b/lib/libc/rpc/key_prot_xdr.c new file mode 100644 index 000000000000..8cd6b6b0678e --- /dev/null +++ b/lib/libc/rpc/key_prot_xdr.c @@ -0,0 +1,166 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#include <rpc/key_prot.h> +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#pragma ident	"@(#)key_prot.x	1.7	94/04/29 SMI" + +/* Copyright (c)  1990, 1991 Sun Microsystems, Inc. */ + +/*  + * Compiled from key_prot.x using rpcgen. + * DO NOT EDIT THIS FILE! + * This is NOT source code! + */ + +bool_t +xdr_keystatus(register XDR *xdrs, keystatus *objp) +{ + +	if (!xdr_enum(xdrs, (enum_t *)objp)) +		return (FALSE); +	return (TRUE); +} + +bool_t +xdr_keybuf(register XDR *xdrs, keybuf objp) +{ + +	if (!xdr_opaque(xdrs, objp, HEXKEYBYTES)) +		return (FALSE); +	return (TRUE); +} + +bool_t +xdr_netnamestr(register XDR *xdrs, netnamestr *objp) +{ + +	if (!xdr_string(xdrs, objp, MAXNETNAMELEN)) +		return (FALSE); +	return (TRUE); +} + +bool_t +xdr_cryptkeyarg(register XDR *xdrs, cryptkeyarg *objp) +{ + +	if (!xdr_netnamestr(xdrs, &objp->remotename)) +		return (FALSE); +	if (!xdr_des_block(xdrs, &objp->deskey)) +		return (FALSE); +	return (TRUE); +} + +bool_t +xdr_cryptkeyarg2(register XDR *xdrs, cryptkeyarg2 *objp) +{ + +	if (!xdr_netnamestr(xdrs, &objp->remotename)) +		return (FALSE); +	if (!xdr_netobj(xdrs, &objp->remotekey)) +		return (FALSE); +	if (!xdr_des_block(xdrs, &objp->deskey)) +		return (FALSE); +	return (TRUE); +} + +bool_t +xdr_cryptkeyres(register XDR *xdrs, cryptkeyres *objp) +{ + +	if (!xdr_keystatus(xdrs, &objp->status)) +		return (FALSE); +	switch (objp->status) { +	case KEY_SUCCESS: +		if (!xdr_des_block(xdrs, &objp->cryptkeyres_u.deskey)) +			return (FALSE); +		break; +	} +	return (TRUE); +} + +bool_t +xdr_unixcred(register XDR *xdrs, unixcred *objp) +{ + +	if (!xdr_u_int(xdrs, &objp->uid)) +		return (FALSE); +	if (!xdr_u_int(xdrs, &objp->gid)) +		return (FALSE); +	if (!xdr_array(xdrs, (char **)&objp->gids.gids_val, (u_int *) &objp->gids.gids_len, MAXGIDS, +		sizeof (u_int), (xdrproc_t) xdr_u_int)) +		return (FALSE); +	return (TRUE); +} + +bool_t +xdr_getcredres(register XDR *xdrs, getcredres *objp) +{ + +	if (!xdr_keystatus(xdrs, &objp->status)) +		return (FALSE); +	switch (objp->status) { +	case KEY_SUCCESS: +		if (!xdr_unixcred(xdrs, &objp->getcredres_u.cred)) +			return (FALSE); +		break; +	} +	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; +	} +	return (TRUE); +} diff --git a/lib/libc/rpc/netname.c b/lib/libc/rpc/netname.c new file mode 100644 index 000000000000..3a3942b8a249 --- /dev/null +++ b/lib/libc/rpc/netname.c @@ -0,0 +1,136 @@ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user or with the express written consent of + * Sun Microsystems, Inc. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)netname.c 1.8 91/03/11 Copyr 1986 Sun Micro"; +#endif + +/* + * netname utility routines + * convert from unix names to network names and vice-versa + * This module is operating system dependent! + * What we define here will work with any unix system that has adopted + * the sun NIS domain architecture. + */ + +#include <sys/param.h> +#include <rpc/rpc.h> +#include <rpc/rpc_com.h> +#ifdef YP +#include <rpcsvc/yp_prot.h> +#include <rpcsvc/ypclnt.h> +#endif +#include <ctype.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdio.h> + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 256 +#endif +#ifndef NGROUPS +#define NGROUPS 16 +#endif + +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]; +	uid_t uid; +	char *domain; +{ +	char *dfltdom; + +#define MAXIPRINT	(11)	/* max length of printed integer */ + +	if (domain == NULL) { +		if (_rpc_get_default_domain(&dfltdom) != 0) { +			return (0); +		} +		domain = dfltdom; +	} +	if (strlen(domain) + 1 + MAXIPRINT > MAXNETNAMELEN) { +		return (0); +	} +	(void) sprintf(netname, "%s.%ld@%s", OPSYS, uid, domain);	 +	return (1); +} + + +/* + * Convert host to network-name + */ +int +host2netname(netname, host, domain) +	char netname[MAXNETNAMELEN + 1]; +	char *host; +	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) > MAXNETNAMELEN) { +		return (0); +	}  +	(void) sprintf(netname, "%s.%s@%s", OPSYS, host, domain); +	return (1); +} diff --git a/lib/libc/rpc/netnamer.c b/lib/libc/rpc/netnamer.c new file mode 100644 index 000000000000..391cc208e0d4 --- /dev/null +++ b/lib/libc/rpc/netnamer.c @@ -0,0 +1,326 @@ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user or with the express written consent of + * Sun Microsystems, Inc. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)netnamer.c 1.13 91/03/11 Copyr 1986 Sun Micro"; +#endif +/* + * netname utility routines convert from unix names to network names and + * vice-versa This module is operating system dependent! What we define here + * will work with any unix system that has adopted the sun NIS domain + * architecture. + */ +#include <sys/param.h> +#include <rpc/rpc.h> +#include <rpc/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> + +static char    *OPSYS = "unix"; +static char    *NETID = "netid.byname"; +static char    *NETIDFILE = "/etc/netid"; + +static int getnetid __P(( char *, char * )); +static int _getgroups __P(( char *, gid_t * )); + +#ifndef NGROUPS +#define NGROUPS 16 +#endif + +/* + * Convert network-name into unix credential + */ +int +netname2user(netname, uidp, gidp, gidlenp, gidlist) +	char            netname[MAXNETNAMELEN + 1]; +	uid_t            *uidp; +	gid_t            *gidp; +	int            *gidlenp; +	gid_t	       *gidlist; +{ +	char           *p; +	int             gidlen; +	uid_t           uid; +	struct passwd  *pwd; +	char            val[1024]; +	char           *val1, *val2; +	char           *domain; +	int             vallen; +	int             err; + +	if (getnetid(netname, val)) { +		p = strtok(val, ":"); +		if (p == NULL) +			return (0); +		*uidp = (uid_t) atol(val); +		p = strtok(NULL, "\n,"); +		*gidp = (gid_t) atol(p); +		if (p == NULL) { +			return (0); +		} +		gidlen = 0; +		for (gidlen = 0; gidlen < NGROUPS; gidlen++) { +			p = strtok(NULL, "\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 */ + +	/* XXX: uid_t have different sizes on different OS's. sigh! */ +	if (sizeof (uid_t) == sizeof (short)) { +		if (sscanf(val, "%hd", (short *)&uid) != 1) +			return (0); +	} else { +	if (sscanf(val, "%ld", &uid) != 1) +		return (0); +	} +	/* use initgroups method */ +	pwd = getpwuid(uid); +	if (pwd == NULL) +		return (0); +	*uidp = pwd->pw_uid; +	*gidp = pwd->pw_gid; +	*gidlenp = _getgroups(pwd->pw_name, gidlist); +	return (1); +} + +/* + * initgroups + */ + +static int +_getgroups(uname, groups) +	char           *uname; +	gid_t          groups[NGROUPS]; +{ +	gid_t           ngroups = 0; +	register struct group *grp; +	register int    i; +	register int    j; +	int             filter; + +	setgrent(); +	while ((grp = getgrent())) { +		for (i = 0; grp->gr_mem[i]; i++) +			if (!strcmp(grp->gr_mem[i], uname)) { +				if (ngroups == NGROUPS) { +#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 == (FILE *) 0) { +#ifdef YP +		res = "+"; +		goto getnetidyp; +#else +		return (0); +#endif +	} +	for (;;) { +		if (fd == (FILE *) 0) +			return (0);	/* getnetidyp brings us here */ +		res = fgets(buf, 1024, fd); +		if (res == 0) { +			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); +			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 = strtok(buf, "\t "); +			if (mkey == NULL) { +				fprintf(stderr, +		"Bad record in %s -- %s", NETIDFILE, buf); +				continue; +			} +			mval = strtok(NULL, " \t#\n"); +			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/lib/libc/rpc/publickey.3 b/lib/libc/rpc/publickey.3 new file mode 100644 index 000000000000..7063e8a43ccc --- /dev/null +++ b/lib/libc/rpc/publickey.3 @@ -0,0 +1,44 @@ +.\" @(#)publickey.3r	2.1 88/08/07 4.0 RPCSRC +.TH PUBLICKEY 3R  "6 October 1987" +.SH NAME +publickey, getpublickey, getsecretkey \- get public or secret key +.SH SYNOPSIS +.nf +.B #include <rpc/rpc.h> +.B #include <rpc/key_prot.h> +.LP +.B getpublickey(netname, publickey) +.B	char netname[\s-1MAXNETNAMELEN\s0+1]; +.B	char publickey[\s-1HEXKEYBYTES\s0+1]; +.LP +.B getsecretkey(netname, secretkey, passwd) +.B	char netname[\s-1MAXNETNAMELEN\s0+1]; +.B	char secretkey[\s-1HEXKEYBYTES\s0+1]; +.B	char *passwd; +.fi +.SH DESCRIPTION +.IX "getpublickey function" "" "\fLgetpublickey()\fP function" +.IX "getsecretkey function" "" "\fLgetsecretkey()\fP function" +These routines are used to get public and secret keys from the +.SM YP +database. +.B getsecretkey(\|) +has an extra argument, +.IR passwd , +which is used to decrypt the encrypted secret key stored in the database. +Both routines return 1 if they are successful in finding the key, 0 otherwise. +The keys are returned as +.SM NULL\s0-terminated, +hexadecimal strings. If the password supplied to +.B getsecretkey(\|) +fails to decrypt the secret key, the routine will return 1 but the +.I secretkey +argument will be a +.SM NULL +string (``''). +.SH "SEE ALSO" +.BR publickey (5) +.LP +.I \s-1RPC\s0 Programmer's Manual +in +.TX NETP diff --git a/lib/libc/rpc/publickey.5 b/lib/libc/rpc/publickey.5 new file mode 100644 index 000000000000..de3c1e99e779 --- /dev/null +++ b/lib/libc/rpc/publickey.5 @@ -0,0 +1,37 @@ +.\" @(#)publickey.5	2.1 88/08/07 4.0 RPCSRC; from 1.6 88/02/29 SMI; +.TH PUBLICKEY 5 "19 October 1987" +.SH NAME +publickey \- public key database +.SH SYNOPSIS +.B /etc/publickey +.SH DESCRIPTION +.LP +.B /etc/publickey +is the public key database used for secure +networking. Each entry in +the database consists of a network user +name (which may either refer to +a user or a hostname), followed by the user's +public key (in hex +notation), a colon, and then the user's +secret key encrypted with +its login password (also in hex notation). +.LP +This file is altered either by the user through the +.BR chkey (1) +command or by the system administrator through the +.BR newkey (8) +command. +The file +.B /etc/publickey +should only contain data on the Yellow +Pages master machine, where it +is converted into the +.SM YP +database +.BR publickey.byname . +.SH SEE ALSO +.BR chkey (1), +.BR publickey (3R), +.BR newkey (8), +.BR ypupdated (8C) diff --git a/lib/libc/rpc/rpc_secure.3 b/lib/libc/rpc/rpc_secure.3 new file mode 100644 index 000000000000..6e9a2ee362f8 --- /dev/null +++ b/lib/libc/rpc/rpc_secure.3 @@ -0,0 +1,330 @@ +.\" @(#)rpc_secure.3n	2.1 88/08/08 4.0 RPCSRC; from 1.19 88/06/24 SMI +.TH RPC 3N "16 February 1988" +.SH NAME +rpc_secure \- library routines for secure remote procedure calls +.SH SYNOPSIS AND DESCRIPTION +These routines are part of the RPC library.  They implement DES +Authentication.  See +.BR rpc (3N) +for further details about RPC. +.LP +.ft B +.nf +.sp .5 +#include <rpc/rpc.h> +.fi +.ft R +.br +.if t .ne 22 +.LP +.ft B +.nf +.sp .5 +\s-1AUTH\s0 * +authdes_create(name, window, syncaddr, ckey) +char *name; +unsigned window; +struct sockaddr_in *addr; +des_block *ckey; +.fi +.ft R +.IP +.B authdes_create(\|) +is the first of two routines which interface to the +.SM RPC +secure authentication system, known as +.SM DES +authentication. +The second is +.BR authdes_getucred(\|) , +below. Note: the keyserver daemon +.BR keyserv (8C) +must be running for the +.SM DES +authentication system to work. +.IP +.BR authdes_create(\|) , +used on the client side, returns an authentication handle that +will enable the use of the secure authentication system. +The first parameter +.I name +is the network name, or +.IR netname , +of the owner of the server process. This field usually +represents a +.I hostname +derived from the utility routine +.BR host2netname , +but could also represent a user name using +.BR user2netname . +The second field is window on the validity of +the client credential, given in seconds.  A small +window is more secure than a large one, but choosing +too small of a window will increase the frequency of +resynchronizations because of clock drift. The third +parameter +.I syncaddr +is optional.  If it is +.SM NULL\s0, +then the authentication system will assume +that the local clock is always in sync with the server's +clock, and will not attempt resynchronizations. If an address +is supplied, however, then the system will use the address +for consulting the remote time service whenever +resynchronization +is required. This parameter is usually the +address of the +.SM RPC +server itself. The final parameter +.I ckey +is also optional.  If it is +.SM NULL\s0, +then the authentication system will +generate a random +.SM DES +key to be used for the encryption of credentials. +If it is supplied, however, then it will be used instead. +.br +.if t .ne 13 +.LP +.ft B +.nf +.sp .5 +authdes_getucred(adc, uid, gid, grouplen, groups) +struct authdes_cred *adc; +short *uid; +short *gid; +short *grouplen; +int *groups; +.fi +.ft R +.IP +.BR authdes_getucred(\|) , +the second of the two +.SM DES +authentication routines, +is used on the server side for converting a +.SM DES +credential, which is +operating system independent, into a +.UX +credential. This routine differs from utility routine +.B netname2user +in that +.B authdes_getucred(\|) +pulls its information from a cache, and does not have to do a +Yellow Pages lookup every time it is called to get its information. +.br +.ft .ne 8 +.LP +.ft B +.nf +.sp .5 +host2netname(name, host, domain) +char *name; +char *host; +char *domain; +.fi +.ft R +.IP +Convert from a domain-specific hostname to an +operating-system independent netname. Return +.SM TRUE +if it succeeds and +.SM FALSE +if it fails. Inverse of +.BR netname2host(\|) . +.br +.if t .ne 9 +.LP +.ft B +.nf +.sp .5 +key_decryptsession(remotename, deskey) +char *remotename; +des_block *deskey; +.fi +.ft R +.IP +.B key_decryptsession(\|) +is an interface to the keyserver daemon, which is associated +with +.SM RPC\s0's +secure authentication system (\s-1DES\s0 +authentication). +User programs rarely need to call it, or its associated routines +.BR key_encryptsession(\|) , +.B key_gendes(\|) +and +.BR key_setsecret(\|) . +System commands such as +.B login +and the +.SM RPC +library are the main clients of these four routines. +.IP +.B key_decryptsession(\|) +takes a server netname and a des key, and decrypts the key by +using the the public key of the the server and the secret key +associated with the effective uid of the calling process.  It +is the inverse of +.BR key_encryptsession(\|) . +.br +.if t .ne 8 +.LP +.ft B +.nf +.sp .5 +key_encryptsession(remotename, deskey) +char *remotename; +des_block *deskey; +.fi +.ft R +.IP +.B key_encryptsession(\|) +is a keyserver interface routine. It +takes a server netname and a des key, and encrypts +it using the public key of the the server and the secret key +associated with the effective uid of the calling process.  It +is the inverse of +.BR key_decryptsession(\|) . +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +key_gendes(deskey) +des_block *deskey; +.fi +.ft R +.IP +.B key_gendes(\|) +is a keyserver interface routine. It +is used to ask the keyserver for a secure conversation key. +Choosing one at \(lqrandom\(rq is usually not good enough, +because +the common ways of choosing random numbers, such as using the +current time, are very easy to guess. +.br +.if t .ne 6 +.LP +.ft B +.nf +.sp .5 +key_setsecret(key) +char *key; +.fi +.ft R +.IP +.B key_setsecret(\|) +is a keyserver interface routine. It is used to set the key for +the effective +.I uid +of the calling process. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +getnetname(name) +char name[\s-1MAXNETNAMELEN\s0]; +.fi +.ft R +.IP +.B getnetname(\|) +installs the unique, operating-system independent netname of +the +caller in the fixed-length array +.IR name . +Returns +.SM TRUE +if it succeeds and +.SM FALSE +if it fails. +.br +.if t .ne 6 +.LP +.ft B +.nf +.sp .5 +netname2host(name, host, hostlen) +char *name; +char *host; +int hostlen; +.fi +.ft R +.IP +Convert from an operating-system independent netname to a +domain-specific hostname. Returns +.SM TRUE +if it succeeds and +.SM FALSE +if it fails.  Inverse of +.BR host2netname(\|) . +.br +.if t .ne 9 +.LP +.ft B +.nf +.sp .5 +netname2user(name, uidp, gidp, gidlenp, gidlist) +char *name; +int *uidp; +int *gidp; +int *gidlenp; +int *gidlist; +.fi +.ft R +.IP +Convert from an operating-system independent netname to a +domain-specific user +.SM ID. +Returns +.SM TRUE +if it succeeds and +.SM FALSE +if it fails. Inverse of +.BR user2netname(\|) . +.br +.if t .ne 8 +.LP +.ft B +.nf +.sp .5 +user2netname(name, uid, domain) +char *name; +int uid; +char *domain; +.fi +.ft R +.IP +Convert from a domain-specific username to an operating-system +independent netname. Returns +.SM TRUE +if it succeeds and +.SM FALSE +if it fails. Inverse of +.BR netname2user(\|) . +.br +.SH SEE ALSO +.BR xdr (3N), +.BR keyserv (8C), +.BR rpc (3N) +.br +The following manuals: +.RS +.ft I +Remote Procedure Calls: Protocol Specification +.br +Remote Procedure Call Programming Guide +.br +rpcgen Programming Guide +.br +.ft R +.RE +.IR "\s-1RPC\s0: Remote Procedure Call Protocol Specification" , +.SM RFC1050, Sun Microsystems, Inc., +.SM USC-ISI\s0. + diff --git a/lib/libc/rpc/rpcdname.c b/lib/libc/rpc/rpcdname.c new file mode 100644 index 000000000000..f28b4fda9b8a --- /dev/null +++ b/lib/libc/rpc/rpcdname.c @@ -0,0 +1,77 @@ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user or with the express written consent of + * Sun Microsystems, Inc. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)rpcdname.c 1.7 91/03/11 Copyr 1989 Sun Micro"; +#endif + +/* + * rpcdname.c + * Gets the default domain name + */ + +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +static char *default_domain = 0; + +static char * +get_default_domain() +{ +	char temp[256]; + +	if (default_domain) +		return (default_domain); +	if (getdomainname(temp, sizeof(temp)) < 0) +		return (0); +	if ((int) strlen(temp) > 0) { +		default_domain = (char *)malloc((strlen(temp)+(unsigned)1)); +		if (default_domain == 0) +			return (0); +		(void) strcpy(default_domain, temp); +		return (default_domain); +	} +	return (0); +} + +/* + * This is a wrapper for the system call getdomainname which returns a + * ypclnt.h error code in the failure case.  It also checks to see that + * the domain name is non-null, knowing that the null string is going to + * get rejected elsewhere in the NIS client package. + */ +int +_rpc_get_default_domain(domain) +	char **domain; +{ +	if ((*domain = get_default_domain()) != 0) +		return (0); +	return (-1); +} diff --git a/lib/libc/rpc/rtime.3 b/lib/libc/rpc/rtime.3 new file mode 100644 index 000000000000..af0c1ca15960 --- /dev/null +++ b/lib/libc/rpc/rtime.3 @@ -0,0 +1,43 @@ +.\" @(#)rtime.3n	2.1 88/08/08 4.0 RPCSRC; from 1.5 88/02/08 SMI +.TH RTIME 3  "22 November 1987" +.SH NAME +rtime \- get remote time +.SH SYNOPSIS +.nf +.B #include <sys/types.h> +.B #include <sys/time.h> +.B #include <netinet/in.h> +.LP +.B int rtime(addrp, timep, timeout) +.B struct sockaddr_in \(**addrp; +.B struct timeval \(**timep; +.B struct timeval \(**timeout; +.fi +.SH DESCRIPTION +.B rtime(\|) +consults the Internet Time Server at the address pointed to by +.I addrp +and returns the remote time in the +.B timeval +struct pointed to by +.IR timep . +Normally, the +.SM UDP +protocol is used when consulting the Time Server. The +.I timeout +parameter specifies how long the +routine should wait before giving +up when waiting for a reply.  If +.I timeout +is specified as +.SM NULL\s0, +however, the routine will instead use +.SM TCP +and block until a reply is received from the time server. +.LP +The routine returns 0 if it is successful. Otherwise, +it returns \-1 and +.B errno +is set to reflect the cause of the error. +.SH "SEE ALSO" +.BR timed (8c) diff --git a/lib/libc/rpc/rtime.c b/lib/libc/rpc/rtime.c new file mode 100644 index 000000000000..fb2b4021f5f1 --- /dev/null +++ b/lib/libc/rpc/rtime.c @@ -0,0 +1,157 @@ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * Copyright (c) 1988 by Sun Microsystems, Inc. + + */ + +/* + * 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 <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> + +#if defined(LIBC_SCCS) && !defined(lint) +/* from: static char sccsid[] = 	"@(#)rtime.c	2.2 88/08/10 4.0 RPCSRC; from 1.8 88/02/08 SMI"; */ +static const char rcsid[] = "$Id$"; +#endif + +extern int _rpc_dtablesize __P(( void )); + +#define NYEARS	(unsigned long)(1970 - 1900) +#define TOFFSET (unsigned long)(60*60*24*(365*NYEARS + (NYEARS/4))) + +static void do_close __P(( 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; +	int 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/lib/libc/rpc/svc_auth_des.c b/lib/libc/rpc/svc_auth_des.c new file mode 100644 index 000000000000..889182e6992f --- /dev/null +++ b/lib/libc/rpc/svc_auth_des.c @@ -0,0 +1,531 @@ + +/* + * Copyright (c) 1988 by Sun Microsystems, Inc. + */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * 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 <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <rpc/des_crypt.h> +#include <sys/param.h> +#include <netinet/in.h> +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <rpc/auth.h> +#include <rpc/auth_des.h> +#include <rpc/svc.h> +#include <rpc/rpc_msg.h> +#include <rpc/svc_auth.h> + +#if defined(LIBC_SCCS) && !defined(lint) +/* from: static char sccsid[] = 	"@(#)svcauth_des.c	2.3 89/07/11 4.0 RPCSRC; from 1.15 88/02/08 SMI"; */ +static const char rcsid[] = "$Id$"; +#endif + +#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) +	register struct svc_req *rqst; +	register struct rpc_msg *msg; +{ + +	register long *ixdr; +	des_block cryptbuf[2]; +	register struct authdes_cred *cred; +	struct authdes_verf verf; +	int status; +	register 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 >= 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() +{ +	register 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) +	register short sid; +{ +	register int i; +	register short curr; +	register 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) +	register des_block *key; +	char *name; +	struct timeval *timestamp; +{ +	register struct cache_entry *cp; +	register int i; +	register 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 { +	short uid;		/* cached uid */ +	short gid;		/* cached gid */ +	short grouplen;	/* length of cached groups */ +	short groups[NGROUPS];	/* cached groups */ +}; + +/* + * Map a des credential into a unix cred. + * We cache the credential here so the application does + * not have to make an rpc call every time to interpret + * the credential. + */ +int +authdes_getucred(adc, uid, gid, grouplen, groups) +	struct authdes_cred *adc; +	uid_t *uid; +	gid_t *gid; +	int *grouplen; +	register gid_t *groups; +{ +	unsigned sid; +	register 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/lib/libc/rpc/svc_unix.c b/lib/libc/rpc/svc_unix.c new file mode 100644 index 000000000000..04e3223d2eeb --- /dev/null +++ b/lib/libc/rpc/svc_unix.c @@ -0,0 +1,511 @@ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +#if defined(LIBC_SCCS) && !defined(lint) +/*static char *sccsid = "from: @(#)svc_unix.c 1.21 87/08/11 Copyr 1984 Sun Micro";*/ +/*static char *sccsid = "from: @(#)svc_unix.c	2.2 88/08/01 4.0 RPCSRC";*/ +static char *rcsid = "$Id: svc_unix.c,v 1.8 1996/12/30 15:19:08 peter Exp $"; +#endif + +/* + * svc_unix.c, Server side for TCP/IP based RPC. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * Actually implements two flavors of transporter - + * a unix rendezvouser (a listner and connection establisher) + * and a record/unix stream. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <rpc/rpc.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/uio.h> +#include <errno.h> + +/* + * Ops vector for AF_UNIX based rpc service handle + */ +static bool_t		svcunix_recv(); +static enum xprt_stat	svcunix_stat(); +static bool_t		svcunix_getargs(); +static bool_t		svcunix_reply(); +static bool_t		svcunix_freeargs(); +static void		svcunix_destroy(); + +static struct xp_ops svcunix_op = { +	svcunix_recv, +	svcunix_stat, +	svcunix_getargs, +	svcunix_reply, +	svcunix_freeargs, +	svcunix_destroy +}; + +/* + * Ops vector for TCP/IP rendezvous handler + */ +static bool_t		rendezvous_request(); +static enum xprt_stat	rendezvous_stat(); + +static struct xp_ops svcunix_rendezvous_op = { +	rendezvous_request, +	rendezvous_stat, +	(bool_t (*)())abort, +	(bool_t (*)())abort, +	(bool_t (*)())abort, +	svcunix_destroy +}; + +static int readunix(), writeunix(); +static SVCXPRT *makefd_xprt(); + +struct unix_rendezvous { /* kept in xprt->xp_p1 */ +	u_int sendsize; +	u_int recvsize; +}; + +struct unix_conn {  /* kept in xprt->xp_p1 */ +	enum xprt_stat strm_stat; +	u_long x_id; +	XDR xdrs; +	char verf_body[MAX_AUTH_BYTES]; +}; + + +struct cmessage { +	struct cmsghdr cmsg; +	struct cmsgcred cmcred; +}; + +static struct cmessage cm; + +static int __msgread(sock, buf, cnt) +	int sock; +	void *buf; +	size_t cnt; +{ +	struct iovec iov[1]; +	struct msghdr msg; + +	bzero((char *)&cm, sizeof(cm)); +	iov[0].iov_base = buf; +	iov[0].iov_len = cnt; + +	msg.msg_iov = iov; +	msg.msg_iovlen = 1; +	msg.msg_name = NULL; +	msg.msg_namelen = 0; +	msg.msg_control = (caddr_t)&cm; +	msg.msg_controllen = sizeof(struct cmessage); +	msg.msg_flags = 0; + +	return(recvmsg(sock, &msg, 0)); +} + +static int __msgwrite(sock, buf, cnt) +	int sock; +	void *buf; +	size_t cnt; +{ +	struct iovec iov[1]; +	struct msghdr msg; + +	bzero((char *)&cm, sizeof(cm)); +	iov[0].iov_base = buf; +	iov[0].iov_len = cnt; + +	cm.cmsg.cmsg_type = SCM_CREDS; +	cm.cmsg.cmsg_level = SOL_SOCKET; +	cm.cmsg.cmsg_len = sizeof(struct cmessage); + +	msg.msg_iov = iov; +	msg.msg_iovlen = 1; +	msg.msg_name = NULL; +	msg.msg_namelen = 0; +	msg.msg_control = (caddr_t)&cm; +	msg.msg_controllen = sizeof(struct cmessage); +	msg.msg_flags = 0; + +	return(sendmsg(sock, &msg, 0)); +} + +/* + * Usage: + *	xprt = svcunix_create(sock, send_buf_size, recv_buf_size); + * + * Creates, registers, and returns a (rpc) unix based transporter. + * Once *xprt is initialized, it is registered as a transporter + * see (svc.h, xprt_register).  This routine returns + * a NULL if a problem occurred. + * + * If sock<0 then a socket is created, else sock is used. + * If the socket, sock is not bound to a port then svcunix_create + * binds it to an arbitrary port.  The routine then starts a unix + * listener on the socket's associated port.  In any (successful) case, + * xprt->xp_sock is the registered socket number and xprt->xp_port is the + * associated port number. + * + * Since unix streams do buffered io similar to stdio, the caller can specify + * how big the send and receive buffers are via the second and third parms; + * 0 => use the system default. + */ +SVCXPRT * +svcunix_create(sock, sendsize, recvsize, path) +	register int sock; +	u_int sendsize; +	u_int recvsize; +	char *path; +{ +	bool_t madesock = FALSE; +	register SVCXPRT *xprt; +	register struct unix_rendezvous *r; +	struct sockaddr_un addr; +	int len = sizeof(struct sockaddr_un); + +	if (sock == RPC_ANYSOCK) { +		if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { +			perror("svc_unix.c - AF_UNIX socket creation problem"); +			return ((SVCXPRT *)NULL); +		} +		madesock = TRUE; +	} +	memset(&addr, 0, sizeof (addr)); +	addr.sun_family = AF_UNIX; +	strcpy(addr.sun_path, path); +	len = strlen(addr.sun_path) + sizeof(addr.sun_family) + +		sizeof(addr.sun_len) + 1; +	addr.sun_len = len; + +	bind(sock, (struct sockaddr *)&addr, len); + +	if ((getsockname(sock, (struct sockaddr *)&addr, &len) != 0)  || +	    (listen(sock, 2) != 0)) { +		perror("svc_unix.c - cannot getsockname or listen"); +		if (madesock) +		       (void)close(sock); +		return ((SVCXPRT *)NULL); +	} +	r = (struct unix_rendezvous *)mem_alloc(sizeof(*r)); +	if (r == NULL) { +		(void) fprintf(stderr, "svcunix_create: out of memory\n"); +		return (NULL); +	} +	r->sendsize = sendsize; +	r->recvsize = recvsize; +	xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT)); +	if (xprt == NULL) { +		(void) fprintf(stderr, "svcunix_create: out of memory\n"); +		return (NULL); +	} +	xprt->xp_p2 = NULL; +	xprt->xp_p1 = (caddr_t)r; +	xprt->xp_verf = _null_auth; +	xprt->xp_ops = &svcunix_rendezvous_op; +	xprt->xp_port = -1 /*ntohs(addr.sin_port)*/; +	xprt->xp_sock = sock; +	xprt_register(xprt); +	return (xprt); +} + +/* + * Like svunix_create(), except the routine takes any *open* UNIX file + * descriptor as its first input. + */ +SVCXPRT * +svcunixfd_create(fd, sendsize, recvsize) +	int fd; +	u_int sendsize; +	u_int recvsize; +{ + +	return (makefd_xprt(fd, sendsize, recvsize)); +} + +static SVCXPRT * +makefd_xprt(fd, sendsize, recvsize) +	int fd; +	u_int sendsize; +	u_int recvsize; +{ +	register SVCXPRT *xprt; +	register struct unix_conn *cd; + +	xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT)); +	if (xprt == (SVCXPRT *)NULL) { +		(void) fprintf(stderr, "svc_unix: makefd_xprt: out of memory\n"); +		goto done; +	} +	cd = (struct unix_conn *)mem_alloc(sizeof(struct unix_conn)); +	if (cd == (struct unix_conn *)NULL) { +		(void) fprintf(stderr, "svc_unix: makefd_xprt: out of memory\n"); +		mem_free((char *) xprt, sizeof(SVCXPRT)); +		xprt = (SVCXPRT *)NULL; +		goto done; +	} +	cd->strm_stat = XPRT_IDLE; +	xdrrec_create(&(cd->xdrs), sendsize, recvsize, +	    (caddr_t)xprt, readunix, writeunix); +	xprt->xp_p2 = NULL; +	xprt->xp_p1 = (caddr_t)cd; +	xprt->xp_verf.oa_base = cd->verf_body; +	xprt->xp_addrlen = 0; +	xprt->xp_ops = &svcunix_op;  /* truely deals with calls */ +	xprt->xp_port = 0;  /* this is a connection, not a rendezvouser */ +	xprt->xp_sock = fd; +	xprt_register(xprt); +    done: +	return (xprt); +} + +static bool_t +rendezvous_request(xprt) +	register SVCXPRT *xprt; +{ +	int sock; +	struct unix_rendezvous *r; +	struct sockaddr_un addr; +	struct sockaddr_in in_addr; +	int len; + +	r = (struct unix_rendezvous *)xprt->xp_p1; +    again: +	len = sizeof(struct sockaddr_in); +	if ((sock = accept(xprt->xp_sock, (struct sockaddr *)&addr, +	    &len)) < 0) { +		if (errno == EINTR) +			goto again; +	       return (FALSE); +	} + +	/* +	 * make a new transporter (re-uses xprt) +	 */ +	bzero((char *)&in_addr, sizeof(in_addr)); +	in_addr.sin_family = AF_UNIX; +	xprt = makefd_xprt(sock, r->sendsize, r->recvsize); +	xprt->xp_raddr = in_addr; +	xprt->xp_addrlen = len; +	return (FALSE); /* there is never an rpc msg to be processed */ +} + +static enum xprt_stat +rendezvous_stat() +{ + +	return (XPRT_IDLE); +} + +static void +svcunix_destroy(xprt) +	register SVCXPRT *xprt; +{ +	register struct unix_conn *cd = (struct unix_conn *)xprt->xp_p1; + +	xprt_unregister(xprt); +	(void)close(xprt->xp_sock); +	if (xprt->xp_port != 0) { +		/* a rendezvouser socket */ +		xprt->xp_port = 0; +	} else { +		/* an actual connection socket */ +		XDR_DESTROY(&(cd->xdrs)); +	} +	mem_free((caddr_t)cd, sizeof(struct unix_conn)); +	mem_free((caddr_t)xprt, sizeof(SVCXPRT)); +} + +/* + * All read operations timeout after 35 seconds. + * A timeout is fatal for the connection. + */ +static struct timeval wait_per_try = { 35, 0 }; + +/* + * reads data from the unix conection. + * any error is fatal and the connection is closed. + * (And a read of zero bytes is a half closed stream => error.) + */ +static int +readunix(xprt, buf, len) +	register SVCXPRT *xprt; +	caddr_t buf; +	register int len; +{ +	register int sock = xprt->xp_sock; +	struct timeval start, delta, tv; +	struct timeval tmp1, tmp2; +	fd_set *fds, readfds; + +	if (sock + 1 > FD_SETSIZE) { +		int bytes = howmany(sock+1, NFDBITS) * sizeof(fd_mask); +		fds = (fd_set *)malloc(bytes); + +		if (fds == NULL) +			goto fatal_err; +		memset(fds, 0, bytes); +	} else { +		fds = &readfds; +		FD_ZERO(fds); +	} + +	delta = wait_per_try; +	gettimeofday(&start, NULL); +	do { +		/* XXX we know the other bits are still clear */ +		FD_SET(sock, fds); +		tv = delta;	/* in case select() implements writeback */ +		switch (select(sock + 1, fds, NULL, NULL, &tv)) { +		case -1: +			if (errno != EINTR) +				goto fatal_err; +			gettimeofday(&tmp1, NULL); +			timersub(&tmp1, &start, &tmp2); +			timersub(&delta, &tmp2, &tmp1); +			if (tmp1.tv_sec < 0 || !timerisset(&tmp1)) +				goto fatal_err; +			delta = tmp1; +			continue; +		case 0: +			goto fatal_err; +		} +	} while (!FD_ISSET(sock, fds)); +	if ((len = __msgread(sock, buf, len)) > 0) { +		if (fds != &readfds) +			free(fds); +		return (len); +	} +fatal_err: +	((struct unix_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED; +	if (fds != &readfds) +		free(fds); +	return (-1); +} + +/* + * writes data to the unix connection. + * Any error is fatal and the connection is closed. + */ +static int +writeunix(xprt, buf, len) +	register SVCXPRT *xprt; +	caddr_t buf; +	int len; +{ +	register int i, cnt; + +	for (cnt = len; cnt > 0; cnt -= i, buf += i) { +		if ((i = __msgwrite(xprt->xp_sock, buf, cnt)) < 0) { +			((struct unix_conn *)(xprt->xp_p1))->strm_stat = +			    XPRT_DIED; +			return (-1); +		} +	} +	return (len); +} + +static enum xprt_stat +svcunix_stat(xprt) +	SVCXPRT *xprt; +{ +	register struct unix_conn *cd = +	    (struct unix_conn *)(xprt->xp_p1); + +	if (cd->strm_stat == XPRT_DIED) +		return (XPRT_DIED); +	if (! xdrrec_eof(&(cd->xdrs))) +		return (XPRT_MOREREQS); +	return (XPRT_IDLE); +} + +static bool_t +svcunix_recv(xprt, msg) +	SVCXPRT *xprt; +	register struct rpc_msg *msg; +{ +	register struct unix_conn *cd = +	    (struct unix_conn *)(xprt->xp_p1); +	register XDR *xdrs = &(cd->xdrs); + +	xdrs->x_op = XDR_DECODE; +	(void)xdrrec_skiprecord(xdrs); +	if (xdr_callmsg(xdrs, msg)) { +		cd->x_id = msg->rm_xid; +		/* set up verifiers */ +		msg->rm_call.cb_verf.oa_flavor = AUTH_UNIX; +		msg->rm_call.cb_verf.oa_base = (caddr_t)&cm; +		msg->rm_call.cb_verf.oa_length = sizeof(cm); +		return (TRUE); +	} +	return (FALSE); +} + +static bool_t +svcunix_getargs(xprt, xdr_args, args_ptr) +	SVCXPRT *xprt; +	xdrproc_t xdr_args; +	caddr_t args_ptr; +{ + +	return ((*xdr_args)(&(((struct unix_conn *)(xprt->xp_p1))->xdrs), args_ptr)); +} + +static bool_t +svcunix_freeargs(xprt, xdr_args, args_ptr) +	SVCXPRT *xprt; +	xdrproc_t xdr_args; +	caddr_t args_ptr; +{ +	register XDR *xdrs = +	    &(((struct unix_conn *)(xprt->xp_p1))->xdrs); + +	xdrs->x_op = XDR_FREE; +	return ((*xdr_args)(xdrs, args_ptr)); +} + +static bool_t +svcunix_reply(xprt, msg) +	SVCXPRT *xprt; +	register struct rpc_msg *msg; +{ +	register struct unix_conn *cd = +	    (struct unix_conn *)(xprt->xp_p1); +	register XDR *xdrs = &(cd->xdrs); +	register bool_t stat; + +	xdrs->x_op = XDR_ENCODE; +	msg->rm_xid = cd->x_id; +	stat = xdr_replymsg(xdrs, msg); +	(void)xdrrec_endofrecord(xdrs, TRUE); +	return (stat); +} | 
