Logo Search packages:      
Sourcecode: ksh version File versions

csrecv.c

/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*           Copyright (c) 1990-2007 AT&T Knowledge Ventures            *
*                      and is licensed under the                       *
*                  Common Public License, Version 1.0                  *
*                      by AT&T Knowledge Ventures                      *
*                                                                      *
*                A copy of the License is available at                 *
*            http://www.opensource.org/licenses/cpl1.0.txt             *
*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
*                                                                      *
*              Information and Software Systems Research               *
*                            AT&T Research                             *
*                           Florham Park NJ                            *
*                                                                      *
*                 Glenn Fowler <gsf@research.att.com>                  *
*                                                                      *
***********************************************************************/
#pragma prototyped
                  
/*
 * Glenn Fowler
 * AT&T Research
 *
 * receive up to n fds from stream fd
 * number of fds received is returned
 *
 * NOTE: cssend() only supported for local host
 *       for local host Csid_t.hid==0, Csid_t.pid not trusted
 *     for remote host csauth() can authenticate Csid_t.[ug]id
 */

#include "cslib.h"

#if CS_LIB_SOCKET_RIGHTS && !CS_LIB_STREAM

static int
sockrecv(int fd, Csid_t* id, int* fds, int n)
{
      struct iovec            iov;
      struct msghdr           msg;
#if _mem_msg_control_msghdr
      struct
      {
      struct cmsghdr          hdr;
      int               fds[OPEN_MAX + 1];
      }                 ctl;
#else
#define msg_control     msg_accrights
#define msg_controllen  msg_accrightslen
#endif

      msg.msg_name = 0;
      msg.msg_namelen = 0;
      msg.msg_iov = &iov;
      msg.msg_iovlen = 1;
      iov.iov_base = (caddr_t)id;
      iov.iov_len = sizeof(*id);
#if _mem_msg_control_msghdr
      msg.msg_control = (caddr_t)&ctl;
      msg.msg_controllen = (char*)&ctl.fds[n] - (char*)&ctl;
      ctl.hdr.cmsg_len = msg.msg_controllen;
      ctl.hdr.cmsg_level = SOL_SOCKET;
      ctl.hdr.cmsg_type = SCM_RIGHTS;
#else
      msg.msg_control = (caddr_t)fds;
      msg.msg_controllen = n * sizeof(fds[0]);
#endif
      if (recvmsg(fd, &msg, 0) < 0) return -1;
      id->hid = id->hid;
      id->pid = id->pid;
      id->uid = id->uid;
      id->gid = id->gid;
#if _mem_msg_control_msghdr
      if (ctl.hdr.cmsg_level != SOL_SOCKET || ctl.hdr.cmsg_type != SCM_RIGHTS)
            return -1;
      n = (ctl.hdr.cmsg_len - sizeof(ctl.hdr)) / sizeof(fds[0]);
      for (fd = 0; fd < n; fd++)
            fds[fd] = ctl.fds[fd];
      return n;
#else
      return msg.msg_controllen / sizeof(fds[0]);
#endif
}

#endif

