PageRenderTime 47ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/src/pdsh/privsep.c

https://code.google.com/
C | 338 lines | 229 code | 63 blank | 46 comment | 29 complexity | b5adc6fef3d4874507c14338fba5dfa5 MD5 | raw file
Possible License(s): GPL-2.0
  1. /*****************************************************************************\
  2. * $Id$
  3. *****************************************************************************
  4. * Copyright (C) 2001-2006 The Regents of the University of California.
  5. * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
  6. * Written by Jim Garlick <garlick@llnl.gov>.
  7. * UCRL-CODE-2003-005.
  8. *
  9. * This file is part of Pdsh, a parallel remote shell program.
  10. * For details, see <http://www.llnl.gov/linux/pdsh/>.
  11. *
  12. * Pdsh is free software; you can redistribute it and/or modify it under
  13. * the terms of the GNU General Public License as published by the Free
  14. * Software Foundation; either version 2 of the License, or (at your option)
  15. * any later version.
  16. *
  17. * Pdsh is distributed in the hope that it will be useful, but WITHOUT ANY
  18. * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  19. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  20. * details.
  21. *
  22. * You should have received a copy of the GNU General Public License along
  23. * with Pdsh; if not, write to the Free Software Foundation, Inc.,
  24. * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  25. \*****************************************************************************/
  26. #if HAVE_CONFIG_H
  27. # include <config.h>
  28. #endif
  29. #include <sys/types.h>
  30. #if HAVE_SYS_UIO_H
  31. # include <sys/uio.h>
  32. #endif
  33. #include <sys/socket.h>
  34. #include <sys/wait.h>
  35. #include <unistd.h>
  36. #include <pthread.h>
  37. #include <stdlib.h>
  38. #include <netdb.h> /* rresvport */
  39. #include <assert.h>
  40. #include <string.h>
  41. #include <errno.h>
  42. #include "src/common/err.h"
  43. #include "src/common/fd.h"
  44. #define CONTROLLEN sizeof (struct cmsghdr) + sizeof (int)
  45. static pthread_mutex_t privsep_mutex = PTHREAD_MUTEX_INITIALIZER;
  46. static pid_t cpid;
  47. static int client_fd = -1;
  48. static int server_fd = -1;
  49. uid_t user_uid = -1;
  50. gid_t user_gid = -1;
  51. uid_t priv_uid = -1;
  52. gid_t priv_gid = -1;
  53. /*
  54. * Top 16 bits of port sent to privsep server is used to encode
  55. * the address family (for rresvport_af()). Currently, value is
  56. * either AF_INET AF_INET6 (if zero, then AF_INET).
  57. */
  58. static int privsep_get_family (int *lport)
  59. {
  60. int family = (*lport>>16) & 0xffff;
  61. /*
  62. * Mask out family from lport:
  63. */
  64. *lport &= 0xffff;
  65. return (family ? family : AF_INET);
  66. }
  67. static int privsep_set_family (int *lport, int family)
  68. {
  69. if (family > 0xffff)
  70. return (-1);
  71. *lport |= (family<<16);
  72. return (0);
  73. }
  74. static int create_socketpair (void)
  75. {
  76. int pfds[2];
  77. if (socketpair (AF_UNIX, SOCK_STREAM, 0, pfds) < 0) {
  78. err ("%p: socketpair failed in privilege separation: %m\n");
  79. return -1;
  80. }
  81. client_fd = pfds[0];
  82. server_fd = pfds[1];
  83. return (0);
  84. }
  85. static void drop_privileges (void)
  86. {
  87. user_uid = getuid ();
  88. priv_uid = geteuid ();
  89. user_gid = getgid ();
  90. priv_gid = getegid ();
  91. #ifdef _POSIX_SAVED_IDS
  92. seteuid (user_uid);
  93. setegid (user_gid);
  94. #else
  95. setreuid (priv_uid, user_uid);
  96. setregid (priv_gid, user_gid);
  97. #endif
  98. }
  99. static int send_rresvport (int pipefd, int fd, int lport)
  100. {
  101. struct iovec iov[1];
  102. struct msghdr msg;
  103. #if !HAVE_MSGHDR_ACCRIGHTS
  104. struct cmsghdr *cmsg;
  105. char * buf[CONTROLLEN];
  106. cmsg = (struct cmsghdr *) &buf;
  107. #endif
  108. memset (&msg, 0, sizeof (msg));
  109. iov->iov_base = (void *) &lport;
  110. iov->iov_len = sizeof (lport);
  111. msg.msg_iov = iov;
  112. msg.msg_iovlen = 1;
  113. #if HAVE_MSGHDR_ACCRIGHTS
  114. if (fd < 0) {
  115. msg.msg_accrights = NULL;
  116. msg.msg_accrightslen = 0;
  117. } else {
  118. msg.msg_accrights = (caddr_t) &fd;
  119. msg.msg_accrightslen = sizeof (int);
  120. }
  121. #else
  122. if (fd < 0) {
  123. msg.msg_control = NULL;
  124. msg.msg_controllen = 0;
  125. lport = -1;
  126. } else {
  127. cmsg->cmsg_level = SOL_SOCKET;
  128. cmsg->cmsg_type = SCM_RIGHTS;
  129. cmsg->cmsg_len = CONTROLLEN;
  130. msg.msg_control = (caddr_t) cmsg;
  131. msg.msg_controllen = CONTROLLEN;
  132. * (int *) CMSG_DATA(cmsg) = fd;
  133. }
  134. #endif
  135. if (sendmsg (pipefd, &msg, 0) != sizeof (int)) {
  136. err ("%p: privsep: sendmsg: %m\n");
  137. return (-1);
  138. }
  139. return (0);
  140. }
  141. static int recv_rresvport (int pipefd, int *lptr)
  142. {
  143. int fd = -1;
  144. struct iovec iov[1];
  145. struct msghdr msg;
  146. #if !HAVE_MSGHDR_ACCRIGHTS
  147. struct cmsghdr *cmsg;
  148. char * buf[CONTROLLEN];
  149. cmsg = (struct cmsghdr *) &buf;
  150. #endif
  151. memset (&msg, 0, sizeof (msg));
  152. iov->iov_base = (void *) lptr;
  153. iov->iov_len = sizeof (int);
  154. msg.msg_iov = iov;
  155. msg.msg_iovlen = 1;
  156. #if HAVE_MSGHDR_ACCRIGHTS
  157. msg.msg_accrights = (caddr_t) &fd;
  158. msg.msg_accrightslen = sizeof (int);
  159. #else /* !HAVE_MSGHDR_ACCRIGHTS */
  160. cmsg->cmsg_level = SOL_SOCKET;
  161. cmsg->cmsg_type = SCM_RIGHTS;
  162. cmsg->cmsg_len = CONTROLLEN;
  163. msg.msg_control = (caddr_t) cmsg;
  164. msg.msg_controllen = CONTROLLEN;
  165. #endif
  166. if (recvmsg (pipefd, &msg, 0) < 0)
  167. err ("%p: privsep: recvmsg: %m\n");
  168. if (*lptr < 0)
  169. return (-1);
  170. #if !HAVE_MSGHDR_ACCRIGHTS
  171. fd = *(int *) CMSG_DATA (cmsg);
  172. #endif
  173. return (fd);
  174. }
  175. static int p_rresvport_af (int *port, int family)
  176. {
  177. #if HAVE_RRESVPORT_AF
  178. return rresvport_af (port, family);
  179. #else
  180. /* Family must be AF_INET
  181. */
  182. if (family != AF_INET)
  183. err ("%p: rresvport called with family != AF_INET!\n");
  184. /* ignore family != AF_INET */
  185. return rresvport (port);
  186. #endif
  187. }
  188. static int privsep_server (void)
  189. {
  190. int rc;
  191. int lport;
  192. close (client_fd);
  193. /*
  194. * for each request on server_fd create a reserved port and
  195. * send the created fd back to the client.
  196. */
  197. while ((rc = read (server_fd, &lport, sizeof (lport))) > 0) {
  198. int family = privsep_get_family (&lport);
  199. int s = p_rresvport_af (&lport, family);
  200. send_rresvport (server_fd, s, lport);
  201. close (s);
  202. }
  203. if (rc < 0)
  204. err ("%p: privsep: server read failed: %m\n");
  205. close (server_fd);
  206. return (0);
  207. }
  208. static int create_privileged_child (void)
  209. {
  210. if ((cpid = fork ()) < 0) {
  211. err ("%p: fork failed in privilege separation: %m\n");
  212. return -1;
  213. }
  214. if (cpid == 0) {
  215. /*
  216. * Child: become privilege port server.
  217. */
  218. privsep_server ();
  219. exit (0);
  220. }
  221. /*
  222. * Parent: drop privileges, close server_fd and return.
  223. */
  224. close (server_fd);
  225. drop_privileges ();
  226. return (0);
  227. }
  228. int privsep_init (void)
  229. {
  230. if (geteuid() == getuid())
  231. return 0;
  232. if (create_socketpair () < 0)
  233. return -1;
  234. return (create_privileged_child ());
  235. }
  236. int privsep_fini (void)
  237. {
  238. int status;
  239. if (client_fd < 0 || cpid < 0)
  240. return (0);
  241. close (client_fd);
  242. if (waitpid (cpid, &status, 0) < 0) {
  243. err ("%p: failed to reap priveleged child: %m\n");
  244. return (-1);
  245. }
  246. if (status)
  247. err ("%p: privileged chiled exited with status %d\n", status);
  248. return (0);
  249. }
  250. int privsep_rresvport_af (int *lport, int family)
  251. {
  252. int s = -1;
  253. if (client_fd < 0)
  254. return (p_rresvport_af (lport, family));
  255. if (privsep_set_family (lport, family) < 0) {
  256. err ("%p: privsep_rresvport_af: Invalid family %d\n", family);
  257. errno = EINVAL;
  258. return (-1);
  259. }
  260. if ((errno = pthread_mutex_lock (&privsep_mutex)))
  261. errx ("%p: %s:%d: mutex_lock: %m\n", __FILE__, __LINE__);
  262. if (write (client_fd, lport, sizeof (*lport)) < 0) {
  263. err ("%p: privsep: client write: %m\n");
  264. goto out;
  265. }
  266. s = recv_rresvport (client_fd, lport);
  267. out:
  268. if ((errno = pthread_mutex_unlock (&privsep_mutex)))
  269. errx ("%p: %s:%d: mutex_unlock: %m\n", __FILE__, __LINE__);
  270. return (s);
  271. }
  272. int privsep_rresvport (int *lport)
  273. {
  274. return privsep_rresvport_af (lport, AF_INET);
  275. }