示例#1
0
struct command *read_command( int cmd_fd ) {
	struct command *cmd = malloc(sizeof(struct command));
	if (! cmd) {
		fprintf(stderr, "Unable to allocate memory for command!\n");
		return NULL;
	}

	int fd[1] = {-1};
	char buffer[CMSG_SPACE(sizeof fd)];

	struct iovec v = {
		.iov_base = cmd,
		.iov_len  = sizeof(*cmd)
	};
	struct msghdr msg = {
		.msg_iov        = &v,
		.msg_iovlen     = 1,
		.msg_control    = buffer,
		.msg_controllen = sizeof(buffer)
	};

	int done = recvmsg( cmd_fd, &msg, 0 );

	if (done == -1) {
		fprintf(stderr, "Error reading command.");
		free(cmd);
		return NULL;
	}
	struct cmsghdr *cmessage = CMSG_FIRSTHDR(&msg);
	if (cmessage) {
		memcpy(fd, CMSG_DATA(cmessage), sizeof fd);
		/* place FD back in the command message */
		cmd->fd = (int) fd[0];
	}
	return cmd;
}

int send_command( int cmd_fd, enum command_type type, char *param, int passfd, int exclusive, char *tag ) {
	if (type == CMD_ADD && passfd == 1) {
		type = CMD_PASSFD;
	}
	struct command cmd = {
		.fd    = -1,
		.exclusive = exclusive,
		.type  = type,
		.param = {0},
		.tag = {0}
	};
	if (param != NULL) {
		strncpy(cmd.param, param, TH_COMMAND_PARAM_LENGTH);
		cmd.param[TH_COMMAND_PARAM_LENGTH-1] = '\0';
	}
	if (tag != NULL) {
		strncpy(cmd.tag, tag, TH_DEVICE_TAG_LENGTH);
		cmd.tag[TH_DEVICE_TAG_LENGTH-1] = '\0';
	}

	struct iovec v = {
		.iov_base = &cmd,
		.iov_len = sizeof(cmd)
	};
	struct msghdr m = {
		.msg_iov    = &v,
		.msg_iovlen = 1
	};

	/* add FD */
	int dev_fd[1] = { -1 };
	char buffer[CMSG_SPACE(sizeof(dev_fd))];
	if (passfd) {
		int fd = open( param, O_RDONLY );
		if (fd < 0) {
			perror("open");
			return 1;
		}
		dev_fd[0] = fd ;
		m.msg_control = buffer;
		m.msg_controllen = sizeof(buffer);

		struct cmsghdr *cmessage = CMSG_FIRSTHDR(&m);
		cmessage->cmsg_level = SOL_SOCKET;
		cmessage->cmsg_type = SCM_RIGHTS;
		cmessage->cmsg_len = CMSG_LEN(sizeof(dev_fd));

		m.msg_controllen = cmessage->cmsg_len;
		memcpy(CMSG_DATA(cmessage), dev_fd, sizeof dev_fd);
	}
	int done = sendmsg( cmd_fd, &m, 0 );
	return (done == -1);
}
示例#2
0
/*
 * Recv a message accompanied with credentials from a unix socket.
 *
 * Returns the size of received data, or negative error value.
 */
LTTNG_HIDDEN
ssize_t lttcomm_recv_creds_unix_sock(int sock, void *buf, size_t len,
		lttng_sock_cred *creds)
{
	struct msghdr msg;
	struct iovec iov[1];
	ssize_t ret;
	size_t len_last;
#ifdef __linux__
	struct cmsghdr *cmptr;
	size_t sizeof_cred = sizeof(lttng_sock_cred);
	char anc_buf[CMSG_SPACE(sizeof_cred)];
#endif	/* __linux__ */

	memset(&msg, 0, sizeof(msg));

	/* Not allowed */
	if (creds == NULL) {
		ret = -1;
		goto end;
	}

	/* Prepare to receive the structures */
	iov[0].iov_base = buf;
	iov[0].iov_len = len;
	msg.msg_iov = iov;
	msg.msg_iovlen = 1;

#ifdef __linux__
	msg.msg_control = anc_buf;
	msg.msg_controllen = sizeof(anc_buf);
#endif /* __linux__ */

	do {
		len_last = iov[0].iov_len;
		ret = recvmsg(sock, &msg, 0);
		if (ret > 0) {
			iov[0].iov_base += ret;
			iov[0].iov_len -= ret;
			assert(ret <= len_last);
		}
	} while ((ret > 0 && ret < len_last) || (ret < 0 && errno == EINTR));
	if (ret < 0) {
		PERROR("recvmsg fds");
		goto end;
	} else if (ret > 0) {
		ret = len;
	}
	/* Else ret = 0 meaning an orderly shutdown. */

#ifdef __linux__
	if (msg.msg_flags & MSG_CTRUNC) {
		fprintf(stderr, "Error: Control message truncated.\n");
		ret = -1;
		goto end;
	}

	cmptr = CMSG_FIRSTHDR(&msg);
	if (cmptr == NULL) {
		fprintf(stderr, "Error: Invalid control message header\n");
		ret = -1;
		goto end;
	}

	if (cmptr->cmsg_level != SOL_SOCKET ||
			cmptr->cmsg_type != LTTNG_SOCK_CREDS) {
		fprintf(stderr, "Didn't received any credentials\n");
		ret = -1;
		goto end;
	}

	if (cmptr->cmsg_len != CMSG_LEN(sizeof_cred)) {
		fprintf(stderr, "Error: Received %zu bytes of ancillary data, expected %zu\n",
				(size_t) cmptr->cmsg_len, (size_t) CMSG_LEN(sizeof_cred));
		ret = -1;
		goto end;
	}

	memcpy(creds, CMSG_DATA(cmptr), sizeof_cred);
#elif (defined(__FreeBSD__) || defined(__CYGWIN__) || defined(__sun__) || defined(__APPLE__))
	{
		int peer_ret;

		peer_ret = getpeereid(sock, &creds->uid, &creds->gid);
		if (peer_ret != 0) {
			return peer_ret;
		}
	}
#else
#error "Please implement credential support for your OS."
#endif	/* __linux__ */

end:
	return ret;
}
示例#3
0
void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
{
	struct cmsghdr __user *cm
		= (__force struct cmsghdr __user*)msg->msg_control;

	int fdmax = 0;
	int fdnum = scm->fp->count;
	struct file **fp = scm->fp->fp;
	int __user *cmfptr;
	int err = 0, i;

	if (MSG_CMSG_COMPAT & msg->msg_flags) {
		scm_detach_fds_compat(msg, scm);
		return;
	}

	if (msg->msg_controllen > sizeof(struct cmsghdr))
		fdmax = ((msg->msg_controllen - sizeof(struct cmsghdr))
			 / sizeof(int));

	if (fdnum < fdmax)
		fdmax = fdnum;

	for (i=0, cmfptr=(__force int __user *)CMSG_DATA(cm); i<fdmax;
	     i++, cmfptr++)
	{
		int new_fd;
		err = security_file_receive(fp[i]);
		if (err)
			break;
		err = get_unused_fd_flags(MSG_CMSG_CLOEXEC & msg->msg_flags
					  ? O_CLOEXEC : 0);
		if (err < 0)
			break;
		new_fd = err;
		err = put_user(new_fd, cmfptr);
		if (err) {
			put_unused_fd(new_fd);
			break;
		}
		/* Bump the usage count and install the file. */
		get_file(fp[i]);
		fd_install(new_fd, fp[i]);
	}

	if (i > 0)
	{
		int cmlen = CMSG_LEN(i*sizeof(int));
		err = put_user(SOL_SOCKET, &cm->cmsg_level);
		if (!err)
			err = put_user(SCM_RIGHTS, &cm->cmsg_type);
		if (!err)
			err = put_user(cmlen, &cm->cmsg_len);
		if (!err) {
			cmlen = CMSG_SPACE(i*sizeof(int));
			msg->msg_control += cmlen;
			msg->msg_controllen -= cmlen;
		}
	}
	if (i < fdnum || (fdnum && fdmax <= 0))
		msg->msg_flags |= MSG_CTRUNC;

	/*
	 * All of the files that fit in the message have had their
	 * usage counts incremented, so we just free the list.
	 */
	__scm_destroy(scm);
}
示例#4
0
/* Send a UDP packet with it's source address set as "source" 
   unless nowild is true, when we just send it with the kernel default */
static void send_from(int fd, int nowild, char *packet, size_t len, 
		      union mysockaddr *to, struct all_addr *source,
		      unsigned int iface)
{
  struct msghdr msg;
  struct iovec iov[1]; 
  union {
    struct cmsghdr align; /* this ensures alignment */
#if defined(HAVE_LINUX_NETWORK)
    char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
#elif defined(IP_SENDSRCADDR)
    char control[CMSG_SPACE(sizeof(struct in_addr))];
#endif
#ifdef HAVE_IPV6
    char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
#endif
  } control_u;
  
  iov[0].iov_base = packet;
  iov[0].iov_len = len;

  msg.msg_control = NULL;
  msg.msg_controllen = 0;
  msg.msg_flags = 0;
  msg.msg_name = to;
  msg.msg_namelen = sa_len(to);
  msg.msg_iov = iov;
  msg.msg_iovlen = 1;
  
  if (!nowild)
    {
      struct cmsghdr *cmptr;
      msg.msg_control = &control_u;
      msg.msg_controllen = sizeof(control_u);
      cmptr = CMSG_FIRSTHDR(&msg);

      if (to->sa.sa_family == AF_INET)
	{
#if defined(HAVE_LINUX_NETWORK)
	  struct in_pktinfo *pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
	  pkt->ipi_ifindex = 0;
	  pkt->ipi_spec_dst = source->addr.addr4;
	  msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
	  cmptr->cmsg_level = SOL_IP;
	  cmptr->cmsg_type = IP_PKTINFO;
#elif defined(IP_SENDSRCADDR)
	  struct in_addr *a = (struct in_addr *)CMSG_DATA(cmptr);
	  *a = source->addr.addr4;
	  msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
	  cmptr->cmsg_level = IPPROTO_IP;
	  cmptr->cmsg_type = IP_SENDSRCADDR;
#endif
	}
      else
#ifdef HAVE_IPV6
	{
	  struct in6_pktinfo *pkt = (struct in6_pktinfo *)CMSG_DATA(cmptr);
	  pkt->ipi6_ifindex = iface; /* Need iface for IPv6 to handle link-local addrs */
	  pkt->ipi6_addr = source->addr.addr6;
	  msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
	  cmptr->cmsg_type = IPV6_PKTINFO;
	  cmptr->cmsg_level = IPV6_LEVEL;
	}
#else
      iface = 0; /* eliminate warning */
#endif
    }
  
 retry:
  if (sendmsg(fd, &msg, 0) == -1)
    {
      /* certain Linux kernels seem to object to setting the source address in the IPv6 stack
	 by returning EINVAL from sendmsg. In that case, try again without setting the
	 source address, since it will nearly alway be correct anyway.  IPv6 stinks. */
      if (errno == EINVAL && msg.msg_controllen)
	{
	  msg.msg_controllen = 0;
	  goto retry;
	}
      if (retry_send())
	goto retry;
    }
}
示例#5
0
static int
dgram_sctp_write(BIO *b, const char *in, int inl)
{
	int ret;
	bio_dgram_sctp_data *data = (bio_dgram_sctp_data *)b->ptr;
	struct bio_dgram_sctp_sndinfo *sinfo = &(data->sndinfo);
	struct bio_dgram_sctp_prinfo *pinfo = &(data->prinfo);
	struct bio_dgram_sctp_sndinfo handshake_sinfo;
	struct iovec iov[1];
	struct msghdr msg;
	struct cmsghdr *cmsg;
#if defined(SCTP_SNDINFO) && defined(SCTP_PRINFO)
	char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndinfo)) + CMSG_SPACE(sizeof(struct sctp_prinfo))];
	struct sctp_sndinfo *sndinfo;
	struct sctp_prinfo *prinfo;
