/src/qsnet/mqshd.c

https://code.google.com/ · C · 523 lines · 305 code · 88 blank · 130 comment · 74 complexity · 887e2c21394dff279c876e5a3321395d MD5 · raw file

  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. /*-
  27. * Started with BSD rshd which is:
  28. *
  29. * Copyright (c) 1988, 1989 The Regents of the University of California.
  30. * All rights reserved.
  31. *
  32. * Redistribution and use in source and binary forms, with or without
  33. * modification, are permitted provided that the following conditions
  34. * are met:
  35. * 1. Redistributions of source code must retain the above copyright
  36. * notice, this list of conditions and the following disclaimer.
  37. *
  38. * 2. Redistributions in binary form must reproduce the above copyright
  39. * notice, this list of conditions and the following disclaimer in the
  40. * documentation and/or other materials provided with the distribution.
  41. *
  42. * 3. All advertising materials mentioning features or use of this software
  43. * must display the following acknowledgement:
  44. * This product includes software developed by the University of
  45. * California, Berkeley and its contributors.
  46. *
  47. * 4. Neither the name of the University nor the names of its contributors
  48. * may be used to endorse or promote products derived from this software
  49. * without specific prior written permission.
  50. *
  51. * 5. This is free software; you can redistribute it and/or modify it
  52. * under the terms of the GNU General Public License as published
  53. * by the Free Software Foundation; either version 2 of the
  54. * License, or (at your option) any later version.
  55. *
  56. * 6. This is distributed in the hope that it will be useful, but
  57. * WITHOUT ANY WARRANTY; without even the implied warranty of
  58. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  59. * GNU General Public License for more details.
  60. *
  61. * 7. You should have received a copy of the GNU General Public License;
  62. * if not, write to the Free Software Foundation, Inc., 59 Temple
  63. * Place, Suite 330, Boston, MA 02111-1307 USA.
  64. *
  65. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  66. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  67. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  68. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  69. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  70. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  71. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  72. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  73. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  74. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  75. * SUCH DAMAGE.
  76. */
  77. /*
  78. * PAM modifications by Michael K. Johnson <johnsonm@redhat.com>
  79. */
  80. char copyright[] =
  81. "@(#) Copyright (c) 1988, 1989, 2003 The Regents of the University of California.\n"
  82. "All rights reserved.\n";
  83. /*
  84. * From: @(#)mqshd.c 5.38 (Berkeley) 3/2/91
  85. */
  86. char rcsid[] = "$Id$";
  87. /* #include "version.h" */
  88. #if HAVE_CONFIG_H
  89. #include "config.h"
  90. #endif
  91. #if HAVE_UNISTD_H
  92. #include <unistd.h>
  93. #endif
  94. #include <fcntl.h>
  95. #include <sys/socket.h> /* connect */
  96. #include <sys/types.h>
  97. #include <netinet/in.h> /* sockaddr_in, htons */
  98. #include <arpa/inet.h> /* inet_ntoa */
  99. #include <netdb.h> /* gethostbyname */
  100. #include <net/if.h> /* struct ifconf, struct ifreq */
  101. #include <sys/ioctl.h> /* ioctl */
  102. #include <sys/param.h> /* MAXHOSTNAMELEN / INET_ADDRSTRLEN */
  103. #include <stdio.h>
  104. #include <stdlib.h>
  105. #include <string.h>
  106. #include <syslog.h>
  107. #include <errno.h>
  108. #include <munge.h>
  109. #include "src/common/fd.h"
  110. #include "src/common/xmalloc.h"
  111. #include "qshell.h"
  112. #ifndef MAXHOSTNAMELEN
  113. #define MAXHOSTNAMELEN 64
  114. #endif
  115. #ifndef INET_ADDRSTRLEN
  116. #define INET_ADDRSTRLEN 16
  117. #endif
  118. #define MAX_MBUF_SIZE 4096
  119. extern int paranoid;
  120. extern int sent_null;
  121. #define ERRMSGLEN 4096
  122. static char errmsgbuf[ERRMSGLEN];
  123. static const char *errmsg = NULL;
  124. #if USE_PAM
  125. extern char *pam_errmsg;
  126. #endif
  127. static char *munge_parse(char *buf, char *buf_end) {
  128. int len = strlen(buf);
  129. buf += (len + 1);
  130. if (buf >= buf_end) {
  131. syslog(LOG_ERR, "parser went beyond valid data");
  132. errmsg = "Internal Error";
  133. return NULL;
  134. }
  135. return buf;
  136. }
  137. static int getifrlen(struct ifreq *ifr) {
  138. int len;
  139. /* Calculations below are necessary b/c socket addresses can have
  140. * variable length
  141. */
  142. #if HAVE_SA_LEN
  143. if (sizeof(struct sockaddr) > ifr->ifr_addr.sa_len)
  144. len = sizeof(struct sockaddr);
  145. else
  146. len = ifr->ifr_addr.sa_len;
  147. #else /* !HAVE_SA_LEN */
  148. /* For now we only assume AF_INET and AF_INET6 */
  149. switch(ifr->ifr_addr.sa_family) {
  150. #ifdef HAVE_IPV6
  151. case AF_INET6:
  152. len = sizeof(struct sockaddr_in6);
  153. break;
  154. #endif /* HAVE_IPV6 */
  155. case AF_INET:
  156. default:
  157. len = sizeof(struct sockaddr_in);
  158. break;
  159. }
  160. /* On ia32 struct sockaddr_in6/sockaddr_in was the largest
  161. * structure in struct ifreq, but not on ia64. This fixes things
  162. */
  163. if (len < (sizeof(struct ifreq) - IFNAMSIZ))
  164. len = sizeof(struct ifreq) - IFNAMSIZ;
  165. #endif /* HAVE_SA_LEN */
  166. return len;
  167. }
  168. static int check_interfaces(void *munge_addr, int addr_len) {
  169. struct ifconf ifc;
  170. struct ifreq *ifr;
  171. int s, found = 0, lastlen = -1;
  172. int len = sizeof(struct ifreq) * 100;
  173. void *buf = NULL, *ptr = NULL;
  174. struct sockaddr_in *sin;
  175. char *addr;
  176. /* Significant amounts of this code are from Unix Network
  177. * Programming, by R. Stevens, Chapter 16
  178. */
  179. if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  180. syslog(LOG_ERR, "socket call failed: %m");
  181. errmsg = "Internal System Error";
  182. goto bad;
  183. }
  184. /* get all active interfaces */
  185. while(1) {
  186. if ((buf = (char *)malloc(len)) == NULL) {
  187. syslog(LOG_ERR, "malloc failed: %m");
  188. errmsg = "Out of Memory";
  189. goto bad;
  190. }
  191. ifc.ifc_len = len;
  192. ifc.ifc_buf = buf;
  193. if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
  194. syslog(LOG_ERR, "ioctl SIOCGIFCONF failed: %m");
  195. errmsg = "Internal System Error";
  196. goto bad;
  197. }
  198. else {
  199. if (ifc.ifc_len == lastlen)
  200. break;
  201. lastlen = ifc.ifc_len;
  202. }
  203. /* Run ioctl() twice for portability reasons. See Unix Network
  204. * Programming, section 16.6
  205. */
  206. len += 10 * sizeof(struct ifreq);
  207. free(buf);
  208. }
  209. /* get IP addresses for all interfaces */
  210. for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
  211. ifr = (struct ifreq *)ptr;
  212. len = getifrlen(ifr);
  213. ptr += sizeof(ifr->ifr_name) + len;
  214. /* Currently, we only care about IPv4 (i.e. AF_INET) */
  215. if (ifr->ifr_addr.sa_family != AF_INET)
  216. continue;
  217. sin = (struct sockaddr_in *)&ifr->ifr_addr;
  218. /* Skip 127.0.0.1 */
  219. addr = inet_ntoa(sin->sin_addr);
  220. if (strcmp(addr,"127.0.0.1") == 0)
  221. continue;
  222. if (memcmp(munge_addr, (void *)&sin->sin_addr.s_addr, addr_len) == 0) {
  223. found++;
  224. break;
  225. }
  226. }
  227. free(buf);
  228. return found;
  229. bad:
  230. free(buf);
  231. return -1;
  232. }
  233. static int check_munge_ip(char *ip) {
  234. struct in_addr in;
  235. char ipbuf[INET_ADDRSTRLEN];
  236. strncpy(ipbuf, ip, INET_ADDRSTRLEN);
  237. ipbuf[INET_ADDRSTRLEN-1] = '\0';
  238. if (inet_pton(AF_INET, ipbuf, &in) <= 0) {
  239. syslog(LOG_ERR, "failed inet_pton: %m");
  240. errmsg = "Internal System Error";
  241. return -1;
  242. }
  243. return check_interfaces(&in, sizeof(struct in_addr));
  244. }
  245. static void mqshell_get_args(struct sockaddr_in *fromp,
  246. struct qshell_args *args)
  247. {
  248. struct sockaddr_in sin;
  249. struct passwd cred;
  250. int rv = -1;
  251. int buf_length;
  252. unsigned short port = 0;
  253. unsigned int randnum;
  254. char *mptr = NULL;
  255. char *m_end = NULL;
  256. char *m_head = NULL;
  257. char mbuf[MAX_MBUF_SIZE];
  258. char cmdbuf[ARG_MAX + 1];
  259. errmsg = NULL;
  260. args->sock = -1;
  261. /* read munge blob for authentication */
  262. memset(&mbuf[0],0,sizeof(mbuf));
  263. if ((buf_length = fd_null_read_n(0, &mbuf[0], MAX_MBUF_SIZE)) < 0) {
  264. syslog(LOG_ERR, "%s: %m", "mqshd: bad read error.");
  265. errmsg = "Internal System Error";
  266. goto error_out;
  267. }
  268. if (buf_length == 0) {
  269. syslog(LOG_ERR, "mqshd: null munge credential.");
  270. errmsg = "Protocol Error";
  271. goto error_out;
  272. }
  273. /*
  274. * The format of our munge buffer is as follows (each a string terminated
  275. * with a '\0' (null):
  276. *
  277. * SIZE EXAMPLE
  278. * ========== =============
  279. * remote_user_name variable "mhaskell"
  280. * '\0'
  281. * dotted_decimal_address_of_this_server 7-15 bytes "134.9.11.155"
  282. * '\0'
  283. * stderr_port_number 4-8 bytes "50111"
  284. * '\0
  285. * random number 1-8 bytes "1f79ca0e"
  286. * '\0'
  287. * users_command variable "ls -al"
  288. * '\0' '\0'
  289. *
  290. */
  291. mptr = &mbuf[0];
  292. if ((rv = munge_decode(mbuf,0,(void **)&mptr,&buf_length,
  293. &cred.pw_uid,&cred.pw_gid)) != EMUNGE_SUCCESS) {
  294. syslog(LOG_ERR, "%s: %s", "munge_decode error", munge_strerror(rv));
  295. snprintf(errmsgbuf, ERRMSGLEN, "Authentication Failure: %s",
  296. munge_strerror(rv));
  297. errmsg = &errmsgbuf[0];
  298. goto error_out;
  299. }
  300. if ((mptr == NULL) || (buf_length <= 0)) {
  301. syslog(LOG_ERR, "Null munge buffer");
  302. errmsg = "Protocol Error";
  303. goto error_out;
  304. }
  305. m_head = mptr;
  306. m_end = mptr + buf_length;
  307. /* Verify User Id */
  308. if ((args->pwd = getpwnam_common(m_head)) == NULL) {
  309. syslog(LOG_ERR, "bad getpwnam(): %m");
  310. errmsg = "Permission Denied";
  311. goto error_out;
  312. }
  313. if ((args->pwd->pw_uid != cred.pw_uid) && cred.pw_uid != 0) {
  314. syslog(LOG_ERR, "failed credential check: %m");
  315. errmsg = "Permission Denied";
  316. goto error_out;
  317. }
  318. /* Verify IP address */
  319. if ((m_head = munge_parse(m_head, m_end)) == NULL)
  320. goto error_out;
  321. if ((rv = check_munge_ip(m_head)) < 0)
  322. goto error_out;
  323. if (rv == 0) {
  324. syslog(LOG_ERR, "%s: %s", "Munge IP address doesn't match", m_head);
  325. errmsg = "Permission Denied";
  326. goto error_out;
  327. }
  328. /* Verify Port */
  329. if ((m_head = munge_parse(m_head, m_end)) == NULL)
  330. goto error_out;
  331. errno = 0;
  332. port = strtol(m_head, (char **)NULL, 10);
  333. if (errno != 0) {
  334. syslog(LOG_ERR, "%s: %s", "Bad port number from client", m_head);
  335. errmsg = "Internal Error";
  336. goto error_out;
  337. }
  338. if (port != args->port) {
  339. syslog(LOG_ERR, "%s: %d, %d", "Port mismatch", args->port, port);
  340. errmsg = "Protocol Error";
  341. goto error_out;
  342. }
  343. /* Get Random Number */
  344. if ((m_head = munge_parse(m_head, m_end)) == NULL)
  345. goto error_out;
  346. errno = 0;
  347. randnum = strtol(m_head,(char **)NULL,10);
  348. if (errno != 0) {
  349. syslog(LOG_ERR, "%s: %d", "mqshd: Bad random number from client.", randnum);
  350. errmsg = "Internal Error";
  351. goto error_out;
  352. }
  353. if (args->port == 0 && randnum != 0) {
  354. syslog(LOG_ERR,"protocol error, rand should be 0, %d", randnum);
  355. errmsg = "Protocol Error";
  356. goto error_out;
  357. }
  358. /* Get Command */
  359. if ((m_head = munge_parse(m_head, m_end)) == NULL)
  360. goto error_out;
  361. if (strlen(m_head) < ARG_MAX) {
  362. strncpy(&cmdbuf[0], m_head, sizeof(cmdbuf));
  363. cmdbuf[sizeof(cmdbuf) - 1] = '\0';
  364. } else {
  365. syslog(LOG_ERR, "Not enough space for command: %s", m_head);
  366. errmsg = "Command too long";
  367. goto error_out;
  368. }
  369. free(mptr);
  370. mptr = NULL;
  371. if ((args->hostname = findhostname(fromp)) == NULL) {
  372. errmsg = "Host Address Mismatch";
  373. goto error_out;
  374. }
  375. #ifdef USE_PAM
  376. if (pamauth(args->pwd, "mqshell", args->pwd->pw_name,
  377. args->hostname, args->pwd->pw_name ) < 0) {
  378. syslog(LOG_ERR, "PAM failed authentication");
  379. errmsg = pam_errmsg;
  380. goto error_out;
  381. }
  382. #endif
  383. error_out:
  384. /* If desired, setup stderr connection */
  385. args->sock = 0;
  386. if (args->port != 0) {
  387. char c;
  388. if ((args->sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  389. syslog(LOG_ERR,"create socket: %m");
  390. goto bad;
  391. }
  392. sin.sin_family = AF_INET;
  393. sin.sin_port = htons(args->port);
  394. sin.sin_addr.s_addr = fromp->sin_addr.s_addr;
  395. if (connect(args->sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
  396. syslog(LOG_ERR,"%s: %m","connect second port: %m");
  397. goto bad;
  398. }
  399. /* Sync with client to avoid race condition */
  400. rv = read(0,&c,1);
  401. if (rv != 1 || c != '\0') {
  402. syslog (LOG_ERR, "%s", "mqshd: Client not ready.");
  403. goto bad;
  404. }
  405. }
  406. if (errmsg != NULL) {
  407. char buf[BUFSIZ], *bp = buf;
  408. snprintf(bp, sizeof(buf)-1, "%c%s\n", '\01', errmsg);
  409. fd_write_n(args->sock, buf, strlen(buf));
  410. goto bad;
  411. }
  412. /* Write random number to stderr */
  413. if (args->port != 0) {
  414. randnum = htonl(randnum);
  415. if ((rv = fd_write_n(args->sock, &randnum, sizeof(randnum))) == -1) {
  416. syslog(LOG_ERR, "%s: %m", "write to stderr port: ");
  417. error("Write error, %s\n", strerror(errno));
  418. goto bad;
  419. }
  420. }
  421. args->remuser = NULL;
  422. args->locuser = NULL;
  423. args->cmdbuf = Strdup(cmdbuf);
  424. return;
  425. bad:
  426. free(mptr);
  427. close(args->sock);
  428. exit(1);
  429. }
  430. int main(int argc, char *argv[]) {
  431. return qshell(argc, argv, &mqshell_get_args, "mqshd", 0);
  432. }
  433. /*
  434. * vi: tabstop=4 shiftwidth=4 expandtab
  435. */