int
csrecv(register Cs_t* state, int fd, Csid_t* id, int* fds, int n)
{
      int               oerrno;
      Csid_t                  ignore;

#if CS_LIB_SOCKET

      Sock_size_t       namlen;
      struct sockaddr_in      nam;

#if CS_LIB_SOCKET_UN && !CS_LIB_STREAM

#if CS_LIB_SOCKET_RIGHTS
      int               rfd[OPEN_MAX + 1];
#endif
      struct stat       st;

#endif

#endif

#if CS_LIB_STREAM || CS_LIB_V10

      int               m;
      struct strrecvfd  rcv;
      struct csfdhdr          hdr;

#if CS_LIB_V10

      struct tcpuser          tcp;

#endif

#endif

#if CS_LIB_STREAM || CS_LIB_V10 || CS_LIB_SOCKET_RIGHTS

      register int            i;

#endif

      messagef((state->id, NiL, -8, "recv(%d,%d) call", fd, n));
      if (n < 1)
      {
            errno = EINVAL;
            return -1;
      }
      if (!id) id = &ignore;
      memzero(id, sizeof(*id));
      oerrno = errno;
      csprotect(&cs);

#if CS_LIB_V10

      if (!ioctl(fd, TCPGETADDR, &tcp))
      {
            if ((fds[0] = tcp_accept(fd, &tcp)) < 0)
            {
                  messagef((state->id, NiL, -1, "recv: %d: tcp accept error", fd));
                  return -1;
            }
            id->hid = tcp.faddr;
            return 1;
      }
      messagef((state->id, NiL, -1, "recv: %d: ioctl TCPGETADDR error", fd));

#else

#if CS_LIB_SOCKET

      namlen = sizeof(nam);
      if ((fds[0] = accept(fd, (struct sockaddr*)&nam, &namlen)) >= 0)
      {

#if CS_LIB_SOCKET_UN && !CS_LIB_STREAM

#if defined(__linux__) && defined(AF_UNSPEC)
            if (nam.sin_family == AF_UNSPEC)
                  nam.sin_family = AF_UNIX;
#endif
            if (nam.sin_family == AF_UNIX)
            {
#if CS_LIB_SOCKET_RIGHTS
                  if (write(fds[0], "", 1) != 1)
                  {
                        messagef((state->id, NiL, -1, "recv: %d: ping write error", fd));
                        close(fds[0]);
                        return -1;
                  }
                  if (sockrecv(fds[0], id, rfd, 1) != 1)
                  {
                        messagef((state->id, NiL, -1, "recv: %d: sockrecv error", fd));
                        goto eperm;
                  }
                  if (fstat(rfd[0], &st))
                  {
                        messagef((state->id, NiL, -1, "recv: %d: %d: authentication stat error", fd, rfd[0]));
                  drop:
                        close(rfd[0]);
                  eperm:
                        close(fds[0]);
                        errno = EPERM;
                        return -1;
                  }
                  if ((st.st_mode & CS_AUTH_MASK) != CS_AUTH_MODE)
                  {
                        messagef((state->id, NiL, -1, "recv: %d: %d: invalid authentication mode %04o", fd, rfd[0], st.st_mode & CS_AUTH_MASK));
                        goto drop;
                  }
                  close(rfd[0]);
#else
                  if (fstat(fds[0], &st))
                  {
                        st.st_uid = geteuid();
                        st.st_gid = getegid();
                  }
#endif
                  id->uid = st.st_uid;
                  id->gid = st.st_gid;
            }
            else

#endif

            if (nam.sin_family == AF_INET)
                  id->hid = (unsigned long)nam.sin_addr.s_addr;
            return 1;
      }
      messagef((state->id, NiL, -1, "recv: %d: accept error", fd));

#endif

#endif

#if CS_LIB_STREAM || CS_LIB_V10

      if (ioctl(fd, I_RECVFD, &rcv) < 0)
      {
            messagef((state->id, NiL, -1, "recv: %d: ioctl I_RECVFD error", fd));
            switch (errno)
            {
            case EIO:
#ifdef EBADMSG
            case EBADMSG:
#endif
                  break;
            default:
                  return -1;
            }
#if CS_LIB_STREAM
            if (!(m = read(fd, &hdr, sizeof(hdr))))
#endif
            m = read(fd, &hdr, sizeof(hdr));
            if (m != sizeof(hdr))
            {
                  errno = EINVAL;
                  messagef((state->id, NiL, -1, "recv: %d: hdr read error", fd));
                  return -1;
            }
            if (hdr.count <= 0)
            {
                  errno = EINVAL;
                  messagef((state->id, NiL, -1, "recv: %d: invalid hdr count %d", fd, hdr.count));
                  return -1;
            }
            for (i = 0; i < hdr.count; i++)
            {
                  if (ioctl(fd, I_RECVFD, &rcv) < 0)
                  {
                        messagef((state->id, NiL, -1, "recv: %d: ioctl I_RECVFD #%d error", fd, i + 1));
                        while (--i >= 0) close(fds[i]);
                        return -1;
                  }
                  fds[i] = rcv.fd;
            }
            id->pid = hdr.pid;
      }

#ifdef I_ACCEPT

      else if (ioctl(rcv.fd, I_ACCEPT, NiL) < 0)
      {
            messagef((state->id, NiL, -1, "recv: %d: ioctl I_ACCEPT error", fd));
            close(rcv.fd);
            return -1;
      }

#endif

      else
      {

            i = 1;
            fds[0] = rcv.fd;
      }
      id->uid = rcv.uid;
      id->gid = rcv.gid;
      errno = oerrno;
      return i;

#else

#if CS_LIB_SOCKET_RIGHTS

      if ((i = sockrecv(fd, id, rfd, n + 1)) <= 1)
      {
            messagef((state->id, NiL, -1, "recv: %d: sockrecv error", fd));
      nope:
            if (i >= 0)
            {
                  errno = EPERM;
                  while (--i >= 0) close(rfd[i]);
            }
            return -1;
      }
      if (fstat(rfd[0], &st))
      {
            messagef((state->id, NiL, -1, "recv: %d: %d: authentication stat error", fd, rfd[0]));
            goto nope;
      }
      if ((st.st_mode & CS_AUTH_MASK) != CS_AUTH_MODE)
      {
            messagef((state->id, NiL, -1, "recv: %d: %d: invalid authentication mode %04o", fd, rfd[0], st.st_mode & CS_AUTH_MASK));
            goto nope;
      }
      close(rfd[0]);
      for (n = --i; i > 0; i--) fds[i - 1] = rfd[i];
      id->uid = st.st_uid;
      id->gid = st.st_gid;
      return n;

#else

      if (!access(CS_PROC_FD_TST, F_OK))
      {
            register int      i;
            register int      j;
            char*       s;
            unsigned long     pid;
            struct stat st;

            s = state->temp;
            if ((i = recv(fd, s, sizeof(state->temp), 0)) <= 0)
            {
                  messagef((state->id, NiL, -1, "recv: %d: read error", fd));
                  return -1;
            }
            if (i >= sizeof(state->temp))
                  i = sizeof(state->temp) - 1;
            s[i] = 0;
            messagef((state->id, NiL, -8, "recv: `%s'", s));
            pid = strtol(s, &s, 0);
            i = strtol(s, &s, 0);
            if (i < n)
                  n = i;
            for (i = 0; i < n; i++)
                  fds[i] = strtol(s, &s, 0);
            s = state->temp;
            for (i = j = 0; i < n; i++)
            {
                  sfsprintf(s, sizeof(state->temp), CS_PROC_FD_FMT, pid, fds[i]);
                  if (!stat(s, &st) && (fds[i] = open(s, (st.st_mode & (S_IRUSR|S_IWUSR)) == (S_IRUSR|S_IWUSR) ? O_RDWR : (st.st_mode & S_IWUSR) ? O_WRONLY : O_RDONLY)) >= 0)
                        j++;
            }
            if (id)
            {
                  id->hid = 0;
                  id->pid = pid;
                  if (!stat(CS_PROC_FD_TST, &st))
                  {
                        id->uid = st.st_uid;
                        id->gid = st.st_gid;
                  }
                  else
                  {
                        id->uid = geteuid();
                        id->gid = getegid();
                  }
            }
            messagef((state->id, NiL, -8, "recv: %d fds", j));
            return j;
      }
      errno = EINVAL;
      return -1;

#endif

#endif

}

int
_cs_recv(int fd, Csid_t* id, int* fds, int n)
{
      return csrecv(&cs, fd, id, fds, n);
}

Generated by  Doxygen 1.6.0   Back to index