#else
	char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
	struct sctp_sndrcvinfo *sndrcvinfo;
#endif

	errno = 0;

	/* If we're send anything else than application data,
	 * disable all user parameters and flags.
	 */
	if (in[0] != 23) {
		memset(&handshake_sinfo, 0x00, sizeof(struct bio_dgram_sctp_sndinfo));
#ifdef SCTP_SACK_IMMEDIATELY
		handshake_sinfo.snd_flags = SCTP_SACK_IMMEDIATELY;
#endif
		sinfo = &handshake_sinfo;
	}

	/* If we have to send a shutdown alert message and the
	 * socket is not dry yet, we have to save it and send it
	 * as soon as the socket gets dry.
	 */
	if (data->save_shutdown && !BIO_dgram_sctp_wait_for_dry(b)) {
		data->saved_message.bio = b;
		data->saved_message.length = inl;
		data->saved_message.data = malloc(inl);
		memcpy(data->saved_message.data, in, inl);
		return inl;
	}

	iov[0].iov_base = (char *)in;
	iov[0].iov_len = inl;
	msg.msg_name = NULL;
	msg.msg_namelen = 0;
	msg.msg_iov = iov;
	msg.msg_iovlen = 1;
	msg.msg_control = (caddr_t)cmsgbuf;
	msg.msg_controllen = 0;
	msg.msg_flags = 0;
#if defined(SCTP_SNDINFO) && defined(SCTP_PRINFO)
	cmsg = (struct cmsghdr *)cmsgbuf;
	cmsg->cmsg_level = IPPROTO_SCTP;
	cmsg->cmsg_type = SCTP_SNDINFO;
	cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo));
	sndinfo = (struct sctp_sndinfo *)CMSG_DATA(cmsg);
	memset(sndinfo, 0, sizeof(struct sctp_sndinfo));
	sndinfo->snd_sid = sinfo->snd_sid;
	sndinfo->snd_flags = sinfo->snd_flags;
	sndinfo->snd_ppid = sinfo->snd_ppid;
	sndinfo->snd_context = sinfo->snd_context;
	msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo));

	cmsg = (struct cmsghdr *)&cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndinfo))];
	cmsg->cmsg_level = IPPROTO_SCTP;
	cmsg->cmsg_type = SCTP_PRINFO;
	cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo));
	prinfo = (struct sctp_prinfo *)CMSG_DATA(cmsg);
	memset(prinfo, 0, sizeof(struct sctp_prinfo));
	prinfo->pr_policy = pinfo->pr_policy;
	prinfo->pr_value = pinfo->pr_value;
	msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo));
#else
	cmsg = (struct cmsghdr *)cmsgbuf;
	cmsg->cmsg_level = IPPROTO_SCTP;
	cmsg->cmsg_type = SCTP_SNDRCV;
	cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
	sndrcvinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
	memset(sndrcvinfo, 0, sizeof(struct sctp_sndrcvinfo));
	sndrcvinfo->sinfo_stream = sinfo->snd_sid;
	sndrcvinfo->sinfo_flags = sinfo->snd_flags;
#ifdef __FreeBSD__
	sndrcvinfo->sinfo_flags |= pinfo->pr_policy;
#endif
	sndrcvinfo->sinfo_ppid = sinfo->snd_ppid;
	sndrcvinfo->sinfo_context = sinfo->snd_context;
	sndrcvinfo->sinfo_timetolive = pinfo->pr_value;
	msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndrcvinfo));
#endif

	ret = sendmsg(b->num, &msg, 0);

	BIO_clear_retry_flags(b);
	if (ret <= 0) {
		if (BIO_dgram_should_retry(ret)) {
			BIO_set_retry_write(b);

			data->_errno = errno;
		}
	}
	return (ret);
}
示例#6
0
int get_creds(int sd, char *username, char *hostname)
  {
  int             nb/*, sync*/;
  char            ctrl[CMSG_SPACE(sizeof(struct ucred))];
  size_t          size;

  struct iovec    iov[1];

  struct msghdr   msg;

  struct cmsghdr  *cmptr;
  ucreds *credentials;

  struct passwd *cpwd;
  char dummy;

  msg.msg_name = NULL;
  msg.msg_namelen = 0;
  msg.msg_iov = iov;
  msg.msg_iovlen = 1;
  msg.msg_control = ctrl;
  msg.msg_controllen = sizeof(ctrl);
  msg.msg_flags = 0;

#ifdef LOCAL_CREDS
  nb = 1;

  if (setsockopt(sd, 0, LOCAL_CREDS, &nb, sizeof(nb)) == -1) return 0;

#else
#ifdef SO_PASSCRED
  nb = 1;

  if (setsockopt(sd, SOL_SOCKET, SO_PASSCRED, &nb, sizeof(nb)) == -1)
    return 0;

#endif
#endif

  dummy = '\0';

  do
    {
    msg.msg_iov->iov_base = (void *) & dummy;
    msg.msg_iov->iov_len  = sizeof(dummy);
    nb = recvmsg(sd, &msg, 0);
    }
  while (nb == -1 && (errno == EINTR || errno == EAGAIN));

  if (nb == -1) return 0;

  if ((unsigned)msg.msg_controllen < sizeof(struct cmsghdr)) return 0;

  cmptr = CMSG_FIRSTHDR(&msg);

#ifndef __NetBSD__
  size = sizeof(ucreds);

#else
  if (cmptr->cmsg_len < SOCKCREDSIZE(0)) return 0;

  size = SOCKCREDSIZE(((cred *)CMSG_DATA(cmptr))->sc_ngroups);

#endif
  if ((unsigned)cmptr->cmsg_len != CMSG_LEN(size)) return 0;

  if (cmptr->cmsg_level != SOL_SOCKET) return 0;

  if (cmptr->cmsg_type != SCM_CREDS) return 0;

  if (!(credentials = (ucreds *)malloc(size))) return 0;

  memcpy(credentials, CMSG_DATA(cmptr), size);

  cpwd = getpwuid(SPC_PEER_UID(credentials));

  if (cpwd)
    strcpy(username, cpwd->pw_name);

  strcpy(hostname, server_name);

  free(credentials);

  return 0;
  }
示例#7
0
ngx_int_t
ngx_read_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size, ngx_log_t *log)
{
    ssize_t             n;
    ngx_err_t           err;
    struct iovec        iov[1];
    struct msghdr       msg;

#if (NGX_HAVE_MSGHDR_MSG_CONTROL)
    union {
        struct cmsghdr  cm;
        char            space[CMSG_SPACE(sizeof(int))];
    } cmsg;
#else
    int                 fd;
#endif

    iov[0].iov_base = (char *) ch;
    iov[0].iov_len = size;

    msg.msg_name = NULL;
    msg.msg_namelen = 0;
    msg.msg_iov = iov;
    msg.msg_iovlen = 1;

#if (NGX_HAVE_MSGHDR_MSG_CONTROL)
    msg.msg_control = (caddr_t) &cmsg;
    msg.msg_controllen = sizeof(cmsg);
#else
    msg.msg_accrights = (caddr_t) &fd;
    msg.msg_accrightslen = sizeof(int);
#endif

    n = recvmsg(s, &msg, 0);

    if (n == -1) {
        err = ngx_errno;
        if (err == NGX_EAGAIN) {
            return NGX_AGAIN;
        }

        ngx_log_error(NGX_LOG_ALERT, log, err, "recvmsg() failed");
        return NGX_ERROR;
    }

    if (n == 0) {
        ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, 0, "recvmsg() returned zero");
        return NGX_ERROR;
    }

    if ((size_t) n < sizeof(ngx_channel_t)) {
        ngx_log_error(NGX_LOG_ALERT, log, 0,
                      "recvmsg() returned not enough data: %uz", n);
        return NGX_ERROR;
    }

#if (NGX_HAVE_MSGHDR_MSG_CONTROL)

    if (ch->command == NGX_CMD_OPEN_CHANNEL) {

        if (cmsg.cm.cmsg_len < (socklen_t) CMSG_LEN(sizeof(int))) {
            ngx_log_error(NGX_LOG_ALERT, log, 0,
                          "recvmsg() returned too small ancillary data");
            return NGX_ERROR;
        }

        if (cmsg.cm.cmsg_level != SOL_SOCKET || cmsg.cm.cmsg_type != SCM_RIGHTS)
        {
            ngx_log_error(NGX_LOG_ALERT, log, 0,
                          "recvmsg() returned invalid ancillary data "
                          "level %d or type %d",
                          cmsg.cm.cmsg_level, cmsg.cm.cmsg_type);
            return NGX_ERROR;
        }

        ch->fd = *(int *) CMSG_DATA(&cmsg.cm);
    }

    if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) {
        ngx_log_error(NGX_LOG_ALERT, log, 0,
                      "recvmsg() truncated data");
    }

#else

    if (ch->command == NGX_CMD_OPEN_CHANNEL) {
        if (msg.msg_accrightslen != sizeof(int)) {
            ngx_log_error(NGX_LOG_ALERT, log, 0,
                          "recvmsg() returned no ancillary data");
            return NGX_ERROR;
        }

        ch->fd = fd;
    }

#endif

    return n;
}
示例#8
0
文件: ps.c 项目: OPSF/uClinux
/*
 * This function runs in the context of the background proxy process.
 * Receive a control message from the parent (sent by the port_share_sendmsg
 * function above) and act on it.  Return false if the proxy process should
 * exit, true otherwise.
 */
static bool
control_message_from_parent (const socket_descriptor_t sd_control,
			     struct proxy_connection **list,
			     struct event_set *es,
			     const in_addr_t server_addr,
			     const int server_port)
{
  struct buffer buf = alloc_buf (PROXY_CONNECTION_BUFFER_SIZE);
  struct msghdr mesg;
  struct cmsghdr* h;
  struct iovec iov[2];
  char command = 0;
  ssize_t status;
  int ret = true;

  CLEAR (mesg);

  iov[0].iov_base = &command;
  iov[0].iov_len = sizeof (command);
  iov[1].iov_base = BPTR (&buf);
  iov[1].iov_len = BCAP (&buf);
  mesg.msg_iov = iov;
  mesg.msg_iovlen = 2;

  mesg.msg_controllen = cmsg_size ();
  mesg.msg_control = (char *) malloc (mesg.msg_controllen);
  check_malloc_return (mesg.msg_control);
  mesg.msg_flags = 0;

  h = CMSG_FIRSTHDR(&mesg);
  h->cmsg_len = CMSG_LEN(sizeof(socket_descriptor_t));
  h->cmsg_level = SOL_SOCKET;
  h->cmsg_type = SCM_RIGHTS;
  *((socket_descriptor_t*)CMSG_DATA(h)) = SOCKET_UNDEFINED;

  status = recvmsg (sd_control, &mesg, MSG_NOSIGNAL);
  if (status != -1)
    {
      if (   h == NULL
	  || h->cmsg_len    != CMSG_LEN(sizeof(socket_descriptor_t))
	  || h->cmsg_level  != SOL_SOCKET
	  || h->cmsg_type   != SCM_RIGHTS )
	{
	  ret = false;
	}
      else
	{
	  const socket_descriptor_t received_fd = *((socket_descriptor_t*)CMSG_DATA(h));
	  dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: RECEIVED sd=%d", (int)received_fd);

	  if (status >= 2 && command == COMMAND_REDIRECT)
	    {
	      buf.len = status - 1;
	      if (proxy_entry_new (list,
				   es,
				   server_addr,
				   server_port,
				   received_fd,
				   &buf))
		{
		  CLEAR (buf); /* we gave the buffer to proxy_entry_new */
		}
	      else
		{
		  openvpn_close_socket (received_fd);
		}
	    }
	  else if (status >= 1 && command == COMMAND_EXIT)
	    {
	      dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: RECEIVED COMMAND_EXIT");
	      openvpn_close_socket (received_fd); /* null socket */
	      ret = false;
	    }
	}
    }
  free (mesg.msg_control);
  free_buf (&buf);
  return ret;
}
示例#9
0
文件: cmsg.c 项目: caniszczyk/runc
/*
 * Receives a file descriptor from the sockfd provided. Returns the file
 * descriptor as sent from sendfd(). It will return the file descriptor
 * or die (literally) trying. Any synchronisation and preparation of
 * state should be done external to this (we expect the other side to be
 * in sendfd() in the code).
 */
