Index: stable/10/lib/libc/rpc/auth_des.c =================================================================== --- stable/10/lib/libc/rpc/auth_des.c (revision 309488) +++ stable/10/lib/libc/rpc/auth_des.c (revision 309489) @@ -1,497 +1,497 @@ /*- * Copyright (c) 2009, Sun Microsystems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of Sun Microsystems, Inc. nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright (c) 1988 by Sun Microsystems, Inc. */ /* * auth_des.c, client-side implementation of DES authentication */ #include "namespace.h" #include "reentrant.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #undef NIS #include #include "un-namespace.h" #include "mt_misc.h" #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)auth_des.c 2.2 88/07/29 4.0 RPCSRC; from 1.9 88/02/08 SMI"; #endif #include __FBSDID("$FreeBSD$"); #define USEC_PER_SEC 1000000 #define RTIME_TIMEOUT 5 /* seconds to wait for sync */ #define AUTH_PRIVATE(auth) (struct ad_private *) auth->ah_private #define ALLOC(object_type) (object_type *) mem_alloc(sizeof(object_type)) #define FREE(ptr, size) mem_free((char *)(ptr), (int) size) #define ATTEMPT(xdr_op) if (!(xdr_op)) return (FALSE) extern bool_t xdr_authdes_cred( XDR *, struct authdes_cred *); extern bool_t xdr_authdes_verf( XDR *, struct authdes_verf *); extern int key_encryptsession_pk(char *, netobj *, des_block *); extern bool_t __rpc_get_time_offset(struct timeval *, nis_server *, char *, char **, char **); /* * DES authenticator operations vector */ static void authdes_nextverf(AUTH *); static bool_t authdes_marshal(AUTH *, XDR *); static bool_t authdes_validate(AUTH *, struct opaque_auth *); static bool_t authdes_refresh(AUTH *, void *); static void authdes_destroy(AUTH *); static struct auth_ops *authdes_ops(void); /* * This struct is pointed to by the ah_private field of an "AUTH *" */ struct ad_private { char *ad_fullname; /* client's full name */ u_int ad_fullnamelen; /* length of name, rounded up */ char *ad_servername; /* server's full name */ u_int ad_servernamelen; /* length of name, rounded up */ u_int ad_window; /* client specified window */ bool_t ad_dosync; /* synchronize? */ struct netbuf ad_syncaddr; /* remote host to synch with */ char *ad_timehost; /* remote host to synch with */ struct timeval ad_timediff; /* server's time - client's time */ u_int ad_nickname; /* server's nickname for client */ struct authdes_cred ad_cred; /* storage for credential */ struct authdes_verf ad_verf; /* storage for verifier */ struct timeval ad_timestamp; /* timestamp sent */ des_block ad_xkey; /* encrypted conversation key */ u_char ad_pkey[1024]; /* Server's actual public key */ char *ad_netid; /* Timehost netid */ char *ad_uaddr; /* Timehost uaddr */ nis_server *ad_nis_srvr; /* NIS+ server struct */ }; AUTH *authdes_pk_seccreate(const char *, netobj *, u_int, const char *, const des_block *, nis_server *); /* * documented version of authdes_seccreate */ /* servername: network name of server win: time to live timehost: optional hostname to sync with ckey: optional conversation key to use */ AUTH * authdes_seccreate(const char *servername, const u_int win, const char *timehost, const des_block *ckey) { u_char pkey_data[1024]; netobj pkey; AUTH *dummy; if (! getpublickey(servername, (char *) pkey_data)) { syslog(LOG_ERR, "authdes_seccreate: no public key found for %s", servername); return (NULL); } pkey.n_bytes = (char *) pkey_data; pkey.n_len = (u_int)strlen((char *)pkey_data) + 1; dummy = authdes_pk_seccreate(servername, &pkey, win, timehost, ckey, NULL); return (dummy); } /* * Slightly modified version of authdessec_create which takes the public key * of the server principal as an argument. This spares us a call to * getpublickey() which in the nameserver context can cause a deadlock. */ AUTH * authdes_pk_seccreate(const char *servername, netobj *pkey, u_int window, const char *timehost, const des_block *ckey, nis_server *srvr) { AUTH *auth; struct ad_private *ad; char namebuf[MAXNETNAMELEN+1]; /* * Allocate everything now */ auth = ALLOC(AUTH); if (auth == NULL) { syslog(LOG_ERR, "authdes_pk_seccreate: out of memory"); return (NULL); } ad = ALLOC(struct ad_private); if (ad == NULL) { syslog(LOG_ERR, "authdes_pk_seccreate: out of memory"); goto failed; } ad->ad_fullname = ad->ad_servername = NULL; /* Sanity reasons */ ad->ad_timehost = NULL; ad->ad_netid = NULL; ad->ad_uaddr = NULL; ad->ad_nis_srvr = NULL; ad->ad_timediff.tv_sec = 0; ad->ad_timediff.tv_usec = 0; memcpy(ad->ad_pkey, pkey->n_bytes, pkey->n_len); if (!getnetname(namebuf)) goto failed; ad->ad_fullnamelen = RNDUP((u_int) strlen(namebuf)); ad->ad_fullname = (char *)mem_alloc(ad->ad_fullnamelen + 1); ad->ad_servernamelen = strlen(servername); ad->ad_servername = (char *)mem_alloc(ad->ad_servernamelen + 1); if (ad->ad_fullname == NULL || ad->ad_servername == NULL) { syslog(LOG_ERR, "authdes_seccreate: out of memory"); goto failed; } if (timehost != NULL) { ad->ad_timehost = (char *)mem_alloc(strlen(timehost) + 1); if (ad->ad_timehost == NULL) { syslog(LOG_ERR, "authdes_seccreate: out of memory"); goto failed; } memcpy(ad->ad_timehost, timehost, strlen(timehost) + 1); ad->ad_dosync = TRUE; } else if (srvr != NULL) { ad->ad_nis_srvr = srvr; /* transient */ ad->ad_dosync = TRUE; } else { ad->ad_dosync = FALSE; } memcpy(ad->ad_fullname, namebuf, ad->ad_fullnamelen + 1); memcpy(ad->ad_servername, servername, ad->ad_servernamelen + 1); ad->ad_window = window; if (ckey == NULL) { if (key_gendes(&auth->ah_key) < 0) { syslog(LOG_ERR, "authdes_seccreate: keyserv(1m) is unable to generate session key"); goto failed; } } else { auth->ah_key = *ckey; } /* * Set up auth handle */ auth->ah_cred.oa_flavor = AUTH_DES; auth->ah_verf.oa_flavor = AUTH_DES; auth->ah_ops = authdes_ops(); auth->ah_private = (caddr_t)ad; if (!authdes_refresh(auth, NULL)) { goto failed; } ad->ad_nis_srvr = NULL; /* not needed any longer */ return (auth); failed: if (auth) FREE(auth, sizeof (AUTH)); if (ad) { if (ad->ad_fullname) FREE(ad->ad_fullname, ad->ad_fullnamelen + 1); if (ad->ad_servername) FREE(ad->ad_servername, ad->ad_servernamelen + 1); if (ad->ad_timehost) FREE(ad->ad_timehost, strlen(ad->ad_timehost) + 1); if (ad->ad_netid) FREE(ad->ad_netid, strlen(ad->ad_netid) + 1); if (ad->ad_uaddr) FREE(ad->ad_uaddr, strlen(ad->ad_uaddr) + 1); FREE(ad, sizeof (struct ad_private)); } return (NULL); } /* * Implement the five authentication operations */ /* * 1. Next Verifier */ /*ARGSUSED*/ static void -authdes_nextverf(AUTH *auth) +authdes_nextverf(AUTH *auth __unused) { /* what the heck am I supposed to do??? */ } /* * 2. Marshal */ static bool_t authdes_marshal(AUTH *auth, XDR *xdrs) { /* LINTED pointer alignment */ struct ad_private *ad = AUTH_PRIVATE(auth); struct authdes_cred *cred = &ad->ad_cred; struct authdes_verf *verf = &ad->ad_verf; des_block cryptbuf[2]; des_block ivec; int status; int len; rpc_inline_t *ixdr; /* * Figure out the "time", accounting for any time difference * with the server if necessary. */ (void)gettimeofday(&ad->ad_timestamp, NULL); ad->ad_timestamp.tv_sec += ad->ad_timediff.tv_sec; ad->ad_timestamp.tv_usec += ad->ad_timediff.tv_usec; while (ad->ad_timestamp.tv_usec >= USEC_PER_SEC) { ad->ad_timestamp.tv_usec -= USEC_PER_SEC; ad->ad_timestamp.tv_sec++; } /* * XDR the timestamp and possibly some other things, then * encrypt them. */ ixdr = (rpc_inline_t *)cryptbuf; IXDR_PUT_INT32(ixdr, ad->ad_timestamp.tv_sec); IXDR_PUT_INT32(ixdr, ad->ad_timestamp.tv_usec); if (ad->ad_cred.adc_namekind == ADN_FULLNAME) { IXDR_PUT_U_INT32(ixdr, ad->ad_window); IXDR_PUT_U_INT32(ixdr, ad->ad_window - 1); ivec.key.high = ivec.key.low = 0; status = cbc_crypt((char *)&auth->ah_key, (char *)cryptbuf, (u_int) 2 * sizeof (des_block), DES_ENCRYPT | DES_HW, (char *)&ivec); } else { status = ecb_crypt((char *)&auth->ah_key, (char *)cryptbuf, (u_int) sizeof (des_block), DES_ENCRYPT | DES_HW); } if (DES_FAILED(status)) { syslog(LOG_ERR, "authdes_marshal: DES encryption failure"); return (FALSE); } ad->ad_verf.adv_xtimestamp = cryptbuf[0]; if (ad->ad_cred.adc_namekind == ADN_FULLNAME) { ad->ad_cred.adc_fullname.window = cryptbuf[1].key.high; ad->ad_verf.adv_winverf = cryptbuf[1].key.low; } else { ad->ad_cred.adc_nickname = ad->ad_nickname; ad->ad_verf.adv_winverf = 0; } /* * Serialize the credential and verifier into opaque * authentication data. */ if (ad->ad_cred.adc_namekind == ADN_FULLNAME) { len = ((1 + 1 + 2 + 1)*BYTES_PER_XDR_UNIT + ad->ad_fullnamelen); } else { len = (1 + 1)*BYTES_PER_XDR_UNIT; } if ((ixdr = xdr_inline(xdrs, 2*BYTES_PER_XDR_UNIT))) { IXDR_PUT_INT32(ixdr, AUTH_DES); IXDR_PUT_INT32(ixdr, len); } else { ATTEMPT(xdr_putint32(xdrs, (int *)&auth->ah_cred.oa_flavor)); ATTEMPT(xdr_putint32(xdrs, &len)); } ATTEMPT(xdr_authdes_cred(xdrs, cred)); len = (2 + 1)*BYTES_PER_XDR_UNIT; if ((ixdr = xdr_inline(xdrs, 2*BYTES_PER_XDR_UNIT))) { IXDR_PUT_INT32(ixdr, AUTH_DES); IXDR_PUT_INT32(ixdr, len); } else { ATTEMPT(xdr_putint32(xdrs, (int *)&auth->ah_verf.oa_flavor)); ATTEMPT(xdr_putint32(xdrs, &len)); } ATTEMPT(xdr_authdes_verf(xdrs, verf)); return (TRUE); } /* * 3. Validate */ static bool_t authdes_validate(AUTH *auth, struct opaque_auth *rverf) { /* LINTED pointer alignment */ struct ad_private *ad = AUTH_PRIVATE(auth); struct authdes_verf verf; int status; uint32_t *ixdr; des_block buf; if (rverf->oa_length != (2 + 1) * BYTES_PER_XDR_UNIT) { return (FALSE); } /* LINTED pointer alignment */ ixdr = (uint32_t *)rverf->oa_base; buf.key.high = (uint32_t)*ixdr++; buf.key.low = (uint32_t)*ixdr++; verf.adv_int_u = (uint32_t)*ixdr++; /* * Decrypt the timestamp */ status = ecb_crypt((char *)&auth->ah_key, (char *)&buf, (u_int)sizeof (des_block), DES_DECRYPT | DES_HW); if (DES_FAILED(status)) { syslog(LOG_ERR, "authdes_validate: DES decryption failure"); return (FALSE); } /* * xdr the decrypted timestamp */ /* LINTED pointer alignment */ ixdr = (uint32_t *)buf.c; verf.adv_timestamp.tv_sec = IXDR_GET_INT32(ixdr) + 1; verf.adv_timestamp.tv_usec = IXDR_GET_INT32(ixdr); /* * validate */ if (bcmp((char *)&ad->ad_timestamp, (char *)&verf.adv_timestamp, sizeof(struct timeval)) != 0) { syslog(LOG_DEBUG, "authdes_validate: verifier mismatch"); return (FALSE); } /* * We have a nickname now, let's use it */ ad->ad_nickname = verf.adv_nickname; ad->ad_cred.adc_namekind = ADN_NICKNAME; return (TRUE); } /* * 4. Refresh */ /*ARGSUSED*/ static bool_t -authdes_refresh(AUTH *auth, void *dummy) +authdes_refresh(AUTH *auth, void *dummy __unused) { /* LINTED pointer alignment */ struct ad_private *ad = AUTH_PRIVATE(auth); struct authdes_cred *cred = &ad->ad_cred; int ok; netobj pkey; if (ad->ad_dosync) { ok = __rpc_get_time_offset(&ad->ad_timediff, ad->ad_nis_srvr, ad->ad_timehost, &(ad->ad_uaddr), &(ad->ad_netid)); if (! ok) { /* * Hope the clocks are synced! */ ad->ad_dosync = 0; syslog(LOG_DEBUG, "authdes_refresh: unable to synchronize clock"); } } ad->ad_xkey = auth->ah_key; pkey.n_bytes = (char *)(ad->ad_pkey); pkey.n_len = (u_int)strlen((char *)ad->ad_pkey) + 1; if (key_encryptsession_pk(ad->ad_servername, &pkey, &ad->ad_xkey) < 0) { syslog(LOG_INFO, "authdes_refresh: keyserv(1m) is unable to encrypt session key"); return (FALSE); } cred->adc_fullname.key = ad->ad_xkey; cred->adc_namekind = ADN_FULLNAME; cred->adc_fullname.name = ad->ad_fullname; return (TRUE); } /* * 5. Destroy */ static void authdes_destroy(AUTH *auth) { /* LINTED pointer alignment */ struct ad_private *ad = AUTH_PRIVATE(auth); FREE(ad->ad_fullname, ad->ad_fullnamelen + 1); FREE(ad->ad_servername, ad->ad_servernamelen + 1); if (ad->ad_timehost) FREE(ad->ad_timehost, strlen(ad->ad_timehost) + 1); if (ad->ad_netid) FREE(ad->ad_netid, strlen(ad->ad_netid) + 1); if (ad->ad_uaddr) FREE(ad->ad_uaddr, strlen(ad->ad_uaddr) + 1); FREE(ad, sizeof (struct ad_private)); FREE(auth, sizeof(AUTH)); } static struct auth_ops * authdes_ops(void) { static struct auth_ops ops; /* VARIABLES PROTECTED BY ops_lock: ops */ mutex_lock(&authdes_ops_lock); if (ops.ah_nextverf == NULL) { ops.ah_nextverf = authdes_nextverf; ops.ah_marshal = authdes_marshal; ops.ah_validate = authdes_validate; ops.ah_refresh = authdes_refresh; ops.ah_destroy = authdes_destroy; } mutex_unlock(&authdes_ops_lock); return (&ops); } Index: stable/10/lib/libc/rpc/auth_time.c =================================================================== --- stable/10/lib/libc/rpc/auth_time.c (revision 309488) +++ stable/10/lib/libc/rpc/auth_time.c (revision 309489) @@ -1,507 +1,502 @@ /* #pragma ident "@(#)auth_time.c 1.4 92/11/10 SMI" */ /* * auth_time.c * * This module contains the private function __rpc_get_time_offset() * which will return the difference in seconds between the local system's * notion of time and a remote server's notion of time. This must be * possible without calling any functions that may invoke the name * service. (netdir_getbyxxx, getXbyY, etc). The function is used in the * synchronize call of the authdes code to synchronize clocks between * NIS+ clients and their servers. * * Note to minimize the amount of duplicate code, portions of the * synchronize() function were folded into this code, and the synchronize * call becomes simply a wrapper around this function. Further, if this * function is called with a timehost it *DOES* recurse to the name * server so don't use it in that mode if you are doing name service code. * * Copyright (c) 1992 Sun Microsystems Inc. * All rights reserved. * * Side effects : * When called a client handle to a RPCBIND process is created * and destroyed. Two strings "netid" and "uaddr" are malloc'd * and returned. The SIGALRM processing is modified only if * needed to deal with TCP connections. */ #include __FBSDID("$FreeBSD$"); #include "namespace.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #undef NIS #include #include "un-namespace.h" extern int _rpc_dtablesize( void ); #ifdef TESTING #define msg(x) printf("ERROR: %s\n", x) /* #define msg(x) syslog(LOG_ERR, "%s", x) */ #else #define msg(x) #endif static int saw_alarm = 0; static void -alarm_hndler(s) - int s; +alarm_hndler(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; +static int uaddr_to_sockaddr(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; +free_eps(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. + * + * host - name of the time host + * srv - nis_server struct to use. + * eps[] - array of endpoints + * maxep - max array size */ 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 */ +get_server(struct sockaddr_in *sin, char *host, nis_server *srv, + endpoint eps[], int maxep) { char hname[256]; int num_ep = 0, i; struct hostent *he; struct hostent dummy; char *ptr[2]; endpoint *ep; if (host == NULL && sin == NULL) return (NULL); if (sin == NULL) { he = gethostbyname(host); if (he == NULL) return(NULL); } else { he = &dummy; ptr[0] = (char *)&sin->sin_addr.s_addr; ptr[1] = NULL; dummy.h_addr_list = ptr; } /* * This is lame. We go around once for TCP, then again * for UDP. */ for (i = 0, ep = eps; (he->h_addr_list[i] != NULL) && (num_ep < maxep); i++, ep++, num_ep++) { struct in_addr *a; a = (struct in_addr *)he->h_addr_list[i]; snprintf(hname, sizeof(hname), "%s.0.111", inet_ntoa(*a)); ep->uaddr = strdup(hname); ep->family = strdup("inet"); ep->proto = strdup("tcp"); if (ep->uaddr == NULL || ep->family == NULL || ep->proto == NULL) { free_eps(eps, num_ep + 1); return (NULL); } } for (i = 0; (he->h_addr_list[i] != NULL) && (num_ep < maxep); i++, ep++, num_ep++) { struct in_addr *a; a = (struct in_addr *)he->h_addr_list[i]; snprintf(hname, sizeof(hname), "%s.0.111", inet_ntoa(*a)); ep->uaddr = strdup(hname); ep->family = strdup("inet"); ep->proto = strdup("udp"); if (ep->uaddr == NULL || ep->family == NULL || ep->proto == NULL) { free_eps(eps, num_ep + 1); return (NULL); } } srv->name = (nis_name) host; srv->ep.ep_len = num_ep; srv->ep.ep_val = eps; srv->key_type = NIS_PK_NONE; srv->pkey.n_bytes = NULL; srv->pkey.n_len = 0; return (srv); } /* * __rpc_get_time_offset() * * This function uses a nis_server structure to contact the a remote * machine (as named in that structure) and returns the offset in time * between that machine and this one. This offset is returned in seconds * and may be positive or negative. * * The first time through, a lot of fiddling is done with the netconfig * stuff to find a suitable transport. The function is very aggressive * about choosing UDP or at worst TCP if it can. This is because * those transports support both the RCPBIND call and the internet * time service. * * Once through, *uaddr is set to the universal address of * the machine and *netid is set to the local netid for the transport * that uaddr goes with. On the second call, the netconfig stuff * is skipped and the uaddr/netid pair are used to fetch the netconfig * structure and to then contact the machine for the time. * * td = "server" - "client" + * + * td - Time difference + * srv - NIS Server description + * thost - if no server, this is the timehost + * uaddr - known universal address + * netid - known network identifier */ 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 */ +__rpc_get_time_offset(struct timeval *td, nis_server *srv, char *thost, + char **uaddr, struct sockaddr_in *netid) { 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 */ + void (*oldsig)(int) = NULL; /* old alarm handler */ struct sockaddr_in sin; socklen_t len; int s = RPC_ANYSOCK; int type = 0; td->tv_sec = 0; td->tv_usec = 0; /* * First check to see if we need to find and address for this * server. */ if (*uaddr == NULL) { if ((srv != NULL) && (thost != NULL)) { msg("both timehost and srv pointer used!"); return (0); } if (! srv) { srv = get_server(netid, thost, &tsrv, teps, 32); if (srv == NULL) { msg("unable to contruct server data."); return (0); } needfree = 1; /* need to free data in endpoints */ } ep = srv->ep.ep_val; epl = srv->ep.ep_len; /* Identify the TCP and UDP endpoints */ for (i = 0; (i < epl) && ((udp_ep == -1) || (tcp_ep == -1)); i++) { if (strcasecmp(ep[i].proto, "udp") == 0) udp_ep = i; if (strcasecmp(ep[i].proto, "tcp") == 0) tcp_ep = i; } /* Check to see if it is UDP or TCP */ if (tcp_ep > -1) { useep = &ep[tcp_ep]; useua = ep[tcp_ep].uaddr; type = SOCK_STREAM; } else if (udp_ep > -1) { useep = &ep[udp_ep]; useua = ep[udp_ep].uaddr; type = SOCK_DGRAM; } if (useep == NULL) { msg("no acceptable transport endpoints."); if (needfree) free_eps(teps, tsrv.ep.ep_len); return (0); } } /* * Create a sockaddr from the uaddr. */ if (*uaddr != NULL) useua = *uaddr; /* Fixup test for NIS+ */ sscanf(useua, "%d.%d.%d.%d.", &a1, &a2, &a3, &a4); sprintf(ipuaddr, "%d.%d.%d.%d.0.111", a1, a2, a3, a4); useua = &ipuaddr[0]; bzero((char *)&sin, sizeof(sin)); if (uaddr_to_sockaddr(useua, &sin)) { msg("unable to translate uaddr to sockaddr."); if (needfree) free_eps(teps, tsrv.ep.ep_len); return (0); } /* * Create the client handle to rpcbind. Note we always try * version 3 since that is the earliest version that supports * the RPCB_GETTIME call. Also it is the version that comes * standard with SVR4. Since most everyone supports TCP/IP * we could consider trying the rtime call first. */ clnt = clnttcp_create(&sin, RPCBPROG, RPCBVERS, &s, 0, 0); if (clnt == NULL) { msg("unable to create client handle to rpcbind."); if (needfree) free_eps(teps, tsrv.ep.ep_len); return (0); } tv.tv_sec = 5; tv.tv_usec = 0; time_valid = 0; status = clnt_call(clnt, RPCBPROC_GETTIME, (xdrproc_t)xdr_void, NULL, (xdrproc_t)xdr_u_long, &thetime, tv); /* * The only error we check for is anything but success. In * fact we could have seen PROGMISMATCH if talking to a 4.1 * machine (pmap v2) or TIMEDOUT if the net was busy. */ if (status == RPC_SUCCESS) time_valid = 1; else { int save; /* Blow away possible stale CLNT handle. */ if (clnt != NULL) { clnt_destroy(clnt); clnt = NULL; } /* * Convert PMAP address into timeservice address * We take advantage of the fact that we "know" what * the universal address looks like for inet transports. * * We also know that the internet timeservice is always * listening on port 37. */ sscanf(useua, "%d.%d.%d.%d.", &a1, &a2, &a3, &a4); sprintf(ut, "%d.%d.%d.%d.0.37", a1, a2, a3, a4); if (uaddr_to_sockaddr(ut, &sin)) { msg("cannot convert timeservice uaddr to sockaddr."); goto error; } s = _socket(AF_INET, type, 0); if (s == -1) { msg("unable to open fd to network."); goto error; } /* * Now depending on whether or not we're talking to * UDP we set a timeout or not. */ if (type == SOCK_DGRAM) { struct timeval timeout = { 20, 0 }; struct sockaddr_in from; fd_set readfds; int res; if (_sendto(s, &thetime, sizeof(thetime), 0, (struct sockaddr *)&sin, sizeof(sin)) == -1) { msg("udp : sendto failed."); goto error; } do { FD_ZERO(&readfds); FD_SET(s, &readfds); res = _select(_rpc_dtablesize(), &readfds, (fd_set *)NULL, (fd_set *)NULL, &timeout); } while (res < 0 && errno == EINTR); if (res <= 0) goto error; len = sizeof(from); res = _recvfrom(s, (char *)&thetime, sizeof(thetime), 0, (struct sockaddr *)&from, &len); if (res == -1) { msg("recvfrom failed on udp transport."); goto error; } time_valid = 1; } else { int res; - oldsig = (void (*)())signal(SIGALRM, alarm_hndler); + oldsig = (void (*)(int))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); } Index: stable/10/lib/libc/rpc/clnt_dg.c =================================================================== --- stable/10/lib/libc/rpc/clnt_dg.c (revision 309488) +++ stable/10/lib/libc/rpc/clnt_dg.c (revision 309489) @@ -1,857 +1,851 @@ /* $NetBSD: clnt_dg.c,v 1.4 2000/07/14 08:40:41 fvdl Exp $ */ /*- * Copyright (c) 2009, Sun Microsystems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of Sun Microsystems, Inc. nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright (c) 1986-1991 by Sun Microsystems Inc. */ #if defined(LIBC_SCCS) && !defined(lint) #ident "@(#)clnt_dg.c 1.23 94/04/22 SMI" static char sccsid[] = "@(#)clnt_dg.c 1.19 89/03/16 Copyr 1988 Sun Micro"; #endif #include __FBSDID("$FreeBSD$"); /* * Implements a connectionless client side RPC. */ #include "namespace.h" #include "reentrant.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "un-namespace.h" #include "rpc_com.h" #include "mt_misc.h" #ifdef _FREEFALL_CONFIG /* * Disable RPC exponential back-off for FreeBSD.org systems. */ #define RPC_MAX_BACKOFF 1 /* second */ #else #define RPC_MAX_BACKOFF 30 /* seconds */ #endif static struct clnt_ops *clnt_dg_ops(void); static bool_t time_not_ok(struct timeval *); static enum clnt_stat clnt_dg_call(CLIENT *, rpcproc_t, xdrproc_t, void *, xdrproc_t, void *, struct timeval); static void clnt_dg_geterr(CLIENT *, struct rpc_err *); static bool_t clnt_dg_freeres(CLIENT *, xdrproc_t, void *); static void clnt_dg_abort(CLIENT *); static bool_t clnt_dg_control(CLIENT *, u_int, void *); static void clnt_dg_destroy(CLIENT *); /* * This machinery implements per-fd locks for MT-safety. It is not * sufficient to do per-CLIENT handle locks for MT-safety because a * user may create more than one CLIENT handle with the same fd behind * it. Therfore, we allocate an array of flags (dg_fd_locks), protected * by the clnt_fd_lock mutex, and an array (dg_cv) of condition variables * similarly protected. Dg_fd_lock[fd] == 1 => a call is activte on some * CLIENT handle created for that fd. * The current implementation holds locks across the entire RPC and reply, * including retransmissions. Yes, this is silly, and as soon as this * code is proven to work, this should be the first thing fixed. One step * at a time. */ static int *dg_fd_locks; static cond_t *dg_cv; #define release_fd_lock(fd, mask) { \ mutex_lock(&clnt_fd_lock); \ dg_fd_locks[fd] = 0; \ mutex_unlock(&clnt_fd_lock); \ thr_sigsetmask(SIG_SETMASK, &(mask), NULL); \ cond_signal(&dg_cv[fd]); \ } static const char mem_err_clnt_dg[] = "clnt_dg_create: out of memory"; /* VARIABLES PROTECTED BY clnt_fd_lock: dg_fd_locks, dg_cv */ #define MCALL_MSG_SIZE 24 /* * Private data kept per client handle */ struct cu_data { int cu_fd; /* connections fd */ bool_t cu_closeit; /* opened by library */ struct sockaddr_storage cu_raddr; /* remote address */ int cu_rlen; struct timeval cu_wait; /* retransmit interval */ struct timeval cu_total; /* total time for the call */ struct rpc_err cu_error; XDR cu_outxdrs; u_int cu_xdrpos; u_int cu_sendsz; /* send size */ char cu_outhdr[MCALL_MSG_SIZE]; char *cu_outbuf; u_int cu_recvsz; /* recv size */ int cu_async; int cu_connect; /* Use connect(). */ int cu_connected; /* Have done connect(). */ struct kevent cu_kin; int cu_kq; char cu_inbuf[1]; }; /* * Connection less client creation returns with client handle parameters. * Default options are set, which the user can change using clnt_control(). * fd should be open and bound. * NB: The rpch->cl_auth is initialized to null authentication. * Caller may wish to set this something more useful. * * sendsz and recvsz are the maximum allowable packet sizes that can be * sent and received. Normally they are the same, but they can be * changed to improve the program efficiency and buffer allocation. * If they are 0, use the transport default. * * If svcaddr is NULL, returns NULL. + * + * fd - open file descriptor + * svcaddr - servers address + * program - program number + * version - version number + * sendsz - buffer recv size + * recvsz - buffer send size */ CLIENT * -clnt_dg_create(fd, svcaddr, program, version, sendsz, recvsz) - int fd; /* open file descriptor */ - const struct netbuf *svcaddr; /* servers address */ - rpcprog_t program; /* program number */ - rpcvers_t version; /* version number */ - u_int sendsz; /* buffer recv size */ - u_int recvsz; /* buffer send size */ +clnt_dg_create(int fd, const struct netbuf *svcaddr, rpcprog_t program, + rpcvers_t version, u_int sendsz, u_int recvsz) { CLIENT *cl = NULL; /* client handle */ struct cu_data *cu = NULL; /* private data */ struct timeval now; struct rpc_msg call_msg; sigset_t mask; sigset_t newmask; struct __rpc_sockinfo si; int one = 1; sigfillset(&newmask); thr_sigsetmask(SIG_SETMASK, &newmask, &mask); mutex_lock(&clnt_fd_lock); if (dg_fd_locks == (int *) NULL) { int cv_allocsz; size_t fd_allocsz; int dtbsize = __rpc_dtbsize(); fd_allocsz = dtbsize * sizeof (int); dg_fd_locks = (int *) mem_alloc(fd_allocsz); if (dg_fd_locks == (int *) NULL) { mutex_unlock(&clnt_fd_lock); thr_sigsetmask(SIG_SETMASK, &(mask), NULL); goto err1; } else memset(dg_fd_locks, '\0', fd_allocsz); cv_allocsz = dtbsize * sizeof (cond_t); dg_cv = (cond_t *) mem_alloc(cv_allocsz); if (dg_cv == (cond_t *) NULL) { mem_free(dg_fd_locks, fd_allocsz); dg_fd_locks = (int *) NULL; mutex_unlock(&clnt_fd_lock); thr_sigsetmask(SIG_SETMASK, &(mask), NULL); goto err1; } else { int i; for (i = 0; i < dtbsize; i++) cond_init(&dg_cv[i], 0, (void *) 0); } } mutex_unlock(&clnt_fd_lock); thr_sigsetmask(SIG_SETMASK, &(mask), NULL); if (svcaddr == NULL) { rpc_createerr.cf_stat = RPC_UNKNOWNADDR; return (NULL); } if (!__rpc_fd2sockinfo(fd, &si)) { rpc_createerr.cf_stat = RPC_TLIERROR; rpc_createerr.cf_error.re_errno = 0; return (NULL); } /* * Find the receive and the send size */ sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); if ((sendsz == 0) || (recvsz == 0)) { rpc_createerr.cf_stat = RPC_TLIERROR; /* XXX */ rpc_createerr.cf_error.re_errno = 0; return (NULL); } if ((cl = mem_alloc(sizeof (CLIENT))) == NULL) goto err1; /* * Should be multiple of 4 for XDR. */ sendsz = ((sendsz + 3) / 4) * 4; recvsz = ((recvsz + 3) / 4) * 4; cu = mem_alloc(sizeof (*cu) + sendsz + recvsz); if (cu == NULL) goto err1; (void) memcpy(&cu->cu_raddr, svcaddr->buf, (size_t)svcaddr->len); cu->cu_rlen = svcaddr->len; cu->cu_outbuf = &cu->cu_inbuf[recvsz]; /* Other values can also be set through clnt_control() */ cu->cu_wait.tv_sec = 15; /* heuristically chosen */ cu->cu_wait.tv_usec = 0; cu->cu_total.tv_sec = -1; cu->cu_total.tv_usec = -1; cu->cu_sendsz = sendsz; cu->cu_recvsz = recvsz; cu->cu_async = FALSE; cu->cu_connect = FALSE; cu->cu_connected = FALSE; (void) gettimeofday(&now, NULL); call_msg.rm_xid = __RPC_GETXID(&now); call_msg.rm_call.cb_prog = program; call_msg.rm_call.cb_vers = version; xdrmem_create(&(cu->cu_outxdrs), cu->cu_outhdr, MCALL_MSG_SIZE, XDR_ENCODE); if (! xdr_callhdr(&cu->cu_outxdrs, &call_msg)) { rpc_createerr.cf_stat = RPC_CANTENCODEARGS; /* XXX */ rpc_createerr.cf_error.re_errno = 0; goto err2; } cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs)); XDR_DESTROY(&cu->cu_outxdrs); xdrmem_create(&cu->cu_outxdrs, cu->cu_outbuf, sendsz, XDR_ENCODE); /* XXX fvdl - do we still want this? */ #if 0 (void)bindresvport_sa(fd, (struct sockaddr *)svcaddr->buf); #endif _ioctl(fd, FIONBIO, (char *)(void *)&one); /* * By default, closeit is always FALSE. It is users responsibility * to do a close on it, else the user may use clnt_control * to let clnt_destroy do it for him/her. */ cu->cu_closeit = FALSE; cu->cu_fd = fd; cl->cl_ops = clnt_dg_ops(); cl->cl_private = (caddr_t)(void *)cu; cl->cl_auth = authnone_create(); cl->cl_tp = NULL; cl->cl_netid = NULL; cu->cu_kq = -1; EV_SET(&cu->cu_kin, cu->cu_fd, EVFILT_READ, EV_ADD, 0, 0, 0); return (cl); err1: warnx(mem_err_clnt_dg); rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; err2: if (cl) { mem_free(cl, sizeof (CLIENT)); if (cu) mem_free(cu, sizeof (*cu) + sendsz + recvsz); } return (NULL); } +/* + * cl - client handle + * proc - procedure number + * xargs - xdr routine for args + * argsp - pointer to args + * xresults - xdr routine for results + * resultsp - pointer to results + * utimeout - seconds to wait before giving up + */ static enum clnt_stat -clnt_dg_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout) - CLIENT *cl; /* client handle */ - rpcproc_t proc; /* procedure number */ - xdrproc_t xargs; /* xdr routine for args */ - void *argsp; /* pointer to args */ - xdrproc_t xresults; /* xdr routine for results */ - void *resultsp; /* pointer to results */ - struct timeval utimeout; /* seconds to wait before giving up */ +clnt_dg_call(CLIENT *cl, rpcproc_t proc, xdrproc_t xargs, void *argsp, + xdrproc_t xresults, void *resultsp, struct timeval utimeout) { struct cu_data *cu = (struct cu_data *)cl->cl_private; XDR *xdrs; size_t outlen = 0; struct rpc_msg reply_msg; XDR reply_xdrs; bool_t ok; int nrefreshes = 2; /* number of times to refresh cred */ int nretries = 0; /* number of times we retransmitted */ struct timeval timeout; struct timeval retransmit_time; struct timeval next_sendtime, starttime, time_waited, tv; struct timespec ts; struct kevent kv; struct sockaddr *sa; sigset_t mask; sigset_t newmask; socklen_t salen; ssize_t recvlen = 0; int kin_len, n, rpc_lock_value; u_int32_t xid; outlen = 0; sigfillset(&newmask); thr_sigsetmask(SIG_SETMASK, &newmask, &mask); mutex_lock(&clnt_fd_lock); while (dg_fd_locks[cu->cu_fd]) cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock); if (__isthreaded) rpc_lock_value = 1; else rpc_lock_value = 0; dg_fd_locks[cu->cu_fd] = rpc_lock_value; mutex_unlock(&clnt_fd_lock); if (cu->cu_total.tv_usec == -1) { timeout = utimeout; /* use supplied timeout */ } else { timeout = cu->cu_total; /* use default timeout */ } if (cu->cu_connect && !cu->cu_connected) { if (_connect(cu->cu_fd, (struct sockaddr *)&cu->cu_raddr, cu->cu_rlen) < 0) { cu->cu_error.re_errno = errno; cu->cu_error.re_status = RPC_CANTSEND; goto out; } cu->cu_connected = 1; } if (cu->cu_connected) { sa = NULL; salen = 0; } else { sa = (struct sockaddr *)&cu->cu_raddr; salen = cu->cu_rlen; } time_waited.tv_sec = 0; time_waited.tv_usec = 0; retransmit_time = next_sendtime = cu->cu_wait; gettimeofday(&starttime, NULL); /* Clean up in case the last call ended in a longjmp(3) call. */ if (cu->cu_kq >= 0) _close(cu->cu_kq); if ((cu->cu_kq = kqueue()) < 0) { cu->cu_error.re_errno = errno; cu->cu_error.re_status = RPC_CANTSEND; goto out; } kin_len = 1; call_again: if (cu->cu_async == TRUE && xargs == NULL) goto get_reply; /* * the transaction is the first thing in the out buffer * XXX Yes, and it's in network byte order, so we should to * be careful when we increment it, shouldn't we. */ xid = ntohl(*(u_int32_t *)(void *)(cu->cu_outhdr)); xid++; *(u_int32_t *)(void *)(cu->cu_outhdr) = htonl(xid); call_again_same_xid: xdrs = &(cu->cu_outxdrs); xdrs->x_op = XDR_ENCODE; XDR_SETPOS(xdrs, 0); if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) { if ((! XDR_PUTBYTES(xdrs, cu->cu_outhdr, cu->cu_xdrpos)) || (! XDR_PUTINT32(xdrs, &proc)) || (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || (! (*xargs)(xdrs, argsp))) { cu->cu_error.re_status = RPC_CANTENCODEARGS; goto out; } } else { *(uint32_t *) &cu->cu_outhdr[cu->cu_xdrpos] = htonl(proc); if (!__rpc_gss_wrap(cl->cl_auth, cu->cu_outhdr, cu->cu_xdrpos + sizeof(uint32_t), xdrs, xargs, argsp)) { cu->cu_error.re_status = RPC_CANTENCODEARGS; goto out; } } outlen = (size_t)XDR_GETPOS(xdrs); send_again: if (_sendto(cu->cu_fd, cu->cu_outbuf, outlen, 0, sa, salen) != outlen) { cu->cu_error.re_errno = errno; cu->cu_error.re_status = RPC_CANTSEND; goto out; } /* * Hack to provide rpc-based message passing */ if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { cu->cu_error.re_status = RPC_TIMEDOUT; goto out; } get_reply: /* * sub-optimal code appears here because we have * some clock time to spare while the packets are in flight. * (We assume that this is actually only executed once.) */ reply_msg.acpted_rply.ar_verf = _null_auth; if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) { reply_msg.acpted_rply.ar_results.where = resultsp; reply_msg.acpted_rply.ar_results.proc = xresults; } else { reply_msg.acpted_rply.ar_results.where = NULL; reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void; } for (;;) { /* Decide how long to wait. */ if (timercmp(&next_sendtime, &timeout, <)) timersub(&next_sendtime, &time_waited, &tv); else timersub(&timeout, &time_waited, &tv); if (tv.tv_sec < 0 || tv.tv_usec < 0) tv.tv_sec = tv.tv_usec = 0; TIMEVAL_TO_TIMESPEC(&tv, &ts); n = _kevent(cu->cu_kq, &cu->cu_kin, kin_len, &kv, 1, &ts); /* We don't need to register the event again. */ kin_len = 0; if (n == 1) { if (kv.flags & EV_ERROR) { cu->cu_error.re_errno = kv.data; cu->cu_error.re_status = RPC_CANTRECV; goto out; } /* We have some data now */ do { recvlen = _recvfrom(cu->cu_fd, cu->cu_inbuf, cu->cu_recvsz, 0, NULL, NULL); } while (recvlen < 0 && errno == EINTR); if (recvlen < 0 && errno != EWOULDBLOCK) { cu->cu_error.re_errno = errno; cu->cu_error.re_status = RPC_CANTRECV; goto out; } if (recvlen >= sizeof(u_int32_t) && (cu->cu_async == TRUE || *((u_int32_t *)(void *)(cu->cu_inbuf)) == *((u_int32_t *)(void *)(cu->cu_outbuf)))) { /* We now assume we have the proper reply. */ break; } } if (n == -1 && errno != EINTR) { cu->cu_error.re_errno = errno; cu->cu_error.re_status = RPC_CANTRECV; goto out; } gettimeofday(&tv, NULL); timersub(&tv, &starttime, &time_waited); /* Check for timeout. */ if (timercmp(&time_waited, &timeout, >)) { cu->cu_error.re_status = RPC_TIMEDOUT; goto out; } /* Retransmit if necessary. */ if (timercmp(&time_waited, &next_sendtime, >)) { /* update retransmit_time */ if (retransmit_time.tv_sec < RPC_MAX_BACKOFF) timeradd(&retransmit_time, &retransmit_time, &retransmit_time); timeradd(&next_sendtime, &retransmit_time, &next_sendtime); nretries++; /* * When retransmitting a RPCSEC_GSS message, * we must use a new sequence number (handled * by __rpc_gss_wrap above). */ if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) goto send_again; else goto call_again_same_xid; } } /* * now decode and validate the response */ xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)recvlen, XDR_DECODE); ok = xdr_replymsg(&reply_xdrs, &reply_msg); /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */ if (ok) { if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) && (reply_msg.acpted_rply.ar_stat == SUCCESS)) cu->cu_error.re_status = RPC_SUCCESS; else _seterr_reply(&reply_msg, &(cu->cu_error)); if (cu->cu_error.re_status == RPC_SUCCESS) { if (! AUTH_VALIDATE(cl->cl_auth, &reply_msg.acpted_rply.ar_verf)) { if (nretries && cl->cl_auth->ah_cred.oa_flavor == RPCSEC_GSS) /* * If we retransmitted, its * possible that we will * receive a reply for one of * the earlier transmissions * (which will use an older * RPCSEC_GSS sequence * number). In this case, just * go back and listen for a * new reply. We could keep a * record of all the seq * numbers we have transmitted * so far so that we could * accept a reply for any of * them here. */ goto get_reply; cu->cu_error.re_status = RPC_AUTHERROR; cu->cu_error.re_why = AUTH_INVALIDRESP; } else { if (cl->cl_auth->ah_cred.oa_flavor == RPCSEC_GSS) { if (!__rpc_gss_unwrap(cl->cl_auth, &reply_xdrs, xresults, resultsp)) cu->cu_error.re_status = RPC_CANTDECODERES; } } if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { xdrs->x_op = XDR_FREE; (void) xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf)); } } /* end successful completion */ /* * If unsuccesful AND error is an authentication error * then refresh credentials and try again, else break */ else if (cu->cu_error.re_status == RPC_AUTHERROR) /* maybe our credentials need to be refreshed ... */ if (nrefreshes > 0 && AUTH_REFRESH(cl->cl_auth, &reply_msg)) { nrefreshes--; goto call_again; } /* end of unsuccessful completion */ } /* end of valid reply message */ else { cu->cu_error.re_status = RPC_CANTDECODERES; } out: if (cu->cu_kq >= 0) _close(cu->cu_kq); cu->cu_kq = -1; release_fd_lock(cu->cu_fd, mask); return (cu->cu_error.re_status); } static void -clnt_dg_geterr(cl, errp) - CLIENT *cl; - struct rpc_err *errp; +clnt_dg_geterr(CLIENT *cl, struct rpc_err *errp) { struct cu_data *cu = (struct cu_data *)cl->cl_private; *errp = cu->cu_error; } static bool_t -clnt_dg_freeres(cl, xdr_res, res_ptr) - CLIENT *cl; - xdrproc_t xdr_res; - void *res_ptr; +clnt_dg_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr) { struct cu_data *cu = (struct cu_data *)cl->cl_private; XDR *xdrs = &(cu->cu_outxdrs); bool_t dummy; sigset_t mask; sigset_t newmask; sigfillset(&newmask); thr_sigsetmask(SIG_SETMASK, &newmask, &mask); mutex_lock(&clnt_fd_lock); while (dg_fd_locks[cu->cu_fd]) cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock); xdrs->x_op = XDR_FREE; dummy = (*xdr_res)(xdrs, res_ptr); mutex_unlock(&clnt_fd_lock); thr_sigsetmask(SIG_SETMASK, &mask, NULL); cond_signal(&dg_cv[cu->cu_fd]); return (dummy); } /*ARGSUSED*/ static void -clnt_dg_abort(h) - CLIENT *h; +clnt_dg_abort(CLIENT *h) { } static bool_t -clnt_dg_control(cl, request, info) - CLIENT *cl; - u_int request; - void *info; +clnt_dg_control(CLIENT *cl, u_int request, void *info) { struct cu_data *cu = (struct cu_data *)cl->cl_private; struct netbuf *addr; sigset_t mask; sigset_t newmask; int rpc_lock_value; sigfillset(&newmask); thr_sigsetmask(SIG_SETMASK, &newmask, &mask); mutex_lock(&clnt_fd_lock); while (dg_fd_locks[cu->cu_fd]) cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock); if (__isthreaded) rpc_lock_value = 1; else rpc_lock_value = 0; dg_fd_locks[cu->cu_fd] = rpc_lock_value; mutex_unlock(&clnt_fd_lock); switch (request) { case CLSET_FD_CLOSE: cu->cu_closeit = TRUE; release_fd_lock(cu->cu_fd, mask); return (TRUE); case CLSET_FD_NCLOSE: cu->cu_closeit = FALSE; release_fd_lock(cu->cu_fd, mask); return (TRUE); } /* for other requests which use info */ if (info == NULL) { release_fd_lock(cu->cu_fd, mask); return (FALSE); } switch (request) { case CLSET_TIMEOUT: if (time_not_ok((struct timeval *)info)) { release_fd_lock(cu->cu_fd, mask); return (FALSE); } cu->cu_total = *(struct timeval *)info; break; case CLGET_TIMEOUT: *(struct timeval *)info = cu->cu_total; break; case CLGET_SERVER_ADDR: /* Give him the fd address */ /* Now obsolete. Only for backward compatibility */ (void) memcpy(info, &cu->cu_raddr, (size_t)cu->cu_rlen); break; case CLSET_RETRY_TIMEOUT: if (time_not_ok((struct timeval *)info)) { release_fd_lock(cu->cu_fd, mask); return (FALSE); } cu->cu_wait = *(struct timeval *)info; break; case CLGET_RETRY_TIMEOUT: *(struct timeval *)info = cu->cu_wait; break; case CLGET_FD: *(int *)info = cu->cu_fd; break; case CLGET_SVC_ADDR: addr = (struct netbuf *)info; addr->buf = &cu->cu_raddr; addr->len = cu->cu_rlen; addr->maxlen = sizeof cu->cu_raddr; break; case CLSET_SVC_ADDR: /* set to new address */ addr = (struct netbuf *)info; if (addr->len < sizeof cu->cu_raddr) { release_fd_lock(cu->cu_fd, mask); return (FALSE); } (void) memcpy(&cu->cu_raddr, addr->buf, addr->len); cu->cu_rlen = addr->len; break; case CLGET_XID: /* * use the knowledge that xid is the * first element in the call structure *. * This will get the xid of the PREVIOUS call */ *(u_int32_t *)info = ntohl(*(u_int32_t *)(void *)cu->cu_outhdr); break; case CLSET_XID: /* This will set the xid of the NEXT call */ *(u_int32_t *)(void *)cu->cu_outhdr = htonl(*(u_int32_t *)info - 1); /* decrement by 1 as clnt_dg_call() increments once */ break; case CLGET_VERS: /* * This RELIES on the information that, in the call body, * the version number field is the fifth field from the * begining of the RPC header. MUST be changed if the * call_struct is changed */ *(u_int32_t *)info = ntohl(*(u_int32_t *)(void *)(cu->cu_outhdr + 4 * BYTES_PER_XDR_UNIT)); break; case CLSET_VERS: *(u_int32_t *)(void *)(cu->cu_outhdr + 4 * BYTES_PER_XDR_UNIT) = htonl(*(u_int32_t *)info); break; case CLGET_PROG: /* * This RELIES on the information that, in the call body, * the program number field is the fourth field from the * begining of the RPC header. MUST be changed if the * call_struct is changed */ *(u_int32_t *)info = ntohl(*(u_int32_t *)(void *)(cu->cu_outhdr + 3 * BYTES_PER_XDR_UNIT)); break; case CLSET_PROG: *(u_int32_t *)(void *)(cu->cu_outhdr + 3 * BYTES_PER_XDR_UNIT) = htonl(*(u_int32_t *)info); break; case CLSET_ASYNC: cu->cu_async = *(int *)info; break; case CLSET_CONNECT: cu->cu_connect = *(int *)info; break; default: release_fd_lock(cu->cu_fd, mask); return (FALSE); } release_fd_lock(cu->cu_fd, mask); return (TRUE); } static void -clnt_dg_destroy(cl) - CLIENT *cl; +clnt_dg_destroy(CLIENT *cl) { struct cu_data *cu = (struct cu_data *)cl->cl_private; int cu_fd = cu->cu_fd; sigset_t mask; sigset_t newmask; sigfillset(&newmask); thr_sigsetmask(SIG_SETMASK, &newmask, &mask); mutex_lock(&clnt_fd_lock); while (dg_fd_locks[cu_fd]) cond_wait(&dg_cv[cu_fd], &clnt_fd_lock); if (cu->cu_closeit) (void)_close(cu_fd); if (cu->cu_kq >= 0) _close(cu->cu_kq); XDR_DESTROY(&(cu->cu_outxdrs)); mem_free(cu, (sizeof (*cu) + cu->cu_sendsz + cu->cu_recvsz)); if (cl->cl_netid && cl->cl_netid[0]) mem_free(cl->cl_netid, strlen(cl->cl_netid) +1); if (cl->cl_tp && cl->cl_tp[0]) mem_free(cl->cl_tp, strlen(cl->cl_tp) +1); mem_free(cl, sizeof (CLIENT)); mutex_unlock(&clnt_fd_lock); thr_sigsetmask(SIG_SETMASK, &mask, NULL); cond_signal(&dg_cv[cu_fd]); } static struct clnt_ops * -clnt_dg_ops() +clnt_dg_ops(void) { static struct clnt_ops ops; sigset_t mask; sigset_t newmask; /* VARIABLES PROTECTED BY ops_lock: ops */ sigfillset(&newmask); thr_sigsetmask(SIG_SETMASK, &newmask, &mask); mutex_lock(&ops_lock); if (ops.cl_call == NULL) { ops.cl_call = clnt_dg_call; ops.cl_abort = clnt_dg_abort; ops.cl_geterr = clnt_dg_geterr; ops.cl_freeres = clnt_dg_freeres; ops.cl_destroy = clnt_dg_destroy; ops.cl_control = clnt_dg_control; } mutex_unlock(&ops_lock); thr_sigsetmask(SIG_SETMASK, &mask, NULL); return (&ops); } /* * Make sure that the time is not garbage. -1 value is allowed. */ static bool_t -time_not_ok(t) - struct timeval *t; +time_not_ok(struct timeval *t) { return (t->tv_sec < -1 || t->tv_sec > 100000000 || t->tv_usec < -1 || t->tv_usec > 1000000); } Index: stable/10/lib/libc/rpc/crypt_client.c =================================================================== --- stable/10/lib/libc/rpc/crypt_client.c (revision 309488) +++ stable/10/lib/libc/rpc/crypt_client.c (revision 309489) @@ -1,101 +1,98 @@ /* * Copyright (c) 1996 * Bill Paul . All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "namespace.h" #include #include #include #include #include #include #include "un-namespace.h" int -_des_crypt_call(buf, len, dparms) - char *buf; - int len; - struct desparams *dparms; +_des_crypt_call(char *buf, int len, struct desparams *dparms) { CLIENT *clnt; desresp *result_1; desargs des_crypt_1_arg; struct netconfig *nconf; void *localhandle; int stat; nconf = NULL; localhandle = setnetconfig(); while ((nconf = getnetconfig(localhandle)) != NULL) { if (nconf->nc_protofmly != NULL && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) break; } if (nconf == NULL) { warnx("getnetconfig: %s", nc_sperror()); return(DESERR_HWERROR); } clnt = clnt_tp_create(NULL, CRYPT_PROG, CRYPT_VERS, nconf); if (clnt == (CLIENT *) NULL) { endnetconfig(localhandle); return(DESERR_HWERROR); } endnetconfig(localhandle); des_crypt_1_arg.desbuf.desbuf_len = len; des_crypt_1_arg.desbuf.desbuf_val = buf; des_crypt_1_arg.des_dir = (dparms->des_dir == ENCRYPT) ? ENCRYPT_DES : DECRYPT_DES; des_crypt_1_arg.des_mode = (dparms->des_mode == CBC) ? CBC_DES : ECB_DES; bcopy(dparms->des_ivec, des_crypt_1_arg.des_ivec, 8); bcopy(dparms->des_key, des_crypt_1_arg.des_key, 8); result_1 = des_crypt_1(&des_crypt_1_arg, clnt); if (result_1 == (desresp *) NULL) { clnt_destroy(clnt); return(DESERR_HWERROR); } stat = result_1->stat; if (result_1->stat == DESERR_NONE || result_1->stat == DESERR_NOHWDEVICE) { bcopy(result_1->desbuf.desbuf_val, buf, len); bcopy(result_1->des_ivec, dparms->des_ivec, 8); } clnt_freeres(clnt, (xdrproc_t)xdr_desresp, result_1); clnt_destroy(clnt); return(stat); } Index: stable/10/lib/libc/rpc/des_crypt.c =================================================================== --- stable/10/lib/libc/rpc/des_crypt.c (revision 309488) +++ stable/10/lib/libc/rpc/des_crypt.c (revision 309489) @@ -1,153 +1,140 @@ /*- * Copyright (c) 2009, Sun Microsystems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of Sun Microsystems, Inc. nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * des_crypt.c, DES encryption library routines * Copyright (C) 1986, Sun Microsystems, Inc. */ #include #include #include #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)des_crypt.c 2.2 88/08/10 4.0 RPCSRC; from 1.13 88/02/08 SMI"; #endif #include __FBSDID("$FreeBSD$"); static int common_crypt( char *, char *, unsigned, unsigned, struct desparams * ); int (*__des_crypt_LOCAL)(char *, unsigned, struct desparams *) = 0; extern int _des_crypt_call(char *, int, struct desparams *); /* * Copy 8 bytes */ #define COPY8(src, dst) { \ char *a = (char *) dst; \ char *b = (char *) src; \ *a++ = *b++; *a++ = *b++; *a++ = *b++; *a++ = *b++; \ *a++ = *b++; *a++ = *b++; *a++ = *b++; *a++ = *b++; \ } /* * Copy multiple of 8 bytes */ #define DESCOPY(src, dst, len) { \ char *a = (char *) dst; \ char *b = (char *) src; \ int i; \ for (i = (int) len; i > 0; i -= 8) { \ *a++ = *b++; *a++ = *b++; *a++ = *b++; *a++ = *b++; \ *a++ = *b++; *a++ = *b++; *a++ = *b++; *a++ = *b++; \ } \ } /* * CBC mode encryption */ int -cbc_crypt(key, buf, len, mode, ivec) - char *key; - char *buf; - unsigned len; - unsigned mode; - char *ivec; +cbc_crypt(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; +ecb_crypt(char *key, char *buf, unsigned len, unsigned mode) { struct desparams dp; #ifdef BROKEN_DES dp.UDES.UDES_buf = buf; dp.des_mode = CBC; #else dp.des_mode = ECB; #endif return(common_crypt(key, buf, len, mode, &dp)); } /* * Common code to cbc_crypt() & ecb_crypt() */ static int -common_crypt(key, buf, len, mode, desp) - char *key; - char *buf; - unsigned len; - unsigned mode; - struct desparams *desp; +common_crypt(char *key, char *buf, unsigned len, unsigned mode, + struct desparams *desp) { int desdev; if ((len % 8) != 0 || len > DES_MAXDATA) { return(DESERR_BADPARAM); } desp->des_dir = ((mode & DES_DIRMASK) == DES_ENCRYPT) ? ENCRYPT : DECRYPT; desdev = mode & DES_DEVMASK; COPY8(key, desp->des_key); /* * software */ if (__des_crypt_LOCAL != NULL) { if (!__des_crypt_LOCAL(buf, len, desp)) { return (DESERR_HWERROR); } } else { if (!_des_crypt_call(buf, len, desp)) { return (DESERR_HWERROR); } } return(desdev == DES_SW ? DESERR_NONE : DESERR_NOHWDEVICE); } Index: stable/10/lib/libc/rpc/des_soft.c =================================================================== --- stable/10/lib/libc/rpc/des_soft.c (revision 309488) +++ stable/10/lib/libc/rpc/des_soft.c (revision 309489) @@ -1,70 +1,69 @@ /*- * Copyright (c) 2009, Sun Microsystems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of Sun Microsystems, Inc. nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)des_soft.c 2.2 88/08/10 4.0 RPCSRC; from 1.13 88/02/08 SMI"; #endif #include __FBSDID("$FreeBSD$"); /* * Table giving odd parity in the low bit for ASCII characters */ static char partab[128] = { 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x07, 0x07, 0x08, 0x08, 0x0b, 0x0b, 0x0d, 0x0d, 0x0e, 0x0e, 0x10, 0x10, 0x13, 0x13, 0x15, 0x15, 0x16, 0x16, 0x19, 0x19, 0x1a, 0x1a, 0x1c, 0x1c, 0x1f, 0x1f, 0x20, 0x20, 0x23, 0x23, 0x25, 0x25, 0x26, 0x26, 0x29, 0x29, 0x2a, 0x2a, 0x2c, 0x2c, 0x2f, 0x2f, 0x31, 0x31, 0x32, 0x32, 0x34, 0x34, 0x37, 0x37, 0x38, 0x38, 0x3b, 0x3b, 0x3d, 0x3d, 0x3e, 0x3e, 0x40, 0x40, 0x43, 0x43, 0x45, 0x45, 0x46, 0x46, 0x49, 0x49, 0x4a, 0x4a, 0x4c, 0x4c, 0x4f, 0x4f, 0x51, 0x51, 0x52, 0x52, 0x54, 0x54, 0x57, 0x57, 0x58, 0x58, 0x5b, 0x5b, 0x5d, 0x5d, 0x5e, 0x5e, 0x61, 0x61, 0x62, 0x62, 0x64, 0x64, 0x67, 0x67, 0x68, 0x68, 0x6b, 0x6b, 0x6d, 0x6d, 0x6e, 0x6e, 0x70, 0x70, 0x73, 0x73, 0x75, 0x75, 0x76, 0x76, 0x79, 0x79, 0x7a, 0x7a, 0x7c, 0x7c, 0x7f, 0x7f, }; /* * Add odd parity to low bit of 8 byte key */ void -des_setparity(p) - char *p; +des_setparity(char *p) { int i; for (i = 0; i < 8; i++) { *p = partab[*p & 0x7f]; p++; } } Index: stable/10/lib/libc/rpc/getpublickey.c =================================================================== --- stable/10/lib/libc/rpc/getpublickey.c (revision 309488) +++ stable/10/lib/libc/rpc/getpublickey.c (revision 309489) @@ -1,177 +1,171 @@ /*- * Copyright (c) 2009, Sun Microsystems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of Sun Microsystems, Inc. nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)publickey.c 1.10 91/03/11 Copyr 1986 Sun Micro"; #endif #include __FBSDID("$FreeBSD$"); /* * publickey.c * Copyright (C) 1986, Sun Microsystems, Inc. */ /* * Public key lookup routines */ #include "namespace.h" #include #include #include #include #include #include #include #include #include "un-namespace.h" #define PKFILE "/etc/publickey" /* * Hack to let ypserv/rpc.nisd use AUTH_DES. */ int (*__getpublickey_LOCAL)() = 0; /* * Get somebody's public key */ static int -__getpublickey_real(netname, publickey) - const char *netname; - char *publickey; +__getpublickey_real(const char *netname, char *publickey) { char lookup[3 * HEXKEYBYTES]; char *p; if (publickey == NULL) return (0); if (!getpublicandprivatekey(netname, lookup)) return (0); p = strchr(lookup, ':'); if (p == NULL) { return (0); } *p = '\0'; (void) strncpy(publickey, lookup, HEXKEYBYTES); publickey[HEXKEYBYTES] = '\0'; return (1); } /* * reads the file /etc/publickey looking for a + to optionally go to the * yellow pages */ int -getpublicandprivatekey(key, ret) - const char *key; - char *ret; +getpublicandprivatekey(const char *key, char *ret) { char buf[1024]; /* big enough */ char *res; FILE *fd; char *mkey; char *mval; fd = fopen(PKFILE, "r"); if (fd == NULL) return (0); for (;;) { res = fgets(buf, sizeof(buf), fd); if (res == NULL) { fclose(fd); return (0); } if (res[0] == '#') continue; else if (res[0] == '+') { #ifdef YP char *PKMAP = "publickey.byname"; char *lookup; char *domain; int err; int len; err = yp_get_default_domain(&domain); if (err) { continue; } lookup = NULL; err = yp_match(domain, PKMAP, key, strlen(key), &lookup, &len); if (err) { #ifdef DEBUG fprintf(stderr, "match failed error %d\n", err); #endif continue; } lookup[len] = 0; strcpy(ret, lookup); fclose(fd); free(lookup); return (2); #else /* YP */ #ifdef DEBUG fprintf(stderr, "Bad record in %s '+' -- NIS not supported in this library copy\n", PKFILE); #endif /* DEBUG */ continue; #endif /* YP */ } else { mkey = strsep(&res, "\t "); if (mkey == NULL) { fprintf(stderr, "Bad record in %s -- %s", PKFILE, buf); continue; } do { mval = strsep(&res, " \t#\n"); } while (mval != NULL && !*mval); if (mval == NULL) { fprintf(stderr, "Bad record in %s val problem - %s", PKFILE, buf); continue; } if (strcmp(mkey, key) == 0) { strcpy(ret, mval); fclose(fd); return (1); } } } } -int getpublickey(netname, publickey) - const char *netname; - char *publickey; +int getpublickey(const char *netname, char *publickey) { if (__getpublickey_LOCAL != NULL) return(__getpublickey_LOCAL(netname, publickey)); else return(__getpublickey_real(netname, publickey)); } Index: stable/10/lib/libc/rpc/key_call.c =================================================================== --- stable/10/lib/libc/rpc/key_call.c (revision 309488) +++ stable/10/lib/libc/rpc/key_call.c (revision 309489) @@ -1,479 +1,459 @@ /*- * Copyright (c) 2009, Sun Microsystems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of Sun Microsystems, Inc. nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright (c) 1986-1991 by Sun Microsystems Inc. */ #ident "@(#)key_call.c 1.25 94/04/24 SMI" #include __FBSDID("$FreeBSD$"); /* * key_call.c, Interface to keyserver * * setsecretkey(key) - set your secret key * encryptsessionkey(agent, deskey) - encrypt a session key to talk to agent * decryptsessionkey(agent, deskey) - decrypt ditto * gendeskey(deskey) - generate a secure des key */ #include "namespace.h" #include "reentrant.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "un-namespace.h" #include "mt_misc.h" #define KEY_TIMEOUT 5 /* per-try timeout in seconds */ #define KEY_NRETRY 12 /* number of retries */ #ifdef DEBUG #define debug(msg) (void) fprintf(stderr, "%s\n", msg); #else #define debug(msg) #endif /* DEBUG */ /* * Hack to allow the keyserver to use AUTH_DES (for authenticated * NIS+ calls, for example). The only functions that get called * are key_encryptsession_pk, key_decryptsession_pk, and key_gendes. * * The approach is to have the keyserver fill in pointers to local * implementations of these functions, and to call those in key_call(). */ cryptkeyres *(*__key_encryptsession_pk_LOCAL)() = 0; cryptkeyres *(*__key_decryptsession_pk_LOCAL)() = 0; des_block *(*__key_gendes_LOCAL)() = 0; static int key_call( u_long, xdrproc_t, void *, xdrproc_t, void *); int -key_setsecret(secretkey) - const char *secretkey; +key_setsecret(const char *secretkey) { keystatus status; if (!key_call((u_long) KEY_SET, (xdrproc_t)xdr_keybuf, (void *)secretkey, (xdrproc_t)xdr_keystatus, &status)) { return (-1); } if (status != KEY_SUCCESS) { debug("set status is nonzero"); return (-1); } return (0); } /* key_secretkey_is_set() returns 1 if the keyserver has a secret key * stored for the caller's effective uid; it returns 0 otherwise * * N.B.: The KEY_NET_GET key call is undocumented. Applications shouldn't * be using it, because it allows them to get the user's secret key. */ int key_secretkey_is_set(void) { struct key_netstres kres; memset((void*)&kres, 0, sizeof (kres)); if (key_call((u_long) KEY_NET_GET, (xdrproc_t)xdr_void, NULL, (xdrproc_t)xdr_key_netstres, &kres) && (kres.status == KEY_SUCCESS) && (kres.key_netstres_u.knet.st_priv_key[0] != 0)) { /* avoid leaving secret key in memory */ memset(kres.key_netstres_u.knet.st_priv_key, 0, HEXKEYBYTES); return (1); } return (0); } int -key_encryptsession_pk(remotename, remotekey, deskey) - char *remotename; - netobj *remotekey; - des_block *deskey; +key_encryptsession_pk(char *remotename, netobj *remotekey, des_block *deskey) { cryptkeyarg2 arg; cryptkeyres res; arg.remotename = remotename; arg.remotekey = *remotekey; arg.deskey = *deskey; if (!key_call((u_long)KEY_ENCRYPT_PK, (xdrproc_t)xdr_cryptkeyarg2, &arg, (xdrproc_t)xdr_cryptkeyres, &res)) { return (-1); } if (res.status != KEY_SUCCESS) { debug("encrypt status is nonzero"); return (-1); } *deskey = res.cryptkeyres_u.deskey; return (0); } int -key_decryptsession_pk(remotename, remotekey, deskey) - char *remotename; - netobj *remotekey; - des_block *deskey; +key_decryptsession_pk(char *remotename, netobj *remotekey, des_block *deskey) { cryptkeyarg2 arg; cryptkeyres res; arg.remotename = remotename; arg.remotekey = *remotekey; arg.deskey = *deskey; if (!key_call((u_long)KEY_DECRYPT_PK, (xdrproc_t)xdr_cryptkeyarg2, &arg, (xdrproc_t)xdr_cryptkeyres, &res)) { return (-1); } if (res.status != KEY_SUCCESS) { debug("decrypt status is nonzero"); return (-1); } *deskey = res.cryptkeyres_u.deskey; return (0); } int -key_encryptsession(remotename, deskey) - const char *remotename; - des_block *deskey; +key_encryptsession(const char *remotename, des_block *deskey) { cryptkeyarg arg; cryptkeyres res; arg.remotename = (char *) remotename; arg.deskey = *deskey; if (!key_call((u_long)KEY_ENCRYPT, (xdrproc_t)xdr_cryptkeyarg, &arg, (xdrproc_t)xdr_cryptkeyres, &res)) { return (-1); } if (res.status != KEY_SUCCESS) { debug("encrypt status is nonzero"); return (-1); } *deskey = res.cryptkeyres_u.deskey; return (0); } int -key_decryptsession(remotename, deskey) - const char *remotename; - des_block *deskey; +key_decryptsession(const char *remotename, des_block *deskey) { cryptkeyarg arg; cryptkeyres res; arg.remotename = (char *) remotename; arg.deskey = *deskey; if (!key_call((u_long)KEY_DECRYPT, (xdrproc_t)xdr_cryptkeyarg, &arg, (xdrproc_t)xdr_cryptkeyres, &res)) { return (-1); } if (res.status != KEY_SUCCESS) { debug("decrypt status is nonzero"); return (-1); } *deskey = res.cryptkeyres_u.deskey; return (0); } int -key_gendes(key) - des_block *key; +key_gendes(des_block *key) { if (!key_call((u_long)KEY_GEN, (xdrproc_t)xdr_void, NULL, (xdrproc_t)xdr_des_block, key)) { return (-1); } return (0); } int -key_setnet(arg) -struct key_netstarg *arg; +key_setnet(struct key_netstarg *arg) { keystatus status; if (!key_call((u_long) KEY_NET_PUT, (xdrproc_t)xdr_key_netstarg, arg, (xdrproc_t)xdr_keystatus, &status)){ return (-1); } if (status != KEY_SUCCESS) { debug("key_setnet status is nonzero"); return (-1); } return (1); } int -key_get_conv(pkey, deskey) - char *pkey; - des_block *deskey; +key_get_conv(char *pkey, des_block *deskey) { cryptkeyres res; if (!key_call((u_long) KEY_GET_CONV, (xdrproc_t)xdr_keybuf, pkey, (xdrproc_t)xdr_cryptkeyres, &res)) { return (-1); } if (res.status != KEY_SUCCESS) { debug("get_conv status is nonzero"); return (-1); } *deskey = res.cryptkeyres_u.deskey; return (0); } struct key_call_private { CLIENT *client; /* Client handle */ pid_t pid; /* process-id at moment of creation */ uid_t uid; /* user-id at last authorization */ }; static struct key_call_private *key_call_private_main = NULL; static thread_key_t key_call_key; static once_t key_call_once = ONCE_INITIALIZER; static int key_call_key_error; static void key_call_destroy(void *vp) { struct key_call_private *kcp = (struct key_call_private *)vp; if (kcp) { if (kcp->client) clnt_destroy(kcp->client); free(kcp); } } static void key_call_init(void) { key_call_key_error = thr_keycreate(&key_call_key, key_call_destroy); } /* * Keep the handle cached. This call may be made quite often. */ static CLIENT * -getkeyserv_handle(vers) -int vers; +getkeyserv_handle(int vers) { void *localhandle; struct netconfig *nconf; struct netconfig *tpconf; struct key_call_private *kcp; struct timeval wait_time; struct utsname u; int main_thread; int fd; #define TOTAL_TIMEOUT 30 /* total timeout talking to keyserver */ #define TOTAL_TRIES 5 /* Number of tries */ if ((main_thread = thr_main())) { kcp = key_call_private_main; } else { if (thr_once(&key_call_once, key_call_init) != 0 || key_call_key_error != 0) return ((CLIENT *) NULL); kcp = (struct key_call_private *)thr_getspecific(key_call_key); } if (kcp == (struct key_call_private *)NULL) { kcp = (struct key_call_private *)malloc(sizeof (*kcp)); if (kcp == (struct key_call_private *)NULL) { return ((CLIENT *) NULL); } if (main_thread) key_call_private_main = kcp; else thr_setspecific(key_call_key, (void *) kcp); kcp->client = NULL; } /* if pid has changed, destroy client and rebuild */ if (kcp->client != NULL && kcp->pid != getpid()) { clnt_destroy(kcp->client); kcp->client = NULL; } if (kcp->client != NULL) { /* if uid has changed, build client handle again */ if (kcp->uid != geteuid()) { kcp->uid = geteuid(); auth_destroy(kcp->client->cl_auth); kcp->client->cl_auth = authsys_create("", kcp->uid, 0, 0, NULL); if (kcp->client->cl_auth == NULL) { clnt_destroy(kcp->client); kcp->client = NULL; return ((CLIENT *) NULL); } } /* Change the version number to the new one */ clnt_control(kcp->client, CLSET_VERS, (void *)&vers); return (kcp->client); } if (!(localhandle = setnetconfig())) { return ((CLIENT *) NULL); } tpconf = NULL; #if defined(__FreeBSD__) if (uname(&u) == -1) #else #if defined(i386) if (_nuname(&u) == -1) #elif defined(sparc) if (_uname(&u) == -1) #else #error Unknown architecture! #endif #endif { endnetconfig(localhandle); return ((CLIENT *) NULL); } while ((nconf = getnetconfig(localhandle)) != NULL) { if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) { /* * We use COTS_ORD here so that the caller can * find out immediately if the server is dead. */ if (nconf->nc_semantics == NC_TPI_COTS_ORD) { kcp->client = clnt_tp_create(u.nodename, KEY_PROG, vers, nconf); if (kcp->client) break; } else { tpconf = nconf; } } } if ((kcp->client == (CLIENT *) NULL) && (tpconf)) /* Now, try the CLTS or COTS loopback transport */ kcp->client = clnt_tp_create(u.nodename, KEY_PROG, vers, tpconf); endnetconfig(localhandle); if (kcp->client == (CLIENT *) NULL) { return ((CLIENT *) NULL); } kcp->uid = geteuid(); kcp->pid = getpid(); kcp->client->cl_auth = authsys_create("", kcp->uid, 0, 0, NULL); if (kcp->client->cl_auth == NULL) { clnt_destroy(kcp->client); kcp->client = NULL; return ((CLIENT *) NULL); } wait_time.tv_sec = TOTAL_TIMEOUT/TOTAL_TRIES; wait_time.tv_usec = 0; (void) clnt_control(kcp->client, CLSET_RETRY_TIMEOUT, (char *)&wait_time); if (clnt_control(kcp->client, CLGET_FD, (char *)&fd)) _fcntl(fd, F_SETFD, 1); /* make it "close on exec" */ return (kcp->client); } /* returns 0 on failure, 1 on success */ static int -key_call(proc, xdr_arg, arg, xdr_rslt, rslt) - u_long proc; - xdrproc_t xdr_arg; - void *arg; - xdrproc_t xdr_rslt; - void *rslt; +key_call(u_long proc, xdrproc_t xdr_arg, void *arg, xdrproc_t xdr_rslt, + void *rslt) { CLIENT *clnt; struct timeval wait_time; if (proc == KEY_ENCRYPT_PK && __key_encryptsession_pk_LOCAL) { cryptkeyres *res; res = (*__key_encryptsession_pk_LOCAL)(geteuid(), arg); *(cryptkeyres*)rslt = *res; return (1); } else if (proc == KEY_DECRYPT_PK && __key_decryptsession_pk_LOCAL) { cryptkeyres *res; res = (*__key_decryptsession_pk_LOCAL)(geteuid(), arg); *(cryptkeyres*)rslt = *res; return (1); } else if (proc == KEY_GEN && __key_gendes_LOCAL) { des_block *res; res = (*__key_gendes_LOCAL)(geteuid(), 0); *(des_block*)rslt = *res; return (1); } if ((proc == KEY_ENCRYPT_PK) || (proc == KEY_DECRYPT_PK) || (proc == KEY_NET_GET) || (proc == KEY_NET_PUT) || (proc == KEY_GET_CONV)) clnt = getkeyserv_handle(2); /* talk to version 2 */ else clnt = getkeyserv_handle(1); /* talk to version 1 */ if (clnt == NULL) { return (0); } wait_time.tv_sec = TOTAL_TIMEOUT; wait_time.tv_usec = 0; if (clnt_call(clnt, proc, xdr_arg, arg, xdr_rslt, rslt, wait_time) == RPC_SUCCESS) { return (1); } else { return (0); } } Index: stable/10/lib/libc/rpc/rpc_soc.c =================================================================== --- stable/10/lib/libc/rpc/rpc_soc.c (revision 309488) +++ stable/10/lib/libc/rpc/rpc_soc.c (revision 309489) @@ -1,578 +1,533 @@ /* $NetBSD: rpc_soc.c,v 1.6 2000/07/06 03:10:35 christos Exp $ */ /*- * Copyright (c) 2009, Sun Microsystems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of Sun Microsystems, Inc. nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* #ident "@(#)rpc_soc.c 1.17 94/04/24 SMI" */ /* * Copyright (c) 1986-1991 by Sun Microsystems Inc. * In addition, portions of such source code were derived from Berkeley * 4.3 BSD under license from the Regents of the University of * California. */ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)rpc_soc.c 1.41 89/05/02 Copyr 1988 Sun Micro"; #endif #include __FBSDID("$FreeBSD$"); #ifdef PORTMAP /* * rpc_soc.c * * The backward compatibility routines for the earlier implementation * of RPC, where the only transports supported were tcp/ip and udp/ip. * Based on berkeley socket abstraction, now implemented on the top * of TLI/Streams */ #include "namespace.h" #include "reentrant.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "un-namespace.h" #include "rpc_com.h" #include "mt_misc.h" static CLIENT *clnt_com_create(struct sockaddr_in *, rpcprog_t, rpcvers_t, int *, u_int, u_int, char *); static SVCXPRT *svc_com_create(int, u_int, u_int, char *); static bool_t rpc_wrap_bcast(char *, struct netbuf *, struct netconfig *); /* XXX */ #define IN4_LOCALHOST_STRING "127.0.0.1" #define IN6_LOCALHOST_STRING "::1" /* * A common clnt create routine */ static CLIENT * -clnt_com_create(raddr, prog, vers, sockp, sendsz, recvsz, tp) - struct sockaddr_in *raddr; - rpcprog_t prog; - rpcvers_t vers; - int *sockp; - u_int sendsz; - u_int recvsz; - char *tp; +clnt_com_create(struct sockaddr_in *raddr, rpcprog_t prog, rpcvers_t vers, int *sockp, + u_int sendsz, u_int recvsz, char *tp) { CLIENT *cl; int madefd = FALSE; int fd = *sockp; struct netconfig *nconf; struct netbuf bindaddr; mutex_lock(&rpcsoc_lock); if ((nconf = __rpc_getconfip(tp)) == NULL) { rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; mutex_unlock(&rpcsoc_lock); return (NULL); } if (fd == RPC_ANYSOCK) { fd = __rpc_nconf2fd(nconf); if (fd == -1) goto syserror; madefd = TRUE; } if (raddr->sin_port == 0) { u_int proto; u_short sport; mutex_unlock(&rpcsoc_lock); /* pmap_getport is recursive */ proto = strcmp(tp, "udp") == 0 ? IPPROTO_UDP : IPPROTO_TCP; sport = pmap_getport(raddr, (u_long)prog, (u_long)vers, proto); if (sport == 0) { goto err; } raddr->sin_port = htons(sport); mutex_lock(&rpcsoc_lock); /* pmap_getport is recursive */ } /* Transform sockaddr_in to netbuf */ bindaddr.maxlen = bindaddr.len = sizeof (struct sockaddr_in); bindaddr.buf = raddr; bindresvport(fd, NULL); cl = clnt_tli_create(fd, nconf, &bindaddr, prog, vers, sendsz, recvsz); if (cl) { if (madefd == TRUE) { /* * The fd should be closed while destroying the handle. */ (void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL); *sockp = fd; } (void) freenetconfigent(nconf); mutex_unlock(&rpcsoc_lock); return (cl); } goto err; syserror: rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; err: if (madefd == TRUE) (void)_close(fd); (void) freenetconfigent(nconf); mutex_unlock(&rpcsoc_lock); return (NULL); } CLIENT * -clntudp_bufcreate(raddr, prog, vers, wait, sockp, sendsz, recvsz) - struct sockaddr_in *raddr; - u_long prog; - u_long vers; - struct timeval wait; - int *sockp; - u_int sendsz; - u_int recvsz; +clntudp_bufcreate(struct sockaddr_in *raddr, u_long prog, u_long vers, + struct timeval wait, int *sockp, u_int sendsz, u_int recvsz) { CLIENT *cl; cl = clnt_com_create(raddr, (rpcprog_t)prog, (rpcvers_t)vers, sockp, sendsz, recvsz, "udp"); if (cl == NULL) { return (NULL); } (void) CLNT_CONTROL(cl, CLSET_RETRY_TIMEOUT, &wait); return (cl); } CLIENT * -clntudp_create(raddr, program, version, wait, sockp) - struct sockaddr_in *raddr; - u_long program; - u_long version; - struct timeval wait; - int *sockp; +clntudp_create(struct sockaddr_in *raddr, u_long program, u_long version, + struct timeval wait, int *sockp) { return clntudp_bufcreate(raddr, program, version, wait, sockp, UDPMSGSIZE, UDPMSGSIZE); } CLIENT * -clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz) - struct sockaddr_in *raddr; - u_long prog; - u_long vers; - int *sockp; - u_int sendsz; - u_int recvsz; +clnttcp_create(struct sockaddr_in *raddr, u_long prog, u_long vers, int *sockp, + u_int sendsz, u_int recvsz) { return clnt_com_create(raddr, (rpcprog_t)prog, (rpcvers_t)vers, sockp, sendsz, recvsz, "tcp"); } CLIENT * -clntraw_create(prog, vers) - u_long prog; - u_long vers; +clntraw_create(u_long prog, u_long vers) { return clnt_raw_create((rpcprog_t)prog, (rpcvers_t)vers); } /* * A common server create routine */ static SVCXPRT * -svc_com_create(fd, sendsize, recvsize, netid) - int fd; - u_int sendsize; - u_int recvsize; - char *netid; +svc_com_create(int fd, u_int sendsize, u_int recvsize, char *netid) { struct netconfig *nconf; SVCXPRT *svc; int madefd = FALSE; int port; struct sockaddr_in sin; if ((nconf = __rpc_getconfip(netid)) == NULL) { (void) syslog(LOG_ERR, "Could not get %s transport", netid); return (NULL); } if (fd == RPC_ANYSOCK) { fd = __rpc_nconf2fd(nconf); if (fd == -1) { (void) freenetconfigent(nconf); (void) syslog(LOG_ERR, "svc%s_create: could not open connection", netid); return (NULL); } madefd = TRUE; } memset(&sin, 0, sizeof sin); sin.sin_family = AF_INET; bindresvport(fd, &sin); _listen(fd, SOMAXCONN); svc = svc_tli_create(fd, nconf, NULL, sendsize, recvsize); (void) freenetconfigent(nconf); if (svc == NULL) { if (madefd) (void)_close(fd); return (NULL); } port = (((struct sockaddr_in *)svc->xp_ltaddr.buf)->sin_port); svc->xp_port = ntohs(port); return (svc); } SVCXPRT * -svctcp_create(fd, sendsize, recvsize) - int fd; - u_int sendsize; - u_int recvsize; +svctcp_create(int fd, u_int sendsize, u_int recvsize) { return svc_com_create(fd, sendsize, recvsize, "tcp"); } SVCXPRT * -svcudp_bufcreate(fd, sendsz, recvsz) - int fd; - u_int sendsz, recvsz; +svcudp_bufcreate(int fd, u_int sendsz, u_int recvsz) { return svc_com_create(fd, sendsz, recvsz, "udp"); } SVCXPRT * -svcfd_create(fd, sendsize, recvsize) - int fd; - u_int sendsize; - u_int recvsize; +svcfd_create(int fd, u_int sendsize, u_int recvsize) { return svc_fd_create(fd, sendsize, recvsize); } SVCXPRT * -svcudp_create(fd) - int fd; +svcudp_create(int fd) { return svc_com_create(fd, UDPMSGSIZE, UDPMSGSIZE, "udp"); } SVCXPRT * svcraw_create(void) { return svc_raw_create(); } int -get_myaddress(addr) - struct sockaddr_in *addr; +get_myaddress(struct sockaddr_in *addr) { memset((void *) addr, 0, sizeof(*addr)); addr->sin_family = AF_INET; addr->sin_port = htons(PMAPPORT); addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK); return (0); } /* * For connectionless "udp" transport. Obsoleted by rpc_call(). */ int -callrpc(host, prognum, versnum, procnum, inproc, in, outproc, out) - const char *host; - int prognum, versnum, procnum; - xdrproc_t inproc, outproc; - void *in, *out; +callrpc(const char *host, int prognum, int versnum, int procnum, + xdrproc_t inproc, void *in, xdrproc_t outproc, void *out) { return (int)rpc_call(host, (rpcprog_t)prognum, (rpcvers_t)versnum, (rpcproc_t)procnum, inproc, in, outproc, out, "udp"); } /* * For connectionless kind of transport. Obsoleted by rpc_reg() */ int -registerrpc(prognum, versnum, procnum, progname, inproc, outproc) - int prognum, versnum, procnum; - char *(*progname)(char [UDPMSGSIZE]); - xdrproc_t inproc, outproc; +registerrpc(int prognum, int versnum, int procnum, + char *(*progname)(char [UDPMSGSIZE]), + xdrproc_t inproc, xdrproc_t outproc) { return rpc_reg((rpcprog_t)prognum, (rpcvers_t)versnum, (rpcproc_t)procnum, progname, inproc, outproc, "udp"); } /* * All the following clnt_broadcast stuff is convulated; it supports * the earlier calling style of the callback function */ static thread_key_t clnt_broadcast_key; static resultproc_t clnt_broadcast_result_main; static once_t clnt_broadcast_once = ONCE_INITIALIZER; static void clnt_broadcast_key_init(void) { thr_keycreate(&clnt_broadcast_key, free); } /* * Need to translate the netbuf address into sockaddr_in address. * Dont care about netid here. */ /* ARGSUSED */ static bool_t -rpc_wrap_bcast(resultp, addr, nconf) - char *resultp; /* results of the call */ - struct netbuf *addr; /* address of the guy who responded */ - struct netconfig *nconf; /* Netconf of the transport */ +rpc_wrap_bcast(char *resultp, struct netbuf *addr, struct netconfig *nconf) +/* + * char *resultp; // results of the call + * struct netbuf *addr; // address of the guy who responded + * struct netconfig *nconf; // Netconf of the transport + */ { resultproc_t clnt_broadcast_result; if (strcmp(nconf->nc_netid, "udp")) return (FALSE); if (thr_main()) clnt_broadcast_result = clnt_broadcast_result_main; else clnt_broadcast_result = (resultproc_t)thr_getspecific(clnt_broadcast_key); return (*clnt_broadcast_result)(resultp, (struct sockaddr_in *)addr->buf); } /* * Broadcasts on UDP transport. Obsoleted by rpc_broadcast(). */ enum clnt_stat -clnt_broadcast(prog, vers, proc, xargs, argsp, xresults, resultsp, eachresult) - u_long prog; /* program number */ - u_long vers; /* version number */ - u_long proc; /* procedure number */ - xdrproc_t xargs; /* xdr routine for args */ - void *argsp; /* pointer to args */ - xdrproc_t xresults; /* xdr routine for results */ - void *resultsp; /* pointer to results */ - resultproc_t eachresult; /* call with each result obtained */ +clnt_broadcast(u_long prog, u_long vers, u_long proc, xdrproc_t xargs, + void *argsp, xdrproc_t xresults, void *resultsp, resultproc_t eachresult) +/* + * u_long prog; // program number + * u_long vers; // version number + * u_long proc; // procedure number + * xdrproc_t xargs; // xdr routine for args + * void *argsp; // pointer to args + * xdrproc_t xresults; // xdr routine for results + * void *resultsp; // pointer to results + * resultproc_t eachresult; // call with each result obtained + */ { if (thr_main()) clnt_broadcast_result_main = eachresult; else { thr_once(&clnt_broadcast_once, clnt_broadcast_key_init); thr_setspecific(clnt_broadcast_key, (void *) eachresult); } return rpc_broadcast((rpcprog_t)prog, (rpcvers_t)vers, (rpcproc_t)proc, xargs, argsp, xresults, resultsp, (resultproc_t) rpc_wrap_bcast, "udp"); } /* * Create the client des authentication object. Obsoleted by * authdes_seccreate(). */ AUTH * -authdes_create(servername, window, syncaddr, ckey) - char *servername; /* network name of server */ - u_int window; /* time to live */ - struct sockaddr *syncaddr; /* optional hostaddr to sync with */ - des_block *ckey; /* optional conversation key to use */ +authdes_create(char *servername, u_int window, struct sockaddr *syncaddr, + des_block *ckey) +/* + * char *servername; // network name of server + * u_int window; // time to live + * struct sockaddr *syncaddr; // optional hostaddr to sync with + * des_block *ckey; // optional conversation key to use + */ { AUTH *dummy; AUTH *nauth; char hostname[NI_MAXHOST]; if (syncaddr) { /* * Change addr to hostname, because that is the way * new interface takes it. */ if (getnameinfo(syncaddr, syncaddr->sa_len, hostname, sizeof hostname, NULL, 0, 0) != 0) goto fallback; nauth = authdes_seccreate(servername, window, hostname, ckey); return (nauth); } fallback: dummy = authdes_seccreate(servername, window, NULL, ckey); return (dummy); } /* * Create a client handle for a unix connection. Obsoleted by clnt_vc_create() */ CLIENT * -clntunix_create(raddr, prog, vers, sockp, sendsz, recvsz) - struct sockaddr_un *raddr; - u_long prog; - u_long vers; - int *sockp; - u_int sendsz; - u_int recvsz; +clntunix_create(struct sockaddr_un *raddr, u_long prog, u_long vers, int *sockp, + u_int sendsz, u_int recvsz) { struct netbuf *svcaddr; CLIENT *cl; int len; cl = NULL; svcaddr = NULL; if ((raddr->sun_len == 0) || ((svcaddr = malloc(sizeof(struct netbuf))) == NULL ) || ((svcaddr->buf = malloc(sizeof(struct sockaddr_un))) == NULL)) { free(svcaddr); rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; return(cl); } if (*sockp < 0) { *sockp = _socket(AF_LOCAL, SOCK_STREAM, 0); len = raddr->sun_len = SUN_LEN(raddr); if ((*sockp < 0) || (_connect(*sockp, (struct sockaddr *)raddr, len) < 0)) { rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; if (*sockp != -1) (void)_close(*sockp); goto done; } } svcaddr->buf = raddr; svcaddr->len = raddr->sun_len; svcaddr->maxlen = sizeof (struct sockaddr_un); cl = clnt_vc_create(*sockp, svcaddr, prog, vers, sendsz, recvsz); done: free(svcaddr->buf); free(svcaddr); return(cl); } /* * Creates, registers, and returns a (rpc) unix based transporter. * Obsoleted by svc_vc_create(). */ SVCXPRT * -svcunix_create(sock, sendsize, recvsize, path) - int sock; - u_int sendsize; - u_int recvsize; - char *path; +svcunix_create(int sock, u_int sendsize, u_int recvsize, char *path) { struct netconfig *nconf; void *localhandle; struct sockaddr_un sun; struct sockaddr *sa; struct t_bind taddr; SVCXPRT *xprt; int addrlen; xprt = (SVCXPRT *)NULL; localhandle = setnetconfig(); while ((nconf = getnetconfig(localhandle)) != NULL) { if (nconf->nc_protofmly != NULL && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) break; } if (nconf == NULL) goto done; if ((sock = __rpc_nconf2fd(nconf)) < 0) goto done; memset(&sun, 0, sizeof sun); sun.sun_family = AF_LOCAL; if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >= sizeof(sun.sun_path)) goto done; sun.sun_len = SUN_LEN(&sun); addrlen = sizeof (struct sockaddr_un); sa = (struct sockaddr *)&sun; if (_bind(sock, sa, addrlen) < 0) goto done; taddr.addr.len = taddr.addr.maxlen = addrlen; taddr.addr.buf = malloc(addrlen); if (taddr.addr.buf == NULL) goto done; memcpy(taddr.addr.buf, sa, addrlen); if (nconf->nc_semantics != NC_TPI_CLTS) { if (_listen(sock, SOMAXCONN) < 0) { free(taddr.addr.buf); goto done; } } xprt = (SVCXPRT *)svc_tli_create(sock, nconf, &taddr, sendsize, recvsize); done: endnetconfig(localhandle); return(xprt); } /* * Like svunix_create(), except the routine takes any *open* UNIX file * descriptor as its first input. Obsoleted by svc_fd_create(); */ SVCXPRT * -svcunixfd_create(fd, sendsize, recvsize) - int fd; - u_int sendsize; - u_int recvsize; +svcunixfd_create(int fd, u_int sendsize, u_int recvsize) { return (svc_fd_create(fd, sendsize, recvsize)); } #endif /* PORTMAP */ Index: stable/10/lib/libc/rpc/rpcb_clnt.c =================================================================== --- stable/10/lib/libc/rpc/rpcb_clnt.c (revision 309488) +++ stable/10/lib/libc/rpc/rpcb_clnt.c (revision 309489) @@ -1,1331 +1,1303 @@ /* $NetBSD: rpcb_clnt.c,v 1.6 2000/07/16 06:41:43 itojun Exp $ */ /*- * Copyright (c) 2010, Oracle America, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of the "Oracle America, Inc." nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* #ident "@(#)rpcb_clnt.c 1.27 94/04/24 SMI" */ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)rpcb_clnt.c 1.30 89/06/21 Copyr 1988 Sun Micro"; #endif #include __FBSDID("$FreeBSD$"); /* * rpcb_clnt.c * interface to rpcbind rpc service. */ #include "namespace.h" #include "reentrant.h" #include #include #include #include #include #include #include #include #ifdef PORTMAP #include /* FOR IPPROTO_TCP/UDP definitions */ #include #endif /* PORTMAP */ #include #include #include #include #include #include #include #include "un-namespace.h" #include "rpc_com.h" #include "mt_misc.h" static struct timeval tottimeout = { 60, 0 }; static const struct timeval rmttimeout = { 3, 0 }; static struct timeval rpcbrmttime = { 15, 0 }; extern bool_t xdr_wrapstring(XDR *, char **); static const char nullstring[] = "\000"; #define CACHESIZE 6 struct address_cache { char *ac_host; char *ac_netid; char *ac_uaddr; struct netbuf *ac_taddr; struct address_cache *ac_next; }; static struct address_cache *front; static int cachesize; #define CLCR_GET_RPCB_TIMEOUT 1 #define CLCR_SET_RPCB_TIMEOUT 2 extern int __rpc_lowvers; static struct address_cache *check_cache(const char *, const char *); static void delete_cache(struct netbuf *); static void add_cache(const char *, const char *, struct netbuf *, char *); static CLIENT *getclnthandle(const char *, const struct netconfig *, char **); static CLIENT *local_rpcb(void); static struct netbuf *got_entry(rpcb_entry_list_ptr, const struct netconfig *); /* * This routine adjusts the timeout used for calls to the remote rpcbind. * Also, this routine can be used to set the use of portmapper version 2 * only when doing rpc_broadcasts * These are private routines that may not be provided in future releases. */ bool_t -__rpc_control(request, info) - int request; - void *info; +__rpc_control(int request, void *info) { switch (request) { case CLCR_GET_RPCB_TIMEOUT: *(struct timeval *)info = tottimeout; break; case CLCR_SET_RPCB_TIMEOUT: tottimeout = *(struct timeval *)info; break; case CLCR_SET_LOWVERS: __rpc_lowvers = *(int *)info; break; case CLCR_GET_LOWVERS: *(int *)info = __rpc_lowvers; break; default: return (FALSE); } return (TRUE); } /* * It might seem that a reader/writer lock would be more reasonable here. * However because getclnthandle(), the only user of the cache functions, * may do a delete_cache() operation if a check_cache() fails to return an * address useful to clnt_tli_create(), we may as well use a mutex. */ /* * As it turns out, if the cache lock is *not* a reader/writer lock, we will * block all clnt_create's if we are trying to connect to a host that's down, * since the lock will be held all during that time. */ /* * The routines check_cache(), add_cache(), delete_cache() manage the * cache of rpcbind addresses for (host, netid). */ static struct address_cache * -check_cache(host, netid) - const char *host, *netid; +check_cache(const char *host, const char *netid) { struct address_cache *cptr; /* READ LOCK HELD ON ENTRY: rpcbaddr_cache_lock */ for (cptr = front; cptr != NULL; cptr = cptr->ac_next) { if (!strcmp(cptr->ac_host, host) && !strcmp(cptr->ac_netid, netid)) { #ifdef ND_DEBUG fprintf(stderr, "Found cache entry for %s: %s\n", host, netid); #endif return (cptr); } } return ((struct address_cache *) NULL); } static void -delete_cache(addr) - struct netbuf *addr; +delete_cache(struct netbuf *addr) { struct address_cache *cptr, *prevptr = NULL; /* WRITE LOCK HELD ON ENTRY: rpcbaddr_cache_lock */ for (cptr = front; cptr != NULL; cptr = cptr->ac_next) { if (!memcmp(cptr->ac_taddr->buf, addr->buf, addr->len)) { free(cptr->ac_host); free(cptr->ac_netid); free(cptr->ac_taddr->buf); free(cptr->ac_taddr); free(cptr->ac_uaddr); if (prevptr) prevptr->ac_next = cptr->ac_next; else front = cptr->ac_next; free(cptr); cachesize--; break; } prevptr = cptr; } } static void add_cache(const char *host, const char *netid, struct netbuf *taddr, char *uaddr) { struct address_cache *ad_cache, *cptr, *prevptr; ad_cache = (struct address_cache *) malloc(sizeof (struct address_cache)); if (!ad_cache) { return; } ad_cache->ac_host = strdup(host); ad_cache->ac_netid = strdup(netid); ad_cache->ac_uaddr = uaddr ? strdup(uaddr) : NULL; ad_cache->ac_taddr = (struct netbuf *)malloc(sizeof (struct netbuf)); if (!ad_cache->ac_host || !ad_cache->ac_netid || !ad_cache->ac_taddr || (uaddr && !ad_cache->ac_uaddr)) { goto out; } ad_cache->ac_taddr->len = ad_cache->ac_taddr->maxlen = taddr->len; ad_cache->ac_taddr->buf = (char *) malloc(taddr->len); if (ad_cache->ac_taddr->buf == NULL) { out: free(ad_cache->ac_host); free(ad_cache->ac_netid); free(ad_cache->ac_uaddr); free(ad_cache->ac_taddr); free(ad_cache); return; } memcpy(ad_cache->ac_taddr->buf, taddr->buf, taddr->len); #ifdef ND_DEBUG fprintf(stderr, "Added to cache: %s : %s\n", host, netid); #endif /* VARIABLES PROTECTED BY rpcbaddr_cache_lock: cptr */ rwlock_wrlock(&rpcbaddr_cache_lock); if (cachesize < CACHESIZE) { ad_cache->ac_next = front; front = ad_cache; cachesize++; } else { /* Free the last entry */ cptr = front; prevptr = NULL; while (cptr->ac_next) { prevptr = cptr; cptr = cptr->ac_next; } #ifdef ND_DEBUG fprintf(stderr, "Deleted from cache: %s : %s\n", cptr->ac_host, cptr->ac_netid); #endif free(cptr->ac_host); free(cptr->ac_netid); free(cptr->ac_taddr->buf); free(cptr->ac_taddr); free(cptr->ac_uaddr); if (prevptr) { prevptr->ac_next = NULL; ad_cache->ac_next = front; front = ad_cache; } else { front = ad_cache; ad_cache->ac_next = NULL; } free(cptr); } rwlock_unlock(&rpcbaddr_cache_lock); } /* * This routine will return a client handle that is connected to the * rpcbind. If targaddr is non-NULL, the "universal address" of the * host will be stored in *targaddr; the caller is responsible for * freeing this string. * On error, returns NULL and free's everything. */ static CLIENT * -getclnthandle(host, nconf, targaddr) - const char *host; - const struct netconfig *nconf; - char **targaddr; +getclnthandle(const char *host, const struct netconfig *nconf, char **targaddr) { CLIENT *client; struct netbuf *addr, taddr; struct netbuf addr_to_delete; struct __rpc_sockinfo si; struct addrinfo hints, *res, *tres; struct address_cache *ad_cache; char *tmpaddr; /* VARIABLES PROTECTED BY rpcbaddr_cache_lock: ad_cache */ /* Get the address of the rpcbind. Check cache first */ client = NULL; addr_to_delete.len = 0; rwlock_rdlock(&rpcbaddr_cache_lock); ad_cache = NULL; if (host != NULL) ad_cache = check_cache(host, nconf->nc_netid); if (ad_cache != NULL) { addr = ad_cache->ac_taddr; client = clnt_tli_create(RPC_ANYFD, nconf, addr, (rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS4, 0, 0); if (client != NULL) { if (targaddr) *targaddr = strdup(ad_cache->ac_uaddr); rwlock_unlock(&rpcbaddr_cache_lock); return (client); } addr_to_delete.len = addr->len; addr_to_delete.buf = (char *)malloc(addr->len); if (addr_to_delete.buf == NULL) { addr_to_delete.len = 0; } else { memcpy(addr_to_delete.buf, addr->buf, addr->len); } } rwlock_unlock(&rpcbaddr_cache_lock); if (addr_to_delete.len != 0) { /* * Assume this may be due to cache data being * outdated */ rwlock_wrlock(&rpcbaddr_cache_lock); delete_cache(&addr_to_delete); rwlock_unlock(&rpcbaddr_cache_lock); free(addr_to_delete.buf); } if (!__rpc_nconf2sockinfo(nconf, &si)) { rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; return NULL; } memset(&hints, 0, sizeof hints); hints.ai_family = si.si_af; hints.ai_socktype = si.si_socktype; hints.ai_protocol = si.si_proto; #ifdef CLNT_DEBUG printf("trying netid %s family %d proto %d socktype %d\n", nconf->nc_netid, si.si_af, si.si_proto, si.si_socktype); #endif if (nconf->nc_protofmly != NULL && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) { client = local_rpcb(); if (! client) { #ifdef ND_DEBUG clnt_pcreateerror("rpcbind clnt interface"); #endif return (NULL); } else { struct sockaddr_un sun; if (targaddr) { *targaddr = malloc(sizeof(sun.sun_path)); if (*targaddr == NULL) { CLNT_DESTROY(client); return (NULL); } strncpy(*targaddr, _PATH_RPCBINDSOCK, sizeof(sun.sun_path)); } return (client); } } else { if (getaddrinfo(host, "sunrpc", &hints, &res) != 0) { rpc_createerr.cf_stat = RPC_UNKNOWNHOST; return NULL; } } for (tres = res; tres != NULL; tres = tres->ai_next) { taddr.buf = tres->ai_addr; taddr.len = taddr.maxlen = tres->ai_addrlen; #ifdef ND_DEBUG { char *ua; ua = taddr2uaddr(nconf, &taddr); fprintf(stderr, "Got it [%s]\n", ua); free(ua); } #endif #ifdef ND_DEBUG { int i; fprintf(stderr, "\tnetbuf len = %d, maxlen = %d\n", taddr.len, taddr.maxlen); fprintf(stderr, "\tAddress is "); for (i = 0; i < taddr.len; i++) fprintf(stderr, "%u.", ((char *)(taddr.buf))[i]); fprintf(stderr, "\n"); } #endif client = clnt_tli_create(RPC_ANYFD, nconf, &taddr, (rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS4, 0, 0); #ifdef ND_DEBUG if (! client) { clnt_pcreateerror("rpcbind clnt interface"); } #endif if (client) { tmpaddr = targaddr ? taddr2uaddr(nconf, &taddr) : NULL; add_cache(host, nconf->nc_netid, &taddr, tmpaddr); if (targaddr) *targaddr = tmpaddr; break; } } if (res) freeaddrinfo(res); return (client); } /* XXX */ #define IN4_LOCALHOST_STRING "127.0.0.1" #define IN6_LOCALHOST_STRING "::1" /* * This routine will return a client handle that is connected to the local * rpcbind. Returns NULL on error and free's everything. */ static CLIENT * local_rpcb(void) { CLIENT *client; static struct netconfig *loopnconf; static char *hostname; int sock; size_t tsize; struct netbuf nbuf; struct sockaddr_un sun; /* * Try connecting to the local rpcbind through a local socket * first. If this doesn't work, try all transports defined in * the netconfig file. */ memset(&sun, 0, sizeof sun); sock = _socket(AF_LOCAL, SOCK_STREAM, 0); if (sock < 0) goto try_nconf; sun.sun_family = AF_LOCAL; strcpy(sun.sun_path, _PATH_RPCBINDSOCK); nbuf.len = sun.sun_len = SUN_LEN(&sun); nbuf.maxlen = sizeof (struct sockaddr_un); nbuf.buf = &sun; tsize = __rpc_get_t_size(AF_LOCAL, 0, 0); client = clnt_vc_create(sock, &nbuf, (rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS, tsize, tsize); if (client != NULL) { /* Mark the socket to be closed in destructor */ (void) CLNT_CONTROL(client, CLSET_FD_CLOSE, NULL); return client; } /* Nobody needs this socket anymore; free the descriptor. */ _close(sock); try_nconf: /* VARIABLES PROTECTED BY loopnconf_lock: loopnconf */ mutex_lock(&loopnconf_lock); if (loopnconf == NULL) { struct netconfig *nconf, *tmpnconf = NULL; void *nc_handle; int fd; nc_handle = setnetconfig(); if (nc_handle == NULL) { /* fails to open netconfig file */ syslog (LOG_ERR, "rpc: failed to open " NETCONFIG); rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; mutex_unlock(&loopnconf_lock); return (NULL); } while ((nconf = getnetconfig(nc_handle)) != NULL) { #ifdef INET6 if ((strcmp(nconf->nc_protofmly, NC_INET6) == 0 || #else if (( #endif strcmp(nconf->nc_protofmly, NC_INET) == 0) && (nconf->nc_semantics == NC_TPI_COTS || nconf->nc_semantics == NC_TPI_COTS_ORD)) { fd = __rpc_nconf2fd(nconf); /* * Can't create a socket, assume that * this family isn't configured in the kernel. */ if (fd < 0) continue; _close(fd); tmpnconf = nconf; if (!strcmp(nconf->nc_protofmly, NC_INET)) hostname = IN4_LOCALHOST_STRING; else hostname = IN6_LOCALHOST_STRING; } } endnetconfig(nc_handle); if (tmpnconf == NULL) { rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; mutex_unlock(&loopnconf_lock); return (NULL); } loopnconf = getnetconfigent(tmpnconf->nc_netid); /* loopnconf is never freed */ } mutex_unlock(&loopnconf_lock); client = getclnthandle(hostname, loopnconf, NULL); return (client); } /* * Set a mapping between program, version and address. * Calls the rpcbind service to do the mapping. + * + * nconf - Network structure of transport + * address - Services netconfig address */ bool_t -rpcb_set(program, version, nconf, address) - rpcprog_t program; - rpcvers_t version; - const struct netconfig *nconf; /* Network structure of transport */ - const struct netbuf *address; /* Services netconfig address */ +rpcb_set(rpcprog_t program, rpcvers_t version, const struct netconfig *nconf, + const struct netbuf *address) { CLIENT *client; bool_t rslt = FALSE; RPCB parms; char uidbuf[32]; /* parameter checking */ if (nconf == NULL) { rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; return (FALSE); } if (address == NULL) { rpc_createerr.cf_stat = RPC_UNKNOWNADDR; return (FALSE); } client = local_rpcb(); if (! client) { return (FALSE); } /* convert to universal */ /*LINTED const castaway*/ parms.r_addr = taddr2uaddr((struct netconfig *) nconf, (struct netbuf *)address); if (!parms.r_addr) { CLNT_DESTROY(client); rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE; return (FALSE); /* no universal address */ } parms.r_prog = program; parms.r_vers = version; parms.r_netid = nconf->nc_netid; /* * Though uid is not being used directly, we still send it for * completeness. For non-unix platforms, perhaps some other * string or an empty string can be sent. */ (void) snprintf(uidbuf, sizeof uidbuf, "%d", geteuid()); parms.r_owner = uidbuf; CLNT_CALL(client, (rpcproc_t)RPCBPROC_SET, (xdrproc_t) xdr_rpcb, (char *)(void *)&parms, (xdrproc_t) xdr_bool, (char *)(void *)&rslt, tottimeout); CLNT_DESTROY(client); free(parms.r_addr); return (rslt); } /* * Remove the mapping between program, version and netbuf address. * Calls the rpcbind service to do the un-mapping. * If netbuf is NULL, unset for all the transports, otherwise unset * only for the given transport. */ bool_t -rpcb_unset(program, version, nconf) - rpcprog_t program; - rpcvers_t version; - const struct netconfig *nconf; +rpcb_unset(rpcprog_t program, rpcvers_t version, const struct netconfig *nconf) { CLIENT *client; bool_t rslt = FALSE; RPCB parms; char uidbuf[32]; client = local_rpcb(); if (! client) { return (FALSE); } parms.r_prog = program; parms.r_vers = version; if (nconf) parms.r_netid = nconf->nc_netid; else { /*LINTED const castaway*/ parms.r_netid = (char *) &nullstring[0]; /* unsets all */ } /*LINTED const castaway*/ parms.r_addr = (char *) &nullstring[0]; (void) snprintf(uidbuf, sizeof uidbuf, "%d", geteuid()); parms.r_owner = uidbuf; CLNT_CALL(client, (rpcproc_t)RPCBPROC_UNSET, (xdrproc_t) xdr_rpcb, (char *)(void *)&parms, (xdrproc_t) xdr_bool, (char *)(void *)&rslt, tottimeout); CLNT_DESTROY(client); return (rslt); } /* * From the merged list, find the appropriate entry */ static struct netbuf * -got_entry(relp, nconf) - rpcb_entry_list_ptr relp; - const struct netconfig *nconf; +got_entry(rpcb_entry_list_ptr relp, const struct netconfig *nconf) { struct netbuf *na = NULL; rpcb_entry_list_ptr sp; rpcb_entry *rmap; for (sp = relp; sp != NULL; sp = sp->rpcb_entry_next) { rmap = &sp->rpcb_entry_map; if ((strcmp(nconf->nc_proto, rmap->r_nc_proto) == 0) && (strcmp(nconf->nc_protofmly, rmap->r_nc_protofmly) == 0) && (nconf->nc_semantics == rmap->r_nc_semantics) && (rmap->r_maddr != NULL) && (rmap->r_maddr[0] != 0)) { na = uaddr2taddr(nconf, rmap->r_maddr); #ifdef ND_DEBUG fprintf(stderr, "\tRemote address is [%s].\n", rmap->r_maddr); if (!na) fprintf(stderr, "\tCouldn't resolve remote address!\n"); #endif break; } } return (na); } /* * Quick check to see if rpcbind is up. Tries to connect over * local transport. */ static bool_t __rpcbind_is_up(void) { struct netconfig *nconf; struct sockaddr_un sun; void *localhandle; int sock; nconf = NULL; localhandle = setnetconfig(); while ((nconf = getnetconfig(localhandle)) != NULL) { if (nconf->nc_protofmly != NULL && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) break; } endnetconfig(localhandle); if (nconf == NULL) return (FALSE); memset(&sun, 0, sizeof sun); sock = _socket(AF_LOCAL, SOCK_STREAM, 0); if (sock < 0) return (FALSE); sun.sun_family = AF_LOCAL; strncpy(sun.sun_path, _PATH_RPCBINDSOCK, sizeof(sun.sun_path)); sun.sun_len = SUN_LEN(&sun); if (_connect(sock, (struct sockaddr *)&sun, sun.sun_len) < 0) { _close(sock); return (FALSE); } _close(sock); return (TRUE); } /* * An internal function which optimizes rpcb_getaddr function. It also * returns the client handle that it uses to contact the remote rpcbind. * * The algorithm used: If the transports is TCP or UDP, it first tries * version 2 (portmap), 4 and then 3 (svr4). This order should be * changed in the next OS release to 4, 2 and 3. We are assuming that by * that time, version 4 would be available on many machines on the network. * With this algorithm, we get performance as well as a plan for * obsoleting version 2. * * For all other transports, the algorithm remains as 4 and then 3. * * XXX: Due to some problems with t_connect(), we do not reuse the same client * handle for COTS cases and hence in these cases we do not return the * client handle. This code will change if t_connect() ever * starts working properly. Also look under clnt_vc.c. */ struct netbuf * -__rpcb_findaddr_timed(program, version, nconf, host, clpp, tp) - rpcprog_t program; - rpcvers_t version; - const struct netconfig *nconf; - const char *host; - CLIENT **clpp; - struct timeval *tp; +__rpcb_findaddr_timed(rpcprog_t program, rpcvers_t version, + const struct netconfig *nconf, const char *host, + CLIENT **clpp, struct timeval *tp) { static bool_t check_rpcbind = TRUE; CLIENT *client = NULL; RPCB parms; enum clnt_stat clnt_st; char *ua = NULL; rpcvers_t vers; struct netbuf *address = NULL; rpcvers_t start_vers = RPCBVERS4; struct netbuf servaddr; /* parameter checking */ if (nconf == NULL) { rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; return (NULL); } parms.r_addr = NULL; /* * Use default total timeout if no timeout is specified. */ if (tp == NULL) tp = &tottimeout; #ifdef PORTMAP /* Try version 2 for TCP or UDP */ if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { u_short port = 0; struct netbuf remote; rpcvers_t pmapvers = 2; struct pmap pmapparms; /* * Try UDP only - there are some portmappers out * there that use UDP only. */ if (strcmp(nconf->nc_proto, NC_TCP) == 0) { struct netconfig *newnconf; if ((newnconf = getnetconfigent("udp")) == NULL) { rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; return (NULL); } client = getclnthandle(host, newnconf, &parms.r_addr); freenetconfigent(newnconf); } else { client = getclnthandle(host, nconf, &parms.r_addr); } if (client == NULL) return (NULL); /* * Set version and retry timeout. */ CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime); CLNT_CONTROL(client, CLSET_VERS, (char *)&pmapvers); pmapparms.pm_prog = program; pmapparms.pm_vers = version; pmapparms.pm_prot = strcmp(nconf->nc_proto, NC_TCP) ? IPPROTO_UDP : IPPROTO_TCP; pmapparms.pm_port = 0; /* not needed */ clnt_st = CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT, (xdrproc_t) xdr_pmap, (caddr_t)(void *)&pmapparms, (xdrproc_t) xdr_u_short, (caddr_t)(void *)&port, *tp); if (clnt_st != RPC_SUCCESS) { if ((clnt_st == RPC_PROGVERSMISMATCH) || (clnt_st == RPC_PROGUNAVAIL)) goto try_rpcbind; /* Try different versions */ rpc_createerr.cf_stat = RPC_PMAPFAILURE; clnt_geterr(client, &rpc_createerr.cf_error); goto error; } else if (port == 0) { address = NULL; rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; goto error; } port = htons(port); CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)&remote); if (((address = (struct netbuf *) malloc(sizeof (struct netbuf))) == NULL) || ((address->buf = (char *) malloc(remote.len)) == NULL)) { rpc_createerr.cf_stat = RPC_SYSTEMERROR; clnt_geterr(client, &rpc_createerr.cf_error); free(address); address = NULL; goto error; } memcpy(address->buf, remote.buf, remote.len); memcpy(&((char *)address->buf)[sizeof (short)], (char *)(void *)&port, sizeof (short)); address->len = address->maxlen = remote.len; goto done; } #endif /* PORTMAP */ try_rpcbind: /* * Check if rpcbind is up. This prevents needless delays when * accessing applications such as the keyserver while booting * disklessly. */ if (check_rpcbind && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) { if (!__rpcbind_is_up()) { rpc_createerr.cf_stat = RPC_PMAPFAILURE; rpc_createerr.cf_error.re_errno = 0; goto error; } check_rpcbind = FALSE; } /* * Now we try version 4 and then 3. * We also send the remote system the address we used to * contact it in case it can help to connect back with us */ parms.r_prog = program; parms.r_vers = version; /*LINTED const castaway*/ parms.r_owner = (char *) &nullstring[0]; /* not needed; */ /* just for xdring */ parms.r_netid = nconf->nc_netid; /* not really needed */ /* * If a COTS transport is being used, try getting address via CLTS * transport. This works only with version 4. */ if (nconf->nc_semantics == NC_TPI_COTS_ORD || nconf->nc_semantics == NC_TPI_COTS) { void *handle; struct netconfig *nconf_clts; rpcb_entry_list_ptr relp = NULL; if (client == NULL) { /* This did not go through the above PORTMAP/TCP code */ if ((handle = __rpc_setconf("datagram_v")) != NULL) { while ((nconf_clts = __rpc_getconf(handle)) != NULL) { if (strcmp(nconf_clts->nc_protofmly, nconf->nc_protofmly) != 0) { continue; } client = getclnthandle(host, nconf_clts, &parms.r_addr); break; } __rpc_endconf(handle); } if (client == NULL) goto regular_rpcbind; /* Go the regular way */ } else { /* This is a UDP PORTMAP handle. Change to version 4 */ vers = RPCBVERS4; CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); } /* * We also send the remote system the address we used to * contact it in case it can help it connect back with us */ if (parms.r_addr == NULL) { /*LINTED const castaway*/ parms.r_addr = (char *) &nullstring[0]; /* for XDRing */ } CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime); clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDRLIST, (xdrproc_t) xdr_rpcb, (char *)(void *)&parms, (xdrproc_t) xdr_rpcb_entry_list_ptr, (char *)(void *)&relp, *tp); if (clnt_st == RPC_SUCCESS) { if ((address = got_entry(relp, nconf)) != NULL) { xdr_free((xdrproc_t) xdr_rpcb_entry_list_ptr, (char *)(void *)&relp); CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)(void *)&servaddr); __rpc_fixup_addr(address, &servaddr); goto done; } /* Entry not found for this transport */ xdr_free((xdrproc_t) xdr_rpcb_entry_list_ptr, (char *)(void *)&relp); /* * XXX: should have perhaps returned with error but * since the remote machine might not always be able * to send the address on all transports, we try the * regular way with regular_rpcbind */ goto regular_rpcbind; } else if ((clnt_st == RPC_PROGVERSMISMATCH) || (clnt_st == RPC_PROGUNAVAIL)) { start_vers = RPCBVERS; /* Try version 3 now */ goto regular_rpcbind; /* Try different versions */ } else { rpc_createerr.cf_stat = RPC_PMAPFAILURE; clnt_geterr(client, &rpc_createerr.cf_error); goto error; } } regular_rpcbind: /* Now the same transport is to be used to get the address */ if (client && ((nconf->nc_semantics == NC_TPI_COTS_ORD) || (nconf->nc_semantics == NC_TPI_COTS))) { /* A CLTS type of client - destroy it */ CLNT_DESTROY(client); client = NULL; } if (client == NULL) { client = getclnthandle(host, nconf, &parms.r_addr); if (client == NULL) { goto error; } } if (parms.r_addr == NULL) { /*LINTED const castaway*/ parms.r_addr = (char *) &nullstring[0]; } /* First try from start_vers and then version 3 (RPCBVERS) */ CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *) &rpcbrmttime); for (vers = start_vers; vers >= RPCBVERS; vers--) { /* Set the version */ CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDR, (xdrproc_t) xdr_rpcb, (char *)(void *)&parms, (xdrproc_t) xdr_wrapstring, (char *)(void *) &ua, *tp); if (clnt_st == RPC_SUCCESS) { if ((ua == NULL) || (ua[0] == 0)) { /* address unknown */ rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; goto error; } address = uaddr2taddr(nconf, ua); #ifdef ND_DEBUG fprintf(stderr, "\tRemote address is [%s]\n", ua); if (!address) fprintf(stderr, "\tCouldn't resolve remote address!\n"); #endif xdr_free((xdrproc_t)xdr_wrapstring, (char *)(void *)&ua); if (! address) { /* We don't know about your universal address */ rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE; goto error; } CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)(void *)&servaddr); __rpc_fixup_addr(address, &servaddr); goto done; } else if (clnt_st == RPC_PROGVERSMISMATCH) { struct rpc_err rpcerr; clnt_geterr(client, &rpcerr); if (rpcerr.re_vers.low > RPCBVERS4) goto error; /* a new version, can't handle */ } else if (clnt_st != RPC_PROGUNAVAIL) { /* Cant handle this error */ rpc_createerr.cf_stat = clnt_st; clnt_geterr(client, &rpc_createerr.cf_error); goto error; } } error: if (client) { CLNT_DESTROY(client); client = NULL; } done: if (nconf->nc_semantics != NC_TPI_CLTS) { /* This client is the connectionless one */ if (client) { CLNT_DESTROY(client); client = NULL; } } if (clpp) { *clpp = client; } else if (client) { CLNT_DESTROY(client); } if (parms.r_addr != NULL && parms.r_addr != nullstring) free(parms.r_addr); return (address); } /* * Find the mapped address for program, version. * Calls the rpcbind service remotely to do the lookup. * Uses the transport specified in nconf. * Returns FALSE (0) if no map exists, else returns 1. * * Assuming that the address is all properly allocated */ int -rpcb_getaddr(program, version, nconf, address, host) - rpcprog_t program; - rpcvers_t version; - const struct netconfig *nconf; - struct netbuf *address; - const char *host; +rpcb_getaddr(rpcprog_t program, rpcvers_t version, const struct netconfig *nconf, + struct netbuf *address, const char *host) { struct netbuf *na; if ((na = __rpcb_findaddr_timed(program, version, (struct netconfig *) nconf, (char *) host, (CLIENT **) NULL, (struct timeval *) NULL)) == NULL) return (FALSE); if (na->len > address->maxlen) { /* Too long address */ free(na->buf); free(na); rpc_createerr.cf_stat = RPC_FAILED; return (FALSE); } memcpy(address->buf, na->buf, (size_t)na->len); address->len = na->len; free(na->buf); free(na); return (TRUE); } /* * Get a copy of the current maps. * Calls the rpcbind service remotely to get the maps. * * It returns only a list of the services * It returns NULL on failure. */ rpcblist * -rpcb_getmaps(nconf, host) - const struct netconfig *nconf; - const char *host; +rpcb_getmaps(const struct netconfig *nconf, const char *host) { rpcblist_ptr head = NULL; CLIENT *client; enum clnt_stat clnt_st; rpcvers_t vers = 0; client = getclnthandle(host, nconf, NULL); if (client == NULL) { return (head); } clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_DUMP, (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_rpcblist_ptr, (char *)(void *)&head, tottimeout); if (clnt_st == RPC_SUCCESS) goto done; if ((clnt_st != RPC_PROGVERSMISMATCH) && (clnt_st != RPC_PROGUNAVAIL)) { rpc_createerr.cf_stat = RPC_RPCBFAILURE; clnt_geterr(client, &rpc_createerr.cf_error); goto done; } /* fall back to earlier version */ CLNT_CONTROL(client, CLGET_VERS, (char *)(void *)&vers); if (vers == RPCBVERS4) { vers = RPCBVERS; CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_DUMP, (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_rpcblist_ptr, (char *)(void *)&head, tottimeout) == RPC_SUCCESS) goto done; } rpc_createerr.cf_stat = RPC_RPCBFAILURE; clnt_geterr(client, &rpc_createerr.cf_error); done: CLNT_DESTROY(client); return (head); } /* * rpcbinder remote-call-service interface. * This routine is used to call the rpcbind remote call service * which will look up a service program in the address maps, and then * remotely call that routine with the given parameters. This allows * programs to do a lookup and call in one step. * * nconf -Netconfig structure * host - Remote host name * proc - Remote proc identifiers * xdrargs, xdrres; XDR routines * argsp, resp - Argument and Result * tout - Timeout value for this call * addr_ptr - Preallocated netbuf address */ enum clnt_stat rpcb_rmtcall(const struct netconfig *nconf, const char *host, rpcprog_t prog, rpcvers_t vers, rpcproc_t proc, xdrproc_t xdrargs, caddr_t argsp, xdrproc_t xdrres, caddr_t resp, struct timeval tout, const struct netbuf *addr_ptr) { CLIENT *client; enum clnt_stat stat; struct r_rpcb_rmtcallargs a; struct r_rpcb_rmtcallres r; rpcvers_t rpcb_vers; stat = 0; client = getclnthandle(host, nconf, NULL); if (client == NULL) { return (RPC_FAILED); } /*LINTED const castaway*/ CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)(void *)&rmttimeout); a.prog = prog; a.vers = vers; a.proc = proc; a.args.args_val = argsp; a.xdr_args = xdrargs; r.addr = NULL; r.results.results_val = resp; r.xdr_res = xdrres; for (rpcb_vers = RPCBVERS4; rpcb_vers >= RPCBVERS; rpcb_vers--) { CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&rpcb_vers); stat = CLNT_CALL(client, (rpcproc_t)RPCBPROC_CALLIT, (xdrproc_t) xdr_rpcb_rmtcallargs, (char *)(void *)&a, (xdrproc_t) xdr_rpcb_rmtcallres, (char *)(void *)&r, tout); if ((stat == RPC_SUCCESS) && (addr_ptr != NULL)) { struct netbuf *na; /*LINTED const castaway*/ na = uaddr2taddr((struct netconfig *) nconf, r.addr); if (!na) { stat = RPC_N2AXLATEFAILURE; /*LINTED const castaway*/ ((struct netbuf *) addr_ptr)->len = 0; goto error; } if (na->len > addr_ptr->maxlen) { /* Too long address */ stat = RPC_FAILED; /* XXX A better error no */ free(na->buf); free(na); /*LINTED const castaway*/ ((struct netbuf *) addr_ptr)->len = 0; goto error; } memcpy(addr_ptr->buf, na->buf, (size_t)na->len); /*LINTED const castaway*/ ((struct netbuf *)addr_ptr)->len = na->len; free(na->buf); free(na); break; } else if ((stat != RPC_PROGVERSMISMATCH) && (stat != RPC_PROGUNAVAIL)) { goto error; } } error: CLNT_DESTROY(client); if (r.addr) xdr_free((xdrproc_t) xdr_wrapstring, (char *)(void *)&r.addr); return (stat); } /* * Gets the time on the remote host. * Returns 1 if succeeds else 0. */ bool_t -rpcb_gettime(host, timep) - const char *host; - time_t *timep; +rpcb_gettime(const char *host, time_t *timep) { CLIENT *client = NULL; void *handle; struct netconfig *nconf; rpcvers_t vers; enum clnt_stat st; if ((host == NULL) || (host[0] == 0)) { time(timep); return (TRUE); } if ((handle = __rpc_setconf("netpath")) == NULL) { rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; return (FALSE); } rpc_createerr.cf_stat = RPC_SUCCESS; while (client == NULL) { if ((nconf = __rpc_getconf(handle)) == NULL) { if (rpc_createerr.cf_stat == RPC_SUCCESS) rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; break; } client = getclnthandle(host, nconf, NULL); if (client) break; } __rpc_endconf(handle); if (client == (CLIENT *) NULL) { return (FALSE); } st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETTIME, (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_int, (char *)(void *)timep, tottimeout); if ((st == RPC_PROGVERSMISMATCH) || (st == RPC_PROGUNAVAIL)) { CLNT_CONTROL(client, CLGET_VERS, (char *)(void *)&vers); if (vers == RPCBVERS4) { /* fall back to earlier version */ vers = RPCBVERS; CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETTIME, (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_int, (char *)(void *)timep, tottimeout); } } CLNT_DESTROY(client); return (st == RPC_SUCCESS? TRUE: FALSE); } /* * Converts taddr to universal address. This routine should never * really be called because local n2a libraries are always provided. */ char * -rpcb_taddr2uaddr(nconf, taddr) - struct netconfig *nconf; - struct netbuf *taddr; +rpcb_taddr2uaddr(struct netconfig *nconf, struct netbuf *taddr) { CLIENT *client; char *uaddr = NULL; /* parameter checking */ if (nconf == NULL) { rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; return (NULL); } if (taddr == NULL) { rpc_createerr.cf_stat = RPC_UNKNOWNADDR; return (NULL); } client = local_rpcb(); if (! client) { return (NULL); } CLNT_CALL(client, (rpcproc_t)RPCBPROC_TADDR2UADDR, (xdrproc_t) xdr_netbuf, (char *)(void *)taddr, (xdrproc_t) xdr_wrapstring, (char *)(void *)&uaddr, tottimeout); CLNT_DESTROY(client); return (uaddr); } /* * Converts universal address to netbuf. This routine should never * really be called because local n2a libraries are always provided. */ struct netbuf * -rpcb_uaddr2taddr(nconf, uaddr) - struct netconfig *nconf; - char *uaddr; +rpcb_uaddr2taddr(struct netconfig *nconf, char *uaddr) { CLIENT *client; struct netbuf *taddr; /* parameter checking */ if (nconf == NULL) { rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; return (NULL); } if (uaddr == NULL) { rpc_createerr.cf_stat = RPC_UNKNOWNADDR; return (NULL); } client = local_rpcb(); if (! client) { return (NULL); } taddr = (struct netbuf *)calloc(1, sizeof (struct netbuf)); if (taddr == NULL) { CLNT_DESTROY(client); return (NULL); } if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_UADDR2TADDR, (xdrproc_t) xdr_wrapstring, (char *)(void *)&uaddr, (xdrproc_t) xdr_netbuf, (char *)(void *)taddr, tottimeout) != RPC_SUCCESS) { free(taddr); taddr = NULL; } CLNT_DESTROY(client); return (taddr); } Index: stable/10/lib/libc/rpc/rpcdname.c =================================================================== --- stable/10/lib/libc/rpc/rpcdname.c (revision 309488) +++ stable/10/lib/libc/rpc/rpcdname.c (revision 309489) @@ -1,80 +1,79 @@ /*- * Copyright (c) 2009, Sun Microsystems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of Sun Microsystems, Inc. nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)rpcdname.c 1.7 91/03/11 Copyr 1989 Sun Micro"; #endif #include __FBSDID("$FreeBSD$"); /* * rpcdname.c * Gets the default domain name */ #include "namespace.h" #include #include #include #include "un-namespace.h" static char *default_domain; static char * get_default_domain(void) { char temp[256]; if (default_domain != NULL) return (default_domain); if (getdomainname(temp, sizeof(temp)) < 0) return (0); if ((int) strlen(temp) > 0) { default_domain = malloc((strlen(temp) + (unsigned)1)); if (default_domain == NULL) 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; +__rpc_get_default_domain(char **domain) { if ((*domain = get_default_domain()) != NULL) return (0); return (-1); } Index: stable/10/lib/libc/rpc/rtime.c =================================================================== --- stable/10/lib/libc/rpc/rtime.c (revision 309488) +++ stable/10/lib/libc/rpc/rtime.c (revision 309489) @@ -1,159 +1,156 @@ /*- * Copyright (c) 2009, Sun Microsystems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of Sun Microsystems, Inc. nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright (c) 1988 by Sun Microsystems, Inc. */ /* * rtime - get time from remote machine * * gets time, obtaining value from host * on the udp/time socket. Since timeserver returns * with time of day in seconds since Jan 1, 1900, must * subtract seconds before Jan 1, 1970 to get * what unix uses. */ #include "namespace.h" #include #include #include #include #include #include #include #include #include #include #include "un-namespace.h" #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)rtime.c 2.2 88/08/10 4.0 RPCSRC; from 1.8 88/02/08 SMI"; #endif #include __FBSDID("$FreeBSD$"); extern int _rpc_dtablesize( void ); #define NYEARS (unsigned long)(1970 - 1900) #define TOFFSET (unsigned long)(60*60*24*(365*NYEARS + (NYEARS/4))) static void do_close( int ); int -rtime(addrp, timep, timeout) - struct sockaddr_in *addrp; - struct timeval *timep; - struct timeval *timeout; +rtime(struct sockaddr_in *addrp, struct timeval *timep, + struct timeval *timeout) { int s; fd_set readfds; int res; unsigned long thetime; struct sockaddr_in from; socklen_t fromlen; int type; struct servent *serv; if (timeout == NULL) { type = SOCK_STREAM; } else { type = SOCK_DGRAM; } s = _socket(AF_INET, type, 0); if (s < 0) { return(-1); } addrp->sin_family = AF_INET; /* TCP and UDP port are the same in this case */ if ((serv = getservbyname("time", "tcp")) == NULL) { return(-1); } addrp->sin_port = serv->s_port; if (type == SOCK_DGRAM) { res = _sendto(s, (char *)&thetime, sizeof(thetime), 0, (struct sockaddr *)addrp, sizeof(*addrp)); if (res < 0) { do_close(s); return(-1); } do { FD_ZERO(&readfds); FD_SET(s, &readfds); res = _select(_rpc_dtablesize(), &readfds, (fd_set *)NULL, (fd_set *)NULL, timeout); } while (res < 0 && errno == EINTR); if (res <= 0) { if (res == 0) { errno = ETIMEDOUT; } do_close(s); return(-1); } fromlen = sizeof(from); res = _recvfrom(s, (char *)&thetime, sizeof(thetime), 0, (struct sockaddr *)&from, &fromlen); do_close(s); if (res < 0) { return(-1); } } else { if (_connect(s, (struct sockaddr *)addrp, sizeof(*addrp)) < 0) { do_close(s); return(-1); } res = _read(s, (char *)&thetime, sizeof(thetime)); do_close(s); if (res < 0) { return(-1); } } if (res != sizeof(thetime)) { errno = EIO; return(-1); } thetime = ntohl(thetime); timep->tv_sec = thetime - TOFFSET; timep->tv_usec = 0; return(0); } static void -do_close(s) - int s; +do_close(int s) { int save; save = errno; (void)_close(s); errno = save; } Index: stable/10/lib/libc/rpc/svc_auth.c =================================================================== --- stable/10/lib/libc/rpc/svc_auth.c (revision 309488) +++ stable/10/lib/libc/rpc/svc_auth.c (revision 309489) @@ -1,231 +1,224 @@ /* $NetBSD: svc_auth.c,v 1.12 2000/07/06 03:10:35 christos Exp $ */ /*- * Copyright (c) 2009, Sun Microsystems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of Sun Microsystems, Inc. nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright (c) 1986-1991 by Sun Microsystems Inc. */ #if defined(LIBC_SCCS) && !defined(lint) #ident "@(#)svc_auth.c 1.16 94/04/24 SMI" static char sccsid[] = "@(#)svc_auth.c 1.26 89/02/07 Copyr 1984 Sun Micro"; #endif #include __FBSDID("$FreeBSD$"); /* * svc_auth.c, Server-side rpc authenticator interface. * */ #include "namespace.h" #include "reentrant.h" #include #include #include #include "un-namespace.h" #include "mt_misc.h" /* * svcauthsw is the bdevsw of server side authentication. * * Server side authenticators are called from authenticate by * using the client auth struct flavor field to index into svcauthsw. * The server auth flavors must implement a routine that looks * like: * * enum auth_stat * flavorx_auth(rqst, msg) * struct svc_req *rqst; * struct rpc_msg *msg; * */ /* declarations to allow servers to specify new authentication flavors */ struct authsvc { int flavor; enum auth_stat (*handler)(struct svc_req *, struct rpc_msg *); struct authsvc *next; }; static struct authsvc *Auths = NULL; struct svc_auth_ops svc_auth_null_ops; /* * The call rpc message, msg has been obtained from the wire. The msg contains * the raw form of credentials and verifiers. authenticate returns AUTH_OK * if the msg is successfully authenticated. If AUTH_OK then the routine also * does the following things: * set rqst->rq_xprt->verf to the appropriate response verifier; * sets rqst->rq_client_cred to the "cooked" form of the credentials. * * NB: rqst->rq_cxprt->verf must be pre-alloctaed; * its length is set appropriately. * * The caller still owns and is responsible for msg->u.cmb.cred and * msg->u.cmb.verf. The authentication system retains ownership of * rqst->rq_client_cred, the cooked credentials. * * There is an assumption that any flavour less than AUTH_NULL is * invalid. */ enum auth_stat _authenticate(struct svc_req *rqst, struct rpc_msg *msg) { int cred_flavor; struct authsvc *asp; enum auth_stat dummy; /* VARIABLES PROTECTED BY authsvc_lock: asp, Auths */ rqst->rq_cred = msg->rm_call.cb_cred; SVC_AUTH(rqst->rq_xprt).svc_ah_ops = &svc_auth_null_ops; SVC_AUTH(rqst->rq_xprt).svc_ah_private = NULL; rqst->rq_xprt->xp_verf.oa_flavor = _null_auth.oa_flavor; rqst->rq_xprt->xp_verf.oa_length = 0; cred_flavor = rqst->rq_cred.oa_flavor; switch (cred_flavor) { case AUTH_NULL: dummy = _svcauth_null(rqst, msg); return (dummy); case AUTH_SYS: dummy = _svcauth_unix(rqst, msg); return (dummy); case AUTH_SHORT: dummy = _svcauth_short(rqst, msg); return (dummy); #ifdef DES_BUILTIN case AUTH_DES: dummy = _svcauth_des(rqst, msg); return (dummy); #endif default: break; } /* flavor doesn't match any of the builtin types, so try new ones */ mutex_lock(&authsvc_lock); for (asp = Auths; asp; asp = asp->next) { if (asp->flavor == cred_flavor) { enum auth_stat as; as = (*asp->handler)(rqst, msg); mutex_unlock(&authsvc_lock); return (as); } } mutex_unlock(&authsvc_lock); return (AUTH_REJECTEDCRED); } /* * A set of null auth methods used by any authentication protocols * that don't need to inspect or modify the message body. */ static bool_t -svcauth_null_wrap(auth, xdrs, xdr_func, xdr_ptr) - SVCAUTH *auth; - XDR *xdrs; - xdrproc_t xdr_func; - caddr_t xdr_ptr; +svcauth_null_wrap(SVCAUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr) { return (xdr_func(xdrs, xdr_ptr)); } struct svc_auth_ops svc_auth_null_ops = { svcauth_null_wrap, svcauth_null_wrap, }; /*ARGSUSED*/ enum auth_stat -_svcauth_null(rqst, msg) - struct svc_req *rqst; - struct rpc_msg *msg; +_svcauth_null(struct svc_req *rqst, struct rpc_msg *msg) { return (AUTH_OK); } /* * Allow the rpc service to register new authentication types that it is * prepared to handle. When an authentication flavor is registered, * the flavor is checked against already registered values. If not * registered, then a new Auths entry is added on the list. * * There is no provision to delete a registration once registered. * * This routine returns: * 0 if registration successful * 1 if flavor already registered * -1 if can't register (errno set) */ int -svc_auth_reg(cred_flavor, handler) - int cred_flavor; - enum auth_stat (*handler)(struct svc_req *, struct rpc_msg *); +svc_auth_reg(int cred_flavor, + enum auth_stat (*handler)(struct svc_req *, struct rpc_msg *)) { struct authsvc *asp; switch (cred_flavor) { case AUTH_NULL: case AUTH_SYS: case AUTH_SHORT: #ifdef DES_BUILTIN case AUTH_DES: #endif /* already registered */ return (1); default: mutex_lock(&authsvc_lock); for (asp = Auths; asp; asp = asp->next) { if (asp->flavor == cred_flavor) { /* already registered */ mutex_unlock(&authsvc_lock); return (1); } } /* this is a new one, so go ahead and register it */ asp = mem_alloc(sizeof (*asp)); if (asp == NULL) { mutex_unlock(&authsvc_lock); return (-1); } asp->flavor = cred_flavor; asp->handler = handler; asp->next = Auths; Auths = asp; mutex_unlock(&authsvc_lock); break; } return (0); } Index: stable/10/lib/libc/rpc/svc_auth_des.c =================================================================== --- stable/10/lib/libc/rpc/svc_auth_des.c (revision 309488) +++ stable/10/lib/libc/rpc/svc_auth_des.c (revision 309489) @@ -1,537 +1,526 @@ /* * Copyright (c) 1988 by Sun Microsystems, Inc. */ /*- * Copyright (c) 2009, Sun Microsystems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of Sun Microsystems, Inc. nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * svcauth_des.c, server-side des authentication * * We insure for the service the following: * (1) The timestamp microseconds do not exceed 1 million. * (2) The timestamp plus the window is less than the current time. * (3) The timestamp is not less than the one previously * seen in the current session. * * It is up to the server to determine if the window size is * too small . * */ #include "namespace.h" #include "reentrant.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "libc_private.h" #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)svcauth_des.c 2.3 89/07/11 4.0 RPCSRC; from 1.15 88/02/08 SMI"; #endif #include __FBSDID("$FreeBSD$"); extern int key_decryptsession_pk(const char *, netobj *, des_block *); #define debug(msg) printf("svcauth_des: %s\n", msg) #define USEC_PER_SEC ((u_long) 1000000L) #define BEFORE(t1, t2) timercmp(t1, t2, <) /* * LRU cache of conversation keys and some other useful items. */ #define AUTHDES_CACHESZ 64 struct cache_entry { des_block key; /* conversation key */ char *rname; /* client's name */ u_int window; /* credential lifetime window */ struct timeval laststamp; /* detect replays of creds */ char *localcred; /* generic local credential */ }; static struct cache_entry *authdes_cache/* [AUTHDES_CACHESZ] */; static short *authdes_lru/* [AUTHDES_CACHESZ] */; static void cache_init(void); /* initialize the cache */ static short cache_spot(des_block *, char *, struct timeval *); /* find an entry in the cache */ -static void cache_ref(/*short sid*/); /* note that sid was ref'd */ +static void cache_ref(short sid); /* note that sid was ref'd */ static void invalidate(char *); /* invalidate entry in cache */ /* * cache statistics */ static struct { u_long ncachehits; /* times cache hit, and is not replay */ u_long ncachereplays; /* times cache hit, and is replay */ u_long ncachemisses; /* times cache missed */ } svcauthdes_stats; /* * Service side authenticator for AUTH_DES */ enum auth_stat -_svcauth_des(rqst, msg) - struct svc_req *rqst; - struct rpc_msg *msg; +_svcauth_des(struct svc_req *rqst, struct rpc_msg *msg) { long *ixdr; des_block cryptbuf[2]; struct authdes_cred *cred; struct authdes_verf verf; int status; struct cache_entry *entry; short sid = 0; des_block *sessionkey; des_block ivec; u_int window; struct timeval timestamp; u_long namelen; struct area { struct authdes_cred area_cred; char area_netname[MAXNETNAMELEN+1]; } *area; if (authdes_cache == NULL) { cache_init(); } area = (struct area *)rqst->rq_clntcred; cred = (struct authdes_cred *)&area->area_cred; /* * Get the credential */ ixdr = (long *)msg->rm_call.cb_cred.oa_base; cred->adc_namekind = IXDR_GET_ENUM(ixdr, enum authdes_namekind); switch (cred->adc_namekind) { case ADN_FULLNAME: namelen = IXDR_GET_U_LONG(ixdr); if (namelen > MAXNETNAMELEN) { return (AUTH_BADCRED); } cred->adc_fullname.name = area->area_netname; bcopy((char *)ixdr, cred->adc_fullname.name, (u_int)namelen); cred->adc_fullname.name[namelen] = 0; ixdr += (RNDUP(namelen) / BYTES_PER_XDR_UNIT); cred->adc_fullname.key.key.high = (u_long)*ixdr++; cred->adc_fullname.key.key.low = (u_long)*ixdr++; cred->adc_fullname.window = (u_long)*ixdr++; break; case ADN_NICKNAME: cred->adc_nickname = (u_long)*ixdr++; break; default: return (AUTH_BADCRED); } /* * Get the verifier */ ixdr = (long *)msg->rm_call.cb_verf.oa_base; verf.adv_xtimestamp.key.high = (u_long)*ixdr++; verf.adv_xtimestamp.key.low = (u_long)*ixdr++; verf.adv_int_u = (u_long)*ixdr++; /* * Get the conversation key */ if (cred->adc_namekind == ADN_FULLNAME) { netobj pkey; char pkey_data[1024]; sessionkey = &cred->adc_fullname.key; if (! getpublickey(cred->adc_fullname.name, pkey_data)) { debug("getpublickey"); return(AUTH_BADCRED); } pkey.n_bytes = pkey_data; pkey.n_len = strlen(pkey_data) + 1; if (key_decryptsession_pk(cred->adc_fullname.name, &pkey, sessionkey) < 0) { debug("decryptsessionkey"); return (AUTH_BADCRED); /* key not found */ } } else { /* ADN_NICKNAME */ sid = (short)cred->adc_nickname; if (sid < 0 || sid >= AUTHDES_CACHESZ) { debug("bad nickname"); return (AUTH_BADCRED); /* garbled credential */ } sessionkey = &authdes_cache[sid].key; } /* * Decrypt the timestamp */ cryptbuf[0] = verf.adv_xtimestamp; if (cred->adc_namekind == ADN_FULLNAME) { cryptbuf[1].key.high = cred->adc_fullname.window; cryptbuf[1].key.low = verf.adv_winverf; ivec.key.high = ivec.key.low = 0; status = cbc_crypt((char *)sessionkey, (char *)cryptbuf, 2*sizeof(des_block), DES_DECRYPT | DES_HW, (char *)&ivec); } else { status = ecb_crypt((char *)sessionkey, (char *)cryptbuf, sizeof(des_block), DES_DECRYPT | DES_HW); } if (DES_FAILED(status)) { debug("decryption failure"); return (AUTH_FAILED); /* system error */ } /* * XDR the decrypted timestamp */ ixdr = (long *)cryptbuf; timestamp.tv_sec = IXDR_GET_LONG(ixdr); timestamp.tv_usec = IXDR_GET_LONG(ixdr); /* * Check for valid credentials and verifiers. * They could be invalid because the key was flushed * out of the cache, and so a new session should begin. * Be sure and send AUTH_REJECTED{CRED, VERF} if this is the case. */ { struct timeval current; int nick; int winverf; if (cred->adc_namekind == ADN_FULLNAME) { window = IXDR_GET_U_LONG(ixdr); winverf = IXDR_GET_U_LONG(ixdr); if (winverf != window - 1) { debug("window verifier mismatch"); return (AUTH_BADCRED); /* garbled credential */ } sid = cache_spot(sessionkey, cred->adc_fullname.name, ×tamp); if (sid < 0) { debug("replayed credential"); return (AUTH_REJECTEDCRED); /* replay */ } nick = 0; } else { /* ADN_NICKNAME */ window = authdes_cache[sid].window; nick = 1; } if ((u_long)timestamp.tv_usec >= USEC_PER_SEC) { debug("invalid usecs"); /* cached out (bad key), or garbled verifier */ return (nick ? AUTH_REJECTEDVERF : AUTH_BADVERF); } if (nick && BEFORE(×tamp, &authdes_cache[sid].laststamp)) { debug("timestamp before last seen"); return (AUTH_REJECTEDVERF); /* replay */ } (void)gettimeofday(¤t, 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(void) { 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(void) { return (authdes_lru[AUTHDES_CACHESZ-1]); } /* * Note that sid was referenced */ static void -cache_ref(sid) - short sid; +cache_ref(short sid) { int i; short curr; short prev; prev = authdes_lru[0]; authdes_lru[0] = sid; for (i = 1; prev != sid; i++) { curr = authdes_lru[i]; authdes_lru[i] = prev; prev = curr; } } /* * Find a spot in the cache for a credential containing * the items given. Return -1 if a replay is detected, otherwise * return the spot in the cache. */ static short -cache_spot(key, name, timestamp) - des_block *key; - char *name; - struct timeval *timestamp; +cache_spot(des_block *key, char *name, struct timeval *timestamp) { struct cache_entry *cp; int i; u_long hi; hi = key->key.high; for (cp = authdes_cache, i = 0; i < AUTHDES_CACHESZ; i++, cp++) { if (cp->key.key.high == hi && cp->key.key.low == key->key.low && cp->rname != NULL && bcmp(cp->rname, name, strlen(name) + 1) == 0) { if (BEFORE(timestamp, &cp->laststamp)) { svcauthdes_stats.ncachereplays++; return (-1); /* replay */ } svcauthdes_stats.ncachehits++; return (i); /* refresh */ } } svcauthdes_stats.ncachemisses++; return (cache_victim()); /* new credential */ } #if (defined(sun) || defined(vax) || defined(__FreeBSD__)) /* * Local credential handling stuff. * NOTE: bsd unix dependent. * Other operating systems should put something else here. */ #define UNKNOWN -2 /* grouplen, if cached cred is unknown user */ #define INVALID -1 /* grouplen, if cache entry is invalid */ struct bsdcred { uid_t uid; /* cached uid */ gid_t gid; /* cached gid */ int grouplen; /* length of cached groups */ gid_t groups[NGRPS]; /* cached groups */ }; /* * Map a des credential into a unix cred. * We cache the credential here so the application does * not have to make an rpc call every time to interpret * the credential. */ int -authdes_getucred(adc, uid, gid, grouplen, groups) - struct authdes_cred *adc; - uid_t *uid; - gid_t *gid; - int *grouplen; - gid_t *groups; +authdes_getucred(struct authdes_cred *adc, uid_t *uid, gid_t *gid, + int *grouplen, gid_t *groups) { unsigned sid; int i; uid_t i_uid; gid_t i_gid; int i_grouplen; struct bsdcred *cred; sid = adc->adc_nickname; if (sid >= AUTHDES_CACHESZ) { debug("invalid nickname"); return (0); } cred = (struct bsdcred *)authdes_cache[sid].localcred; if (cred == NULL) { cred = (struct bsdcred *)mem_alloc(sizeof(struct bsdcred)); authdes_cache[sid].localcred = (char *)cred; cred->grouplen = INVALID; } if (cred->grouplen == INVALID) { /* * not in cache: lookup */ if (!netname2user(adc->adc_fullname.name, &i_uid, &i_gid, &i_grouplen, groups)) { debug("unknown netname"); cred->grouplen = UNKNOWN; /* mark as lookup up, but not found */ return (0); } debug("missed ucred cache"); *uid = cred->uid = i_uid; *gid = cred->gid = i_gid; *grouplen = cred->grouplen = i_grouplen; for (i = i_grouplen - 1; i >= 0; i--) { cred->groups[i] = groups[i]; /* int to short */ } return (1); } else if (cred->grouplen == UNKNOWN) { /* * Already lookup up, but no match found */ return (0); } /* * cached credentials */ *uid = cred->uid; *gid = cred->gid; *grouplen = cred->grouplen; for (i = cred->grouplen - 1; i >= 0; i--) { groups[i] = cred->groups[i]; /* short to int */ } return (1); } static void -invalidate(cred) - char *cred; +invalidate(char *cred) { if (cred == NULL) { return; } ((struct bsdcred *)cred)->grouplen = INVALID; } #endif Index: stable/10/lib/libc/rpc/svc_dg.c =================================================================== --- stable/10/lib/libc/rpc/svc_dg.c (revision 309488) +++ stable/10/lib/libc/rpc/svc_dg.c (revision 309489) @@ -1,737 +1,710 @@ /* $NetBSD: svc_dg.c,v 1.4 2000/07/06 03:10:35 christos Exp $ */ /*- * Copyright (c) 2009, Sun Microsystems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of Sun Microsystems, Inc. nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright (c) 1986-1991 by Sun Microsystems Inc. */ #if defined(LIBC_SCCS) && !defined(lint) #ident "@(#)svc_dg.c 1.17 94/04/24 SMI" #endif #include __FBSDID("$FreeBSD$"); /* * svc_dg.c, Server side for connectionless RPC. * * Does some caching in the hopes of achieving execute-at-most-once semantics. */ #include "namespace.h" #include "reentrant.h" #include #include #include #include #include #include #include #include #include #include #ifdef RPC_CACHE_DEBUG #include #include #endif #include #include "un-namespace.h" #include "rpc_com.h" #include "mt_misc.h" #define su_data(xprt) ((struct svc_dg_data *)(xprt->xp_p2)) #define rpc_buffer(xprt) ((xprt)->xp_p1) #ifndef MAX #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif static void svc_dg_ops(SVCXPRT *); static enum xprt_stat svc_dg_stat(SVCXPRT *); static bool_t svc_dg_recv(SVCXPRT *, struct rpc_msg *); static bool_t svc_dg_reply(SVCXPRT *, struct rpc_msg *); static bool_t svc_dg_getargs(SVCXPRT *, xdrproc_t, void *); static bool_t svc_dg_freeargs(SVCXPRT *, xdrproc_t, void *); static void svc_dg_destroy(SVCXPRT *); static bool_t svc_dg_control(SVCXPRT *, const u_int, void *); static int cache_get(SVCXPRT *, struct rpc_msg *, char **, size_t *); static void cache_set(SVCXPRT *, size_t); int svc_dg_enablecache(SVCXPRT *, u_int); /* * Usage: * xprt = svc_dg_create(sock, sendsize, recvsize); * Does other connectionless specific initializations. * Once *xprt is initialized, it is registered. * see (svc.h, xprt_register). If recvsize or sendsize are 0 suitable * system defaults are chosen. * The routines returns NULL if a problem occurred. */ static const char svc_dg_str[] = "svc_dg_create: %s"; static const char svc_dg_err1[] = "could not get transport information"; static const char svc_dg_err2[] = "transport does not support data transfer"; static const char svc_dg_err3[] = "getsockname failed"; static const char svc_dg_err4[] = "cannot set IP_RECVDSTADDR"; static const char __no_mem_str[] = "out of memory"; SVCXPRT * -svc_dg_create(fd, sendsize, recvsize) - int fd; - u_int sendsize; - u_int recvsize; +svc_dg_create(int fd, u_int sendsize, u_int recvsize) { SVCXPRT *xprt; struct svc_dg_data *su = NULL; struct __rpc_sockinfo si; struct sockaddr_storage ss; socklen_t slen; if (!__rpc_fd2sockinfo(fd, &si)) { warnx(svc_dg_str, svc_dg_err1); return (NULL); } /* * Find the receive and the send size */ sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize); recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize); if ((sendsize == 0) || (recvsize == 0)) { warnx(svc_dg_str, svc_dg_err2); return (NULL); } xprt = svc_xprt_alloc(); if (xprt == NULL) goto freedata; su = mem_alloc(sizeof (*su)); if (su == NULL) goto freedata; su->su_iosz = ((MAX(sendsize, recvsize) + 3) / 4) * 4; if ((rpc_buffer(xprt) = mem_alloc(su->su_iosz)) == NULL) goto freedata; xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, XDR_DECODE); su->su_cache = NULL; xprt->xp_fd = fd; xprt->xp_p2 = su; xprt->xp_verf.oa_base = su->su_verfbody; svc_dg_ops(xprt); xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage); slen = sizeof ss; if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { warnx(svc_dg_str, svc_dg_err3); goto freedata_nowarn; } xprt->xp_ltaddr.buf = mem_alloc(sizeof (struct sockaddr_storage)); xprt->xp_ltaddr.maxlen = sizeof (struct sockaddr_storage); xprt->xp_ltaddr.len = slen; memcpy(xprt->xp_ltaddr.buf, &ss, slen); if (ss.ss_family == AF_INET) { struct sockaddr_in *sin; static const int true_value = 1; sin = (struct sockaddr_in *)(void *)&ss; if (sin->sin_addr.s_addr == INADDR_ANY) { su->su_srcaddr.buf = mem_alloc(sizeof (ss)); su->su_srcaddr.maxlen = sizeof (ss); if (_setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &true_value, sizeof(true_value))) { warnx(svc_dg_str, svc_dg_err4); goto freedata_nowarn; } } } xprt_register(xprt); return (xprt); freedata: (void) warnx(svc_dg_str, __no_mem_str); freedata_nowarn: if (xprt) { if (su) (void) mem_free(su, sizeof (*su)); svc_xprt_free(xprt); } return (NULL); } /*ARGSUSED*/ static enum xprt_stat -svc_dg_stat(xprt) - SVCXPRT *xprt; +svc_dg_stat(SVCXPRT *xprt) { return (XPRT_IDLE); } static int svc_dg_recvfrom(int fd, char *buf, int buflen, struct sockaddr *raddr, socklen_t *raddrlen, struct sockaddr *laddr, socklen_t *laddrlen) { struct msghdr msg; struct iovec msg_iov[1]; struct sockaddr_in *lin = (struct sockaddr_in *)laddr; int rlen; bool_t have_lin = FALSE; char tmp[CMSG_LEN(sizeof(*lin))]; struct cmsghdr *cmsg; memset((char *)&msg, 0, sizeof(msg)); msg_iov[0].iov_base = buf; msg_iov[0].iov_len = buflen; msg.msg_iov = msg_iov; msg.msg_iovlen = 1; msg.msg_namelen = *raddrlen; msg.msg_name = (char *)raddr; if (laddr != NULL) { msg.msg_control = (caddr_t)tmp; msg.msg_controllen = CMSG_LEN(sizeof(*lin)); } rlen = _recvmsg(fd, &msg, 0); if (rlen >= 0) *raddrlen = msg.msg_namelen; if (rlen == -1 || laddr == NULL || msg.msg_controllen < sizeof(struct cmsghdr) || msg.msg_flags & MSG_CTRUNC) return rlen; for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) { if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR) { have_lin = TRUE; memcpy(&lin->sin_addr, (struct in_addr *)CMSG_DATA(cmsg), sizeof(struct in_addr)); break; } } lin->sin_family = AF_INET; lin->sin_port = 0; *laddrlen = sizeof(struct sockaddr_in); if (!have_lin) lin->sin_addr.s_addr = INADDR_ANY; return rlen; } static bool_t -svc_dg_recv(xprt, msg) - SVCXPRT *xprt; - struct rpc_msg *msg; +svc_dg_recv(SVCXPRT *xprt, struct rpc_msg *msg) { struct svc_dg_data *su = su_data(xprt); XDR *xdrs = &(su->su_xdrs); char *reply; struct sockaddr_storage ss; socklen_t alen; size_t replylen; ssize_t rlen; again: alen = sizeof (struct sockaddr_storage); rlen = svc_dg_recvfrom(xprt->xp_fd, rpc_buffer(xprt), su->su_iosz, (struct sockaddr *)(void *)&ss, &alen, (struct sockaddr *)su->su_srcaddr.buf, &su->su_srcaddr.len); if (rlen == -1 && errno == EINTR) goto again; if (rlen == -1 || (rlen < (ssize_t)(4 * sizeof (u_int32_t)))) return (FALSE); if (xprt->xp_rtaddr.len < alen) { if (xprt->xp_rtaddr.len != 0) mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.len); xprt->xp_rtaddr.buf = mem_alloc(alen); xprt->xp_rtaddr.len = alen; } memcpy(xprt->xp_rtaddr.buf, &ss, alen); #ifdef PORTMAP if (ss.ss_family == AF_INET) { xprt->xp_raddr = *(struct sockaddr_in *)xprt->xp_rtaddr.buf; xprt->xp_addrlen = sizeof (struct sockaddr_in); } #endif /* PORTMAP */ xdrs->x_op = XDR_DECODE; XDR_SETPOS(xdrs, 0); if (! xdr_callmsg(xdrs, msg)) { return (FALSE); } su->su_xid = msg->rm_xid; if (su->su_cache != NULL) { if (cache_get(xprt, msg, &reply, &replylen)) { (void)_sendto(xprt->xp_fd, reply, replylen, 0, (struct sockaddr *)(void *)&ss, alen); return (FALSE); } } return (TRUE); } static int svc_dg_sendto(int fd, char *buf, int buflen, const struct sockaddr *raddr, socklen_t raddrlen, const struct sockaddr *laddr, socklen_t laddrlen) { struct msghdr msg; struct iovec msg_iov[1]; struct sockaddr_in *laddr_in = (struct sockaddr_in *)laddr; struct in_addr *lin = &laddr_in->sin_addr; char tmp[CMSG_SPACE(sizeof(*lin))]; struct cmsghdr *cmsg; memset((char *)&msg, 0, sizeof(msg)); msg_iov[0].iov_base = buf; msg_iov[0].iov_len = buflen; msg.msg_iov = msg_iov; msg.msg_iovlen = 1; msg.msg_namelen = raddrlen; msg.msg_name = (char *)raddr; if (laddr != NULL && laddr->sa_family == AF_INET && lin->s_addr != INADDR_ANY) { msg.msg_control = (caddr_t)tmp; msg.msg_controllen = CMSG_LEN(sizeof(*lin)); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_len = CMSG_LEN(sizeof(*lin)); cmsg->cmsg_level = IPPROTO_IP; cmsg->cmsg_type = IP_SENDSRCADDR; memcpy(CMSG_DATA(cmsg), lin, sizeof(*lin)); } return _sendmsg(fd, &msg, 0); } static bool_t -svc_dg_reply(xprt, msg) - SVCXPRT *xprt; - struct rpc_msg *msg; +svc_dg_reply(SVCXPRT *xprt, struct rpc_msg *msg) { struct svc_dg_data *su = su_data(xprt); XDR *xdrs = &(su->su_xdrs); bool_t stat = TRUE; size_t slen; xdrproc_t xdr_proc; caddr_t xdr_where; xdrs->x_op = XDR_ENCODE; XDR_SETPOS(xdrs, 0); msg->rm_xid = su->su_xid; if (msg->rm_reply.rp_stat == MSG_ACCEPTED && msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { xdr_proc = msg->acpted_rply.ar_results.proc; xdr_where = msg->acpted_rply.ar_results.where; msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void; msg->acpted_rply.ar_results.where = NULL; if (!xdr_replymsg(xdrs, msg) || !SVCAUTH_WRAP(&SVC_AUTH(xprt), xdrs, xdr_proc, xdr_where)) stat = FALSE; } else { stat = xdr_replymsg(xdrs, msg); } if (stat) { slen = XDR_GETPOS(xdrs); if (svc_dg_sendto(xprt->xp_fd, rpc_buffer(xprt), slen, (struct sockaddr *)xprt->xp_rtaddr.buf, (socklen_t)xprt->xp_rtaddr.len, (struct sockaddr *)su->su_srcaddr.buf, (socklen_t)su->su_srcaddr.len) == (ssize_t) slen) { stat = TRUE; if (su->su_cache) cache_set(xprt, slen); } } return (stat); } static bool_t -svc_dg_getargs(xprt, xdr_args, args_ptr) - SVCXPRT *xprt; - xdrproc_t xdr_args; - void *args_ptr; +svc_dg_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr) { struct svc_dg_data *su; assert(xprt != NULL); su = su_data(xprt); return (SVCAUTH_UNWRAP(&SVC_AUTH(xprt), &su->su_xdrs, xdr_args, args_ptr)); } static bool_t -svc_dg_freeargs(xprt, xdr_args, args_ptr) - SVCXPRT *xprt; - xdrproc_t xdr_args; - void *args_ptr; +svc_dg_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr) { XDR *xdrs = &(su_data(xprt)->su_xdrs); xdrs->x_op = XDR_FREE; return (*xdr_args)(xdrs, args_ptr); } static void -svc_dg_destroy(xprt) - SVCXPRT *xprt; +svc_dg_destroy(SVCXPRT *xprt) { struct svc_dg_data *su = su_data(xprt); xprt_unregister(xprt); if (xprt->xp_fd != -1) (void)_close(xprt->xp_fd); XDR_DESTROY(&(su->su_xdrs)); (void) mem_free(rpc_buffer(xprt), su->su_iosz); if (su->su_srcaddr.buf) (void) mem_free(su->su_srcaddr.buf, su->su_srcaddr.maxlen); (void) mem_free(su, sizeof (*su)); if (xprt->xp_rtaddr.buf) (void) mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen); if (xprt->xp_ltaddr.buf) (void) mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen); free(xprt->xp_tp); svc_xprt_free(xprt); } static bool_t /*ARGSUSED*/ -svc_dg_control(xprt, rq, in) - SVCXPRT *xprt; - const u_int rq; - void *in; +svc_dg_control(SVCXPRT *xprt, const u_int rq, void *in) { return (FALSE); } static void -svc_dg_ops(xprt) - SVCXPRT *xprt; +svc_dg_ops(SVCXPRT *xprt) { static struct xp_ops ops; static struct xp_ops2 ops2; /* VARIABLES PROTECTED BY ops_lock: ops */ mutex_lock(&ops_lock); if (ops.xp_recv == NULL) { ops.xp_recv = svc_dg_recv; ops.xp_stat = svc_dg_stat; ops.xp_getargs = svc_dg_getargs; ops.xp_reply = svc_dg_reply; ops.xp_freeargs = svc_dg_freeargs; ops.xp_destroy = svc_dg_destroy; ops2.xp_control = svc_dg_control; } xprt->xp_ops = &ops; xprt->xp_ops2 = &ops2; mutex_unlock(&ops_lock); } /* The CACHING COMPONENT */ /* * Could have been a separate file, but some part of it depends upon the * private structure of the client handle. * * Fifo cache for cl server * Copies pointers to reply buffers into fifo cache * Buffers are sent again if retransmissions are detected. */ #define SPARSENESS 4 /* 75% sparse */ #define ALLOC(type, size) \ (type *) mem_alloc((sizeof (type) * (size))) #define MEMZERO(addr, type, size) \ (void) memset((void *) (addr), 0, sizeof (type) * (int) (size)) #define FREE(addr, type, size) \ mem_free((addr), (sizeof (type) * (size))) /* * An entry in the cache */ typedef struct cache_node *cache_ptr; struct cache_node { /* * Index into cache is xid, proc, vers, prog and address */ u_int32_t cache_xid; rpcproc_t cache_proc; rpcvers_t cache_vers; rpcprog_t cache_prog; struct netbuf cache_addr; /* * The cached reply and length */ char *cache_reply; size_t cache_replylen; /* * Next node on the list, if there is a collision */ cache_ptr cache_next; }; /* * The entire cache */ struct cl_cache { u_int uc_size; /* size of cache */ cache_ptr *uc_entries; /* hash table of entries in cache */ cache_ptr *uc_fifo; /* fifo list of entries in cache */ u_int uc_nextvictim; /* points to next victim in fifo list */ rpcprog_t uc_prog; /* saved program number */ rpcvers_t uc_vers; /* saved version number */ rpcproc_t uc_proc; /* saved procedure number */ }; /* * the hashing function */ #define CACHE_LOC(transp, xid) \ (xid % (SPARSENESS * ((struct cl_cache *) \ su_data(transp)->su_cache)->uc_size)) /* * Enable use of the cache. Returns 1 on success, 0 on failure. * Note: there is no disable. */ static const char cache_enable_str[] = "svc_enablecache: %s %s"; static const char alloc_err[] = "could not allocate cache "; static const char enable_err[] = "cache already enabled"; int -svc_dg_enablecache(transp, size) - SVCXPRT *transp; - u_int size; +svc_dg_enablecache(SVCXPRT *transp, u_int size) { struct svc_dg_data *su = su_data(transp); struct cl_cache *uc; mutex_lock(&dupreq_lock); if (su->su_cache != NULL) { (void) warnx(cache_enable_str, enable_err, " "); mutex_unlock(&dupreq_lock); return (0); } uc = ALLOC(struct cl_cache, 1); if (uc == NULL) { warnx(cache_enable_str, alloc_err, " "); mutex_unlock(&dupreq_lock); return (0); } uc->uc_size = size; uc->uc_nextvictim = 0; uc->uc_entries = ALLOC(cache_ptr, size * SPARSENESS); if (uc->uc_entries == NULL) { warnx(cache_enable_str, alloc_err, "data"); FREE(uc, struct cl_cache, 1); mutex_unlock(&dupreq_lock); return (0); } MEMZERO(uc->uc_entries, cache_ptr, size * SPARSENESS); uc->uc_fifo = ALLOC(cache_ptr, size); if (uc->uc_fifo == NULL) { warnx(cache_enable_str, alloc_err, "fifo"); FREE(uc->uc_entries, cache_ptr, size * SPARSENESS); FREE(uc, struct cl_cache, 1); mutex_unlock(&dupreq_lock); return (0); } MEMZERO(uc->uc_fifo, cache_ptr, size); su->su_cache = (char *)(void *)uc; mutex_unlock(&dupreq_lock); return (1); } /* * Set an entry in the cache. It assumes that the uc entry is set from * the earlier call to cache_get() for the same procedure. This will always * happen because cache_get() is calle by svc_dg_recv and cache_set() is called * by svc_dg_reply(). All this hoopla because the right RPC parameters are * not available at svc_dg_reply time. */ static const char cache_set_str[] = "cache_set: %s"; static const char cache_set_err1[] = "victim not found"; static const char cache_set_err2[] = "victim alloc failed"; static const char cache_set_err3[] = "could not allocate new rpc buffer"; static void -cache_set(xprt, replylen) - SVCXPRT *xprt; - size_t replylen; +cache_set(SVCXPRT *xprt, size_t replylen) { cache_ptr victim; cache_ptr *vicp; struct svc_dg_data *su = su_data(xprt); struct cl_cache *uc = (struct cl_cache *) su->su_cache; u_int loc; char *newbuf; #ifdef RPC_CACHE_DEBUG struct netconfig *nconf; char *uaddr; #endif mutex_lock(&dupreq_lock); /* * Find space for the new entry, either by * reusing an old entry, or by mallocing a new one */ victim = uc->uc_fifo[uc->uc_nextvictim]; if (victim != NULL) { loc = CACHE_LOC(xprt, victim->cache_xid); for (vicp = &uc->uc_entries[loc]; *vicp != NULL && *vicp != victim; vicp = &(*vicp)->cache_next) ; if (*vicp == NULL) { warnx(cache_set_str, cache_set_err1); mutex_unlock(&dupreq_lock); return; } *vicp = victim->cache_next; /* remove from cache */ newbuf = victim->cache_reply; } else { victim = ALLOC(struct cache_node, 1); if (victim == NULL) { warnx(cache_set_str, cache_set_err2); mutex_unlock(&dupreq_lock); return; } newbuf = mem_alloc(su->su_iosz); if (newbuf == NULL) { warnx(cache_set_str, cache_set_err3); FREE(victim, struct cache_node, 1); mutex_unlock(&dupreq_lock); return; } } /* * Store it away */ #ifdef RPC_CACHE_DEBUG if (nconf = getnetconfigent(xprt->xp_netid)) { uaddr = taddr2uaddr(nconf, &xprt->xp_rtaddr); freenetconfigent(nconf); printf( "cache set for xid= %x prog=%d vers=%d proc=%d for rmtaddr=%s\n", su->su_xid, uc->uc_prog, uc->uc_vers, uc->uc_proc, uaddr); free(uaddr); } #endif victim->cache_replylen = replylen; victim->cache_reply = rpc_buffer(xprt); rpc_buffer(xprt) = newbuf; xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, XDR_ENCODE); victim->cache_xid = su->su_xid; victim->cache_proc = uc->uc_proc; victim->cache_vers = uc->uc_vers; victim->cache_prog = uc->uc_prog; victim->cache_addr = xprt->xp_rtaddr; victim->cache_addr.buf = ALLOC(char, xprt->xp_rtaddr.len); (void) memcpy(victim->cache_addr.buf, xprt->xp_rtaddr.buf, (size_t)xprt->xp_rtaddr.len); loc = CACHE_LOC(xprt, victim->cache_xid); victim->cache_next = uc->uc_entries[loc]; uc->uc_entries[loc] = victim; uc->uc_fifo[uc->uc_nextvictim++] = victim; uc->uc_nextvictim %= uc->uc_size; mutex_unlock(&dupreq_lock); } /* * Try to get an entry from the cache * return 1 if found, 0 if not found and set the stage for cache_set() */ static int -cache_get(xprt, msg, replyp, replylenp) - SVCXPRT *xprt; - struct rpc_msg *msg; - char **replyp; - size_t *replylenp; +cache_get(SVCXPRT *xprt, struct rpc_msg *msg, char **replyp, size_t *replylenp) { u_int loc; cache_ptr ent; struct svc_dg_data *su = su_data(xprt); struct cl_cache *uc = (struct cl_cache *) su->su_cache; #ifdef RPC_CACHE_DEBUG struct netconfig *nconf; char *uaddr; #endif mutex_lock(&dupreq_lock); loc = CACHE_LOC(xprt, su->su_xid); for (ent = uc->uc_entries[loc]; ent != NULL; ent = ent->cache_next) { if (ent->cache_xid == su->su_xid && ent->cache_proc == msg->rm_call.cb_proc && ent->cache_vers == msg->rm_call.cb_vers && ent->cache_prog == msg->rm_call.cb_prog && ent->cache_addr.len == xprt->xp_rtaddr.len && (memcmp(ent->cache_addr.buf, xprt->xp_rtaddr.buf, xprt->xp_rtaddr.len) == 0)) { #ifdef RPC_CACHE_DEBUG if (nconf = getnetconfigent(xprt->xp_netid)) { uaddr = taddr2uaddr(nconf, &xprt->xp_rtaddr); freenetconfigent(nconf); printf( "cache entry found for xid=%x prog=%d vers=%d proc=%d for rmtaddr=%s\n", su->su_xid, msg->rm_call.cb_prog, msg->rm_call.cb_vers, msg->rm_call.cb_proc, uaddr); free(uaddr); } #endif *replyp = ent->cache_reply; *replylenp = ent->cache_replylen; mutex_unlock(&dupreq_lock); return (1); } } /* * Failed to find entry * Remember a few things so we can do a set later */ uc->uc_proc = msg->rm_call.cb_proc; uc->uc_vers = msg->rm_call.cb_vers; uc->uc_prog = msg->rm_call.cb_prog; mutex_unlock(&dupreq_lock); return (0); } Index: stable/10/lib/libc/rpc/svc_vc.c =================================================================== --- stable/10/lib/libc/rpc/svc_vc.c (revision 309488) +++ stable/10/lib/libc/rpc/svc_vc.c (revision 309489) @@ -1,822 +1,783 @@ /* $NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $ */ /*- * Copyright (c) 2009, Sun Microsystems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of Sun Microsystems, Inc. nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #if defined(LIBC_SCCS) && !defined(lint) static char *sccsid2 = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro"; static char *sccsid = "@(#)svc_tcp.c 2.2 88/08/01 4.0 RPCSRC"; #endif #include __FBSDID("$FreeBSD$"); /* * svc_vc.c, Server side for Connection Oriented based RPC. * * Actually implements two flavors of transporter - * a tcp rendezvouser (a listner and connection establisher) * and a record/tcp stream. */ #include "namespace.h" #include "reentrant.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "rpc_com.h" #include "mt_misc.h" #include "un-namespace.h" static SVCXPRT *makefd_xprt(int, u_int, u_int); static bool_t rendezvous_request(SVCXPRT *, struct rpc_msg *); static enum xprt_stat rendezvous_stat(SVCXPRT *); static void svc_vc_destroy(SVCXPRT *); static void __svc_vc_dodestroy (SVCXPRT *); static int read_vc(void *, void *, int); static int write_vc(void *, void *, int); static enum xprt_stat svc_vc_stat(SVCXPRT *); static bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *); static bool_t svc_vc_getargs(SVCXPRT *, xdrproc_t, void *); static bool_t svc_vc_freeargs(SVCXPRT *, xdrproc_t, void *); static bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *); static void svc_vc_rendezvous_ops(SVCXPRT *); static void svc_vc_ops(SVCXPRT *); static bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in); static bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq, void *in); struct cf_rendezvous { /* kept in xprt->xp_p1 for rendezvouser */ u_int sendsize; u_int recvsize; int maxrec; }; struct cf_conn { /* kept in xprt->xp_p1 for actual connection */ enum xprt_stat strm_stat; u_int32_t x_id; XDR xdrs; char verf_body[MAX_AUTH_BYTES]; u_int sendsize; u_int recvsize; int maxrec; bool_t nonblock; struct timeval last_recv_time; }; /* * Usage: * xprt = svc_vc_create(sock, send_buf_size, recv_buf_size); * * Creates, registers, and returns a (rpc) tcp based transporter. * Once *xprt is initialized, it is registered as a transporter * see (svc.h, xprt_register). This routine returns * a NULL if a problem occurred. * * The filedescriptor passed in is expected to refer to a bound, but * not yet connected socket. * * Since streams do buffered io similar to stdio, the caller can specify * how big the send and receive buffers are via the second and third parms; * 0 => use the system default. */ SVCXPRT * -svc_vc_create(fd, sendsize, recvsize) - int fd; - u_int sendsize; - u_int recvsize; +svc_vc_create(int fd, u_int sendsize, u_int recvsize) { SVCXPRT *xprt; struct cf_rendezvous *r = NULL; struct __rpc_sockinfo si; struct sockaddr_storage sslocal; socklen_t slen; if (!__rpc_fd2sockinfo(fd, &si)) return NULL; r = mem_alloc(sizeof(*r)); if (r == NULL) { warnx("svc_vc_create: out of memory"); goto cleanup_svc_vc_create; } r->sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize); r->recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize); r->maxrec = __svc_maxrec; xprt = svc_xprt_alloc(); if (xprt == NULL) { warnx("svc_vc_create: out of memory"); goto cleanup_svc_vc_create; } xprt->xp_p1 = r; xprt->xp_verf = _null_auth; svc_vc_rendezvous_ops(xprt); xprt->xp_port = (u_short)-1; /* It is the rendezvouser */ xprt->xp_fd = fd; slen = sizeof (struct sockaddr_storage); if (_getsockname(fd, (struct sockaddr *)(void *)&sslocal, &slen) < 0) { warnx("svc_vc_create: could not retrieve local addr"); goto cleanup_svc_vc_create; } xprt->xp_ltaddr.maxlen = xprt->xp_ltaddr.len = sslocal.ss_len; xprt->xp_ltaddr.buf = mem_alloc((size_t)sslocal.ss_len); if (xprt->xp_ltaddr.buf == NULL) { warnx("svc_vc_create: no mem for local addr"); goto cleanup_svc_vc_create; } memcpy(xprt->xp_ltaddr.buf, &sslocal, (size_t)sslocal.ss_len); xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage); xprt_register(xprt); return (xprt); cleanup_svc_vc_create: if (xprt) mem_free(xprt, sizeof(*xprt)); if (r != NULL) mem_free(r, sizeof(*r)); return (NULL); } /* * Like svtcp_create(), except the routine takes any *open* UNIX file * descriptor as its first input. */ SVCXPRT * -svc_fd_create(fd, sendsize, recvsize) - int fd; - u_int sendsize; - u_int recvsize; +svc_fd_create(int fd, u_int sendsize, u_int recvsize) { struct sockaddr_storage ss; socklen_t slen; SVCXPRT *ret; assert(fd != -1); ret = makefd_xprt(fd, sendsize, recvsize); if (ret == NULL) return NULL; slen = sizeof (struct sockaddr_storage); if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { warnx("svc_fd_create: could not retrieve local addr"); goto freedata; } ret->xp_ltaddr.maxlen = ret->xp_ltaddr.len = ss.ss_len; ret->xp_ltaddr.buf = mem_alloc((size_t)ss.ss_len); if (ret->xp_ltaddr.buf == NULL) { warnx("svc_fd_create: no mem for local addr"); goto freedata; } memcpy(ret->xp_ltaddr.buf, &ss, (size_t)ss.ss_len); slen = sizeof (struct sockaddr_storage); if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { warnx("svc_fd_create: could not retrieve remote addr"); goto freedata; } ret->xp_rtaddr.maxlen = ret->xp_rtaddr.len = ss.ss_len; ret->xp_rtaddr.buf = mem_alloc((size_t)ss.ss_len); if (ret->xp_rtaddr.buf == NULL) { warnx("svc_fd_create: no mem for local addr"); goto freedata; } memcpy(ret->xp_rtaddr.buf, &ss, (size_t)ss.ss_len); #ifdef PORTMAP if (ss.ss_family == AF_INET || ss.ss_family == AF_LOCAL) { ret->xp_raddr = *(struct sockaddr_in *)ret->xp_rtaddr.buf; ret->xp_addrlen = sizeof (struct sockaddr_in); } #endif /* PORTMAP */ return ret; freedata: if (ret->xp_ltaddr.buf != NULL) mem_free(ret->xp_ltaddr.buf, rep->xp_ltaddr.maxlen); return NULL; } static SVCXPRT * -makefd_xprt(fd, sendsize, recvsize) - int fd; - u_int sendsize; - u_int recvsize; +makefd_xprt(int fd, u_int sendsize, u_int recvsize) { SVCXPRT *xprt; struct cf_conn *cd; const char *netid; struct __rpc_sockinfo si; assert(fd != -1); xprt = svc_xprt_alloc(); if (xprt == NULL) { warnx("svc_vc: makefd_xprt: out of memory"); goto done; } cd = mem_alloc(sizeof(struct cf_conn)); if (cd == NULL) { warnx("svc_tcp: makefd_xprt: out of memory"); svc_xprt_free(xprt); xprt = NULL; goto done; } cd->strm_stat = XPRT_IDLE; xdrrec_create(&(cd->xdrs), sendsize, recvsize, xprt, read_vc, write_vc); xprt->xp_p1 = cd; xprt->xp_verf.oa_base = cd->verf_body; svc_vc_ops(xprt); /* truely deals with calls */ xprt->xp_port = 0; /* this is a connection, not a rendezvouser */ xprt->xp_fd = fd; if (__rpc_fd2sockinfo(fd, &si) && __rpc_sockinfo2netid(&si, &netid)) xprt->xp_netid = strdup(netid); xprt_register(xprt); done: return (xprt); } /*ARGSUSED*/ static bool_t -rendezvous_request(xprt, msg) - SVCXPRT *xprt; - struct rpc_msg *msg; +rendezvous_request(SVCXPRT *xprt, struct rpc_msg *msg) { int sock, flags; struct cf_rendezvous *r; struct cf_conn *cd; struct sockaddr_storage addr, sslocal; socklen_t len, slen; struct __rpc_sockinfo si; SVCXPRT *newxprt; fd_set cleanfds; assert(xprt != NULL); assert(msg != NULL); r = (struct cf_rendezvous *)xprt->xp_p1; again: len = sizeof addr; if ((sock = _accept(xprt->xp_fd, (struct sockaddr *)(void *)&addr, &len)) < 0) { if (errno == EINTR) goto again; /* * Clean out the most idle file descriptor when we're * running out. */ if (errno == EMFILE || errno == ENFILE) { cleanfds = svc_fdset; __svc_clean_idle(&cleanfds, 0, FALSE); goto again; } return (FALSE); } /* * make a new transporter (re-uses xprt) */ newxprt = makefd_xprt(sock, r->sendsize, r->recvsize); newxprt->xp_rtaddr.buf = mem_alloc(len); if (newxprt->xp_rtaddr.buf == NULL) return (FALSE); memcpy(newxprt->xp_rtaddr.buf, &addr, len); newxprt->xp_rtaddr.len = len; #ifdef PORTMAP if (addr.ss_family == AF_INET || addr.ss_family == AF_LOCAL) { newxprt->xp_raddr = *(struct sockaddr_in *)newxprt->xp_rtaddr.buf; newxprt->xp_addrlen = sizeof (struct sockaddr_in); } #endif /* PORTMAP */ if (__rpc_fd2sockinfo(sock, &si) && si.si_proto == IPPROTO_TCP) { len = 1; /* XXX fvdl - is this useful? */ _setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &len, sizeof (len)); } cd = (struct cf_conn *)newxprt->xp_p1; cd->recvsize = r->recvsize; cd->sendsize = r->sendsize; cd->maxrec = r->maxrec; if (cd->maxrec != 0) { flags = _fcntl(sock, F_GETFL, 0); if (flags == -1) return (FALSE); if (_fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) return (FALSE); if (cd->recvsize > cd->maxrec) cd->recvsize = cd->maxrec; cd->nonblock = TRUE; __xdrrec_setnonblock(&cd->xdrs, cd->maxrec); } else cd->nonblock = FALSE; slen = sizeof(struct sockaddr_storage); if(_getsockname(sock, (struct sockaddr *)(void *)&sslocal, &slen) < 0) { warnx("svc_vc_create: could not retrieve local addr"); newxprt->xp_ltaddr.maxlen = newxprt->xp_ltaddr.len = 0; } else { newxprt->xp_ltaddr.maxlen = newxprt->xp_ltaddr.len = sslocal.ss_len; newxprt->xp_ltaddr.buf = mem_alloc((size_t)sslocal.ss_len); if (newxprt->xp_ltaddr.buf == NULL) { warnx("svc_vc_create: no mem for local addr"); newxprt->xp_ltaddr.maxlen = newxprt->xp_ltaddr.len = 0; } else { memcpy(newxprt->xp_ltaddr.buf, &sslocal, (size_t)sslocal.ss_len); } } gettimeofday(&cd->last_recv_time, NULL); return (FALSE); /* there is never an rpc msg to be processed */ } /*ARGSUSED*/ static enum xprt_stat -rendezvous_stat(xprt) - SVCXPRT *xprt; +rendezvous_stat(SVCXPRT *xprt) { return (XPRT_IDLE); } static void -svc_vc_destroy(xprt) - SVCXPRT *xprt; +svc_vc_destroy(SVCXPRT *xprt) { assert(xprt != NULL); xprt_unregister(xprt); __svc_vc_dodestroy(xprt); } static void -__svc_vc_dodestroy(xprt) - SVCXPRT *xprt; +__svc_vc_dodestroy(SVCXPRT *xprt) { struct cf_conn *cd; struct cf_rendezvous *r; cd = (struct cf_conn *)xprt->xp_p1; if (xprt->xp_fd != RPC_ANYFD) (void)_close(xprt->xp_fd); if (xprt->xp_port != 0) { /* a rendezvouser socket */ r = (struct cf_rendezvous *)xprt->xp_p1; mem_free(r, sizeof (struct cf_rendezvous)); xprt->xp_port = 0; } else { /* an actual connection socket */ XDR_DESTROY(&(cd->xdrs)); mem_free(cd, sizeof(struct cf_conn)); } if (xprt->xp_rtaddr.buf) mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen); if (xprt->xp_ltaddr.buf) mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen); free(xprt->xp_tp); free(xprt->xp_netid); svc_xprt_free(xprt); } /*ARGSUSED*/ static bool_t -svc_vc_control(xprt, rq, in) - SVCXPRT *xprt; - const u_int rq; - void *in; +svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in) { return (FALSE); } static bool_t -svc_vc_rendezvous_control(xprt, rq, in) - SVCXPRT *xprt; - const u_int rq; - void *in; +svc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq, void *in) { struct cf_rendezvous *cfp; cfp = (struct cf_rendezvous *)xprt->xp_p1; if (cfp == NULL) return (FALSE); switch (rq) { case SVCGET_CONNMAXREC: *(int *)in = cfp->maxrec; break; case SVCSET_CONNMAXREC: cfp->maxrec = *(int *)in; break; default: return (FALSE); } return (TRUE); } /* * reads data from the tcp or uip connection. * any error is fatal and the connection is closed. * (And a read of zero bytes is a half closed stream => error.) * All read operations timeout after 35 seconds. A timeout is * fatal for the connection. */ static int -read_vc(xprtp, buf, len) - void *xprtp; - void *buf; - int len; +read_vc(void *xprtp, void *buf, int len) { SVCXPRT *xprt; int sock; int milliseconds = 35 * 1000; struct pollfd pollfd; struct cf_conn *cfp; xprt = (SVCXPRT *)xprtp; assert(xprt != NULL); sock = xprt->xp_fd; cfp = (struct cf_conn *)xprt->xp_p1; if (cfp->nonblock) { len = _read(sock, buf, (size_t)len); if (len < 0) { if (errno == EAGAIN) len = 0; else goto fatal_err; } if (len != 0) gettimeofday(&cfp->last_recv_time, NULL); return len; } do { pollfd.fd = sock; pollfd.events = POLLIN; pollfd.revents = 0; switch (_poll(&pollfd, 1, milliseconds)) { case -1: if (errno == EINTR) continue; /*FALLTHROUGH*/ case 0: goto fatal_err; default: break; } } while ((pollfd.revents & POLLIN) == 0); if ((len = _read(sock, buf, (size_t)len)) > 0) { gettimeofday(&cfp->last_recv_time, NULL); return (len); } fatal_err: ((struct cf_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED; return (-1); } /* * writes data to the tcp connection. * Any error is fatal and the connection is closed. */ static int -write_vc(xprtp, buf, len) - void *xprtp; - void *buf; - int len; +write_vc(void *xprtp, void *buf, int len) { SVCXPRT *xprt; int i, cnt; struct cf_conn *cd; struct timeval tv0, tv1; xprt = (SVCXPRT *)xprtp; assert(xprt != NULL); cd = (struct cf_conn *)xprt->xp_p1; if (cd->nonblock) gettimeofday(&tv0, NULL); for (cnt = len; cnt > 0; cnt -= i, buf = (char *)buf + i) { i = _write(xprt->xp_fd, buf, (size_t)cnt); if (i < 0) { if (errno != EAGAIN || !cd->nonblock) { cd->strm_stat = XPRT_DIED; return (-1); } if (cd->nonblock) { /* * For non-blocking connections, do not * take more than 2 seconds writing the * data out. * * XXX 2 is an arbitrary amount. */ gettimeofday(&tv1, NULL); if (tv1.tv_sec - tv0.tv_sec >= 2) { cd->strm_stat = XPRT_DIED; return (-1); } } i = 0; } } return (len); } static enum xprt_stat -svc_vc_stat(xprt) - SVCXPRT *xprt; +svc_vc_stat(SVCXPRT *xprt) { struct cf_conn *cd; assert(xprt != NULL); cd = (struct cf_conn *)(xprt->xp_p1); if (cd->strm_stat == XPRT_DIED) return (XPRT_DIED); if (! xdrrec_eof(&(cd->xdrs))) return (XPRT_MOREREQS); return (XPRT_IDLE); } static bool_t -svc_vc_recv(xprt, msg) - SVCXPRT *xprt; - struct rpc_msg *msg; +svc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg) { struct cf_conn *cd; XDR *xdrs; assert(xprt != NULL); assert(msg != NULL); cd = (struct cf_conn *)(xprt->xp_p1); xdrs = &(cd->xdrs); if (cd->nonblock) { if (!__xdrrec_getrec(xdrs, &cd->strm_stat, TRUE)) return FALSE; } else { (void)xdrrec_skiprecord(xdrs); } xdrs->x_op = XDR_DECODE; if (xdr_callmsg(xdrs, msg)) { cd->x_id = msg->rm_xid; return (TRUE); } cd->strm_stat = XPRT_DIED; return (FALSE); } static bool_t -svc_vc_getargs(xprt, xdr_args, args_ptr) - SVCXPRT *xprt; - xdrproc_t xdr_args; - void *args_ptr; +svc_vc_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr) { struct cf_conn *cd; assert(xprt != NULL); cd = (struct cf_conn *)(xprt->xp_p1); return (SVCAUTH_UNWRAP(&SVC_AUTH(xprt), &cd->xdrs, xdr_args, args_ptr)); } static bool_t -svc_vc_freeargs(xprt, xdr_args, args_ptr) - SVCXPRT *xprt; - xdrproc_t xdr_args; - void *args_ptr; +svc_vc_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr) { XDR *xdrs; assert(xprt != NULL); /* args_ptr may be NULL */ xdrs = &(((struct cf_conn *)(xprt->xp_p1))->xdrs); xdrs->x_op = XDR_FREE; return ((*xdr_args)(xdrs, args_ptr)); } static bool_t -svc_vc_reply(xprt, msg) - SVCXPRT *xprt; - struct rpc_msg *msg; +svc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg) { struct cf_conn *cd; XDR *xdrs; bool_t rstat; xdrproc_t xdr_proc; caddr_t xdr_where; u_int pos; assert(xprt != NULL); assert(msg != NULL); cd = (struct cf_conn *)(xprt->xp_p1); xdrs = &(cd->xdrs); xdrs->x_op = XDR_ENCODE; msg->rm_xid = cd->x_id; rstat = TRUE; if (msg->rm_reply.rp_stat == MSG_ACCEPTED && msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { xdr_proc = msg->acpted_rply.ar_results.proc; xdr_where = msg->acpted_rply.ar_results.where; msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void; msg->acpted_rply.ar_results.where = NULL; pos = XDR_GETPOS(xdrs); if (!xdr_replymsg(xdrs, msg) || !SVCAUTH_WRAP(&SVC_AUTH(xprt), xdrs, xdr_proc, xdr_where)) { XDR_SETPOS(xdrs, pos); rstat = FALSE; } } else { rstat = xdr_replymsg(xdrs, msg); } if (rstat) (void)xdrrec_endofrecord(xdrs, TRUE); return (rstat); } static void -svc_vc_ops(xprt) - SVCXPRT *xprt; +svc_vc_ops(SVCXPRT *xprt) { static struct xp_ops ops; static struct xp_ops2 ops2; /* VARIABLES PROTECTED BY ops_lock: ops, ops2 */ mutex_lock(&ops_lock); if (ops.xp_recv == NULL) { ops.xp_recv = svc_vc_recv; ops.xp_stat = svc_vc_stat; ops.xp_getargs = svc_vc_getargs; ops.xp_reply = svc_vc_reply; ops.xp_freeargs = svc_vc_freeargs; ops.xp_destroy = svc_vc_destroy; ops2.xp_control = svc_vc_control; } xprt->xp_ops = &ops; xprt->xp_ops2 = &ops2; mutex_unlock(&ops_lock); } static void -svc_vc_rendezvous_ops(xprt) - SVCXPRT *xprt; +svc_vc_rendezvous_ops(SVCXPRT *xprt) { static struct xp_ops ops; static struct xp_ops2 ops2; mutex_lock(&ops_lock); if (ops.xp_recv == NULL) { ops.xp_recv = rendezvous_request; ops.xp_stat = rendezvous_stat; ops.xp_getargs = (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort; ops.xp_reply = (bool_t (*)(SVCXPRT *, struct rpc_msg *))abort; ops.xp_freeargs = (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort; ops.xp_destroy = svc_vc_destroy; ops2.xp_control = svc_vc_rendezvous_control; } xprt->xp_ops = &ops; xprt->xp_ops2 = &ops2; mutex_unlock(&ops_lock); } /* * Get the effective UID of the sending process. Used by rpcbind, keyserv * and rpc.yppasswdd on AF_LOCAL. */ int __rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) { int sock, ret; gid_t egid; uid_t euid; struct sockaddr *sa; sock = transp->xp_fd; sa = (struct sockaddr *)transp->xp_rtaddr.buf; if (sa->sa_family == AF_LOCAL) { ret = getpeereid(sock, &euid, &egid); if (ret == 0) *uid = euid; return (ret); } else return (-1); } /* * Destroy xprts that have not have had any activity in 'timeout' seconds. * If 'cleanblock' is true, blocking connections (the default) are also * cleaned. If timeout is 0, the least active connection is picked. */ bool_t __svc_clean_idle(fd_set *fds, int timeout, bool_t cleanblock) { int i, ncleaned; SVCXPRT *xprt, *least_active; struct timeval tv, tdiff, tmax; struct cf_conn *cd; gettimeofday(&tv, NULL); tmax.tv_sec = tmax.tv_usec = 0; least_active = NULL; rwlock_wrlock(&svc_fd_lock); for (i = ncleaned = 0; i <= svc_maxfd; i++) { if (FD_ISSET(i, fds)) { xprt = __svc_xports[i]; if (xprt == NULL || xprt->xp_ops == NULL || xprt->xp_ops->xp_recv != svc_vc_recv) continue; cd = (struct cf_conn *)xprt->xp_p1; if (!cleanblock && !cd->nonblock) continue; if (timeout == 0) { timersub(&tv, &cd->last_recv_time, &tdiff); if (timercmp(&tdiff, &tmax, >)) { tmax = tdiff; least_active = xprt; } continue; } if (tv.tv_sec - cd->last_recv_time.tv_sec > timeout) { __xprt_unregister_unlocked(xprt); __svc_vc_dodestroy(xprt); ncleaned++; } } } if (timeout == 0 && least_active != NULL) { __xprt_unregister_unlocked(least_active); __svc_vc_dodestroy(least_active); ncleaned++; } rwlock_unlock(&svc_fd_lock); return ncleaned > 0 ? TRUE : FALSE; } Index: stable/10 =================================================================== --- stable/10 (revision 309488) +++ stable/10 (revision 309489) Property changes on: stable/10 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r287341-287342,287348