]> Zhao Yanbai Git Server - minix.git/commitdiff
- Add support for file descriptor passing to PFS.
authorThomas Veerman <thomas@minix3.org>
Mon, 30 Aug 2010 13:46:44 +0000 (13:46 +0000)
committerThomas Veerman <thomas@minix3.org>
Mon, 30 Aug 2010 13:46:44 +0000 (13:46 +0000)
- For security reasons move some libc code to PFS.
- Fix a few bugs in PFS.
Contributed by Thomas Cort.

lib/libc/ip/bind.c
lib/libc/ip/connect.c
lib/libc/ip/recvmsg.c
lib/libc/ip/sendmsg.c
lib/libc/ip/sendto.c
servers/pfs/dev_uds.c
servers/pfs/inc.h
servers/pfs/proto.h
servers/pfs/uds.c
servers/pfs/uds.h

index 2749ab7b1799e89af7d5f860075d80badfc477a9..72393526f4a0e9f4f3040148d45fa47aefe96089 100644 (file)
@@ -207,14 +207,7 @@ static int in_group(uid_t uid, gid_t gid)
 static int _uds_bind(int socket, const struct sockaddr *address,
        socklen_t address_len, struct sockaddr_un *uds_addr)
 {
-       mode_t bits, perm_bits, access_desired;
-       struct stat buf;
-       uid_t euid;
-       gid_t egid;
-       char real_sun_path[PATH_MAX+1];
-       char *realpath_result;
-       int i, r, shift;
-       int null_found;
+       int r;
        int did_mknod;
 
        if (address == NULL) {
@@ -222,120 +215,14 @@ static int _uds_bind(int socket, const struct sockaddr *address,
                return -1;
        }
 
-       /* sun_family is always supposed to be AF_UNIX */
-       if (((struct sockaddr_un *) address)->sun_family != AF_UNIX) {
-               errno = EAFNOSUPPORT;
-               return -1;
-       }
-
-       /* an empty path is not supported */
-       if (((struct sockaddr_un *) address)->sun_path[0] == '\0') {
-               errno = ENOENT;
-               return -1;
-       }
-
-       /* the path must be a null terminated string for realpath to work */
-       for (null_found = i = 0;
-               i < sizeof(((struct sockaddr_un *) address)->sun_path); i++) {
-               if (((struct sockaddr_un *) address)->sun_path[i] == '\0') {
-                       null_found = 1;
-                       break;
-               }
-       }
-
-       if (!null_found) {
-               errno = EINVAL;
-               return -1;
-       }
-
-       /*
-        * Get the realpath(3) of the socket file.
-        */
-
-       realpath_result = realpath(((struct sockaddr_un *) address)->sun_path,
-                                               real_sun_path);
-       if (realpath_result == NULL) {
-               return -1;
-       }
-
-       if (strlen(real_sun_path) >= UNIX_PATH_MAX) {
-               errno = ENAMETOOLONG;
-               return -1;
-       }
-
-       strcpy(((struct sockaddr_un *) address)->sun_path, real_sun_path);
-
-       /*
-        * input parameters look good -- create the socket file on the 
-        * file system
-        */
-
        did_mknod = 0;
 
        r = mknod(((struct sockaddr_un *) address)->sun_path,
                S_IFSOCK|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, 0);
 
-       if (r == -1) {
-               if (errno == EEXIST) {
-                       /* file already exists, verify that it is a socket */
-
-                       r = stat(((struct sockaddr_un *) address)->sun_path,
-                                                               &buf);
-                       if (r == -1) {
-                               return -1;
-                       }
-
-                       if (!S_ISSOCK(buf.st_mode)) {
-                               errno = EADDRINUSE;
-                               return -1;
-                       }
-
-                       /* check permissions the permissions of the 
-                        * socket file.
-                        */
-
-                       /* read + write access */
-                       access_desired = R_BIT | W_BIT;
-
-                       euid = geteuid();
-                       egid = getegid();
-
-                       if (euid == -1 || egid == -1) {
-                               errno = EACCES;
-                               return -1;
-                       }
-
-                       bits = buf.st_mode;
-
-                       if (euid == ((uid_t) 0)) {
-                               perm_bits = R_BIT | W_BIT;
-                       } else {
-                               if (euid == buf.st_uid) {
-                                       shift = 6; /* owner */
-                               } else if (egid == buf.st_gid) {
-                                       shift = 3; /* group */
-                               } else if (in_group(euid, buf.st_gid)) {
-                                       shift = 3; /* suppl. groups */
-                               } else {
-                                       shift = 0; /* other */
-                               }
-
-                               perm_bits = 
-                               (bits >> shift) & (R_BIT | W_BIT | X_BIT);
-                       }
-
-                       if ((perm_bits | access_desired) != perm_bits) {
-                               errno = EACCES;
-                               return -1;
-                       }
-
-                       /* if we get here permissions are OK */
-
-               } else {
-
-                       return -1;
-               }
-       } else {
+       if (r == -1 && errno != EEXIST) {
+               return -1;
+       } else if (r == 0) {
                did_mknod = 1;
        }
 
index 292df6e79e3faaa8c91ec24ec24f907270f8a14f..f1f4b66a5375b7e6db4e896c0f6e8d266abf0e6a 100644 (file)
@@ -160,147 +160,15 @@ static int _udp_connect(int socket, const struct sockaddr *address,
        return r;
 }
 
-static int in_group(uid_t uid, gid_t gid)
-{
-       int r, i;
-       int size;
-       gid_t *list;
-
-       size = sysconf(_SC_NGROUPS_MAX);
-       list = malloc(size * sizeof(gid_t));
-
-       if (list == NULL) {
-               return 0;
-       }
-
-       r= getgroups(size, list);
-       if (r == -1) {
-               free(list);
-               return 0;
-       }
-
-       for (i = 0; i < r; i++) {
-               if (gid == list[i]) {
-                       free(list);
-                       return 1;
-               }
-       }
-
-       free(list);
-       return 0;
-}
-
 static int _uds_connect(int socket, const struct sockaddr *address,
        socklen_t address_len)
 {
-       mode_t bits, perm_bits, access_desired;
-       struct stat buf;
-       uid_t euid;
-       gid_t egid;
-       char real_sun_path[PATH_MAX+1];
-       char *realpath_result;
-       int i, r, shift;
-       int null_found;
 
        if (address == NULL) {
                errno = EFAULT;
                return -1;
        }
 
-       /* sun_family is always supposed to be AF_UNIX */
-       if (((struct sockaddr_un *) address)->sun_family != AF_UNIX) {
-               errno = EAFNOSUPPORT;
-               return -1;
-       }
-
-       /* an empty path is not supported */
-       if (((struct sockaddr_un *) address)->sun_path[0] == '\0') {
-               errno = EINVAL;
-               return -1;
-       }
-
-       /* the path must be a null terminated string for realpath to work */
-       for (null_found = i = 0;
-               i < sizeof(((struct sockaddr_un *) address)->sun_path); i++) {
-
-               if (((struct sockaddr_un *) address)->sun_path[i] == '\0') {
-                       null_found = 1;
-                       break;
-               }
-       }
-
-       if (!null_found) {
-               errno = EINVAL;
-               return -1;
-       }
-
-       /*
-        * Get the realpath(3) of the socket file.
-        */
-
-       realpath_result = realpath(((struct sockaddr_un *) address)->sun_path,
-                                                       real_sun_path);
-       if (realpath_result == NULL) {
-               return -1;
-       }
-
-       if (strlen(real_sun_path) >= UNIX_PATH_MAX) {
-               errno = ENAMETOOLONG;
-               return -1;
-       }
-
-       strcpy(((struct sockaddr_un *) address)->sun_path, real_sun_path);
-
-       /*
-        * input parameters look good -- check the permissions of the 
-        * socket file. emulate eaccess() (i.e. the access(2) function 
-        * with effective UID/GID).
-        */
-
-       access_desired = R_BIT | W_BIT; /* read + write access */
-
-       euid = geteuid();
-       egid = getegid();
-
-       if (euid == -1 || egid == -1) {
-               errno = EACCES;
-               return -1;
-       }
-
-       r= stat(((struct sockaddr_un *) address)->sun_path, &buf);
-       if (r == -1) {
-               return -1;
-       }
-
-       if (!S_ISSOCK(buf.st_mode)) {
-               errno = EINVAL;
-               return -1;
-       }
-
-       bits = buf.st_mode;
-
-       if (euid == ((uid_t) 0)) {
-               perm_bits = R_BIT | W_BIT;
-       } else {
-               if (euid == buf.st_uid) {
-                       shift = 6; /* owner */
-               } else if (egid == buf.st_gid) {
-                       shift = 3; /* group */
-               } else if (in_group(euid, buf.st_gid)) {
-                       shift = 3; /* suppl. groups */
-               } else {
-                       shift = 0; /* other */
-               }
-
-               perm_bits = (bits >> shift) & (R_BIT | W_BIT | X_BIT);
-       }
-
-       if ((perm_bits | access_desired) != perm_bits) {
-               errno = EACCES;
-               return -1;
-       }
-
        /* perform the connect */
-       r= ioctl(socket, NWIOSUDSCONN, (void *) address);
-       return r;
+       return ioctl(socket, NWIOSUDSCONN, (void *) address);
 }
index 426c719f02b70e2a69b4b2bbfd20f60d85ebea2c..9b8f4fccf3b07189f238a9647ebbdff890d3e3ed 100644 (file)
@@ -23,8 +23,7 @@ ssize_t recvmsg(int socket, struct msghdr *msg, int flags)
        }
 
        r= ioctl(socket, NWIOGUDSSOTYPE, &uds_sotype);
-       if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
-       {
+       if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) {
                if (r == -1) {
                        return r;
                }
@@ -46,7 +45,7 @@ ssize_t recvmsg(int socket, struct msghdr *msg, int flags)
 
 static ssize_t _uds_recvmsg_conn(int socket, struct msghdr *msg, int flags)
 {
-       int r;
+       int r, rc;
 
        if (flags != 0) {
 #if DEBUG
@@ -56,13 +55,30 @@ static ssize_t _uds_recvmsg_conn(int socket, struct msghdr *msg, int flags)
                return -1;
        }
 
-       r = readv(socket, msg->msg_iov, msg->msg_iovlen);
+       r= readv(socket, msg->msg_iov, msg->msg_iovlen);
 
-       if (r >= 0 && msg->msg_name && msg->msg_namelen > 0)
-       {
+       if (r >= 0 && msg->msg_name && msg->msg_namelen > 0) {
                getpeername(socket, msg->msg_name, &msg->msg_namelen);
        }
 
+       /* get control data */
+       if (r >= 0 && msg->msg_control && msg->msg_controllen > 0) {
+               struct msg_control msg_ctrl;
+
+               memset(&msg_ctrl, '\0', sizeof(struct msg_control));
+               msg_ctrl.msg_controllen = msg->msg_controllen;
+               rc = ioctl(socket, NWIOGUDSCTRL, &msg_ctrl);
+               if (rc == -1) {
+                       return rc;
+               }
+
+               if (msg_ctrl.msg_controllen <= msg->msg_controllen) {
+                       memcpy(msg->msg_control, msg_ctrl.msg_control,
+                                               msg_ctrl.msg_controllen);
+                       msg->msg_controllen = msg_ctrl.msg_controllen;
+               }
+       }
+
        msg->msg_flags = 0;
 
        return r;
@@ -70,7 +86,7 @@ static ssize_t _uds_recvmsg_conn(int socket, struct msghdr *msg, int flags)
 
 static ssize_t _uds_recvmsg_dgram(int socket, struct msghdr *msg, int flags)
 {
-       int r;
+       int r, rc;
 
        if (flags != 0) {
 #if DEBUG
@@ -80,13 +96,34 @@ static ssize_t _uds_recvmsg_dgram(int socket, struct msghdr *msg, int flags)
                return -1;
        }
 
-       r = readv(socket, msg->msg_iov, msg->msg_iovlen);
+       r= readv(socket, msg->msg_iov, msg->msg_iovlen);
 
-       if (r >= 0 && msg->msg_name && msg->msg_namelen > 0)
+       if (r >= 0 && msg->msg_name &&
+                               msg->msg_namelen >= sizeof(struct sockaddr_un))
        {
-               ioctl(socket, NWIOGUDSFADDR, msg->msg_name);
+               rc= ioctl(socket, NWIOGUDSFADDR, msg->msg_name);
+               if (rc == -1) {
+                       return rc;
+               }
                msg->msg_namelen= sizeof(struct sockaddr_un);
+       }
 
+       /* get control data */
+       if (r >= 0 && msg->msg_control && msg->msg_controllen > 0) {
+               struct msg_control msg_ctrl;
+
+               memset(&msg_ctrl, '\0', sizeof(struct msg_control));
+               msg_ctrl.msg_controllen = msg->msg_controllen;
+               rc = ioctl(socket, NWIOGUDSCTRL, &msg_ctrl);
+               if (rc == -1) {
+                       return rc;
+               }
+
+               if (msg_ctrl.msg_controllen <= msg->msg_controllen) {
+                       memcpy(msg->msg_control, msg_ctrl.msg_control,
+                                               msg_ctrl.msg_controllen);
+                       msg->msg_controllen = msg_ctrl.msg_controllen;
+               }
        }
 
        msg->msg_flags = 0;
index 3e70951e03060a0d811e7fe70cfd20754f2db6ca..dc1ebf6cb271a0d1f43ce7c506af249c7902a177 100644 (file)
@@ -26,8 +26,7 @@ ssize_t sendmsg(int socket, const struct msghdr *msg, int flags)
        }
 
        r= ioctl(socket, NWIOGUDSSOTYPE, &uds_sotype);
-       if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
-       {
+       if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) {
                if (r == -1) {
                        return r;
                }
@@ -51,6 +50,8 @@ ssize_t sendmsg(int socket, const struct msghdr *msg, int flags)
 static ssize_t _uds_sendmsg_conn(int socket, const struct msghdr *msg, 
        int flags)
 {
+       struct msg_control msg_ctrl;
+       int r;
 
        if (flags != 0) {
 #if DEBUG
@@ -61,6 +62,23 @@ static ssize_t _uds_sendmsg_conn(int socket, const struct msghdr *msg,
 
        }
 
+       /* grab the control data */
+       memset(&msg_ctrl, '\0', sizeof(struct msg_control));
+       if (msg->msg_controllen > MSG_CONTROL_MAX) {
+               errno = ENOMEM;
+               return -1;
+       } else if (msg->msg_controllen > 0) {
+               memcpy(&msg_ctrl.msg_control, msg->msg_control,
+                                                       msg->msg_controllen);
+       }
+       msg_ctrl.msg_controllen = msg->msg_controllen;
+
+       /* send the control data to PFS */
+       r= ioctl(socket, NWIOSUDSCTRL, (void *) &msg_ctrl);
+       if (r == -1) {
+               return r;
+       }
+
        /* Silently ignore destination, if given. */
 
        return writev(socket, msg->msg_iov, msg->msg_iovlen);
@@ -69,10 +87,8 @@ static ssize_t _uds_sendmsg_conn(int socket, const struct msghdr *msg,
 static ssize_t _uds_sendmsg_dgram(int socket, const struct msghdr *msg, 
        int flags)
 {
-       char real_sun_path[PATH_MAX+1];
-       char *realpath_result;
-       char *dest_addr;
-       int null_found;
+       struct msg_control msg_ctrl;
+       struct sockaddr_un *dest_addr;
        int i, r;
 
        if (flags != 0) {
@@ -90,46 +106,25 @@ static ssize_t _uds_sendmsg_dgram(int socket, const struct msghdr *msg,
                return -1;
        }
 
-       /* sun_family is always supposed to be AF_UNIX */
-       if (((struct sockaddr_un *) dest_addr)->sun_family != AF_UNIX) {
-               errno = EAFNOSUPPORT;
-               return -1;
-       }
-
-       /* an empty path is not supported */
-       if (((struct sockaddr_un *) dest_addr)->sun_path[0] == '\0') {
-               errno = ENOENT;
-               return -1;
-       }
-
-       /* the path must be a null terminated string for realpath to work */
-       for (null_found = i = 0;
-               i < sizeof(((struct sockaddr_un *) dest_addr)->sun_path); i++) {
-               if (((struct sockaddr_un *) dest_addr)->sun_path[i] == '\0') {
-                       null_found = 1;
-                       break;
-               }
-       }
-
-       if (!null_found) {
-               errno = EINVAL;
-               return -1;
-       }
-
-       realpath_result = realpath(
-               ((struct sockaddr_un *) dest_addr)->sun_path, real_sun_path);
-
-       if (realpath_result == NULL) {
-               return -1;
+       /* set the target address */
+       r= ioctl(socket, NWIOSUDSTADDR, (void *) dest_addr);
+       if (r == -1) {
+               return r;
        }
 
-       if (strlen(real_sun_path) >= UNIX_PATH_MAX) {
-               errno = ENAMETOOLONG;
+       /* grab the control data */
+       memset(&msg_ctrl, '\0', sizeof(struct msg_control));
+       if (msg->msg_controllen > MSG_CONTROL_MAX) {
+               errno = ENOMEM;
                return -1;
+       } else if (msg->msg_controllen > 0) {
+               memcpy(&msg_ctrl.msg_control, msg->msg_control,
+                                                       msg->msg_controllen);
        }
+       msg_ctrl.msg_controllen = msg->msg_controllen;
 
-       /* set the target address */
-       r= ioctl(socket, NWIOSUDSTADDR, (void *) dest_addr);
+       /* send the control data to PFS */
+       r= ioctl(socket, NWIOSUDSCTRL, (void *) &msg_ctrl);
        if (r == -1) {
                return r;
        }
index ae62a2658bc5180aeadac193ffb22aee02c9fd63..eaffc565f1fbb13ac59636bf29f87217c0d8ce37 100644 (file)
@@ -206,10 +206,7 @@ static ssize_t _uds_sendto_conn(int socket, const void *message, size_t length,
 static ssize_t _uds_sendto_dgram(int socket, const void *message, size_t length,
        int flags, const struct sockaddr *dest_addr, socklen_t dest_len)
 {
-       char real_sun_path[PATH_MAX+1];
-       char *realpath_result;
-       int null_found;
-       int i, r;
+       int r;
 
        /* for connectionless unix domain sockets (SOCK_DGRAM) */
 
@@ -226,46 +223,6 @@ static ssize_t _uds_sendto_dgram(int socket, const void *message, size_t length,
                return -1;
        }
 
-       /* sun_family is always supposed to be AF_UNIX */
-       if (((struct sockaddr_un *) dest_addr)->sun_family != AF_UNIX) {
-               errno = EAFNOSUPPORT;
-               return -1;
-       }
-
-       /* an empty path is not supported */
-       if (((struct sockaddr_un *) dest_addr)->sun_path[0] == '\0') {
-               errno = ENOENT;
-               return -1;
-       }
-
-       /* the path must be a null terminated string for realpath to work */
-       for (null_found = i = 0;
-               i < sizeof(((struct sockaddr_un *) dest_addr)->sun_path); i++) {
-               if (((struct sockaddr_un *) dest_addr)->sun_path[i] == '\0') {
-                       null_found = 1;
-                       break;
-               }
-       }
-
-       if (!null_found) {
-               errno = EINVAL;
-               return -1;
-       }
-
-       realpath_result = realpath(
-               ((struct sockaddr_un *) dest_addr)->sun_path, real_sun_path);
-
-       if (realpath_result == NULL) {
-               return -1;
-       }
-
-       if (strlen(real_sun_path) >= UNIX_PATH_MAX) {
-               errno = ENAMETOOLONG;
-               return -1;
-       }
-
-       strcpy(((struct sockaddr_un *) dest_addr)->sun_path, real_sun_path);
-
        /* set the target address */
        r= ioctl(socket, NWIOSUDSTADDR, (void *) dest_addr);
        if (r == -1) {
index 83fa49f88de615f9629ff3ebf69ab883c678a793..6b14682e78ea7513660908f47ad903bba04ac96a 100644 (file)
@@ -55,12 +55,13 @@ PUBLIC int uds_open(message *dev_m_in, message *dev_m_out)
         * Find a slot in the descriptor table for the new descriptor.
         * The index of the descriptor in the table will be returned.
         * Subsequent calls to read/write/close/ioctl/etc will use this
-        * minor number.
+        * minor number. The minor number must be different from the
+        * the /dev/uds device's minor number (currently 0).
         */
 
        minor = -1; /* to trap error */
 
-       for (i = 0; i < NR_FDS; i++) {
+       for (i = 1; i < NR_FDS; i++) {
                if (uds_fd_table[i].state == UDS_FREE) {
                        minor = i;
                        break;
@@ -122,6 +123,12 @@ PUBLIC int uds_open(message *dev_m_in, message *dev_m_out)
                uds_fd_table[minor].backlog[i] = -1;
        }
 
+       memset(&uds_fd_table[minor].ancillary_data, '\0', sizeof(struct 
+                                                               ancillary));
+       for (i = 0; i < OPEN_MAX; i++) {
+               uds_fd_table[minor].ancillary_data.fds[i] = -1;
+       }
+
        /* default the size to UDS_SOMAXCONN */
        uds_fd_table[minor].backlog_size = UDS_SOMAXCONN;
 
@@ -138,6 +145,8 @@ PUBLIC int uds_open(message *dev_m_in, message *dev_m_out)
 
        /* initially the socket is not bound or listening on an address */
        memset(&(uds_fd_table[minor].addr), '\0', sizeof(struct sockaddr_un));
+       memset(&(uds_fd_table[minor].source), '\0', sizeof(struct sockaddr_un));
+       memset(&(uds_fd_table[minor].target), '\0', sizeof(struct sockaddr_un));
 
        /* Initially the socket isn't suspended. */
        uds_fd_table[minor].suspended = UDS_NOT_SUSPENDED;
@@ -245,6 +254,10 @@ PUBLIC int uds_close(message *dev_m_in, message *dev_m_out)
                }
        }
 
+       if (uds_fd_table[minor].ancillary_data.nfiledes > 0) {
+               clear_fds(minor, &(uds_fd_table[minor].ancillary_data));
+       }
+
        /* Prepare Request to the FS side of PFS */
 
        fs_m_in.m_type = REQ_PUTNODE;
@@ -325,8 +338,8 @@ PUBLIC int uds_select(message *dev_m_in, message *dev_m_out)
                }
        }
 
-       /* check if we can write at least 1 byte */
-       bytes = uds_perform_write(minor, dev_m_in->m_source, 1, 1);
+       /* check if we can write without blocking */
+       bytes = uds_perform_write(minor, dev_m_in->m_source, PIPE_BUF, 1);
        if (bytes > 0) {
                uds_fd_table[minor].sel_ops_out |= SEL_WR;
        }
@@ -547,6 +560,11 @@ PRIVATE int uds_perform_write(int minor, endpoint_t m_source,
                                break;
                        }
                }
+
+               if (peer == -1) {
+                       errno = ENOENT;
+                       return -1;
+               }
        }
 
        /* check if write would overrun buffer. check if message 
@@ -651,7 +669,8 @@ PUBLIC int uds_read(message *dev_m_in, message *dev_m_out)
        static int call_count = 0;
        printf("(uds) [%d] uds_read() call_count=%d\n", uds_minor(dev_m_in),
                                                        ++call_count);
-       printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->IO_ENDPT, dev_m_in->POSITION);
+       printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->IO_ENDPT,
+                                                       dev_m_in->POSITION);
 #endif
 
        minor = uds_minor(dev_m_in);
@@ -713,7 +732,8 @@ PUBLIC int uds_write(message *dev_m_in, message *dev_m_out)
        static int call_count = 0;
        printf("(uds) [%d] uds_write() call_count=%d\n", uds_minor(dev_m_in),
                                                        ++call_count);
-       printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->IO_ENDPT, dev_m_in->POSITION);
+       printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->IO_ENDPT, 
+                                                       dev_m_in->POSITION);
 #endif
 
        minor = uds_minor(dev_m_in);
@@ -775,7 +795,8 @@ PUBLIC int uds_ioctl(message *dev_m_in, message *dev_m_out)
        static int call_count = 0;
        printf("(uds) [%d] uds_ioctl() call_count=%d\n", uds_minor(dev_m_in),
                                                        ++call_count);
-       printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->IO_ENDPT, dev_m_in->POSITION);
+       printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->IO_ENDPT, 
+                                                       dev_m_in->POSITION);
 #endif
 
        minor = uds_minor(dev_m_in);
@@ -895,6 +916,16 @@ PUBLIC int uds_ioctl(message *dev_m_in, message *dev_m_out)
                        /* set the send buffer size -- setsockopt(SO_SNDBUF) */
                        return do_setsockopt_rcvbuf(dev_m_in, dev_m_out);
 
+               case NWIOSUDSCTRL:
+
+                       /* set the control data -- sendmsg() */
+                       return do_sendmsg(dev_m_in, dev_m_out);
+
+               case NWIOGUDSCTRL:
+
+                       /* set the control data -- recvmsg() */
+                       return do_recvmsg(dev_m_in, dev_m_out);
+
                default:
 
                        /* the IOCTL command is not valid for /dev/uds --
index 09755c5e4260a161b59d5e49573a32e17927e0e4..93c1edde7b62db8250f5359751951217b62993aa 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <ansi.h>
 #include <sys/types.h>
+#include <sys/param.h>
 #include <sys/select.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
index 6e8300d10a5d0291ee3d09a33b0b1b7dba8e1ae7..e6dedfc99b67ab04c9885839f16eb58e6de5bd60 100644 (file)
@@ -7,6 +7,7 @@
 struct buf;
 struct inode;
 struct sockaddr_un;
+struct ancillary;
 
 /* buffer.c */
 _PROTOTYPE( struct buf *get_block, (dev_t dev, ino_t inum)             );
@@ -90,9 +91,11 @@ _PROTOTYPE( int do_setsockopt_rcvbuf,
                                (message *dev_m_in, message *dev_m_out) );
 _PROTOTYPE( int do_sendto, (message *dev_m_in, message *dev_m_out)     );
 _PROTOTYPE( int do_recvfrom, (message *dev_m_in, message *dev_m_out)   );
+_PROTOTYPE( int do_sendmsg, (message *dev_m_in, message *dev_m_out)    );
+_PROTOTYPE( int do_recvmsg, (message *dev_m_in, message *dev_m_out)    );
 _PROTOTYPE( int perform_connection,
                                (message *dev_m_in, message *dev_m_out, 
                                struct sockaddr_un *addr, int minorx, 
                                int minory)                             );
-
+_PROTOTYPE( int clear_fds, (int minor, struct ancillary *data)         );
 #endif
index 3188cad884caa7bd063dd369080ea5fb78b92563..16157c5e4d8b383b1398729b44453c45c9fdcb89 100644 (file)
  *   do_setsockopt_rcvbuf:   handles the  setsockopt(2) syscall.
  *   do_sendto:              handles the      sendto(2) syscall.
  *   do_recvfrom:            handles the    recvfrom(2) syscall.
+ *   do_sendmsg:             handles the     sendmsg(2) syscall.
+ *   do_recvmsg:             handles the     recvmsg(2) syscall.
  *   perform_connection:     performs the connection of two descriptors.
+ *   clear_fds:              calls put_filp for undelivered FDs.
  *
  * Also see...
  *
@@ -50,6 +53,187 @@ PUBLIC void uds_init(void)
        memset(uds_fd_table, '\0', sizeof(uds_fd_t) * NR_FDS);
 }
 
+/* check the permissions of a socket file */
+PRIVATE int check_perms(int minor, struct sockaddr_un *addr)
+{
+       int rc;
+       message vfs_m;
+       cp_grant_id_t grant_id;
+
+       grant_id = cpf_grant_direct(VFS_PROC_NR, (vir_bytes) addr->sun_path,
+                                       UNIX_PATH_MAX, CPF_READ | CPF_WRITE);
+
+       /* ask the VFS to verify the permissions */
+       memset(&vfs_m, '\0', sizeof(message));
+
+       vfs_m.m_type = PFS_REQ_CHECK_PERMS;
+       vfs_m.IO_ENDPT = uds_fd_table[minor].owner;
+       vfs_m.IO_GRANT = (char *) grant_id;
+       vfs_m.COUNT = UNIX_PATH_MAX;
+
+       rc = sendrec(VFS_PROC_NR, &vfs_m);
+       cpf_revoke(grant_id);
+       if (OK != rc) {
+                printf("(uds) sendrec error... req_nr: %d err: %d\n",  
+                       vfs_m.m_type, rc);
+
+                       return EIO;
+       }
+
+#if DEBUG == 1
+       printf("(uds) VFS reply => %d\n", vfs_m.m_type);
+       printf("(uds) Canonical Path => %s\n", addr->sun_path);
+#endif
+
+       return vfs_m.m_type; /* return reply code OK, ELOOP, etc. */
+}
+
+PRIVATE filp_id_t verify_fd(endpoint_t ep, int fd)
+{
+       int rc;
+       message vfs_m;
+
+#if DEBUG == 1
+       static int call_count = 0;
+       printf("(uds) verify_fd(%d,%d) call_count=%d\n", ep, fd, 
+                                                       ++call_count);
+#endif
+
+       memset(&vfs_m, '\0', sizeof(message));
+
+       vfs_m.m_type = PFS_REQ_VERIFY_FD;
+       vfs_m.IO_ENDPT = ep;
+       vfs_m.COUNT = fd;
+
+       rc = sendrec(VFS_PROC_NR, &vfs_m);
+       if (OK != rc) {
+                printf("(uds) sendrec error... req_nr: %d err: %d\n",  
+                       vfs_m.m_type, rc);
+                       return NULL;;
+       }
+
+#if DEBUG == 1
+       printf("(uds) VFS reply => %d\n", vfs_m.m_type);
+#endif
+
+       return vfs_m.ADDRESS;
+}
+
+PRIVATE int set_filp(filp_id_t sfilp)
+{
+       int rc;
+       message vfs_m;
+
+#if DEBUG == 1
+       static int call_count = 0;
+       printf("(uds) set_filp(0x%x) call_count=%d\n", sfilp, ++call_count);
+#endif
+
+       memset(&vfs_m, '\0', sizeof(message));
+
+       vfs_m.m_type = PFS_REQ_SET_FILP;
+       vfs_m.ADDRESS = sfilp;
+
+       rc = sendrec(VFS_PROC_NR, &vfs_m);
+       if (OK != rc) {
+                printf("(uds) sendrec error... req_nr: %d err: %d\n",  
+                       vfs_m.m_type, rc);
+                       return EIO;
+       }
+
+#if DEBUG == 1
+       printf("(uds) VFS reply => %d\n", vfs_m.m_type);
+#endif
+       return vfs_m.m_type; /* return reply code OK, ELOOP, etc. */
+}
+
+PRIVATE int copy_filp(endpoint_t to_ep, filp_id_t cfilp)
+{
+       int rc;
+       message vfs_m;
+
+#if DEBUG == 1
+       static int call_count = 0;
+       printf("(uds) copy_filp(%d, 0x%x) call_count=%d\n",to_ep, cfilp, 
+                                                       ++call_count);
+#endif
+
+       memset(&vfs_m, '\0', sizeof(message));
+
+       vfs_m.m_type = PFS_REQ_COPY_FILP;
+       vfs_m.IO_ENDPT = to_ep;
+       vfs_m.ADDRESS = cfilp;
+
+       rc = sendrec(VFS_PROC_NR, &vfs_m);
+       if (OK != rc) {
+                printf("(uds) sendrec error... req_nr: %d err: %d\n",  
+                       vfs_m.m_type, rc);
+                       return EIO;
+       }
+
+#if DEBUG == 1
+       printf("(uds) VFS reply => %d\n", vfs_m.m_type);
+#endif
+       return vfs_m.m_type;
+}
+
+PRIVATE int put_filp(filp_id_t pfilp)
+{
+       int rc;
+       message vfs_m;
+
+#if DEBUG == 1
+       static int call_count = 0;
+       printf("(uds) put_filp(0x%x) call_count=%d\n", pfilp, ++call_count);
+#endif
+
+       memset(&vfs_m, '\0', sizeof(message));
+
+       vfs_m.m_type = PFS_REQ_PUT_FILP;
+       vfs_m.ADDRESS = pfilp;
+
+       rc = sendrec(VFS_PROC_NR, &vfs_m);
+       if (OK != rc) {
+                printf("(uds) sendrec error... req_nr: %d err: %d\n",  
+                       vfs_m.m_type, rc);
+                       return EIO;
+       }
+
+#if DEBUG == 1
+       printf("(uds) VFS reply => %d\n", vfs_m.m_type);
+#endif
+       return vfs_m.m_type; /* return reply code OK, ELOOP, etc. */
+}
+
+PRIVATE int cancel_fd(endpoint_t ep, int fd)
+{
+       int rc;
+       message vfs_m;
+
+#if DEBUG == 1
+       static int call_count = 0;
+       printf("(uds) cancel_fd(%d,%d) call_count=%d\n", ep, fd, ++call_count);
+#endif
+
+       memset(&vfs_m, '\0', sizeof(message));
+
+       vfs_m.m_type = PFS_REQ_CANCEL_FD;
+       vfs_m.IO_ENDPT = ep;
+       vfs_m.COUNT = fd;
+
+       rc = sendrec(VFS_PROC_NR, &vfs_m);
+       if (OK != rc) {
+                printf("(uds) sendrec error... req_nr: %d err: %d\n",  
+                       vfs_m.m_type, rc);
+                       return EIO;
+       }
+
+#if DEBUG == 1
+       printf("(uds) VFS reply => %d\n", vfs_m.m_type);
+#endif
+       return vfs_m.m_type; /* return reply code OK, ELOOP, etc. */
+}
+
 PUBLIC int perform_connection(message *dev_m_in, message *dev_m_out, 
                        struct sockaddr_un *addr, int minorx, int minory)
 {
@@ -152,7 +336,8 @@ PUBLIC int do_accept(message *dev_m_in, message *dev_m_out)
                if (uds_fd_table[i].addr.sun_family == AF_UNIX &&
                                !strncmp(addr.sun_path, 
                                uds_fd_table[i].addr.sun_path,
-                               UNIX_PATH_MAX)) {
+                               UNIX_PATH_MAX) &&
+                               uds_fd_table[i].listening == 1) {
 
                        rc = 0;
                        break;
@@ -233,7 +418,8 @@ PUBLIC int do_accept(message *dev_m_in, message *dev_m_out)
        /* if peer is blocked on connect() revive peer */
        if (uds_fd_table[minorpeer].suspended) {
 #if DEBUG == 1
-               printf("(uds) [%d] {do_accept} revive %d", minor, minorpeer);
+               printf("(uds) [%d] {do_accept} revive %d\n", minor, 
+                                                               minorpeer);
 #endif
                uds_fd_table[minorpeer].ready_to_revive = 1;
                notify(dev_m_in->m_source);
@@ -298,6 +484,18 @@ PUBLIC int do_connect(message *dev_m_in, message *dev_m_out)
                return EIO;
        }
 
+       rc = check_perms(minor, &addr);
+       if (rc != OK) {
+
+               /* permission denied, socket file doesn't exist, etc. */
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                       (cp_grant_id_t) dev_m_in->IO_GRANT, rc);
+
+               return rc;
+       }
+
        /* look for a socket of the same type that is listening on the 
         * address we want to connect to
         */
@@ -323,7 +521,7 @@ PUBLIC int do_connect(message *dev_m_in, message *dev_m_out)
                                        uds_fd_table[i].child = -1;
 
 #if DEBUG == 1
-                       printf("(uds) [%d] {do_connect} revive %d", minor, i);
+                       printf("(uds) [%d] {do_connect} revive %d\n", minor, i);
 #endif
 
                                        /* wake the parent (server) */
@@ -432,7 +630,7 @@ PUBLIC int do_connect(message *dev_m_in, message *dev_m_out)
        }
 
 #if DEBUG == 1
-       printf("(uds) [%d] {do_connect} suspend", minor);
+       printf("(uds) [%d] {do_connect} suspend\n", minor);
 #endif
 
        /* suspend until the server side completes the connection with accept()
@@ -625,7 +823,7 @@ PUBLIC int do_socket(message *dev_m_in, message *dev_m_out)
 
 PUBLIC int do_bind(message *dev_m_in, message *dev_m_out)
 {
-       int minor;
+       int minor, strlen;
        struct sockaddr_un addr;
        int rc, i;
 
@@ -667,15 +865,39 @@ PUBLIC int do_bind(message *dev_m_in, message *dev_m_out)
        }
 
        /* do some basic sanity checks on the address */
-       if (addr.sun_family != AF_UNIX || addr.sun_path[0] == '\0') {
+       if (addr.sun_family != AF_UNIX) {
+
+               /* bad family */
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT,
+                               EAFNOSUPPORT);
+
+               return EAFNOSUPPORT;
+       }
+
+       if (addr.sun_path[0] == '\0') {
 
                /* bad address */
                uds_fd_table[minor].syscall_done = 1;
 
                uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
-                               (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL);
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, ENOENT);
 
-               return EINVAL;
+               return ENOENT;
+       }
+
+       rc = check_perms(minor, &addr);
+       if (rc != OK) {
+
+               /* permission denied, socket file doesn't exist, etc. */
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                       (cp_grant_id_t) dev_m_in->IO_GRANT, rc);
+
+               return rc;
        }
 
        /* make sure the address isn't already in use by another socket. */
@@ -939,8 +1161,12 @@ PUBLIC int do_socketpair(message *dev_m_in, message *dev_m_out)
 
        minory = (minor(minorin) & BYTE);
 
+#if DEBUG == 1
+       printf("socketpair() %d - %d\n", minorx, minory);
+#endif
+
        /* security check - both sockets must have the same endpoint (owner) */
-       if (uds_fd_table[minorx].endpoint != uds_fd_table[minory].endpoint) {
+       if (uds_fd_table[minorx].owner != uds_fd_table[minory].owner) {
 
                /* we won't allow you to magically connect your socket to
                 * someone elses socket
@@ -1307,6 +1533,17 @@ PUBLIC int do_sendto(message *dev_m_in, message *dev_m_out)
                return EINVAL;
        }
 
+       rc = check_perms(minor, &addr);
+       if (rc != OK) {
+
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, rc);
+
+               return rc;
+       }
+
        memcpy(&(uds_fd_table[minor].target), &addr,
                                        sizeof(struct sockaddr_un));
 
@@ -1352,3 +1589,414 @@ PUBLIC int do_recvfrom(message *dev_m_in, message *dev_m_out)
 
        return OK;
 }
+
+int msg_control_read(struct msg_control *msg_ctrl, struct ancillary *data,
+                                                       int minor)
+{
+       int rc;
+       struct msghdr msghdr;
+       struct cmsghdr *cmsg = NULL;
+
+#if DEBUG == 1
+       static int call_count = 0;
+       printf("(uds) [%d] msg_control_read() call_count=%d\n", minor, 
+                                                       ++call_count);
+#endif
+
+       data->nfiledes = 0;
+
+       memset(&msghdr, '\0', sizeof(struct msghdr));
+       msghdr.msg_control = msg_ctrl->msg_control;
+       msghdr.msg_controllen = msg_ctrl->msg_controllen;
+
+       for(cmsg = CMSG_FIRSTHDR(&msghdr); cmsg != NULL;
+                                       cmsg = CMSG_NXTHDR(&msghdr, cmsg)) {
+
+               if (cmsg->cmsg_level == SOL_SOCKET &&
+                                       cmsg->cmsg_type == SCM_RIGHTS) {
+
+                       int i;
+                       int nfds =
+                               MIN((cmsg->cmsg_len-CMSG_LEN(0))/sizeof(int),
+                                                               OPEN_MAX);
+
+                       for (i = 0; i < nfds; i++) {
+                               if (data->nfiledes == OPEN_MAX) {
+                                       return EOVERFLOW;
+                               }
+
+                               data->fds[data->nfiledes] =
+                                       ((int *) CMSG_DATA(cmsg))[i];
+#if DEBUG == 1
+                               printf("(uds) [%d] fd[%d]=%d\n", minor,
+                               data->nfiledes, data->fds[data->nfiledes]);
+#endif
+                               data->nfiledes++;
+                       }
+               }
+       }
+
+       /* obtain this socket's credentials */
+       rc = getnucred(uds_fd_table[minor].owner, &(data->cred));
+       if (rc == -1) {
+               return errno;
+       }
+#if DEBUG == 1
+       printf("(uds) [%d] cred={%d,%d,%d}\n", minor,
+               data->cred.pid, data->cred.uid,
+               data->cred.gid);
+#endif
+       return OK;
+}
+
+PRIVATE int send_fds(int minor, struct ancillary *data)
+{
+       int rc, i, j;
+
+#if DEBUG == 1
+       static int call_count = 0;
+       printf("(uds) [%d] send_fds() call_count=%d\n", minor, ++call_count);
+#endif
+
+       /* verify the file descriptors and get their filps. */
+       for (i = 0; i < data->nfiledes; i++) {
+               data->filps[i] = verify_fd(uds_fd_table[minor].owner,
+                                               data->fds[i]);
+
+               if (data->filps[i] == NULL) {
+                       return EINVAL;
+               }
+       }
+
+       /* set them as in-flight */
+       for (i = 0; i < data->nfiledes; i++) {
+               rc = set_filp(data->filps[i]);
+               if (rc != OK) {
+                       /* revert set_filp() calls */
+                       for (j = i; j >= 0; j--) {
+                               put_filp(data->filps[j]);
+                       }
+                       return rc;
+               }
+       }
+
+       return OK;
+}
+
+PUBLIC int clear_fds(int minor, struct ancillary *data)
+{
+/* This function calls put_filp() for all of the FDs in data.
+ * This is used when a Unix Domain Socket is closed and there 
+ * exists references to file descriptors that haven't been received 
+ * with recvmsg().
+ */
+       int i;
+
+#if DEBUG == 1
+       static int call_count = 0;
+       printf("(uds) [%d] recv_fds() call_count=%d\n", minor,
+                                                       ++call_count);
+#endif
+
+       for (i = 0; i < data->nfiledes; i++) {
+               put_filp(data->filps[i]);
+#if DEBUG == 1
+               printf("(uds) clear_fds() => %d\n", data->fds[i]);
+#endif
+               data->fds[i] = -1;
+               data->filps[i] = NULL;
+       }
+
+       data->nfiledes = 0;
+
+       return OK;
+}
+
+PRIVATE int recv_fds(int minor, struct ancillary *data,
+                                       struct msg_control *msg_ctrl)
+{
+       int rc, i, j;
+       struct msghdr msghdr;
+       struct cmsghdr *cmsg;
+       endpoint_t to_ep;
+
+#if DEBUG == 1
+       static int call_count = 0;
+       printf("(uds) [%d] recv_fds() call_count=%d\n", minor,
+                                                       ++call_count);
+#endif
+
+       msghdr.msg_control = msg_ctrl->msg_control;
+       msghdr.msg_controllen = msg_ctrl->msg_controllen;
+
+       cmsg = CMSG_FIRSTHDR(&msghdr);
+       cmsg->cmsg_len = CMSG_LEN(sizeof(int) * data->nfiledes);
+       cmsg->cmsg_level = SOL_SOCKET;
+       cmsg->cmsg_type = SCM_RIGHTS;
+
+       to_ep = uds_fd_table[minor].owner;
+
+       /* copy to the target endpoint */
+       for (i = 0; i < data->nfiledes; i++) {
+               rc = copy_filp(to_ep, data->filps[i]);
+               if (rc < 0) {
+                       /* revert set_filp() calls */
+                       for (j = 0; j < data->nfiledes; j++) {
+                               put_filp(data->filps[j]);
+                       }
+                       /* revert copy_filp() calls */
+                       for (j = i; j >= 0; j--) {
+                               cancel_fd(to_ep, data->fds[j]);
+                       }
+                       return rc;
+               }
+               data->fds[i] = rc; /* data->fds[i] now has the new FD */
+       }
+
+       for (i = 0; i < data->nfiledes; i++) {
+               put_filp(data->filps[i]);
+#if DEBUG == 1
+               printf("(uds) recv_fds() => %d\n", data->fds[i]);
+#endif
+               ((int *)CMSG_DATA(cmsg))[i] = data->fds[i];
+               data->fds[i] = -1;
+               data->filps[i] = NULL;
+       }
+
+       data->nfiledes = 0;
+
+       return OK;
+}
+
+PRIVATE int recv_cred(int minor, struct ancillary *data,
+                                       struct msg_control *msg_ctrl)
+{
+       int rc, i;
+       struct msghdr msghdr;
+       struct cmsghdr *cmsg;
+
+#if DEBUG == 1
+       static int call_count = 0;
+       printf("(uds) [%d] recv_cred() call_count=%d\n", minor,
+                                                       ++call_count);
+#endif
+
+       msghdr.msg_control = msg_ctrl->msg_control;
+       msghdr.msg_controllen = msg_ctrl->msg_controllen;
+
+       cmsg = CMSG_FIRSTHDR(&msghdr);
+       if (cmsg->cmsg_len > 0) {
+               cmsg = CMSG_NXTHDR(&msghdr, cmsg);
+       }
+
+       cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
+       cmsg->cmsg_level = SOL_SOCKET;
+       cmsg->cmsg_type = SCM_CREDENTIALS;
+       memcpy(CMSG_DATA(cmsg), &(data->cred), sizeof(struct ucred));
+
+       return OK;
+}
+
+PUBLIC int do_sendmsg(message *dev_m_in, message *dev_m_out)
+{
+       int minor, peer, rc, i;
+       struct msg_control msg_ctrl;
+
+#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);
+
+       memset(&msg_ctrl, '\0', sizeof(struct msg_control));
+
+       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), D);
+
+       if (rc != OK) {
+               uds_fd_table[minor].syscall_done = 1;
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, EIO);
+               return EIO;
+       }
+
+       /* locate peer */
+       peer = -1;
+       if (uds_fd_table[minor].type == SOCK_DGRAM) {
+               if (uds_fd_table[minor].target.sun_path[0] == '\0' ||
+                       uds_fd_table[minor].target.sun_family != AF_UNIX) {
+
+                       uds_fd_table[minor].syscall_done = 1;
+                       uds_set_reply(dev_m_out, TASK_REPLY,
+                               dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT,
+                               EDESTADDRREQ);
+                       return EDESTADDRREQ;
+               }
+
+               for (i = 0; i < NR_FDS; i++) {
+
+                       /* look for a SOCK_DGRAM socket that is bound on
+                        * the target address
+                        */
+                       if (uds_fd_table[i].type == SOCK_DGRAM &&
+                               uds_fd_table[i].addr.sun_family == AF_UNIX &&
+                               !strncmp(uds_fd_table[minor].target.sun_path,
+                               uds_fd_table[i].addr.sun_path, UNIX_PATH_MAX)){
+
+                               peer = i;
+                               break;
+                       }
+               }
+
+               if (peer == -1) {
+                       uds_fd_table[minor].syscall_done = 1;
+                       uds_set_reply(dev_m_out, TASK_REPLY,
+                               dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, ENOENT);
+                       return ENOENT;
+               }
+       } else {
+               peer = uds_fd_table[minor].peer;
+               if (peer == -1) {
+                       uds_fd_table[minor].syscall_done = 1;
+                       uds_set_reply(dev_m_out, TASK_REPLY,
+                               dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, ENOTCONN);
+                       return ENOTCONN;
+               }
+       }
+
+#if DEBUG == 1
+       printf("(uds) [%d] sendmsg() -- peer=%d\n", minor, peer);
+#endif
+       /* note: it's possible that there is already some file 
+        * descriptors in ancillary_data if the peer didn't call
+        * recvmsg() yet. That's okay. The receiver will
+        * get the current file descriptors plus the new ones.
+        */
+       rc = msg_control_read(&msg_ctrl, &uds_fd_table[peer].ancillary_data, 
+                                                               minor);
+       if (rc != OK) {
+               uds_fd_table[minor].syscall_done = 1;
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, rc);
+               return rc;
+       }
+
+       rc = send_fds(minor, &uds_fd_table[peer].ancillary_data);
+       if (rc != OK) {
+               uds_fd_table[minor].syscall_done = 1;
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, rc);
+               return rc;
+       }
+
+       uds_fd_table[minor].syscall_done = 1;
+       uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, OK);
+       return OK;
+}
+
+PUBLIC 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), D);
+
+       if (rc != OK) {
+
+               uds_fd_table[minor].syscall_done = 1;
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, EIO);
+               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) {
+
+               uds_fd_table[minor].syscall_done = 1;
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, EOVERFLOW);
+               return EOVERFLOW;
+       }
+
+       rc = recv_fds(minor, &uds_fd_table[minor].ancillary_data, &msg_ctrl);
+       if (rc != OK) {
+               uds_fd_table[minor].syscall_done = 1;
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, rc);
+               return rc;
+       }
+
+       if (controllen_desired <= controllen_avail) {
+               rc = recv_cred(minor, &uds_fd_table[minor].ancillary_data,
+                                                               &msg_ctrl);
+               if (rc != OK) {
+                       uds_fd_table[minor].syscall_done = 1;
+                       uds_set_reply(dev_m_out, TASK_REPLY, 
+                               dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, rc);
+                       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), D);
+
+       if (rc != OK) {
+               uds_fd_table[minor].syscall_done = 1;
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, EIO);
+               return EIO;
+       }
+
+       uds_fd_table[minor].syscall_done = 1;
+       uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, OK);
+
+       return OK;
+}
index 3af2d57e5c14ad576ae086bafe5d76cb9659d5f4..cd754e3438f86dd9a83f36bddd90ad31809073e8 100644 (file)
@@ -9,7 +9,9 @@
  *   dev_uds.c, table.c, uds.c
  */
 
+#include <limits.h>
 #include <sys/types.h>
+#include <sys/ucred.h>
 #include <sys/un.h>
 
 #include <minix/endpoint.h>
 /* max connection backlog for incoming connections */
 #define UDS_SOMAXCONN 64
 
-/* UDS FD state Flags */
-#define UDS_CONNECTING  0x10
+typedef void* filp_id_t;
+
+/* ancillary data to be sent */
+struct ancillary {
+       filp_id_t filps[OPEN_MAX];
+       int fds[OPEN_MAX];
+       int nfiledes;
+       struct ucred cred;
+};
 
 /*
  * Internal State Information for a socket descriptor.
@@ -122,6 +131,11 @@ struct uds_fd {
         */
        int listening;
 
+       /* stores file pointers and credentials being sent between 
+        * processes with sendmsg(2) and recvmsg(2).
+        */
+       struct ancillary ancillary_data;
+
        /* Holds an errno. This is set when a connected socket is
         * closed and we need to pass ECONNRESET on to a suspended
         * peer.