--- sysdeps/mach/hurd/sendmsg.c | 140 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 127 insertions(+), 13 deletions(-) --- a/sysdeps/mach/hurd/sendmsg.c +++ b/sysdeps/mach/hurd/sendmsg.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2001,2002,2004,2010 Free Software Foundation, Inc. +/* Copyright (C) 2001,2002,2004,2010,2013 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -33,8 +34,10 @@ { error_t err = 0; struct cmsghdr *cmsg; - mach_port_t *ports = NULL; - mach_msg_type_number_t nports = 0; + mach_port_t *ports = NULL, *rports= NULL, *cports = NULL; + mach_msg_type_number_t nports = 0, nrights = 0, ncreds = 0; + mach_port_t ref = NULL; + struct cmsgcred *ucredp = NULL; int *fds, nfds; struct sockaddr_un *addr = message->msg_name; socklen_t addr_len = message->msg_namelen; @@ -107,16 +110,17 @@ } /* SCM_RIGHTS support: get the number of fds to send. */ - cmsg = CMSG_FIRSTHDR (message); - for (; cmsg; cmsg = CMSG_NXTHDR (message, cmsg)) + for (cmsg = CMSG_FIRSTHDR (message); + cmsg != NULL; + cmsg = CMSG_NXTHDR (message, cmsg)) if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) - nports += (cmsg->cmsg_len - CMSG_ALIGN (sizeof (struct cmsghdr))) + nrights += (cmsg->cmsg_len - CMSG_ALIGN (sizeof (struct cmsghdr))) / sizeof (int); - if (nports) - ports = __alloca (nports * sizeof (mach_port_t)); + if (nrights) + rports = __alloca (nrights * sizeof (mach_port_t)); - nports = 0; + nrights = 0; for (cmsg = CMSG_FIRSTHDR (message); cmsg; cmsg = CMSG_NXTHDR (message, cmsg)) @@ -132,10 +136,10 @@ err = HURD_DPORT_USE (fds[i], ({ - err = __io_restrict_auth (port, &ports[nports], + err = __io_restrict_auth (port, &rports[nrights], 0, 0, 0, 0); if (! err) - nports++; + nrights++; /* We pass the flags in the control data. */ fds[i] = descriptor->flags; err; @@ -147,6 +151,51 @@ } } + /* + SCM_CREDS support: Create and send the credentials data together + with the rendezvous port ref. + */ + ncreds = 0; + for (cmsg = CMSG_FIRSTHDR (message); + cmsg != NULL; + cmsg = CMSG_NXTHDR (message, cmsg)) + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDS) + ncreds += 1; + + /* FIXME: Currently only ONE port is supported, error out if more */ + if (ncreds != 0 && ncreds != 1) + { + /* FIXME: Which error to issue here? */ + err = EGRATUITOUS; + goto out; + } + if (ncreds == 1) + cports = __alloca (ncreds * sizeof (mach_port_t)); + + for (cmsg = CMSG_FIRSTHDR (message); + cmsg; + cmsg = CMSG_NXTHDR (message, cmsg)) + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDS) + { + ref = __mach_reply_port (); + err = mach_port_insert_right (mach_task_self (), ref, + ref, MACH_MSG_TYPE_MAKE_SEND); + if (err) + goto out; + cports[0] = ref; + + ucredp = (struct cmsgcred *) CMSG_DATA(cmsg); + /* Fill in credentials data */ + ucredp->cmcred_pid = __getpid(); + ucredp->cmcred_uid = __getuid(); + ucredp->cmcred_euid = __geteuid(); + ucredp->cmcred_gid = __getgid(); + /* egid not in struct csmgcred */ + ucredp->cmcred_ngroups = + __getgroups (sizeof (ucredp->cmcred_groups) / sizeof (gid_t), + ucredp->cmcred_groups); + } + if (addr) { if (addr->sun_family == AF_LOCAL) @@ -172,6 +221,52 @@ err = EIEIO; } + int incr = 0, k, l; + int *idx = NULL; + nports = nrights + ncreds; + if (nports > 0) + { + ports = __alloca (nports * sizeof (mach_port_t)); + idx = __alloca (nports * sizeof (char)); + } + + k = 0; + for (cmsg = CMSG_FIRSTHDR (message); + cmsg != NULL; + cmsg = CMSG_NXTHDR (message, cmsg)) + if (cmsg->cmsg_level == SOL_SOCKET) + { + if (cmsg->cmsg_type == SCM_RIGHTS) + { + incr = (cmsg->cmsg_len - CMSG_ALIGN (sizeof (struct cmsghdr))) + / sizeof (int); + for (l=0; l < incr; l++) + idx[k+l] = 'r'; + k++; + } + if (cmsg->cmsg_type == SCM_CREDS) + { + idx[k] = 'c'; + k++; + } + } + + /* Copy rports and cports arrays to ports array */ + k = 0, l = 0; + for (i = 0; i < nports; i++) + { + if (idx[i] == 'r') + { + ports[i] = rports[k]; + k++; + } + if (idx[i] == 'c') + { + ports[i] = cports[l]; + l++; + } + } + err = HURD_DPORT_USE (fd, ({ if (err) @@ -198,9 +293,35 @@ })); socketrpc = 1; + /* + SCM_CREDS support: call __auth_user_authenticate matched with a + call to __auth_server_authenticate in recvmsg + */ + /* FIXME: Currently only ONE port is used */ + for (cmsg = CMSG_FIRSTHDR (message); + cmsg; + cmsg = CMSG_NXTHDR (message, cmsg)) + { + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDS) + { + //auth_t auth = getauth (); // deallocate auth if used!! + mach_port_t newport; + + err = __USEPORT (AUTH, __auth_user_authenticate (port, + ref, MACH_MSG_TYPE_MAKE_SEND, + &newport)); + if (err) + goto out; + } + } + out: - for (i = 0; i < nports; i++) - __mach_port_deallocate (__mach_task_self (), ports[i]); + for (i = 0; i < nrights; i++) + __mach_port_deallocate (__mach_task_self (), rports[i]); + if (ncreds == 1) + __mach_port_deallocate (__mach_task_self (), cports[0]); + //__mach_port_deallocate (__mach_task_self (), ref); + __mach_port_destroy (__mach_task_self (), ref); if (dealloc) __vm_deallocate (__mach_task_self (), data.addr, len);