- Add support for file descriptor passing to PFS.
- For security reasons move some libc code to PFS. - Fix a few bugs in PFS. Contributed by Thomas Cort.
This commit is contained in:
parent
13ef7f1f38
commit
e8ddc0f46e
10 changed files with 808 additions and 367 deletions
|
@ -207,14 +207,7 @@ static int in_group(uid_t uid, gid_t gid)
|
||||||
static int _uds_bind(int socket, const struct sockaddr *address,
|
static int _uds_bind(int socket, const struct sockaddr *address,
|
||||||
socklen_t address_len, struct sockaddr_un *uds_addr)
|
socklen_t address_len, struct sockaddr_un *uds_addr)
|
||||||
{
|
{
|
||||||
mode_t bits, perm_bits, access_desired;
|
int r;
|
||||||
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 did_mknod;
|
int did_mknod;
|
||||||
|
|
||||||
if (address == NULL) {
|
if (address == NULL) {
|
||||||
|
@ -222,120 +215,14 @@ static int _uds_bind(int socket, const struct sockaddr *address,
|
||||||
return -1;
|
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;
|
did_mknod = 0;
|
||||||
|
|
||||||
r = mknod(((struct sockaddr_un *) address)->sun_path,
|
r = mknod(((struct sockaddr_un *) address)->sun_path,
|
||||||
S_IFSOCK|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, 0);
|
S_IFSOCK|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, 0);
|
||||||
|
|
||||||
if (r == -1) {
|
if (r == -1 && errno != EEXIST) {
|
||||||
if (errno == EEXIST) {
|
return -1;
|
||||||
/* file already exists, verify that it is a socket */
|
} else if (r == 0) {
|
||||||
|
|
||||||
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 {
|
|
||||||
did_mknod = 1;
|
did_mknod = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -160,147 +160,15 @@ static int _udp_connect(int socket, const struct sockaddr *address,
|
||||||
return r;
|
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,
|
static int _uds_connect(int socket, const struct sockaddr *address,
|
||||||
socklen_t address_len)
|
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) {
|
if (address == NULL) {
|
||||||
errno = EFAULT;
|
errno = EFAULT;
|
||||||
return -1;
|
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 */
|
/* perform the connect */
|
||||||
r= ioctl(socket, NWIOSUDSCONN, (void *) address);
|
return ioctl(socket, NWIOSUDSCONN, (void *) address);
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,8 +23,7 @@ ssize_t recvmsg(int socket, struct msghdr *msg, int flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
r= ioctl(socket, NWIOGUDSSOTYPE, &uds_sotype);
|
r= ioctl(socket, NWIOGUDSSOTYPE, &uds_sotype);
|
||||||
if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
|
if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) {
|
||||||
{
|
|
||||||
if (r == -1) {
|
if (r == -1) {
|
||||||
return r;
|
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)
|
static ssize_t _uds_recvmsg_conn(int socket, struct msghdr *msg, int flags)
|
||||||
{
|
{
|
||||||
int r;
|
int r, rc;
|
||||||
|
|
||||||
if (flags != 0) {
|
if (flags != 0) {
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
@ -56,13 +55,30 @@ static ssize_t _uds_recvmsg_conn(int socket, struct msghdr *msg, int flags)
|
||||||
return -1;
|
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);
|
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;
|
msg->msg_flags = 0;
|
||||||
|
|
||||||
return r;
|
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)
|
static ssize_t _uds_recvmsg_dgram(int socket, struct msghdr *msg, int flags)
|
||||||
{
|
{
|
||||||
int r;
|
int r, rc;
|
||||||
|
|
||||||
if (flags != 0) {
|
if (flags != 0) {
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
@ -80,13 +96,34 @@ static ssize_t _uds_recvmsg_dgram(int socket, struct msghdr *msg, int flags)
|
||||||
return -1;
|
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);
|
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;
|
msg->msg_flags = 0;
|
||||||
|
|
|
@ -26,8 +26,7 @@ ssize_t sendmsg(int socket, const struct msghdr *msg, int flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
r= ioctl(socket, NWIOGUDSSOTYPE, &uds_sotype);
|
r= ioctl(socket, NWIOGUDSSOTYPE, &uds_sotype);
|
||||||
if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
|
if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) {
|
||||||
{
|
|
||||||
if (r == -1) {
|
if (r == -1) {
|
||||||
return r;
|
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,
|
static ssize_t _uds_sendmsg_conn(int socket, const struct msghdr *msg,
|
||||||
int flags)
|
int flags)
|
||||||
{
|
{
|
||||||
|
struct msg_control msg_ctrl;
|
||||||
|
int r;
|
||||||
|
|
||||||
if (flags != 0) {
|
if (flags != 0) {
|
||||||
#if DEBUG
|
#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. */
|
/* Silently ignore destination, if given. */
|
||||||
|
|
||||||
return writev(socket, msg->msg_iov, msg->msg_iovlen);
|
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,
|
static ssize_t _uds_sendmsg_dgram(int socket, const struct msghdr *msg,
|
||||||
int flags)
|
int flags)
|
||||||
{
|
{
|
||||||
char real_sun_path[PATH_MAX+1];
|
struct msg_control msg_ctrl;
|
||||||
char *realpath_result;
|
struct sockaddr_un *dest_addr;
|
||||||
char *dest_addr;
|
|
||||||
int null_found;
|
|
||||||
int i, r;
|
int i, r;
|
||||||
|
|
||||||
if (flags != 0) {
|
if (flags != 0) {
|
||||||
|
@ -90,50 +106,29 @@ static ssize_t _uds_sendmsg_dgram(int socket, const struct msghdr *msg,
|
||||||
return -1;
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set the target address */
|
/* set the target address */
|
||||||
r= ioctl(socket, NWIOSUDSTADDR, (void *) dest_addr);
|
r= ioctl(socket, NWIOSUDSTADDR, (void *) dest_addr);
|
||||||
if (r == -1) {
|
if (r == -1) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
/* do the send */
|
/* do the send */
|
||||||
return writev(socket, msg->msg_iov, msg->msg_iovlen);
|
return writev(socket, msg->msg_iov, msg->msg_iovlen);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
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)
|
int flags, const struct sockaddr *dest_addr, socklen_t dest_len)
|
||||||
{
|
{
|
||||||
char real_sun_path[PATH_MAX+1];
|
int r;
|
||||||
char *realpath_result;
|
|
||||||
int null_found;
|
|
||||||
int i, r;
|
|
||||||
|
|
||||||
/* for connectionless unix domain sockets (SOCK_DGRAM) */
|
/* 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;
|
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 */
|
/* set the target address */
|
||||||
r= ioctl(socket, NWIOSUDSTADDR, (void *) dest_addr);
|
r= ioctl(socket, NWIOSUDSTADDR, (void *) dest_addr);
|
||||||
if (r == -1) {
|
if (r == -1) {
|
||||||
|
|
|
@ -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.
|
* Find a slot in the descriptor table for the new descriptor.
|
||||||
* The index of the descriptor in the table will be returned.
|
* The index of the descriptor in the table will be returned.
|
||||||
* Subsequent calls to read/write/close/ioctl/etc will use this
|
* 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 */
|
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) {
|
if (uds_fd_table[i].state == UDS_FREE) {
|
||||||
minor = i;
|
minor = i;
|
||||||
break;
|
break;
|
||||||
|
@ -122,6 +123,12 @@ PUBLIC int uds_open(message *dev_m_in, message *dev_m_out)
|
||||||
uds_fd_table[minor].backlog[i] = -1;
|
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 */
|
/* default the size to UDS_SOMAXCONN */
|
||||||
uds_fd_table[minor].backlog_size = 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 */
|
/* 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].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. */
|
/* Initially the socket isn't suspended. */
|
||||||
uds_fd_table[minor].suspended = UDS_NOT_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 */
|
/* Prepare Request to the FS side of PFS */
|
||||||
|
|
||||||
fs_m_in.m_type = REQ_PUTNODE;
|
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 */
|
/* check if we can write without blocking */
|
||||||
bytes = uds_perform_write(minor, dev_m_in->m_source, 1, 1);
|
bytes = uds_perform_write(minor, dev_m_in->m_source, PIPE_BUF, 1);
|
||||||
if (bytes > 0) {
|
if (bytes > 0) {
|
||||||
uds_fd_table[minor].sel_ops_out |= SEL_WR;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (peer == -1) {
|
||||||
|
errno = ENOENT;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if write would overrun buffer. check if message
|
/* 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;
|
static int call_count = 0;
|
||||||
printf("(uds) [%d] uds_read() call_count=%d\n", uds_minor(dev_m_in),
|
printf("(uds) [%d] uds_read() call_count=%d\n", uds_minor(dev_m_in),
|
||||||
++call_count);
|
++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
|
#endif
|
||||||
|
|
||||||
minor = uds_minor(dev_m_in);
|
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;
|
static int call_count = 0;
|
||||||
printf("(uds) [%d] uds_write() call_count=%d\n", uds_minor(dev_m_in),
|
printf("(uds) [%d] uds_write() call_count=%d\n", uds_minor(dev_m_in),
|
||||||
++call_count);
|
++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
|
#endif
|
||||||
|
|
||||||
minor = uds_minor(dev_m_in);
|
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;
|
static int call_count = 0;
|
||||||
printf("(uds) [%d] uds_ioctl() call_count=%d\n", uds_minor(dev_m_in),
|
printf("(uds) [%d] uds_ioctl() call_count=%d\n", uds_minor(dev_m_in),
|
||||||
++call_count);
|
++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
|
#endif
|
||||||
|
|
||||||
minor = uds_minor(dev_m_in);
|
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) */
|
/* set the send buffer size -- setsockopt(SO_SNDBUF) */
|
||||||
return do_setsockopt_rcvbuf(dev_m_in, dev_m_out);
|
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:
|
default:
|
||||||
|
|
||||||
/* the IOCTL command is not valid for /dev/uds --
|
/* the IOCTL command is not valid for /dev/uds --
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include <ansi.h>
|
#include <ansi.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/param.h>
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
struct buf;
|
struct buf;
|
||||||
struct inode;
|
struct inode;
|
||||||
struct sockaddr_un;
|
struct sockaddr_un;
|
||||||
|
struct ancillary;
|
||||||
|
|
||||||
/* buffer.c */
|
/* buffer.c */
|
||||||
_PROTOTYPE( struct buf *get_block, (dev_t dev, ino_t inum) );
|
_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) );
|
(message *dev_m_in, message *dev_m_out) );
|
||||||
_PROTOTYPE( int do_sendto, (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_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,
|
_PROTOTYPE( int perform_connection,
|
||||||
(message *dev_m_in, message *dev_m_out,
|
(message *dev_m_in, message *dev_m_out,
|
||||||
struct sockaddr_un *addr, int minorx,
|
struct sockaddr_un *addr, int minorx,
|
||||||
int minory) );
|
int minory) );
|
||||||
|
_PROTOTYPE( int clear_fds, (int minor, struct ancillary *data) );
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -23,7 +23,10 @@
|
||||||
* do_setsockopt_rcvbuf: handles the setsockopt(2) syscall.
|
* do_setsockopt_rcvbuf: handles the setsockopt(2) syscall.
|
||||||
* do_sendto: handles the sendto(2) syscall.
|
* do_sendto: handles the sendto(2) syscall.
|
||||||
* do_recvfrom: handles the recvfrom(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.
|
* perform_connection: performs the connection of two descriptors.
|
||||||
|
* clear_fds: calls put_filp for undelivered FDs.
|
||||||
*
|
*
|
||||||
* Also see...
|
* Also see...
|
||||||
*
|
*
|
||||||
|
@ -50,6 +53,187 @@ PUBLIC void uds_init(void)
|
||||||
memset(uds_fd_table, '\0', sizeof(uds_fd_t) * NR_FDS);
|
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,
|
PUBLIC int perform_connection(message *dev_m_in, message *dev_m_out,
|
||||||
struct sockaddr_un *addr, int minorx, int minory)
|
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 &&
|
if (uds_fd_table[i].addr.sun_family == AF_UNIX &&
|
||||||
!strncmp(addr.sun_path,
|
!strncmp(addr.sun_path,
|
||||||
uds_fd_table[i].addr.sun_path,
|
uds_fd_table[i].addr.sun_path,
|
||||||
UNIX_PATH_MAX)) {
|
UNIX_PATH_MAX) &&
|
||||||
|
uds_fd_table[i].listening == 1) {
|
||||||
|
|
||||||
rc = 0;
|
rc = 0;
|
||||||
break;
|
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 peer is blocked on connect() revive peer */
|
||||||
if (uds_fd_table[minorpeer].suspended) {
|
if (uds_fd_table[minorpeer].suspended) {
|
||||||
#if DEBUG == 1
|
#if DEBUG == 1
|
||||||
printf("(uds) [%d] {do_accept} revive %d", minor, minorpeer);
|
printf("(uds) [%d] {do_accept} revive %d\n", minor,
|
||||||
|
minorpeer);
|
||||||
#endif
|
#endif
|
||||||
uds_fd_table[minorpeer].ready_to_revive = 1;
|
uds_fd_table[minorpeer].ready_to_revive = 1;
|
||||||
notify(dev_m_in->m_source);
|
notify(dev_m_in->m_source);
|
||||||
|
@ -298,6 +484,18 @@ PUBLIC int do_connect(message *dev_m_in, message *dev_m_out)
|
||||||
return EIO;
|
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
|
/* look for a socket of the same type that is listening on the
|
||||||
* address we want to connect to
|
* 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;
|
uds_fd_table[i].child = -1;
|
||||||
|
|
||||||
#if DEBUG == 1
|
#if DEBUG == 1
|
||||||
printf("(uds) [%d] {do_connect} revive %d", minor, i);
|
printf("(uds) [%d] {do_connect} revive %d\n", minor, i);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* wake the parent (server) */
|
/* wake the parent (server) */
|
||||||
|
@ -432,7 +630,7 @@ PUBLIC int do_connect(message *dev_m_in, message *dev_m_out)
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG == 1
|
#if DEBUG == 1
|
||||||
printf("(uds) [%d] {do_connect} suspend", minor);
|
printf("(uds) [%d] {do_connect} suspend\n", minor);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* suspend until the server side completes the connection with accept()
|
/* 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)
|
PUBLIC int do_bind(message *dev_m_in, message *dev_m_out)
|
||||||
{
|
{
|
||||||
int minor;
|
int minor, strlen;
|
||||||
struct sockaddr_un addr;
|
struct sockaddr_un addr;
|
||||||
int rc, i;
|
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 */
|
/* 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 */
|
/* bad address */
|
||||||
uds_fd_table[minor].syscall_done = 1;
|
uds_fd_table[minor].syscall_done = 1;
|
||||||
|
|
||||||
uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
|
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. */
|
/* 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);
|
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) */
|
/* 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
|
/* we won't allow you to magically connect your socket to
|
||||||
* someone elses socket
|
* someone elses socket
|
||||||
|
@ -1307,6 +1533,17 @@ PUBLIC int do_sendto(message *dev_m_in, message *dev_m_out)
|
||||||
return EINVAL;
|
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,
|
memcpy(&(uds_fd_table[minor].target), &addr,
|
||||||
sizeof(struct sockaddr_un));
|
sizeof(struct sockaddr_un));
|
||||||
|
|
||||||
|
@ -1352,3 +1589,414 @@ PUBLIC int do_recvfrom(message *dev_m_in, message *dev_m_out)
|
||||||
|
|
||||||
return OK;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -9,7 +9,9 @@
|
||||||
* dev_uds.c, table.c, uds.c
|
* dev_uds.c, table.c, uds.c
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/ucred.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
|
|
||||||
#include <minix/endpoint.h>
|
#include <minix/endpoint.h>
|
||||||
|
@ -17,8 +19,15 @@
|
||||||
/* max connection backlog for incoming connections */
|
/* max connection backlog for incoming connections */
|
||||||
#define UDS_SOMAXCONN 64
|
#define UDS_SOMAXCONN 64
|
||||||
|
|
||||||
/* UDS FD state Flags */
|
typedef void* filp_id_t;
|
||||||
#define UDS_CONNECTING 0x10
|
|
||||||
|
/* 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.
|
* Internal State Information for a socket descriptor.
|
||||||
|
@ -122,6 +131,11 @@ struct uds_fd {
|
||||||
*/
|
*/
|
||||||
int listening;
|
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
|
/* Holds an errno. This is set when a connected socket is
|
||||||
* closed and we need to pass ECONNRESET on to a suspended
|
* closed and we need to pass ECONNRESET on to a suspended
|
||||||
* peer.
|
* peer.
|
||||||
|
|
Loading…
Reference in a new issue