struct file_t recvfd(int sockfd)
{
	struct msghdr msg = {0};
	struct iovec iov[1] = {0};
	struct cmsghdr *cmsg;
	struct file_t file = {0};
	int *fdptr;
	int olderrno;

	union {
		char buf[CMSG_SPACE(sizeof(file.fd))];
		struct cmsghdr align;
	} u;

	/* Allocate a buffer. */
	/* TODO: Make this dynamic with MSG_PEEK. */
	file.name = malloc(TAG_BUFFER);
	if (!file.name)
		error("recvfd: failed to allocate file.tag buffer\n");

	/*
	 * We need to "recieve" the non-ancillary data even though we don't
	 * plan to use it at all. Otherwise, things won't work as expected.
	 * See unix(7) and other well-hidden documentation.
	 */
	iov[0].iov_base = file.name;
	iov[0].iov_len = TAG_BUFFER;

	msg.msg_name = NULL;
	msg.msg_namelen = 0;
	msg.msg_iov = iov;
	msg.msg_iovlen = 1;
	msg.msg_control = u.buf;
	msg.msg_controllen = sizeof(u.buf);

	ssize_t ret = recvmsg(sockfd, &msg, 0);
	if (ret < 0)
		goto err;

	cmsg = CMSG_FIRSTHDR(&msg);
	if (!cmsg)
		error("recvfd: got NULL from CMSG_FIRSTHDR");
	if (cmsg->cmsg_level != SOL_SOCKET)
		error("recvfd: expected SOL_SOCKET in cmsg: %d", cmsg->cmsg_level);
	if (cmsg->cmsg_type != SCM_RIGHTS)
		error("recvfd: expected SCM_RIGHTS in cmsg: %d", cmsg->cmsg_type);
	if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)))
		error("recvfd: expected correct CMSG_LEN in cmsg: %lu", cmsg->cmsg_len);

	fdptr = (int *) CMSG_DATA(cmsg);
	if (!fdptr || *fdptr < 0)
		error("recvfd: recieved invalid pointer");

	file.fd = *fdptr;
	return file;

err:
	olderrno = errno;
	free(file.name);
	errno = olderrno;
	return (struct file_t){0};
}
示例#10
0
int lutil_getpeereid( int s, uid_t *euid, gid_t *egid
#ifdef LDAP_PF_LOCAL_SENDMSG
	, struct berval *peerbv
#endif
	)
{
#ifdef LDAP_PF_LOCAL
#if defined( HAVE_GETPEERUCRED )
	ucred_t *uc = NULL;
	if( getpeerucred( s, &uc ) == 0 )  {
		*euid = ucred_geteuid( uc );
		*egid = ucred_getegid( uc );
		ucred_free( uc );
		return 0;
	}

#elif defined( SO_PEERCRED )
	struct ucred peercred;
	ber_socklen_t peercredlen = sizeof peercred;

	if(( getsockopt( s, SOL_SOCKET, SO_PEERCRED,
		(void *)&peercred, &peercredlen ) == 0 )
		&& ( peercredlen == sizeof peercred ))
	{
		*euid = peercred.uid;
		*egid = peercred.gid;
		return 0;
	}

#elif defined( LOCAL_PEERCRED )
	struct xucred peercred;
	ber_socklen_t peercredlen = sizeof peercred;

	if(( getsockopt( s, LOCAL_PEERCRED, 1,
		(void *)&peercred, &peercredlen ) == 0 )
		&& ( peercred.cr_version == XUCRED_VERSION ))
	{
		*euid = peercred.cr_uid;
		*egid = peercred.cr_gid;
		return 0;
	}
#elif defined( LDAP_PF_LOCAL_SENDMSG ) && defined( MSG_WAITALL )
	int err, fd;
	struct iovec iov;
	struct msghdr msg = {0};
# ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
# ifndef CMSG_SPACE
# define CMSG_SPACE(len)	(_CMSG_ALIGN(sizeof(struct cmsghdr)) + _CMSG_ALIGN(len))
# endif
# ifndef CMSG_LEN
# define CMSG_LEN(len)		(_CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
# endif
	struct {
		struct cmsghdr cm;
		int fd;
	} control_st;
	struct cmsghdr *cmsg;
# endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */
	struct stat st;
	struct sockaddr_un lname, rname;
	ber_socklen_t llen, rlen;

	rlen = sizeof(rname);
	llen = sizeof(lname);
	memset( &lname, 0, sizeof( lname ));
	getsockname(s, (struct sockaddr *)&lname, &llen);

	iov.iov_base = peerbv->bv_val;
	iov.iov_len = peerbv->bv_len;
	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;
	peerbv->bv_len = 0;

# ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
	msg.msg_control = &control_st;
	msg.msg_controllen = sizeof( struct cmsghdr ) + sizeof( int );	/* no padding! */

	cmsg = CMSG_FIRSTHDR( &msg );
# else
	msg.msg_accrights = (char *)&fd;
	msg.msg_accrightslen = sizeof(fd);
# endif

	/*
	 * AIX returns a bogus file descriptor if recvmsg() is
	 * called with MSG_PEEK (is this a bug?). Hence we need
	 * to receive the Abandon PDU.
	 */
	err = recvmsg( s, &msg, MSG_WAITALL );
	if( err >= 0 &&
# ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
	    cmsg->cmsg_len == CMSG_LEN( sizeof(int) ) &&
	    cmsg->cmsg_level == SOL_SOCKET &&
	    cmsg->cmsg_type == SCM_RIGHTS
# else
		msg.msg_accrightslen == sizeof(int)
# endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL*/
	) {
		int mode = S_IFIFO|S_ISUID|S_IRWXU;

		/* We must receive a valid descriptor, it must be a pipe,
		 * it must only be accessible by its owner, and it must
		 * have the name of our socket written on it.
		 */
		peerbv->bv_len = err;
# ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
		fd = (*(int *)CMSG_DATA( cmsg ));
# endif
		err = fstat( fd, &st );
		if ( err == 0 )
			rlen = read(fd, &rname, rlen);
		close(fd);
		if( err == 0 && st.st_mode == mode &&
			llen == rlen && !memcmp(&lname, &rname, llen))
		{
			*euid = st.st_uid;
			*egid = st.st_gid;
			return 0;
		}
	}
#elif defined(SOCKCREDSIZE)
	struct msghdr msg;
	ber_socklen_t crmsgsize;
	void *crmsg;
	struct cmsghdr *cmp;
	struct sockcred *sc;

	memset(&msg, 0, sizeof msg);
	crmsgsize = CMSG_SPACE(SOCKCREDSIZE(NGROUPS));
	if (crmsgsize == 0) goto sc_err;
	crmsg = malloc(crmsgsize);
	if (crmsg == NULL) goto sc_err;
	memset(crmsg, 0, crmsgsize);
	
	msg.msg_control = crmsg;
	msg.msg_controllen = crmsgsize;
	
	if (recvmsg(s, &msg, 0) < 0) {
		free(crmsg);
		goto sc_err;
	}	

	if (msg.msg_controllen == 0 || (msg.msg_flags & MSG_CTRUNC) != 0) {
		free(crmsg);
		goto sc_err;
	}	
	
	cmp = CMSG_FIRSTHDR(&msg);
	if (cmp->cmsg_level != SOL_SOCKET || cmp->cmsg_type != SCM_CREDS) {
		printf("nocreds\n");
		goto sc_err;
	}	
	
	sc = (struct sockcred *)(void *)CMSG_DATA(cmp);
	
	*euid = sc->sc_euid;
	*egid = sc->sc_egid;

	free(crmsg);
	return 0;

sc_err:	
#endif
#endif /* LDAP_PF_LOCAL */

	return -1;
}
示例#11
0
文件: ps.c 项目: OPSF/uClinux
/*
 * Send a command (char), data (head), and a file descriptor (sd_send) to a local process
 * over unix socket sd.  Unfortunately, there's no portable way to send file descriptors
 * to other processes, so this code, as well as its analog (control_message_from_parent below),
 * is Linux-specific. This function runs in the context of the main process and is used to
 * send commands, data, and file descriptors to the background process.
 */
static void
port_share_sendmsg (const socket_descriptor_t sd,
		    const char command,
		    const struct buffer *head,
		    const socket_descriptor_t sd_send)
{
  if (socket_defined (sd))
    {
      struct msghdr mesg;
      struct cmsghdr* h;
      struct iovec iov[2];
      socket_descriptor_t sd_null[2] = { SOCKET_UNDEFINED, SOCKET_UNDEFINED };
      char cmd;
      ssize_t status;

      dmsg (D_PS_PROXY_DEBUG, "PORT SHARE: sendmsg sd=%d len=%d",
	    (int)sd_send,
	    head ? BLEN(head) : -1);

      CLEAR (mesg);

      cmd = command;

      iov[0].iov_base = &cmd;
      iov[0].iov_len = sizeof (cmd);
      mesg.msg_iovlen = 1;

      if (head)
	{
	  iov[1].iov_base = BPTR (head);
	  iov[1].iov_len = BLEN (head);
	  mesg.msg_iovlen = 2;
	}

      mesg.msg_iov = iov;

      mesg.msg_controllen = cmsg_size ();
      mesg.msg_control = (char *) malloc (mesg.msg_controllen);
      check_malloc_return (mesg.msg_control);
      mesg.msg_flags = 0;

      h = CMSG_FIRSTHDR(&mesg);
      h->cmsg_level = SOL_SOCKET;
      h->cmsg_type = SCM_RIGHTS;
      h->cmsg_len = CMSG_LEN(sizeof(socket_descriptor_t));

      if (socket_defined (sd_send))
	{
	  *((socket_descriptor_t*)CMSG_DATA(h)) = sd_send;
	}
      else
	{
	  socketpair (PF_UNIX, SOCK_DGRAM, 0, sd_null);
	  *((socket_descriptor_t*)CMSG_DATA(h)) = sd_null[0];
	}

      status = sendmsg (sd, &mesg, MSG_NOSIGNAL);
      if (status == -1)
	msg (M_WARN, "PORT SHARE: sendmsg failed (unable to communicate with background process)");

      close_socket_if_defined (sd_null[0]);
      close_socket_if_defined (sd_null[1]);
      free (mesg.msg_control);
    }
}
示例#12
0
文件: stream.c 项目: HenryRawas/libuv
/* On success returns NULL. On error returns a pointer to the write request
 * which had the error.
 */
