site_archiver@lists.apple.com Delivered-To: darwin-dev@lists.apple.com User-agent: Mutt/1.5.8i On Sat, Apr 16, 2005 at 01:09:16AM +0300, Dan Bernstein wrote: I'm looking for the authopen source code, if it's available, and for an example of how to use it from within another program with the -stdoutpipe option. The source to authopen is not currently part of Darwin. #include <err.h> #include <errno.h> #include <fcntl.h> #if qDEBUG #include <stdio.h> /* needed for perror */ #endif // qDEBUG #include <sys/types.h> #include <sys/socket.h> #include <unistd.h> #include <sys/wait.h> #include <stdio.h> #if qDEBUG #define dperrret(x) do { perror x; return -1; } while(0) #define dprintf(x) do { printf x; fflush(stdout); } while(0) #define dfflush(x) do { fflush(x); } while(0) #else #define dperrret(x) do { return -1; } while(0) #define dprintf(x) do { } while(0) #define dfflush(x) do { } while(0) #endif /* authopen(3) uses these and they may come in handy */ #define AO_PROGNAME "authopen" #define AO_INSTALL_PATH "/usr/libexec/" #define AO_PATH AO_INSTALL_PATH AO_PROGNAME #define AO_WRITEOPT "-w" #define AO_APPENDOPT "-a" #define AO_PIPEOPT "-stdoutpipe" #define AO_CREATOPT "-c" #define AO_EXCLOPT "-x" #define AO_MODEOPT "-m" #define AO_OFLAGOPT "-o" ssize_t discardfunc(int i, const void* p, size_t l) { return l; } /* ensure authopen's STDOUT is a copy of the pipe */ if(pipe[1] != STDOUT_FILENO) if(dup2(pipe[1], STDOUT_FILENO) != STDOUT_FILENO) err(1, "dup2 failed for STDOUT_FILENO"); /* errors result in child exit */ /* set up arguments */ if(snprintf(oarg, 11, "0x%08x", flags) != 10) dperrret(("snprintf into oarg failed")); if(snprintf(marg, 6, "0%04o", omode) != 5) dperrret(("snprintf into marg failed")); /* now to actually get the fd back */ rval = recv_fd(pipe[0], userfunc); waitpid(pid, &status, 0); return rval; } #include <errno.h> #include <sys/types.h> #include <sys/socket.h> /* struct msghdr */ #include <sys/uio.h> /* struct iovec */ #include <stddef.h> #include <stdlib.h> /* malloc(3) */ #include <unistd.h> static struct cmsghdr *r_cmptr = NULL; /* malloc'ed first time */ #define CONTROLLEN (sizeof(struct cmsghdr) + sizeof(int)) /* size of control buffer to send/recv one file descriptor */ /* Receive a file descriptor from another process (a server). * In addition, any data received from the server is passed * to (*userfunc)(STDERR_FILENO, buf, nbytes). We have a * 2-byte protocol for receiving the fd from send_fd(). */ int recv_fd(int servfd, ssize_t (*userfunc)(int, const void *, size_t)) { int newfd = -1, nread, status; char *ptr, buf[4096]; struct iovec iov[1]; struct msghdr msg; status = -1; for ( ; ; ) { iov[0].iov_base = buf; iov[0].iov_len = sizeof(buf); msg.msg_iov = iov; msg.msg_iovlen = 1; msg.msg_name = NULL; msg.msg_namelen = 0; if (r_cmptr == NULL && (r_cmptr = malloc(CONTROLLEN)) == NULL) return(-1); msg.msg_control = (caddr_t) r_cmptr; msg.msg_controllen = CONTROLLEN; if ((nread = recvmsg(servfd, &msg, 0)) < 0) { if(errno == EINTR) { errno = 0; dprintf(("retrying...\n")); continue; } else dperrret(("recvmsg error")); } else if (nread == 0) { errno = ECONNRESET; dprintf(("connection closed by server\n")); return -1; } /* See if this is the final data with null & status. Null must be next to last byte of buffer, status byte is last byte. Zero status means there must be a file descriptor to receive. */ for (ptr = buf; ptr < &buf[nread]; ) { if (*ptr++ == 0) { if (ptr != &buf[nread-1]) { /* err_dump("message format error"); * this dumped core */ dprintf(("protocol error\n")); errno = EIO; return -1; } status = *ptr & 255; if (status == 0) { if (msg.msg_controllen != CONTROLLEN) { dprintf(("fatal error msg_controllen != CONTROLLEN\n")); errno = EIO; return -1; } /* err_dump("status = 0 but no fd"); */ newfd = *(int *)CMSG_DATA(r_cmptr); /* new descriptor */ } else { newfd = -1; errno = status; } nread -= 2; } } /* if userfunc is NULL, we don't call it */ if (userfunc && nread > 0) if ((*userfunc)(STDERR_FILENO, buf, nread) != nread) return(-1); if (status >= 0) /* final data has arrived */ return(newfd); /* descriptor, or -status */ } } #define CONTROLLEN (sizeof(struct cmsghdr) + sizeof(int)) static struct cmsghdr *s_cmptr = NULL; /* buffer is malloc'ed first time */ /* size of control buffer to send/recv one file descriptor */ /* Pass a file descriptor to another process. * If fd<0, then -fd is sent back instead as the error status. */ int send_fd(int clifd, int fd) { struct iovec iov[1]; struct msghdr msg; char buf[2]; /* send_fd()/recv_fd() 2-byte protocol */ iov[0].iov_base = buf; iov[0].iov_len = 2; msg.msg_iov = iov; msg.msg_iovlen = 1; msg.msg_name = NULL; msg.msg_namelen = 0; if (fd < 0) { dprintf(("sending error %d: %s\n", -fd, strerror(-fd))); msg.msg_control = NULL; msg.msg_controllen = 0; buf[1] = -(char)fd; /* nonzero status means error */ if (buf[1] == 0) buf[1] = 1; /* -256, etc. would screw up protocol */ } else { dprintf(("sending fd\n")); if (s_cmptr==NULL&&(s_cmptr=(struct cmsghdr*)malloc(CONTROLLEN))==NULL) return(-1); s_cmptr->cmsg_level = SOL_SOCKET; s_cmptr->cmsg_type = SCM_RIGHTS; s_cmptr->cmsg_len = CONTROLLEN; msg.msg_control = (caddr_t) s_cmptr; msg.msg_controllen = CONTROLLEN; *(int *)CMSG_DATA(s_cmptr) = fd; /* the fd to pass */ buf[1] = 0; /* zero status means OK */ } buf[0] = 0; /* null byte flag to recv_fd() */ dfflush(stdout); if (sendmsg(clifd, &msg, 0) != 2) return(-1); dprintf(("sendmsg successful\n")); return(0); } -- Soren Spies DiskImages, etc; I/O Kit team Apple Computer, Inc _______________________________________________ Do not post admin requests to the list. They will be ignored. Darwin-dev mailing list (Darwin-dev@lists.apple.com) Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/darwin-dev/site_archiver%40lists.appl... /usr/libexec/authopen is an implementation of an "open server" as described in Stevens' "Advanced Programming in the Unix Environment." The send_fd and recv_fd functions come from that text. Here's an example authopen() function with support (apologies that I'm cribbing this together from various sources; it does compile :): // passfd.h int recv_fd(int servfd, ssize_t (*userfunc)(int, const void *, size_t)); int send_fd(int clifd, int fd); // authopen.h /* * authopen tries to be like open(2) ... returning -1 and letting caller * deal with errno, etc ... now passes everything through to open; needs * to learn to set errno appropriately after getting info from the socket. */ int authopen(const char *path, int flags, mode_t omode) { int pipe[2], pid, rval, status; ssize_t (*userfunc)(int, const void *, size_t); char oarg[11], marg[6]; /* 0x12345678\0 and 01234\0 */ /* could use pipe(2)? */ if(socketpair(AF_UNIX, SOCK_STREAM, 0, pipe) < 0) dperrret(("socketpair failed")); if((pid = fork()) < 0) dperrret(("fork() error")); else if(pid == 0) { /* am child */ close(pipe[0]); /* close the parent's side */ /* fire off authopen itself with flags (execl NULL-termated) */ dprintf((". %s %s %s %s %s %s %s\n", AO_PROGNAME, AO_PIPEOPT, AO_MODEOPT, marg, AO_OFLAGOPT, oarg, path)); if(execl(AO_PATH, AO_PATH, AO_PIPEOPT, AO_MODEOPT, marg, AO_OFLAGOPT, oarg, path, NULL)) err(1, "exec of " AO_PATH " failed"); } /* parent; no 'else' since child exec's or exit's above */ if(close(pipe[1]) < 0) dperrret(("close should not fail")); /* allows recv_fd to spew messages on console or not */ #if qDEBUG #warning enabling output of excess data from authopen userfunc = write; #else userfunc = discardfunc; #endif This email sent to site_archiver@lists.apple.com