[comp.unix.wizards] passing access rights

net@tub.UUCP (Oliver Laumann) (10/20/88)

Although this article contains a question, I think the matter
is `wizardry' enough to justify a posting to comp.unix.wizards.

What I would like to do is to pass a file descriptor from one
process to another one through a connection based on UNIX
domain sockets.  Although the demonstration program attached
to this article works fine under Integrated Solutions 4.3 BSD
and SunOS 4.0, the calls to `sendmsg' and `recvmsg' both
return "Bad address" under vanilla 4.3 BSD on a Microvax.
I can't find the bug; all fields of the message structures
passed to `sendmsg' and `recvmsg' are properly initialized.
Unfortunately, the manual entries for these system calls
do not indicate under what circumstances EFAULT is returned.

Note that the `msg' structures are declared as `static'.
And yes, I know, the programming style is sloppy (returning
no value from main; return values of sys-calls not checked,
etc.); my `real' programs certainly look differently.

Here comes the code; first the server which accepts a
connection on a UNIX domain socket and then opens /etc/passwd
and sends the file descriptor to the client process (note that
I don't want to send any data -- just the file descriptor).

------------------------------------------------------------
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/uio.h>

main () {
    int s, fd;
    struct sockaddr_un a;
    static struct msghdr msg;
    char *name = "foo";

    unlink (name);
    if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1) {
	perror ("socket"); return;
    }
    a.sun_family = AF_UNIX;
    strcpy (a.sun_path, name);
    if (bind (s, (struct sockaddr *)&a, strlen (name)+2) == -1) {
	perror ("bind"); return;
    }
    listen (s, 1);
    s = accept (s, (struct sockaddr *)0, (int *)0);
    if ((fd = open ("/etc/passwd", 0)) == -1) {
	perror ("passwd"); return;
    }
    msg.msg_accrights = (caddr_t)&fd;
    msg.msg_accrightslen = sizeof (fd);
    if (sendmsg (s, &msg, 0) == -1)
	perror ("sendmsg");
}
------------------------------------------------------------

This is the client receiving the file descriptor:

------------------------------------------------------------
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/uio.h>

main () {
    int s, n, fd;
    struct sockaddr_un a;
    static struct msghdr msg;
    char *name = "foo";
    char buf[512];

    if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1) {
	perror ("socket"); return;
    }
    a.sun_family = AF_UNIX;
    strcpy (a.sun_path, name);
    if (connect (s, (struct sockaddr *)&a, strlen (name)+2) == -1) {
	perror ("connect"); return;
    }
    msg.msg_accrights = (caddr_t)&fd;
    msg.msg_accrightslen = sizeof(fd);
    if ((n = recvmsg (s, &msg, 0)) == -1) {
	perror ("recvmsg"); return;
    }
    if ((n = read (fd, buf, 512)) == -1) {
	perror ("read"); return;
    }
    write (1, buf, n);
}
------------------------------------------------------------

Just compile the programs, start the server in the background,
then invoke the client and watch the error messages.

--
Regards,
    Oliver Laumann, Technical University of Berlin, Germany.
    ...!pyramid!tub!net   or   net@TUB.BITNET
    ...!mcvax!unido!tub!net

chris@mimsy.UUCP (Chris Torek) (10/22/88)

In article <705@tub.UUCP> net@tub.UUCP (Oliver Laumann) writes:
>...  Although the demonstration program attached
>to this article works fine under Integrated Solutions 4.3 BSD
>and SunOS 4.0, the calls to `sendmsg' and `recvmsg' both
>return "Bad address" under vanilla 4.3 BSD on a Microvax.
>I can't find the bug; all fields of the message structures
>passed to `sendmsg' and `recvmsg' are properly initialized.
>Unfortunately, the manual entries for these system calls
>do not indicate under what circumstances EFAULT is returned.

As it turns out, the problem is that copyin() may not do what was
intended if it is given a zero length.  In this case, it still probes
one page.  You can get the program to work by giving the address of
some object as `msg.msg_iov': msg.msg_iovlen can still be zero, but
msg.msg_iov must point to something.

Probably copyin() and copyout() should return zero (no error) when
asked to copy no bytes (as should bcopy()), and useracc and kernacc
should grant access to no bytes; then a number of tests for zero
lengths could be dropped elsewhere.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

tchrist@convex.UUCP (Tom Christiansen) (10/22/88)

To make this stuff work, you need to fill in the iovec part
of the message, setting the iovlen to 1.  Odd that Suns don't
care about this;  4.3 Vaxen and Convexen do.

--tom
    Tom Christiansen              {uiucdcs,ut-sally,sun}!convex!tchrist 
    Convex Computer Corporation                     tchrist@convex.COM
	UNIX Support, Training, and System Administration
	    "That's not a bug -- it's a feature!"