static void uv__write(uv_stream_t* stream) {
  uv_write_t* req;
  struct iovec* iov;
  int iovcnt;
  ssize_t n;

start:

  assert(stream->fd >= 0);

  /* Get the request at the head of the queue. */
  req = uv_write_queue_head(stream);
  if (!req) {
    assert(stream->write_queue_size == 0);
    return;
  }

  assert(req->handle == stream);

  /*
   * Cast to iovec. We had to have our own uv_buf_t instead of iovec
   * because Windows's WSABUF is not an iovec.
   */
  assert(sizeof(uv_buf_t) == sizeof(struct iovec));
  iov = (struct iovec*) &(req->bufs[req->write_index]);
  iovcnt = req->bufcnt - req->write_index;

  /*
   * Now do the actual writev. Note that we've been updating the pointers
   * inside the iov each time we write. So there is no need to offset it.
   */

  if (req->send_handle) {
    struct msghdr msg;
    char scratch[64];
    struct cmsghdr *cmsg;
    int fd_to_send = req->send_handle->fd;

    assert(fd_to_send >= 0);

    msg.msg_name = NULL;
    msg.msg_namelen = 0;
    msg.msg_iov = iov;
    msg.msg_iovlen = iovcnt;
    msg.msg_flags = 0;

    msg.msg_control = (void*) scratch;
    msg.msg_controllen = CMSG_LEN(sizeof(fd_to_send));

    cmsg = CMSG_FIRSTHDR(&msg);
    cmsg->cmsg_level = SOL_SOCKET;
    cmsg->cmsg_type = SCM_RIGHTS;
    cmsg->cmsg_len = msg.msg_controllen;
    *(int*) CMSG_DATA(cmsg) = fd_to_send;

    do {
      n = sendmsg(stream->fd, &msg, 0);
    }
    while (n == -1 && errno == EINTR);
  } else {
    do {
      if (iovcnt == 1) {
        n = write(stream->fd, iov[0].iov_base, iov[0].iov_len);
      } else {
        n = writev(stream->fd, iov, iovcnt);
      }
    }
    while (n == -1 && errno == EINTR);
  }

  if (n < 0) {
    if (errno != EAGAIN) {
      /* Error */
      req->error = errno;
      stream->write_queue_size -= uv__write_req_size(req);
      uv__write_req_finish(req);
      return;
    } else if (stream->blocking) {
      /* If this is a blocking stream, try again. */
      goto start;
    }
  } else {
    /* Successful write */

    /* Update the counters. */
    while (n >= 0) {
      uv_buf_t* buf = &(req->bufs[req->write_index]);
      size_t len = buf->len;

      assert(req->write_index < req->bufcnt);

      if ((size_t)n < len) {
        buf->base += n;
        buf->len -= n;
        stream->write_queue_size -= n;
        n = 0;

        /* There is more to write. */
        if (stream->blocking) {
          /*
           * If we're blocking then we should not be enabling the write
           * watcher - instead we need to try again.
           */
          goto start;
        } else {
          /* Break loop and ensure the watcher is pending. */
          break;
        }

      } else {
        /* Finished writing the buf at index req->write_index. */
        req->write_index++;

        assert((size_t)n >= len);
        n -= len;

        assert(stream->write_queue_size >= len);
        stream->write_queue_size -= len;

        if (req->write_index == req->bufcnt) {
          /* Then we're done! */
          assert(n == 0);
          uv__write_req_finish(req);
          /* TODO: start trying to write the next request. */
          return;
        }
      }
    }
  }

  /* Either we've counted n down to zero or we've got EAGAIN. */
  assert(n == 0 || n == -1);

  /* Only non-blocking streams should use the write_watcher. */
  assert(!stream->blocking);

  /* We're not done. */
  ev_io_start(stream->loop->ev, &stream->write_watcher);
}
示例#13
0
int
main(int argc, char *argv[])
{
    struct msghdr msgh;
    struct iovec iov;
    struct ucred *ucredp, ucred;
    int data, lfd, sfd, optval, opt;
    ssize_t nr;
    Boolean useDatagramSocket;
    union {
        struct cmsghdr cmh;
        char   control[CMSG_SPACE(sizeof(struct ucred))];
                        /* Space large enough to hold a ucred structure */
    } control_un;
    struct cmsghdr *cmhp;
    socklen_t len;

    /* Parse command-line arguments */

    useDatagramSocket = FALSE;

    while ((opt = getopt(argc, argv, "d")) != -1) {
        switch (opt) {
        case 'd':
            useDatagramSocket = TRUE;
            break;

        default:
            usageErr("%s [-d]\n"
                    "        -d    use datagram socket\n", argv[0]);
        }
    }

    /* Create socket bound to well-known address */

    if (remove(SOCK_PATH) == -1 && errno != ENOENT)
        errExit("remove-%s", SOCK_PATH);

    if (useDatagramSocket) {
        printf("Receiving via datagram socket\n");
        sfd = unixBind(SOCK_PATH, SOCK_DGRAM);
        if (sfd == -1)
            errExit("unixBind");

    } else {
        printf("Receiving via stream socket\n");
        lfd = unixListen(SOCK_PATH, 5);
        if (lfd == -1)
            errExit("unixListen");

        sfd = accept(lfd, NULL, NULL);
        if (sfd == -1)
            errExit("accept");
    }

    /* We must set the SO_PASSCRED socket option in order to receive
       credentials */

    optval = 1;
    if (setsockopt(sfd, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) == -1)
        errExit("setsockopt");

    /* Set 'control_un' to describe ancillary data that we want to receive */

    control_un.cmh.cmsg_len = CMSG_LEN(sizeof(struct ucred));
    control_un.cmh.cmsg_level = SOL_SOCKET;
    control_un.cmh.cmsg_type = SCM_CREDENTIALS;

    /* Set 'msgh' fields to describe 'control_un' */

    msgh.msg_control = control_un.control;
    msgh.msg_controllen = sizeof(control_un.control);

    /* Set fields of 'msgh' to point to buffer used to receive (real)
       data read by recvmsg() */

    msgh.msg_iov = &iov;
    msgh.msg_iovlen = 1;
    iov.iov_base = &data;
    iov.iov_len = sizeof(int);

    msgh.msg_name = NULL;               /* We don't need address of peer */
    msgh.msg_namelen = 0;

    /* Receive real plus ancillary data */

    nr = recvmsg(sfd, &msgh, 0);
    if (nr == -1)
        errExit("recvmsg");
    printf("recvmsg() returned %ld\n", (long) nr);

    if (nr > 0)
        printf("Received data = %d\n", data);

    /* Extract credentials information from received ancillary data */

    cmhp = CMSG_FIRSTHDR(&msgh);
    if (cmhp == NULL || cmhp->cmsg_len != CMSG_LEN(sizeof(struct ucred)))
        fatal("bad cmsg header / message length");
    if (cmhp->cmsg_level != SOL_SOCKET)
        fatal("cmsg_level != SOL_SOCKET");
    if (cmhp->cmsg_type != SCM_CREDENTIALS)
        fatal("cmsg_type != SCM_CREDENTIALS");

    ucredp = (struct ucred *) CMSG_DATA(cmhp);
    printf("Received credentials pid=%ld, uid=%ld, gid=%ld\n",
                (long) ucredp->pid, (long) ucredp->uid, (long) ucredp->gid);

    /* The Linux-specific, read-only SO_PEERCRED socket option returns
       credential information about the peer, as described in socket(7) */

    len = sizeof(struct ucred);
    if (getsockopt(sfd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == -1)
        errExit("getsockopt");

    printf("Credentials from SO_PEERCRED: pid=%ld, euid=%ld, egid=%ld\n",
            (long) ucred.pid, (long) ucred.uid, (long) ucred.gid);

    exit(EXIT_SUCCESS);
}
int
main(int argc, char *argv[])
{
    struct msghdr msgh;
    struct iovec iov;
    int data, lfd, sfd, fd, opt;
    ssize_t nr;
    Boolean useDatagramSocket;
    union {
        struct cmsghdr cmh;
        char   control[CMSG_SPACE(sizeof(int))];
                        /* Space large enough to hold an 'int' */
    } control_un;
    struct cmsghdr *cmhp;

    /* Parse command-line arguments */

    useDatagramSocket = FALSE;

    while ((opt = getopt(argc, argv, "d")) != -1) {
        switch (opt) {
        case 'd':
            useDatagramSocket = TRUE;
            break;

        default:
            usageErr("%s [-d]\n"
                     "        -d    use datagram socket\n", argv[0]);
        }
    }

    /* Create socket bound to well-known address */

    if (remove(SOCK_PATH) == -1 && errno != ENOENT)
        errExit("remove-%s", SOCK_PATH);

    if (useDatagramSocket) {
        fprintf(stderr, "Receiving via datagram socket\n");
        sfd = unixBind(SOCK_PATH, SOCK_DGRAM);
        if (sfd == -1)
            errExit("unixBind");

    } else {
        fprintf(stderr, "Receiving via stream socket\n");
        lfd = unixListen(SOCK_PATH, 5);
        if (lfd == -1)
            errExit("unixListen");

        sfd = accept(lfd, NULL, 0);
        if (sfd == -1)
            errExit("accept");
    }

    /* Set 'control_un' to describe ancillary data that we want to receive */

    control_un.cmh.cmsg_len = CMSG_LEN(sizeof(int));
    control_un.cmh.cmsg_level = SOL_SOCKET;
    control_un.cmh.cmsg_type = SCM_RIGHTS;

    /* Set 'msgh' fields to describe 'control_un' */

    msgh.msg_control = control_un.control;
    msgh.msg_controllen = sizeof(control_un.control);

    /* Set fields of 'msgh' to point to buffer used to receive (real)
       data read by recvmsg() */

    msgh.msg_iov = &iov;
    msgh.msg_iovlen = 1;
    iov.iov_base = &data;
    iov.iov_len = sizeof(int);

    msgh.msg_name = NULL;               /* We don't need address of peer */
    msgh.msg_namelen = 0;

    /* Receive real plus ancillary data */

    nr = recvmsg(sfd, &msgh, 0);
    if (nr == -1)
        errExit("recvmsg");
    fprintf(stderr, "recvmsg() returned %ld\n", (long) nr);

    if (nr > 0)
        fprintf(stderr, "Received data = %d\n", data);

    /* Get the received file descriptor (which is typically a different
       file descriptor number than was used in the sending process) */

    cmhp = CMSG_FIRSTHDR(&msgh);
    if (cmhp == NULL || cmhp->cmsg_len != CMSG_LEN(sizeof(int)))
        fatal("bad cmsg header / message length");
    if (cmhp->cmsg_level != SOL_SOCKET)
        fatal("cmsg_level != SOL_SOCKET");
    if (cmhp->cmsg_type != SCM_RIGHTS)
        fatal("cmsg_type != SCM_RIGHTS");

    fd = *((int *) CMSG_DATA(cmhp));
    fprintf(stderr, "Received fd=%d\n", fd);

    /* Having obtained the file descriptor, read the file's contents and
       print them on standard output */

    for (;;) {
        char buf[BUF_SIZE];
        ssize_t numRead;

        numRead = read(fd, buf, BUF_SIZE);
        if (numRead == -1)
            errExit("read");

        if (numRead == 0)
            break;

        write(STDOUT_FILENO, buf, numRead);
    }

    exit(EXIT_SUCCESS);
}
示例#15
0
ssize_t FAST_FUNC
send_to_from(int fd, void *buf, size_t len, int flags,
             const struct sockaddr *to,
             const struct sockaddr *from,
             socklen_t tolen)
{
#ifndef IP_PKTINFO
	(void)from; /* suppress "unused from" warning */
	return sendto(fd, buf, len, flags, to, tolen);
#else
	struct iovec iov[1];
	struct msghdr msg;
	union {
		char cmsg[CMSG_SPACE(sizeof(struct in_pktinfo))];
# if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
		char cmsg6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
# endif
	} u;
	struct cmsghdr* cmsgptr;

	if (from->sa_family != AF_INET
# if ENABLE_FEATURE_IPV6
	        && from->sa_family != AF_INET6
# endif
	   ) {
		/* ANY local address */
		return sendto(fd, buf, len, flags, to, tolen);
	}

	/* man recvmsg and man cmsg is needed to make sense of code below */

	iov[0].iov_base = buf;
	iov[0].iov_len = len;

	memset(&u, 0, sizeof(u));

	memset(&msg, 0, sizeof(msg));
	msg.msg_name = (void *)(struct sockaddr *)to; /* or compiler will annoy us */
	msg.msg_namelen = tolen;
	msg.msg_iov = iov;
	msg.msg_iovlen = 1;
	msg.msg_control = &u;
	msg.msg_controllen = sizeof(u);
	msg.msg_flags = flags;

	cmsgptr = CMSG_FIRSTHDR(&msg);
	if (to->sa_family == AF_INET && from->sa_family == AF_INET) {
		struct in_pktinfo *pktptr;
		cmsgptr->cmsg_level = IPPROTO_IP;
		cmsgptr->cmsg_type = IP_PKTINFO;
		cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
		pktptr = (struct in_pktinfo *)(CMSG_DATA(cmsgptr));
		/*pktptr->ipi_ifindex = 0; -- already done by memset(u...) */
		/* In general, CMSG_DATA() can be unaligned, but in this case
		 * we know for sure it is sufficiently aligned:
		 * CMSG_FIRSTHDR simply returns &u above,
		 * and CMSG_DATA returns &u + size_t + int + int.
		 * Thus direct assignment is ok:
		 */
		pktptr->ipi_spec_dst = ((struct sockaddr_in*)from)->sin_addr;
	}
# if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
	else if (to->sa_family == AF_INET6 && from->sa_family == AF_INET6) {
		struct in6_pktinfo *pktptr;
		cmsgptr->cmsg_level = IPPROTO_IPV6;
		cmsgptr->cmsg_type = IPV6_PKTINFO;
		cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
		pktptr = (struct in6_pktinfo *)(CMSG_DATA(cmsgptr));
		/* pktptr->ipi6_ifindex = 0; -- already done by memset(u...) */
		pktptr->ipi6_addr = ((struct sockaddr_in6*)from)->sin6_addr;
	}
# endif
	msg.msg_controllen = cmsgptr->cmsg_len;

	return sendmsg(fd, &msg, flags);
#endif
}
示例#16
0
文件: uds.c 项目: AjeyBohare/minix
int do_recvmsg(message *dev_m_in, message *dev_m_out)
{
	int minor;
	int rc;
	struct msg_control msg_ctrl;
	socklen_t controllen_avail = 0;
	socklen_t controllen_needed = 0;
	socklen_t controllen_desired = 0;

#if DEBUG == 1
	static int call_count = 0;
	printf("(uds) [%d] do_sendmsg() call_count=%d\n",
					uds_minor(dev_m_in), ++call_count);
#endif

	minor = uds_minor(dev_m_in);


#if DEBUG == 1
	printf("(uds) [%d] CREDENTIALS {pid:%d,uid:%d,gid:%d}\n", minor,
				uds_fd_table[minor].ancillary_data.cred.pid,
				uds_fd_table[minor].ancillary_data.cred.uid,
				uds_fd_table[minor].ancillary_data.cred.gid);
#endif

	memset(&msg_ctrl, '\0', sizeof(struct msg_control));

	/* get the msg_control from the user, it will include the
	 * amount of space the user has allocated for control data.
	 */
	rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
					(vir_bytes) 0, (vir_bytes) &msg_ctrl,
					sizeof(struct msg_control));

	if (rc != OK) {
		return EIO;
	}

	controllen_avail = MIN(msg_ctrl.msg_controllen, MSG_CONTROL_MAX);

	if (uds_fd_table[minor].ancillary_data.nfiledes > 0) {
		controllen_needed = CMSG_LEN(sizeof(int) *
				(uds_fd_table[minor].ancillary_data.nfiledes));
	}

	/* if there is room we also include credentials */
	controllen_desired = controllen_needed +
				CMSG_LEN(sizeof(struct ucred));

	if (controllen_needed > controllen_avail) {
		return EOVERFLOW;
	}

	rc = recv_fds(minor, &uds_fd_table[minor].ancillary_data, &msg_ctrl);
	if (rc != OK) {
		return rc;
	}

	if (controllen_desired <= controllen_avail) {
		rc = recv_cred(minor, &uds_fd_table[minor].ancillary_data,
								&msg_ctrl);
		if (rc != OK) {
			return rc;
		}
	}

	/* send the user the control data */
	rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
		(vir_bytes) 0, (vir_bytes) &msg_ctrl,
		sizeof(struct msg_control));

	return rc ? EIO : OK;
}
static GSocketControlMessage *
g_unix_credentials_message_deserialize (gint     level,
                                        gint     type,
                                        gsize    size,
                                        gpointer data)
{
    GSocketControlMessage *message;

    message = NULL;

#ifdef __linux__
    {
        GCredentials *credentials;
        struct ucred *ucred;

        if (level != SOL_SOCKET || type != SCM_CREDENTIALS)
            goto out;

        if (size != sizeof (struct ucred))
        {
            g_warning ("Expected a struct ucred (%" G_GSIZE_FORMAT " bytes) but "
                       "got %" G_GSIZE_FORMAT " bytes of data",
                       sizeof (struct ucred),
                       size);
            goto out;
        }

        ucred = data;

        if (ucred->uid == (uid_t)-1 &&
                ucred->gid == (gid_t)-1)
        {
            /* This happens if the remote side didn't pass the credentials */
            goto out;
        }

        credentials = g_credentials_new ();
        g_credentials_set_native (credentials, G_CREDENTIALS_TYPE_LINUX_UCRED, ucred);
        message = g_unix_credentials_message_new_with_credentials (credentials);
        g_object_unref (credentials);
out:
        ;
    }
#elif defined(__FreeBSD__)
    {
        GCredentials *credentials;
        struct cmsgcred *cred;

        if (level != SOL_SOCKET || type != SCM_CREDS)
        {
            goto out;
        }
        if (size < sizeof *cred)
        {
            g_warning ("Expected a struct cmsgcred (%" G_GSIZE_FORMAT " bytes) but "
                       "got %" G_GSIZE_FORMAT " bytes of data",
                       CMSG_LEN (sizeof *cred),
                       size);
            goto out;
        }

        cred = data;

        credentials = g_credentials_new ();
        g_credentials_set_native (credentials, G_CREDENTIALS_TYPE_FREEBSD_CMSGCRED, cred);
        message = g_unix_credentials_message_new_with_credentials (credentials);
        g_object_unref (credentials);
out:
        ;
    }
#endif

    return message;
}
示例#18
0
int send_r(int sk, int stream, int order, int send_size, int assoc_i)
{
	int error = 0;
	struct msghdr outmsg;
	struct iovec iov;
	char *message = NULL;
	int msglen = 0;
	char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
	struct cmsghdr *cmsg;
	struct sctp_sndrcvinfo *sinfo;

	if (send_size > 0) {
		message = build_msg(send_size);
		msglen = strlen(message) + 1;
		iov.iov_base = message;
		iov.iov_len = msglen;
	}
	else {
		if (do_exit) {
			exit(1);
		} else {
			goto error_out;
		}
	}

	outmsg.msg_name = &s_rem;
       	outmsg.msg_namelen = sizeof(struct sockaddr_storage);
	outmsg.msg_iov = &iov;
	outmsg.msg_iovlen = 1;
	outmsg.msg_control = outcmsg;
	outmsg.msg_controllen = sizeof(outcmsg);
	outmsg.msg_flags = 0;

	cmsg = CMSG_FIRSTHDR(&outmsg);
	cmsg->cmsg_level = IPPROTO_SCTP;
	cmsg->cmsg_type = SCTP_SNDRCV;
	cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));

	outmsg.msg_controllen = cmsg->cmsg_len;
	sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
	memset(sinfo, 0, sizeof(struct sctp_sndrcvinfo));
	sinfo->sinfo_ppid = rand();
	sinfo->sinfo_stream = stream;
	sinfo->sinfo_flags = 0;
	if (!order)
		sinfo->sinfo_flags = SCTP_UNORDERED;

	DEBUG_PRINT(DEBUG_MIN, "\tsendmsg(sk=%d, assoc=%d) %4d bytes.\n",
		    sk, assoc_i, send_size);
	DEBUG_PRINT(DEBUG_MAX, "\t  SNDRCV");
	if (DEBUG_MAX == debug_level) {
        	printf("(stream=%u ", 	sinfo->sinfo_stream);
		printf("flags=0x%x ",	sinfo->sinfo_flags);
		printf("ppid=%u\n",	sinfo->sinfo_ppid);
	}

	/* Send to our neighbor.  */
	error = sendmsg(sk, &outmsg, MSG_WAITALL);
	if (error != msglen) {
		fprintf(stderr, "\n\t\t*** sendmsg: %s ***\n\n",
			strerror(errno));
		fflush(stdout);
	
		if (do_exit) {
			exit(1);
		} else {
			if (!drain)
				goto error_out;
		}
	}

	if (send_size > 0) free(message);
	return 0;
