int setsourcefilter (int s, uint32_t interface, const struct sockaddr *group, socklen_t grouplen, uint32_t fmode, uint32_t numsrc, const struct sockaddr_storage *slist) { /* We have to create an struct ip_msfilter object which we can pass to the kernel. */ size_t needed = GROUP_FILTER_SIZE (numsrc); int use_alloca = __libc_use_alloca (needed); struct group_filter *gf; if (use_alloca) gf = (struct group_filter *) alloca (needed); else { gf = (struct group_filter *) malloc (needed); if (gf == NULL) return -1; } gf->gf_interface = interface; memcpy (&gf->gf_group, group, grouplen); gf->gf_fmode = fmode; gf->gf_numsrc = numsrc; memcpy (gf->gf_slist, slist, numsrc * sizeof (struct sockaddr_storage)); /* We need to provide the appropriate socket level value. */ int result; int sol = __get_sol (group->sa_family, grouplen); if (sol == -1) { __set_errno (EINVAL); result = -1; } else result = __setsockopt (s, sol, MCAST_MSFILTER, gf, needed); if (! use_alloca) { int save_errno = errno; free (gf); __set_errno (save_errno); } return result; }
static int __msgread (int sock, void *data, size_t cnt) { struct iovec iov; struct msghdr msg; int len; iov.iov_base = data; iov.iov_len = cnt; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_name = NULL; msg.msg_namelen = 0; #ifdef SCM_CREDENTIALS msg.msg_control = (caddr_t) &cm; msg.msg_controllen = sizeof (struct cmessage); #endif msg.msg_flags = 0; #ifdef SO_PASSCRED { int on = 1; if (__setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on))) return -1; } #endif restart: len = __recvmsg (sock, &msg, 0); if (len >= 0) { if (msg.msg_flags & MSG_CTRUNC || len == 0) return 0; else return len; } if (errno == EINTR) goto restart; return -1; }
/* * Create a UDP based client handle. * If *sockp<0, *sockp is set to a newly created UPD socket. * If raddr->sin_port is 0 a binder on the remote machine * is consulted for the correct port number. * NB: It is the clients responsibility to close *sockp. * NB: The rpch->cl_auth is initialized to null authentication. * Caller may wish to set this something more useful. * * wait is the amount of time used between retransmitting a call if * no response has been heard; retransmission occurs until the actual * rpc call times out. * * sendsz and recvsz are the maximum allowable packet sizes that can be * sent and received. */ CLIENT * __libc_clntudp_bufcreate (struct sockaddr_in *raddr, u_long program, u_long version, struct timeval wait, int *sockp, u_int sendsz, u_int recvsz, int flags) { CLIENT *cl; struct cu_data *cu = NULL; struct rpc_msg call_msg; cl = (CLIENT *) mem_alloc (sizeof (CLIENT)); sendsz = ((sendsz + 3) / 4) * 4; recvsz = ((recvsz + 3) / 4) * 4; cu = (struct cu_data *) mem_alloc (sizeof (*cu) + sendsz + recvsz); if (cl == NULL || cu == NULL) { struct rpc_createerr *ce = &get_rpc_createerr (); (void) __fxprintf (NULL, "%s: %s", "clntudp_create", _("out of memory\n")); ce->cf_stat = RPC_SYSTEMERROR; ce->cf_error.re_errno = ENOMEM; goto fooy; } cu->cu_outbuf = &cu->cu_inbuf[recvsz]; if (raddr->sin_port == 0) { u_short port; if ((port = pmap_getport (raddr, program, version, IPPROTO_UDP)) == 0) { goto fooy; } raddr->sin_port = htons (port); } cl->cl_ops = (struct clnt_ops *) &udp_ops; cl->cl_private = (caddr_t) cu; cu->cu_raddr = *raddr; cu->cu_rlen = sizeof (cu->cu_raddr); cu->cu_wait = wait; cu->cu_total.tv_sec = -1; cu->cu_total.tv_usec = -1; cu->cu_sendsz = sendsz; cu->cu_recvsz = recvsz; call_msg.rm_xid = _create_xid (); call_msg.rm_direction = CALL; call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; call_msg.rm_call.cb_prog = program; call_msg.rm_call.cb_vers = version; xdrmem_create (&(cu->cu_outxdrs), cu->cu_outbuf, sendsz, XDR_ENCODE); if (!xdr_callhdr (&(cu->cu_outxdrs), &call_msg)) { goto fooy; } cu->cu_xdrpos = XDR_GETPOS (&(cu->cu_outxdrs)); if (*sockp < 0) { #ifdef SOCK_NONBLOCK # ifndef __ASSUME_SOCK_CLOEXEC if (__have_sock_cloexec >= 0) # endif { *sockp = __socket (AF_INET, SOCK_DGRAM|SOCK_NONBLOCK|flags, IPPROTO_UDP); # ifndef __ASSUME_SOCK_CLOEXEC if (__have_sock_cloexec == 0) __have_sock_cloexec = *sockp >= 0 || errno != EINVAL ? 1 : -1; # endif } #endif #ifndef __ASSUME_SOCK_CLOEXEC # ifdef SOCK_CLOEXEC if (__have_sock_cloexec < 0) # endif { *sockp = __socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); # ifdef SOCK_CLOEXEC if (flags & SOCK_CLOEXEC) __fcntl (*sockp, F_SETFD, FD_CLOEXEC); # endif } #endif if (__builtin_expect (*sockp < 0, 0)) { struct rpc_createerr *ce = &get_rpc_createerr (); ce->cf_stat = RPC_SYSTEMERROR; ce->cf_error.re_errno = errno; goto fooy; } /* attempt to bind to prov port */ (void) bindresvport (*sockp, (struct sockaddr_in *) 0); #ifndef __ASSUME_SOCK_CLOEXEC # ifdef SOCK_CLOEXEC if (__have_sock_cloexec < 0) # endif { /* the sockets rpc controls are non-blocking */ int dontblock = 1; (void) __ioctl (*sockp, FIONBIO, (char *) &dontblock); } #endif #ifdef IP_RECVERR { int on = 1; __setsockopt (*sockp, SOL_IP, IP_RECVERR, &on, sizeof(on)); } #endif cu->cu_closeit = TRUE; } else { cu->cu_closeit = FALSE; } cu->cu_sock = *sockp; cl->cl_auth = authnone_create (); return cl; fooy: if (cu) mem_free ((caddr_t) cu, sizeof (*cu) + sendsz + recvsz); if (cl) mem_free ((caddr_t) cl, sizeof (CLIENT)); return (CLIENT *) NULL; }
static bool_t rendezvous_request (SVCXPRT *xprt, struct rpc_msg *errmsg) { int sock; struct unix_rendezvous *r; struct sockaddr_un addr; struct sockaddr_in in_addr; socklen_t len; r = (struct unix_rendezvous *) xprt->xp_p1; again: len = sizeof (struct sockaddr_un); if ((sock = accept (xprt->xp_sock, (struct sockaddr *) &addr, &len)) < 0) { if (errno == EINTR) goto again; if (errno == EMFILE) { struct timespec ts = { .tv_sec = 0, .tv_nsec = 50000000 }; __nanosleep(&ts , NULL); } return FALSE; } /* * make a new transporter (re-uses xprt) */ memset (&in_addr, '\0', sizeof (in_addr)); in_addr.sin_family = AF_UNIX; xprt = makefd_xprt (sock, r->sendsize, r->recvsize); memcpy (&xprt->xp_raddr, &in_addr, sizeof (in_addr)); xprt->xp_addrlen = len; return FALSE; /* there is never an rpc msg to be processed */ } static enum xprt_stat rendezvous_stat (SVCXPRT *xprt) { return XPRT_IDLE; } static void svcunix_destroy (SVCXPRT *xprt) { struct unix_conn *cd = (struct unix_conn *) xprt->xp_p1; xprt_unregister (xprt); __close (xprt->xp_sock); if (xprt->xp_port != 0) { /* a rendezvouser socket */ xprt->xp_port = 0; } else { /* an actual connection socket */ XDR_DESTROY (&(cd->xdrs)); } mem_free ((caddr_t) cd, sizeof (struct unix_conn)); mem_free ((caddr_t) xprt, sizeof (SVCXPRT)); } #ifdef SCM_CREDENTIALS struct cmessage { struct cmsghdr cmsg; struct ucred cmcred; /* hack to make sure we have enough memory */ char dummy[(CMSG_ALIGN (sizeof (struct ucred)) - sizeof (struct ucred) + sizeof (long))]; }; /* XXX This is not thread safe, but since the main functions in svc.c and the rpcgen generated *_svc functions for the daemon are also not thread safe and uses static global variables, it doesn't matter. */ static struct cmessage cm; #endif static int __msgread (int sock, void *data, size_t cnt) { struct iovec iov; struct msghdr msg; int len; iov.iov_base = data; iov.iov_len = cnt; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_name = NULL; msg.msg_namelen = 0; #ifdef SCM_CREDENTIALS msg.msg_control = (caddr_t) &cm; msg.msg_controllen = sizeof (struct cmessage); #endif msg.msg_flags = 0; #ifdef SO_PASSCRED { int on = 1; if (__setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on))) return -1; } #endif restart: len = __recvmsg (sock, &msg, 0); if (len >= 0) { if (msg.msg_flags & MSG_CTRUNC || len == 0) return 0; else return len; } if (errno == EINTR) goto restart; return -1; } static int __msgwrite (int sock, void *data, size_t cnt) { #ifndef SCM_CREDENTIALS /* We cannot implement this reliably. */ __set_errno (ENOSYS); return -1; #else struct iovec iov; struct msghdr msg; struct cmsghdr *cmsg = &cm.cmsg; struct ucred cred; int len; /* XXX I'm not sure, if gete?id() is always correct, or if we should use get?id(). But since keyserv needs geteuid(), we have no other chance. It would be much better, if the kernel could pass both to the server. */ cred.pid = __getpid (); cred.uid = __geteuid (); cred.gid = __getegid (); memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_CREDENTIALS; cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred); iov.iov_base = data; iov.iov_len = cnt; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_control = cmsg; msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len); msg.msg_flags = 0; restart: len = __sendmsg (sock, &msg, 0); if (len >= 0) return len; if (errno == EINTR) goto restart; return -1; #endif }