ptg10805159
648 Advanced IPC Chapter 17
for (ptr = buf; ptr < &buf[nr]; ) {
if (*ptr++ == 0) {
if (ptr != &buf[nr-1])
err_dump("message format error");
status = *ptr & 0xFF; /* prevent sign extension */
if (status == 0) {
if (msg.msg_controllen != CONTROLLEN)
err_dump("status = 0 but no fd");
newfd = *(int *)CMSG_DATA(cmptr);
}else {
newfd = -status;
}
nr -= 2;
}
}
if (nr > 0 && (*userfunc)(STDERR_FILENO, buf, nr) != nr)
return(-1);
if (status >= 0) /* final data has arrived */
return(newfd); /* descriptor, or -status */
}
}
Figure 17.14Receiving a file descriptor over a UNIX domain socket
Note that we arealways prepared to receive a descriptor (we setmsg_controland
msg_controllenbeforeeach call to recvmsg), but only ifmsg_controllenis
nonzero on return did we actually receive a descriptor.
Recall the hoops we needed to jump through to determine the identity of the caller
in theserv_acceptfunction (Figure17.9). It would have been better for the kernel to
pass us the credentials of the caller on return from the call toaccept.Some UNIX
domain socket implementations provide similar functionality when exchanging
messages, but their interfaces differ.
FreeBSD 8.0 and Linux 3.2.0 provide support for sending credentials over UNIX domain
sockets, but they do it differently.Mac OS X 10.6.8 is derived in part from FreeBSD, but has
credential passing disabled. Solaris 10 doesn’t support sending credentials over UNIX domain
sockets. However, it supports the ability to obtain the credentials of a process passing a file
descriptor over a STREAMS pipe, although we do not discuss the details here.
With FreeBSD, credentials aretransmitted as acmsgcredstructure:
#define CMGROUP_MAX 16
struct cmsgcred {
pid_t cmcred_pid; /* sender’s process ID */
uid_t cmcred_uid; /* sender’s real UID */
uid_t cmcred_euid; /* sender’s effective UID */
gid_t cmcred_gid; /* sender’s real GID */
short cmcred_ngroups; /* number of groups */
gid_t cmcred_groups[CMGROUP_MAX]; /* groups */
};