error_out:
	if (send_size > 0) free(message);
	return -1;

} /* send_r() */
示例#19
0
ngx_int_t
ngx_write_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size,
    ngx_log_t *log)
{
    ssize_t             n;
    ngx_err_t           err;
    struct iovec        iov[1];
    struct msghdr       msg;

#if (NGX_HAVE_MSGHDR_MSG_CONTROL)

    union {
        struct cmsghdr  cm;
        char            space[CMSG_SPACE(sizeof(int))];
    } cmsg;

    if (ch->fd == -1) {
        msg.msg_control = NULL;
        msg.msg_controllen = 0;

    } else {
        msg.msg_control = (caddr_t) &cmsg;
        msg.msg_controllen = sizeof(cmsg);

        cmsg.cm.cmsg_len = CMSG_LEN(sizeof(int));
        cmsg.cm.cmsg_level = SOL_SOCKET;
        cmsg.cm.cmsg_type = SCM_RIGHTS;
        *(int *) CMSG_DATA(&cmsg.cm) = ch->fd;
    }

    msg.msg_flags = 0;

#else

    if (ch->fd == -1) {
        msg.msg_accrights = NULL;
        msg.msg_accrightslen = 0;

    } else {
        msg.msg_accrights = (caddr_t) &ch->fd;
        msg.msg_accrightslen = sizeof(int);
    }

#endif

    iov[0].iov_base = (char *) ch;
    iov[0].iov_len = size;

    msg.msg_name = NULL;
    msg.msg_namelen = 0;
    msg.msg_iov = iov;
    msg.msg_iovlen = 1;

    n = sendmsg(s, &msg, 0);

    if (n == -1) {
        err = ngx_errno;
        if (err == NGX_EAGAIN) {
            return NGX_AGAIN;
        }

        ngx_log_error(NGX_LOG_ALERT, log, err, "sendmsg() failed");
        return NGX_ERROR;
    }

    return NGX_OK;
}
示例#20
0
文件: runc.c 项目: kurt-vd/rund
/* convenience wrapper for send with SCM_CREDENTIALS */
static int sendcred(int sock, const void *dat, unsigned int len, int flags)
{
	struct ucred *pcred;
	union {
		struct cmsghdr hdr;
		char dat[CMSG_SPACE(sizeof(struct ucred))];
	} cmsg = {
		.hdr.cmsg_len = CMSG_LEN(sizeof(struct ucred)),
		.hdr.cmsg_level = SOL_SOCKET,
		.hdr.cmsg_type = SCM_CREDENTIALS,
	};
	struct iovec iov = {
		.iov_base = (void *)dat,
		.iov_len = len,
	};
	struct msghdr msg = {
		.msg_iov = &iov,
		.msg_iovlen = 1,
		.msg_control = &cmsg,
		.msg_controllen = cmsg.hdr.cmsg_len,
	};
	pcred = (void *)CMSG_DATA(&cmsg.hdr);
	pcred->pid = getpid();
	pcred->uid = getuid();
	pcred->gid = getgid();
	return sendmsg(sock, &msg, flags);
}

static int ttytest(void)
{
	int fd;

	fd = open("/dev/tty", O_RDWR);
	close(fd);
	/* /dev/tty can only open when a controlling terminal is opened,
	 * /dev/console is not one of them
	 */
	return fd >= 0;
}

