To those wondering why and when this is needed - it is useful for cases when your primary process lacks rights required to open a file or a device (!). So another, privileged process does the open on its behalf and sends the resulting file descriptor to the primary process for processing.
(This is pretty much exactly what this library does--that code is almost identical to lines 89 through 101 in flingfd_send()--so not quite "alternatively" ;P. It also implements receiving the file descriptor, as well as opening the socket, and has some error checking; but the code is only one file with fewer than ten functions wrapping around unix domain sockets.)
> To those wondering why and when this is needed - it is useful for cases when your primary process lacks rights required to open a file or a device (!). So another, privileged process does the open on its behalf and sends the resulting file descriptor to the primary process for processing.
But be careful with who can connect to that socket and grab that fd. If you just name that socket and then tell another process to open it, there's a race. In a traditional privsep scenario the socket between the privileged and unprivileged process is created prior to and shared between them with fork(). Other scenarios (e.g. daemon serving fds to local clients that weren't initially there), you'll need some way to communicate with that client before you can tell it to grab the fd; why not use that ipc socket?
EDIT: Just to clarify, I'm commenting on the approach used by the linked library on github.
> So another, privileged process does the open on its behalf and sends the resulting file descriptor to the primary process for processing.
I must be misunderstanding something. I assume that the unprivileged process still cannot actually read the file, otherwise you could access unauthorized open files by going through every possible file descriptor. What processing can the unprivileged process do? Keep track processes that have open files?
File descriptors are local to a process (after all, fd 0 is each process's personal stdin). The special extra data passed to sendmsg makes the kernel map a new fd in the receiving process, granting it access to the underlying file. It might help to consider that the fds in the two processes are likely not the same number.
The only part you might be missing is that the 'send_fd' command needs to be executed by a cooperating privileged process that 'serves' the fd to the receiver. Since the permission checks are done at the time the fd is opened (and not repeated[1]) the receiving process has the full privileges that the sender had: read, write, truncate, etc.
Receiving the fd via this mechanism is very different that just getting the number of the fd. Nothing is really passed over the socket, rather behind the scenes the kernel is remapping memory within the calling process. It's very similar to what happens when a process 'forks' and its file descriptors are duplicated, but with individual fd granularity.
[1] There are exceptions to this in certain device handlers that use file interfaces, but it holds for regular files.
Permission checks are done when you open[1] a file, not when you otherwise operate on it. So yes, you could access "unauthorized" files. It's up to the sending process whether it wants to share particular filedescriptor to someone else, so you can't gain access to something you're not supposed to though.
[1] I'm not sure about security frameworks, it may be e.g. SELinux provides more granular checks.
Let us journey back in time, to the year 1995. (Technically 1.03 is from 1998, but I'm sure that functions for passing fd's appear in every version.)
qmail-1.03:
fd.h
fd_copy.c
fd_copy.3
fd_move.c
fd_move.3
You could find similar functions in other programs by the same author, e.g., ucspi-tcp, daemontools, etc.
I prefer time-tested, secure code from 1995 to the things you tend to find on Github because this 1990's code is highly portable. It still compiles cleanly 18 years later and is not just tested on one or two systems, e.g., Linux and OSX.
But I'm glad this made the front page. No web browser needed. No installed scripting languages necessary. A single .c file. If only there were more like this on Github.
A very minor gripe, but it seems weird to use the "bool success" return value convention for one function, but the "int return, negative on error" convention for the other.
Also there's a few places where ERRNO is going to get clobbered, eg. by closing the socket before reporting the error back to the caller. A more careful implementation would save errno before calling close.
Otherwise though, good simple abstraction of a relatively obscure feature.
I wrote something similar for sockets (https://github.com/spc476/ipacld) but it's Linux only, since only Linux supports passing the userid/groupid/pid of a process across Unix domain sockets (and I use that for checking credentials).
This library makes the classic error, it returns the first file descriptor that is sent then finishes.
You can then DoS the process by sending it huge numbers of fds instead of just one, which it will omit to close, and thus run out of file descriptors. So to be safe you need to iterate over all the fds and close them.
Yeah, any modern UNIX supports the same sendmsg/SCM_RIGHTS pattern. You might need to tweak the includes and supply your own CMSG_*() macros on some though.
Some older UNIX variants only supported the BSD4.3-style msg_accrights style fd passing, although those are probably nearly extinct at this point.
Can the OP please change the title to append ".. in X lines of C". It's no longer cool to just do stuff... it has to be done in an impressively small number of lines of code to win my upvote.