diff options
Diffstat (limited to 'sunrpc')
-rw-r--r-- | sunrpc/clnt_unix.c | 80 | ||||
-rw-r--r-- | sunrpc/svc_unix.c | 80 |
2 files changed, 101 insertions, 59 deletions
diff --git a/sunrpc/clnt_unix.c b/sunrpc/clnt_unix.c index 240cdbbce4..761ecafb05 100644 --- a/sunrpc/clnt_unix.c +++ b/sunrpc/clnt_unix.c @@ -434,32 +434,26 @@ clntunix_destroy (CLIENT *h) mem_free ((caddr_t) h, sizeof (CLIENT)); } -#ifdef SCM_CREDENTIALS -struct cmessage { - struct cmsghdr cmsg; - struct ucred cmcred; -}; -#endif - static int -__msgread (int sock, void *buf, size_t cnt) +__msgread (int sock, void *data, size_t cnt) { - struct iovec iov[1]; + struct iovec iov; struct msghdr msg; #ifdef SCM_CREDENTIALS - struct cmessage cm; + static char cm[CMSG_SPACE(sizeof (struct ucred))]; #endif + int len; - iov[0].iov_base = buf; - iov[0].iov_len = cnt; + iov.iov_base = data; + iov.iov_len = cnt; - msg.msg_iov = iov; + msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_name = NULL; msg.msg_namelen = 0; #ifdef SCM_CREDENTIALS - msg.msg_control = (caddr_t)&cm; - msg.msg_controllen = sizeof(struct cmessage); + msg.msg_control = (caddr_t) &cm; + msg.msg_controllen = CMSG_SPACE(sizeof (struct ucred)); #endif msg.msg_flags = 0; @@ -471,43 +465,65 @@ __msgread (int sock, void *buf, size_t cnt) } #endif - return recvmsg (sock, &msg, 0); + restart: + len = recvmsg (sock, &msg, 0); + if (len >= 0) + { + if (msg.msg_flags & MSG_CTRUNC || len == 0) + return 0; + else + return len; + } + if (errno == EINTR) + goto restart; + return -1; } static int -__msgwrite (int sock, void *buf, size_t cnt) +__msgwrite (int sock, void *data, size_t cnt) { #ifndef SCM_CREDENTIALS /* We cannot implement this reliably. */ __set_errno (ENOSYS); return -1; #else - struct iovec iov[1]; + struct iovec iov; struct msghdr msg; - struct cmessage cm; - - iov[0].iov_base = buf; - iov[0].iov_len = cnt; + struct cmsghdr *cmsg = alloca (CMSG_SPACE(sizeof (struct ucred))); + struct ucred cred; + int len; - cm.cmsg.cmsg_type = SCM_CREDENTIALS; - cm.cmsg.cmsg_level = SOL_SOCKET; - cm.cmsg.cmsg_len = sizeof (struct cmessage); /* XXX I'm not sure, if gete?id() is always correct, or if we should use get?id(). But since keyserv needs geteuid(), we have no other chance. It would be much better, if the kernel could pass both to the server. */ - cm.cmcred.pid = __getpid (); - cm.cmcred.uid = __geteuid (); - cm.cmcred.gid = __getegid (); + cred.pid = __getpid (); + cred.uid = __geteuid (); + cred.gid = __getegid (); + + memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_CREDENTIALS; + cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred); - msg.msg_iov = iov; + iov.iov_base = data; + iov.iov_len = cnt; + + msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_name = NULL; msg.msg_namelen = 0; - msg.msg_control = (caddr_t) &cm; - msg.msg_controllen = sizeof (struct cmessage); + msg.msg_control = cmsg; + msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len); msg.msg_flags = 0; - return sendmsg (sock, &msg, 0); + restart: + len = sendmsg (sock, &msg, 0); + if (len >= 0) + return len; + if (errno == EINTR) + goto restart; + return -1; + #endif } diff --git a/sunrpc/svc_unix.c b/sunrpc/svc_unix.c index 0ff26aaaba..a34e54dd71 100644 --- a/sunrpc/svc_unix.c +++ b/sunrpc/svc_unix.c @@ -284,6 +284,8 @@ svcunix_destroy (SVCXPRT *xprt) struct cmessage { struct cmsghdr cmsg; struct ucred cmcred; + /* hack to make sure we have enough memory */ + char dummy[(CMSG_ALIGN (sizeof (struct ucred)) - sizeof (struct ucred) + sizeof (long))]; }; /* XXX This is not thread safe, but since the main functions in svc.c @@ -293,15 +295,16 @@ static struct cmessage cm; #endif static int -__msgread (int sock, void *buf, size_t cnt) +__msgread (int sock, void *data, size_t cnt) { - struct iovec iov[1]; + struct iovec iov; struct msghdr msg; + int len; - iov[0].iov_base = buf; - iov[0].iov_len = cnt; + iov.iov_base = data; + iov.iov_len = cnt; - msg.msg_iov = iov; + msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_name = NULL; msg.msg_namelen = 0; @@ -319,42 +322,65 @@ __msgread (int sock, void *buf, size_t cnt) } #endif - return recvmsg (sock, &msg, 0); + restart: + len = recvmsg (sock, &msg, 0); + if (len >= 0) + { + if (msg.msg_flags & MSG_CTRUNC || len == 0) + return 0; + else + return len; + } + if (errno == EINTR) + goto restart; + return -1; } static int -__msgwrite (int sock, void *buf, size_t cnt) +__msgwrite (int sock, void *data, size_t cnt) { #ifndef SCM_CREDENTIALS /* We cannot implement this reliably. */ __set_errno (ENOSYS); return -1; #else - struct iovec iov[1]; + struct iovec iov; struct msghdr msg; - - iov[0].iov_base = buf; - iov[0].iov_len = cnt; - - cm.cmsg.cmsg_type = SCM_CREDENTIALS; - cm.cmsg.cmsg_level = SOL_SOCKET; - cm.cmsg.cmsg_len = sizeof (struct cmessage); - /* XXX I'm not sure, if we really should use gete?id(), or get?id(). - It would be much better, if the kernel could pass both to the - client. */ - cm.cmcred.pid = __getpid (); - cm.cmcred.uid = __geteuid (); - cm.cmcred.gid = __getegid (); - - msg.msg_iov = iov; + struct cmsghdr *cmsg = &cm.cmsg; + struct ucred cred; + int len; + + /* XXX I'm not sure, if gete?id() is always correct, or if we should use + get?id(). But since keyserv needs geteuid(), we have no other chance. + It would be much better, if the kernel could pass both to the server. */ + cred.pid = __getpid (); + cred.uid = __geteuid (); + cred.gid = __getegid (); + + memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_CREDENTIALS; + cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred); + + iov.iov_base = data; + iov.iov_len = cnt; + + msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_name = NULL; msg.msg_namelen = 0; - msg.msg_control = (caddr_t) &cm; - msg.msg_controllen = sizeof (struct cmessage); + msg.msg_control = cmsg; + msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len); msg.msg_flags = 0; - return sendmsg (sock, &msg, 0); + restart: + len = sendmsg (sock, &msg, 0); + if (len >= 0) + return len; + if (errno == EINTR) + goto restart; + return -1; + #endif } @@ -446,8 +472,8 @@ svcunix_recv (SVCXPRT *xprt, struct rpc_msg *msg) { cd->x_id = msg->rm_xid; /* set up verifiers */ - msg->rm_call.cb_verf.oa_flavor = AUTH_UNIX; #ifdef SCM_CREDENTIALS + msg->rm_call.cb_verf.oa_flavor = AUTH_UNIX; msg->rm_call.cb_verf.oa_base = (caddr_t) &cm; msg->rm_call.cb_verf.oa_length = sizeof (cm); #endif |