/* main process */
int main(int argc, char *argv[])
{
	int ret, opt, sock, j, pos;
	struct sockaddr_un name = {
		.sun_family = AF_UNIX,
		.sun_path = "\0rund",
	};
	double repeat = NAN;
	int maxdelay = 0;
	time_t t0;
	int quiet;

	/* prepare cmd */
	static char sbuf[16*1024], rbuf[16*1024];
	char *bufp, *str;

	/* assume quiet operation on non-terminal invocation */
	quiet = !ttytest();
	/* parse program options */
	while ((opt = getopt(argc, argv, optstring)) != -1)
	switch (opt) {
	case 'V':
		fprintf(stderr, "%s: %s\n", NAME, VERSION);
		return 0;
	case 'q':
		quiet = 1;
		break;
	case 'r':
		repeat = optarg ? strtod(optarg, NULL) : 1;
		if (!(repeat > 0))
			mylog(LOG_ERR, "bad rate '%s'", optarg);
		break;
	case 's':
		if (*optarg != '@')
			mylog(LOG_ERR, "bad socket name '%s'", optarg);
		strcpy(name.sun_path+1, optarg+1);
		break;
	case 'm':
		maxdelay = ceil(strtod(optarg, NULL));
		break;
	default:
		fprintf(stderr, "%s: option '%c' unrecognised\n", NAME, opt);
	case '?':
		fputs(help_msg, stderr);
		exit(1);
	}

	for (j = optind, bufp = sbuf; j < argc; ++j) {
		if (!strncmp("USER="******"user '%s' unknown", argv[j]+5);
			/* add the argument manually
			 * don't forget to add null terminator
			 */
			bufp += sprintf(bufp, "USER=#%u", pw->pw_uid)+1;
			continue;
		}
		strcpy(bufp, argv[j]);
		bufp += strlen(bufp)+1;
	}
	if (bufp <= sbuf)
		mylog(LOG_ERR, "no command specified");

	/* install timeout handler using sigalrm */
	signal(SIGALRM, sigalrm);

	/* open client socket */
	ret = sock = socket(PF_UNIX, SOCK_DGRAM, 0);
	if (ret < 0)
		mylog(LOG_ERR, "socket(unix, ...) failed: %s", ESTR(errno));
	/* connect to server */
	ret = connect(sock, (void *)&name, sizeof(name));
	if (ret < 0)
		mylog(LOG_ERR, "connect(@%s) failed: %s", name.sun_path+1, ESTR(errno));

	str = name.sun_path+1;
	str += strlen(str);
	sprintf(str, "-%i", getpid());
	ret = bind(sock, (void *)&name, sizeof(name));
	if (ret < 0)
		mylog(LOG_ERR, "bind(@%s) failed: %s", name.sun_path+1, ESTR(errno));

	t0 = time(NULL);
	do {
		/* schedule timeout */
		alarm(1);
		/* send command */
		ret = sendcred(sock, sbuf, bufp - sbuf, 0);
		if (ret < 0)
			mylog(LOG_ERR, "send ...: %s", ESTR(errno));

		do {
			ret = recv(sock, rbuf, sizeof(rbuf)-1, 0);
			if (ret < 0)
				mylog(LOG_ERR, "recv ...: %s", ESTR(errno));
			if (!ret)
				mylog(LOG_ERR, "empty response");
			rbuf[ret] = 0;
			if (*rbuf != '>')
				break;
			for (pos = 1; pos < ret; ) {
				if (pos > 1)
					fputc(' ', stdout);
				fputs(rbuf+pos, stdout);
				pos += strlen(rbuf+pos)+1;
			}
			printf("\n");
			alarm(1);
		} while (1);
		ret = strtol(rbuf, NULL, 0);
		if (ret < 0)
			mylog(LOG_ERR, "command failed: %s", ESTR(-ret));
		if (isnan(repeat)) {
			if (!quiet)
				printf("%i\n", ret);
			break;
		}
		if (maxdelay && (!ret || (time(NULL) > (t0+maxdelay)))) {
			if (!quiet)
				mylog(LOG_INFO, "%s %s after %lu seconds", sbuf,
					ret ? "aborted" : "finished",
					time(NULL)-t0);
			return !!ret;
		}
		/* remove timeout */
		alarm(0);
		if (ret)
			poll(NULL, 0, repeat*1000);
	} while (ret);
	return EXIT_SUCCESS;
}
void
SharedPortEndpoint::ReceiveSocket( ReliSock *named_sock, ReliSock *return_remote_sock )
{
#ifndef HAVE_SHARED_PORT
	dprintf(D_ALWAYS,"SharedPortEndpoint::ReceiveSocket() not supported.\n");
#elif HAVE_SCM_RIGHTS_PASSFD
	// named_sock is a connection from SharedPortServer on our named socket.
	// Our job is to receive the file descriptor of the connected socket
	// that SharedPortServer is trying to pass to us over named_sock.

	// The documented way to initialize msghdr is to first set msg_controllen
	// to the size of the cmsghdr buffer and then after initializing
	// cmsghdr(s) to set it to the sum of CMSG_LEN() across all cmsghdrs.

	struct msghdr msg;
	char *buf = (char *) malloc(CMSG_SPACE(sizeof(int)));
	msg.msg_name = NULL;
	msg.msg_namelen = 0;
	msg.msg_control = buf;
	msg.msg_controllen = CMSG_SPACE(sizeof(int));
	msg.msg_flags = 0;

		// I have found that on MacOS X 10.5, we must send at least 1 byte,
		// or we get "Message too long" when trying to send 0-byte message.
	struct iovec iov[1];
	int junk = 0;
	iov[0].iov_base = &junk;
	iov[0].iov_len = 1;
	msg.msg_iov = iov;
	msg.msg_iovlen = 1;

	struct cmsghdr *cmsg = CMSG_FIRSTHDR((&msg));
	void *cmsg_data = CMSG_DATA(cmsg);
	ASSERT( cmsg && cmsg_data );

	cmsg->cmsg_len = CMSG_LEN(sizeof(int));
	cmsg->cmsg_level = SOL_SOCKET;
	cmsg->cmsg_type = SCM_RIGHTS;

	int passed_fd = -1;
	memcpy(cmsg_data,&passed_fd,sizeof(int));

	msg.msg_controllen = cmsg->cmsg_len;


	if( recvmsg(named_sock->get_file_desc(),&msg,0) != 1 ) {
		dprintf(D_ALWAYS,
				"SharedPortEndpoint: failed to receive message containing forwarded socket: errno=%d: %s",
				errno,strerror(errno));
		free(buf);
		return;
	}
	cmsg = CMSG_FIRSTHDR((&msg));
	if( !cmsg ) {
		dprintf(D_ALWAYS,
				"SharedPortEndpoint: failed to get ancillary data when receiving file descriptor.\n");
		free(buf);
		return;
	}
	if( cmsg->cmsg_type != SCM_RIGHTS ) {
		dprintf(D_ALWAYS,
				"ERROR: SharedPortEndpoint: expected cmsg_type=%d but got %d\n",
				SCM_RIGHTS,cmsg->cmsg_type);
		free(buf);
		return;
	}

	memcpy(&passed_fd,CMSG_DATA( cmsg ),sizeof(int));

	if( passed_fd == -1 ) {
		dprintf(D_ALWAYS,"ERROR: SharedPortEndpoint: got passed fd -1.\n");
		free(buf);
		return;
	}

		// create a socket object for the file descriptor we just received

	ReliSock *remote_sock = return_remote_sock;
	if( !remote_sock ) {
		remote_sock = new ReliSock();
	}
	remote_sock->assignSocket( passed_fd );
	remote_sock->enter_connected_state();
	remote_sock->isClient(false);

	dprintf(D_FULLDEBUG|D_COMMAND,
			"SharedPortEndpoint: received forwarded connection from %s.\n",
			remote_sock->peer_description());


		// See the comment in SharedPortClient::PassSocket() explaining
		// why this ACK is here.
	int status=0;
	named_sock->encode();
	named_sock->timeout(5);
	if( !named_sock->put(status) || !named_sock->end_of_message() ) {
		dprintf(D_ALWAYS,"SharedPortEndpoint: failed to send final status (success) for SHARED_PORT_PASS_SOCK\n");
	}


	if( !return_remote_sock ) {
		ASSERT( daemonCore );
		daemonCore->HandleReqAsync(remote_sock);
		remote_sock = NULL; // daemonCore took ownership of remote_sock
	}
	free(buf);
#else
#error HAVE_SHARED_PORT is defined, but no method for passing fds is enabled.
#endif
}
示例#22
0
static int
handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
{
	int fd = -1, ret = -1;
	char control[CMSG_SPACE(sizeof(fd))];
	struct cmsghdr *cmsg;
	struct stat s;
	struct msghdr nmsg;
	struct iovec iov;
	struct weston_launcher_open *message;
	union cmsg_data *data;

	message = msg->msg_iov->iov_base;
	if ((size_t)len < sizeof(*message))
		goto err0;

	/* Ensure path is null-terminated */
	((char *) message)[len-1] = '\0';

	fd = open(message->path, message->flags);
	if (fd < 0) {
		fprintf(stderr, "Error opening device %s: %m\n",
			message->path);
		goto err0;
	}

	if (fstat(fd, &s) < 0) {
		close(fd);
		fd = -1;
		fprintf(stderr, "Failed to stat %s\n", message->path);
		goto err0;
	}

	if (major(s.st_rdev) != INPUT_MAJOR &&
	    major(s.st_rdev) != DRM_MAJOR) {
		close(fd);
		fd = -1;
		fprintf(stderr, "Device %s is not an input or drm device\n",
			message->path);
		goto err0;
	}

err0:
	memset(&nmsg, 0, sizeof nmsg);
	nmsg.msg_iov = &iov;
	nmsg.msg_iovlen = 1;
	if (fd != -1) {
		nmsg.msg_control = control;
		nmsg.msg_controllen = sizeof control;
		cmsg = CMSG_FIRSTHDR(&nmsg);
		cmsg->cmsg_level = SOL_SOCKET;
		cmsg->cmsg_type = SCM_RIGHTS;
		cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
		data = (union cmsg_data *) CMSG_DATA(cmsg);
		data->fd = fd;
		nmsg.msg_controllen = cmsg->cmsg_len;
		ret = 0;
	}
	iov.iov_base = &ret;
	iov.iov_len = sizeof ret;

	if (wl->verbose)
		fprintf(stderr, "weston-launch: opened %s: ret: %d, fd: %d\n",
			message->path, ret, fd);
	do {
		len = sendmsg(wl->sock[0], &nmsg, 0);
	} while (len < 0 && errno == EINTR);

	close(fd);

	if (len < 0)
		return -1;

	if (major(s.st_rdev) == DRM_MAJOR)
		wl->drm_fd = fd;

	return 0;
}
示例#23
0
文件: scm.c 项目: 020gzh/linux
int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
{
	struct cmsghdr *cmsg;
	int err;

	for_each_cmsghdr(cmsg, msg) {
		err = -EINVAL;

		/* Verify that cmsg_len is at least sizeof(struct cmsghdr) */
		/* The first check was omitted in <= 2.2.5. The reasoning was
		   that parser checks cmsg_len in any case, so that
		   additional check would be work duplication.
		   But if cmsg_level is not SOL_SOCKET, we do not check
		   for too short ancillary data object at all! Oops.
		   OK, let's add it...
		 */
		if (!CMSG_OK(msg, cmsg))
			goto error;

		if (cmsg->cmsg_level != SOL_SOCKET)
			continue;

		switch (cmsg->cmsg_type)
		{
		case SCM_RIGHTS:
			if (!sock->ops || sock->ops->family != PF_UNIX)
				goto error;
			err=scm_fp_copy(cmsg, &p->fp);
			if (err<0)
				goto error;
			break;
		case SCM_CREDENTIALS:
		{
			struct ucred creds;
			kuid_t uid;
			kgid_t gid;
			if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct ucred)))
				goto error;
			memcpy(&creds, CMSG_DATA(cmsg), sizeof(struct ucred));
			err = scm_check_creds(&creds);
			if (err)
				goto error;

			p->creds.pid = creds.pid;
			if (!p->pid || pid_vnr(p->pid) != creds.pid) {
				struct pid *pid;
				err = -ESRCH;
				pid = find_get_pid(creds.pid);
				if (!pid)
					goto error;
				put_pid(p->pid);
				p->pid = pid;
			}

			err = -EINVAL;
			uid = make_kuid(current_user_ns(), creds.uid);
			gid = make_kgid(current_user_ns(), creds.gid);
			if (!uid_valid(uid) || !gid_valid(gid))
				goto error;

			p->creds.uid = uid;
			p->creds.gid = gid;
			break;
		}
		default:
			goto error;
		}
	}
示例#24
0
int fatipc_recv(int socket, struct FatipcBuffer* buffer)
{
    /*
     * recv fd through socket, from
     * http://stackoverflow.com/questions/28003921/sending-file-descriptor-by-linux-socket
     */
    struct msghdr msg;
    memset(&msg, 0, sizeof msg);
    char m_buffer[256];
    struct iovec io = {.iov_base = m_buffer, .iov_len = sizeof(m_buffer) };
    msg.msg_iov = &io;
    msg.msg_iovlen = 1;
    char c_buffer[256];
    msg.msg_control = c_buffer;
    msg.msg_controllen = sizeof(c_buffer);

    if (recvmsg(socket, &msg, 0) < 0) {
        return -1;
    }

    struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
    unsigned char* data = CMSG_DATA(cmsg);

    int fd = *((int*)data);

    /* got fd, now map new buffer onto it */
    struct stat stat;
    if (fstat(fd, &stat) < 0) {
        close(fd);
        return -3;
    }

    /* mmap */
    void* addr = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
    if (addr == MAP_FAILED) {
        close(fd);
        return -4;
    }

    /* alloc and fill up buffer */
    buffer->data = addr;
    buffer->size = stat.st_size;
    buffer->fd = fd;

    return 0;
}

int fatipc_send(int socket, struct FatipcBuffer* buffer)
{
    /*
     * send fd through socket, from
     * http://stackoverflow.com/questions/28003921/sending-file-descriptor-by-linux-socket
     */
    struct msghdr msg;
    memset(&msg, 0, sizeof msg);
    char buf[CMSG_SPACE(sizeof(buffer->fd))];
    memset(buf, '\0', sizeof(buf));
    struct iovec io = {.iov_base = "ABC", .iov_len = 3 };
    msg.msg_iov = &io;
    msg.msg_iovlen = 1;
    msg.msg_control = buf;
    msg.msg_controllen = sizeof(buf);
    struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
    cmsg->cmsg_level = SOL_SOCKET;
    cmsg->cmsg_type = SCM_RIGHTS;
    cmsg->cmsg_len = CMSG_LEN(sizeof(buffer->fd));

    *((int*)CMSG_DATA(cmsg)) = buffer->fd;
    msg.msg_controllen = cmsg->cmsg_len;

    if (sendmsg(socket, &msg, 0) < 0) {
        return -1;
    }

    return 0;
}
示例#25
0
/*************************************************************************
	> File Name: transfer_sockfd.c
	> Author: canjian
	> Mail:[email protected] 
	> Created Time: Tue 16 Sep 2014 11:45:01 PM PDT
 ************************************************************************/

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <sys/socket.h>

static const int CONTROL_LEN=CMSG_LEN(sizeof(int));

/*发送文件描述符,fd参数是用来传递信息的UNIX域socket,fd_to_send参数是待发送的文件描述符*/

void send_fd(int fd,int fd_to_send){
	struct iovec iov[1];
	struct msghdr msg;
	char buf[0];

	iov[0].iov_base=buf;
	iov[0].iov_len=1;
	msg.msg_name=NULL;
	msg.msg_namelen=0;
	msg.msg_iov=iov;
	msg.msg_iovlen=1;
/**
 * Writes all the data in the specified buffer to the specified socket.
 *
 * Returns 0 on success or -1 if an exception was thrown.
 */
static int socket_write_all(JNIEnv *env, jobject object, int fd,
        void *buf, size_t len)
{
    ssize_t ret;
    struct msghdr msg;
    unsigned char *buffer = (unsigned char *)buf;
    memset(&msg, 0, sizeof(msg));

    jobjectArray outboundFds
            = (jobjectArray)env->GetObjectField(
                object, field_outboundFileDescriptors);

    if (env->ExceptionCheck()) {
        return -1;
    }

    struct cmsghdr *cmsg;
    int countFds = outboundFds == NULL ? 0 : env->GetArrayLength(outboundFds);
    int fds[countFds];
    char msgbuf[CMSG_SPACE(countFds)];

    // Add any pending outbound file descriptors to the message
    if (outboundFds != NULL) {

        if (env->ExceptionCheck()) {
            return -1;
        }

        for (int i = 0; i < countFds; i++) {
            jobject fdObject = env->GetObjectArrayElement(outboundFds, i);
            if (env->ExceptionCheck()) {
                return -1;
            }

            fds[i] = jniGetFDFromFileDescriptor(env, fdObject);
            if (env->ExceptionCheck()) {
                return -1;
            }
        }

        // See "man cmsg" really
        msg.msg_control = msgbuf;
        msg.msg_controllen = sizeof msgbuf;
        cmsg = CMSG_FIRSTHDR(&msg);
        cmsg->cmsg_level = SOL_SOCKET;
        cmsg->cmsg_type = SCM_RIGHTS;
        cmsg->cmsg_len = CMSG_LEN(sizeof fds);
        memcpy(CMSG_DATA(cmsg), fds, sizeof fds);
    }

    // We only write our msg_control during the first write
    while (len > 0) {
        struct iovec iv;
        memset(&iv, 0, sizeof(iv));

        iv.iov_base = buffer;
        iv.iov_len = len;

        msg.msg_iov = &iv;
        msg.msg_iovlen = 1;

        do {
            ret = sendmsg(fd, &msg, MSG_NOSIGNAL);
        } while (ret < 0 && errno == EINTR);

        if (ret < 0) {
            jniThrowIOException(env, errno);
            return -1;
        }

        buffer += ret;
        len -= ret;

        // Wipes out any msg_control too
        memset(&msg, 0, sizeof(msg));
    }

    return 0;
}
示例#27
0
int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
{
	struct cmsghdr *cmsg;
	int err;

	for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg))
	{
		err = -EINVAL;

		/* Verify that cmsg_len is at least sizeof(struct cmsghdr) */
		/* The first check was omitted in <= 2.2.5. The reasoning was
		   that parser checks cmsg_len in any case, so that
		   additional check would be work duplication.
		   But if cmsg_level is not SOL_SOCKET, we do not check
		   for too short ancillary data object at all! Oops.
		   OK, let's add it...
		 */
		if (!CMSG_OK(msg, cmsg))
			goto error;

		if (cmsg->cmsg_level != SOL_SOCKET)
			continue;

		switch (cmsg->cmsg_type)
		{
		case SCM_RIGHTS:
			if (!sock->ops || sock->ops->family != PF_UNIX)
				goto error;
			err=scm_fp_copy(cmsg, &p->fp);
			if (err<0)
				goto error;
			break;
		case SCM_CREDENTIALS:
			if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct ucred)))
				goto error;
			memcpy(&p->creds, CMSG_DATA(cmsg), sizeof(struct ucred));
			err = scm_check_creds(&p->creds);
			if (err)
				goto error;

			if (pid_vnr(p->pid) != p->creds.pid) {
				struct pid *pid;
				err = -ESRCH;
				pid = find_get_pid(p->creds.pid);
				if (!pid)
					goto error;
				put_pid(p->pid);
				p->pid = pid;
			}

			if ((p->cred->euid != p->creds.uid) ||
				(p->cred->egid != p->creds.gid)) {
				struct cred *cred;
				err = -ENOMEM;
				cred = prepare_creds();
				if (!cred)
					goto error;

				cred->uid = cred->euid = p->creds.uid;
				cred->gid = cred->egid = p->creds.uid;
				put_cred(p->cred);
				p->cred = cred;
			}
			break;
		default:
			goto error;
		}
	}

	if (p->fp && !p->fp->count)
	{
		kfree(p->fp);
		p->fp = NULL;
	}
	return 0;

error:
	scm_destroy(p);
	return err;
}
示例#28
0
static int
udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
    struct mbuf *control, struct thread *td)
{
	struct udpiphdr *ui;
	int len = m->m_pkthdr.len;
	struct in_addr faddr, laddr;
	struct cmsghdr *cm;
	struct inpcbinfo *pcbinfo;
	struct sockaddr_in *sin, src;
	int cscov_partial = 0;
	int error = 0;
	int ipflags;
	u_short fport, lport;
	int unlock_udbinfo;
	u_char tos;
	uint8_t pr;
	uint16_t cscov = 0;

	/*
	 * udp_output() may need to temporarily bind or connect the current
	 * inpcb.  As such, we don't know up front whether we will need the
	 * pcbinfo lock or not.  Do any work to decide what is needed up
	 * front before acquiring any locks.
	 */
	if (len + sizeof(struct udpiphdr) > IP_MAXPACKET) {
		if (control)
			m_freem(control);
		m_freem(m);
		return (EMSGSIZE);
	}

	src.sin_family = 0;
	INP_RLOCK(inp);
	tos = inp->inp_ip_tos;
	if (control != NULL) {
		/*
		 * XXX: Currently, we assume all the optional information is
		 * stored in a single mbuf.
		 */
		if (control->m_next) {
			INP_RUNLOCK(inp);
			m_freem(control);
			m_freem(m);
			return (EINVAL);
		}
		for (; control->m_len > 0;
		    control->m_data += CMSG_ALIGN(cm->cmsg_len),
		    control->m_len -= CMSG_ALIGN(cm->cmsg_len)) {
			cm = mtod(control, struct cmsghdr *);
			if (control->m_len < sizeof(*cm) || cm->cmsg_len == 0
			    || cm->cmsg_len > control->m_len) {
				error = EINVAL;
				break;
			}
			if (cm->cmsg_level != IPPROTO_IP)
				continue;

			switch (cm->cmsg_type) {
			case IP_SENDSRCADDR:
				if (cm->cmsg_len !=
				    CMSG_LEN(sizeof(struct in_addr))) {
					error = EINVAL;
					break;
				}
				bzero(&src, sizeof(src));
				src.sin_family = AF_INET;
				src.sin_len = sizeof(src);
				src.sin_port = inp->inp_lport;
				src.sin_addr =
				    *(struct in_addr *)CMSG_DATA(cm);
				break;

			case IP_TOS:
				if (cm->cmsg_len != CMSG_LEN(sizeof(u_char))) {
					error = EINVAL;
					break;
				}
				tos = *(u_char *)CMSG_DATA(cm);
				break;

			default:
				error = ENOPROTOOPT;
				break;
			}
			if (error)
				break;
		}
		m_freem(control);
	}
	if (error) {
		INP_RUNLOCK(inp);
		m_freem(m);
		return (error);
	}

	/*
	 * Depending on whether or not the application has bound or connected
	 * the socket, we may have to do varying levels of work.  The optimal
	 * case is for a connected UDP socket, as a global lock isn't
	 * required at all.
	 *
	 * In order to decide which we need, we require stability of the
	 * inpcb binding, which we ensure by acquiring a read lock on the
	 * inpcb.  This doesn't strictly follow the lock order, so we play
	 * the trylock and retry game; note that we may end up with more
	 * conservative locks than required the second time around, so later
	 * assertions have to accept that.  Further analysis of the number of
	 * misses under contention is required.
	 *
	 * XXXRW: Check that hash locking update here is correct.
	 */
	pr = inp->inp_socket->so_proto->pr_protocol;
	pcbinfo = get_inpcbinfo(pr);
	sin = (struct sockaddr_in *)addr;
	if (sin != NULL &&
	    (inp->inp_laddr.s_addr == INADDR_ANY && inp->inp_lport == 0)) {
		INP_RUNLOCK(inp);
		INP_WLOCK(inp);
		INP_HASH_WLOCK(pcbinfo);
		unlock_udbinfo = UH_WLOCKED;
	} else if ((sin != NULL && (
	    (sin->sin_addr.s_addr == INADDR_ANY) ||
	    (sin->sin_addr.s_addr == INADDR_BROADCAST) ||
	    (inp->inp_laddr.s_addr == INADDR_ANY) ||
	    (inp->inp_lport == 0))) ||
	    (src.sin_family == AF_INET)) {
		INP_HASH_RLOCK(pcbinfo);
		unlock_udbinfo = UH_RLOCKED;
	} else
		unlock_udbinfo = UH_UNLOCKED;

	/*
	 * If the IP_SENDSRCADDR control message was specified, override the
	 * source address for this datagram.  Its use is invalidated if the
	 * address thus specified is incomplete or clobbers other inpcbs.
	 */
	laddr = inp->inp_laddr;
	lport = inp->inp_lport;
	if (src.sin_family == AF_INET) {
		INP_HASH_LOCK_ASSERT(pcbinfo);
		if ((lport == 0) ||
		    (laddr.s_addr == INADDR_ANY &&
		     src.sin_addr.s_addr == INADDR_ANY)) {
			error = EINVAL;
			goto release;
		}
		error = in_pcbbind_setup(inp, (struct sockaddr *)&src,
		    &laddr.s_addr, &lport, td->td_ucred);
		if (error)
			goto release;
	}

	/*
	 * If a UDP socket has been connected, then a local address/port will
	 * have been selected and bound.
	 *
	 * If a UDP socket has not been connected to, then an explicit
	 * destination address must be used, in which case a local
	 * address/port may not have been selected and bound.
	 */
	if (sin != NULL) {
		INP_LOCK_ASSERT(inp);
		if (inp->inp_faddr.s_addr != INADDR_ANY) {
			error = EISCONN;
			goto release;
		}

		/*
		 * Jail may rewrite the destination address, so let it do
		 * that before we use it.
		 */
		error = prison_remote_ip4(td->td_ucred, &sin->sin_addr);
		if (error)
			goto release;

		/*
		 * If a local address or port hasn't yet been selected, or if
		 * the destination address needs to be rewritten due to using
		 * a special INADDR_ constant, invoke in_pcbconnect_setup()
		 * to do the heavy lifting.  Once a port is selected, we
		 * commit the binding back to the socket; we also commit the
		 * binding of the address if in jail.
		 *
		 * If we already have a valid binding and we're not
		 * requesting a destination address rewrite, use a fast path.
		 */
		if (inp->inp_laddr.s_addr == INADDR_ANY ||
		    inp->inp_lport == 0 ||
		    sin->sin_addr.s_addr == INADDR_ANY ||
		    sin->sin_addr.s_addr == INADDR_BROADCAST) {
			INP_HASH_LOCK_ASSERT(pcbinfo);
			error = in_pcbconnect_setup(inp, addr, &laddr.s_addr,
			    &lport, &faddr.s_addr, &fport, NULL,
			    td->td_ucred);
			if (error)
				goto release;

			/*
			 * XXXRW: Why not commit the port if the address is
			 * !INADDR_ANY?
			 */
			/* Commit the local port if newly assigned. */
			if (inp->inp_laddr.s_addr == INADDR_ANY &&
			    inp->inp_lport == 0) {
				INP_WLOCK_ASSERT(inp);
				INP_HASH_WLOCK_ASSERT(pcbinfo);
				/*
				 * Remember addr if jailed, to prevent
				 * rebinding.
				 */
				if (prison_flag(td->td_ucred, PR_IP4))
					inp->inp_laddr = laddr;
				inp->inp_lport = lport;
				if (in_pcbinshash(inp) != 0) {
					inp->inp_lport = 0;
					error = EAGAIN;
					goto release;
				}
				inp->inp_flags |= INP_ANONPORT;
			}
		} else {
			faddr = sin->sin_addr;
			fport = sin->sin_port;
		}
	} else {
		INP_LOCK_ASSERT(inp);
		faddr = inp->inp_faddr;
		fport = inp->inp_fport;
		if (faddr.s_addr == INADDR_ANY) {
			error = ENOTCONN;
			goto release;
		}
	}

	/*
	 * Calculate data length and get a mbuf for UDP, IP, and possible
	 * link-layer headers.  Immediate slide the data pointer back forward
	 * since we won't use that space at this layer.
	 */
	M_PREPEND(m, sizeof(struct udpiphdr) + max_linkhdr, M_NOWAIT);
	if (m == NULL) {
		error = ENOBUFS;
		goto release;
	}
	m->m_data += max_linkhdr;
	m->m_len -= max_linkhdr;
	m->m_pkthdr.len -= max_linkhdr;

	/*
	 * Fill in mbuf with extended UDP header and addresses and length put
	 * into network format.
	 */
	ui = mtod(m, struct udpiphdr *);
	bzero(ui->ui_x1, sizeof(ui->ui_x1));	/* XXX still needed? */
	ui->ui_pr = pr;
	ui->ui_src = laddr;
	ui->ui_dst = faddr;
	ui->ui_sport = lport;
	ui->ui_dport = fport;
	ui->ui_ulen = htons((u_short)len + sizeof(struct udphdr));
	if (pr == IPPROTO_UDPLITE) {
		struct udpcb *up;
		uint16_t plen;

		up = intoudpcb(inp);
		cscov = up->u_txcslen;
		plen = (u_short)len + sizeof(struct udphdr);
		if (cscov >= plen)
			cscov = 0;
		ui->ui_len = htons(plen);
		ui->ui_ulen = htons(cscov);
		/*
		 * For UDP-Lite, checksum coverage length of zero means
		 * the entire UDPLite packet is covered by the checksum.
		 */
		 cscov_partial = (cscov == 0) ? 0 : 1;
	} else
		ui->ui_v = IPVERSION << 4;

	/*
	 * Set the Don't Fragment bit in the IP header.
	 */
	if (inp->inp_flags & INP_DONTFRAG) {
		struct ip *ip;

		ip = (struct ip *)&ui->ui_i;
		ip->ip_off |= htons(IP_DF);
	}

	ipflags = 0;
	if (inp->inp_socket->so_options & SO_DONTROUTE)
		ipflags |= IP_ROUTETOIF;
	if (inp->inp_socket->so_options & SO_BROADCAST)
		ipflags |= IP_ALLOWBROADCAST;
	if (inp->inp_flags & INP_ONESBCAST)
		ipflags |= IP_SENDONES;

#ifdef MAC
	mac_inpcb_create_mbuf(inp, m);
#endif

	/*
	 * Set up checksum and output datagram.
	 */
	ui->ui_sum = 0;
	if (cscov_partial) {
		if (inp->inp_flags & INP_ONESBCAST)
			faddr.s_addr = INADDR_BROADCAST;
		if ((ui->ui_sum = in_cksum(m, sizeof(struct ip) + cscov)) == 0)
			ui->ui_sum = 0xffff;
	} else if (V_udp_cksum || !cscov_partial) {
		if (inp->inp_flags & INP_ONESBCAST)
			faddr.s_addr = INADDR_BROADCAST;
		ui->ui_sum = in_pseudo(ui->ui_src.s_addr, faddr.s_addr,
		    htons((u_short)len + sizeof(struct udphdr) + pr));
		m->m_pkthdr.csum_flags = CSUM_UDP;
		m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum);
	}
	((struct ip *)ui)->ip_len = htons(sizeof(struct udpiphdr) + len);
	((struct ip *)ui)->ip_ttl = inp->inp_ip_ttl;	/* XXX */
	((struct ip *)ui)->ip_tos = tos;		/* XXX */
	UDPSTAT_INC(udps_opackets);

	if (unlock_udbinfo == UH_WLOCKED)
		INP_HASH_WUNLOCK(pcbinfo);
	else if (unlock_udbinfo == UH_RLOCKED)
		INP_HASH_RUNLOCK(pcbinfo);
	UDP_PROBE(send, NULL, inp, &ui->ui_i, inp, &ui->ui_u);
	error = ip_output(m, inp->inp_options, NULL, ipflags,
	    inp->inp_moptions, inp);
	if (unlock_udbinfo == UH_WLOCKED)
		INP_WUNLOCK(inp);
	else
		INP_RUNLOCK(inp);
	return (error);

release:
	if (unlock_udbinfo == UH_WLOCKED) {
		INP_HASH_WUNLOCK(pcbinfo);
		INP_WUNLOCK(inp);
	} else if (unlock_udbinfo == UH_RLOCKED) {
		INP_HASH_RUNLOCK(pcbinfo);
		INP_RUNLOCK(inp);
	} else
		INP_RUNLOCK(inp);
	m_freem(m);
	return (error);
}
示例#29
0
int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc,
		 bool allow_ipv6)
{
	int err, val;
	struct cmsghdr *cmsg;

	for_each_cmsghdr(cmsg, msg) {
		if (!CMSG_OK(msg, cmsg))
			return -EINVAL;
#if IS_ENABLED(CONFIG_IPV6)
		if (allow_ipv6 &&
		    cmsg->cmsg_level == SOL_IPV6 &&
		    cmsg->cmsg_type == IPV6_PKTINFO) {
			struct in6_pktinfo *src_info;

			if (cmsg->cmsg_len < CMSG_LEN(sizeof(*src_info)))
				return -EINVAL;
			src_info = (struct in6_pktinfo *)CMSG_DATA(cmsg);
			if (!ipv6_addr_v4mapped(&src_info->ipi6_addr))
				return -EINVAL;
			ipc->oif = src_info->ipi6_ifindex;
			ipc->addr = src_info->ipi6_addr.s6_addr32[3];
			continue;
		}
#endif
		if (cmsg->cmsg_level != SOL_IP)
			continue;
		switch (cmsg->cmsg_type) {
		case IP_RETOPTS:
			err = cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr));
			err = ip_options_get(net, &ipc->opt, CMSG_DATA(cmsg),
					     err < 40 ? err : 40);
			if (err)
				return err;
			break;
		case IP_PKTINFO:
		{
			struct in_pktinfo *info;
			if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct in_pktinfo)))
				return -EINVAL;
			info = (struct in_pktinfo *)CMSG_DATA(cmsg);
			ipc->oif = info->ipi_ifindex;
			ipc->addr = info->ipi_spec_dst.s_addr;
			break;
		}
		case IP_TTL:
			if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)))
				return -EINVAL;
			val = *(int *)CMSG_DATA(cmsg);
			if (val < 1 || val > 255)
				return -EINVAL;
			ipc->ttl = val;
			break;
		case IP_TOS:
			if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)))
				return -EINVAL;
			val = *(int *)CMSG_DATA(cmsg);
			if (val < 0 || val > 255)
				return -EINVAL;
			ipc->tos = val;
			ipc->priority = rt_tos2priority(ipc->tos);
			break;

		default:
			return -EINVAL;
		}
	}
	return 0;
}
示例#30
0
static int
receive_fd (int source_fd)
{
  struct msghdr msg;
  static struct cmsghdr *control = NULL;
  struct iovec iov[1];
  char buf[4096];
  int return_fd = -1;
  int nbytes;
  int numerrors = 0;
  int control_len = CMSG_LEN (sizeof (int));

  if (control == NULL)
    control = malloc (control_len);

  for (;;)
    {
      iov[0].iov_base = buf;
      iov[0].iov_len = sizeof(buf);
      msg.msg_iov = iov;
      msg.msg_iovlen = 1;

      msg.msg_name = NULL;
      msg.msg_namelen = 0;

      msg.msg_control = control;
      msg.msg_controllen = control_len;

      nbytes = recvmsg (source_fd, &msg, 0);
      if (nbytes < 0)
	{
	  warning ("Error from recvmsg.\n");
	  numerrors++;
	  if (numerrors < 10)
	    {
	      warning ("More than 10 errors, giving up.");
	      return -1;
	    }
	  else
	    continue;
	}
      else if (nbytes == 0)
	{
	  warning ("Source fd %d closed connection.\n", source_fd);
	  return -1;
	}
      else
	{
	  if (msg.msg_controllen != control_len)
	    {
	      warning ("Message received with wrong size for fd: %d.",
		       msg.msg_controllen);
	      return -1;
	    }
	  return_fd = *((int *) CMSG_DATA (control));
	  break;
	}
    }
   
  
  return return_fd;
}