/crypto/heimdal/appl/rcp/rcp.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 789 lines · 666 code · 61 blank · 62 comment · 230 complexity · 3f848dbf1d8a39bc70b29d014efd7603 MD5 · raw file

  1. /*
  2. * Copyright (c) 1983, 1990, 1992, 1993
  3. * The Regents of the University of California. All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the University nor the names of its contributors
  14. * may be used to endorse or promote products derived from this software
  15. * without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  21. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. * SUCH DAMAGE.
  28. */
  29. #include "rcp_locl.h"
  30. #include <getarg.h>
  31. #define RSH_PROGRAM "rsh"
  32. struct passwd *pwd;
  33. uid_t userid;
  34. int errs, remin, remout;
  35. int pflag, iamremote, iamrecursive, targetshouldbedirectory;
  36. int doencrypt, noencrypt;
  37. int usebroken, usekrb4, usekrb5, forwardtkt;
  38. char *port;
  39. int eflag = 0;
  40. #define CMDNEEDS 64
  41. char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */
  42. int response (void);
  43. void rsource (char *, struct stat *);
  44. void sink (int, char *[]);
  45. void source (int, char *[]);
  46. void tolocal (int, char *[]);
  47. void toremote (char *, int, char *[]);
  48. int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout);
  49. static int fflag, tflag;
  50. static int version_flag, help_flag;
  51. struct getargs args[] = {
  52. { NULL, '4', arg_flag, &usekrb4, "use Kerberos 4 authentication" },
  53. { NULL, '5', arg_flag, &usekrb5, "use Kerberos 5 authentication" },
  54. { NULL, 'F', arg_flag, &forwardtkt, "forward credentials" },
  55. { NULL, 'K', arg_flag, &usebroken, "use BSD authentication" },
  56. { NULL, 'P', arg_string, &port, "non-default port", "port" },
  57. { NULL, 'p', arg_flag, &pflag, "preserve file permissions" },
  58. { NULL, 'r', arg_flag, &iamrecursive, "recursive mode" },
  59. { NULL, 'x', arg_flag, &doencrypt, "use encryption" },
  60. { NULL, 'z', arg_flag, &noencrypt, "don't encrypt" },
  61. { NULL, 'd', arg_flag, &targetshouldbedirectory },
  62. { NULL, 'e', arg_flag, &eflag, "passed to rsh" },
  63. { NULL, 'f', arg_flag, &fflag },
  64. { NULL, 't', arg_flag, &tflag },
  65. { "version", 0, arg_flag, &version_flag },
  66. { "help", 0, arg_flag, &help_flag }
  67. };
  68. static void
  69. usage (int ret)
  70. {
  71. arg_printusage (args,
  72. sizeof(args) / sizeof(args[0]),
  73. NULL,
  74. "file1 file2|file... directory");
  75. exit (ret);
  76. }
  77. int
  78. main(int argc, char **argv)
  79. {
  80. char *targ;
  81. int optind = 0;
  82. setprogname(argv[0]);
  83. if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv,
  84. &optind))
  85. usage (1);
  86. if(help_flag)
  87. usage(0);
  88. if (version_flag) {
  89. print_version (NULL);
  90. return 0;
  91. }
  92. iamremote = (fflag || tflag);
  93. argc -= optind;
  94. argv += optind;
  95. if ((pwd = getpwuid(userid = getuid())) == NULL)
  96. errx(1, "unknown user %d", (int)userid);
  97. remin = STDIN_FILENO; /* XXX */
  98. remout = STDOUT_FILENO;
  99. if (fflag) { /* Follow "protocol", send data. */
  100. (void)response();
  101. source(argc, argv);
  102. exit(errs);
  103. }
  104. if (tflag) { /* Receive data. */
  105. sink(argc, argv);
  106. exit(errs);
  107. }
  108. if (argc < 2)
  109. usage(1);
  110. if (argc > 2)
  111. targetshouldbedirectory = 1;
  112. remin = remout = -1;
  113. /* Command to be executed on remote system using "rsh". */
  114. snprintf(cmd, sizeof(cmd),
  115. "rcp%s%s%s", iamrecursive ? " -r" : "",
  116. pflag ? " -p" : "", targetshouldbedirectory ? " -d" : "");
  117. signal(SIGPIPE, lostconn);
  118. if ((targ = colon(argv[argc - 1]))) /* Dest is remote host. */
  119. toremote(targ, argc, argv);
  120. else {
  121. tolocal(argc, argv); /* Dest is local host. */
  122. if (targetshouldbedirectory)
  123. verifydir(argv[argc - 1]);
  124. }
  125. exit(errs);
  126. }
  127. void
  128. toremote(char *targ, int argc, char **argv)
  129. {
  130. int i;
  131. char *bp, *host, *src, *suser, *thost, *tuser;
  132. *targ++ = 0;
  133. if (*targ == 0)
  134. targ = ".";
  135. if ((thost = strchr(argv[argc - 1], '@')) != NULL) {
  136. /* user@host */
  137. *thost++ = 0;
  138. tuser = argv[argc - 1];
  139. if (*tuser == '\0')
  140. tuser = NULL;
  141. else if (!okname(tuser))
  142. exit(1);
  143. } else {
  144. thost = argv[argc - 1];
  145. tuser = NULL;
  146. }
  147. thost = unbracket(thost);
  148. for (i = 0; i < argc - 1; i++) {
  149. src = colon(argv[i]);
  150. if (src) { /* remote to remote */
  151. int ret;
  152. *src++ = 0;
  153. if (*src == 0)
  154. src = ".";
  155. host = strchr(argv[i], '@');
  156. if (host) {
  157. *host++ = '\0';
  158. host = unbracket(host);
  159. suser = argv[i];
  160. if (*suser == '\0')
  161. suser = pwd->pw_name;
  162. else if (!okname(suser))
  163. continue;
  164. ret = asprintf(&bp,
  165. "%s%s %s -l %s -n %s %s '%s%s%s:%s'",
  166. _PATH_RSH, eflag ? " -e" : "",
  167. host, suser, cmd, src,
  168. tuser ? tuser : "", tuser ? "@" : "",
  169. thost, targ);
  170. } else {
  171. host = unbracket(argv[i]);
  172. ret = asprintf(&bp,
  173. "exec %s%s %s -n %s %s '%s%s%s:%s'",
  174. _PATH_RSH, eflag ? " -e" : "",
  175. host, cmd, src,
  176. tuser ? tuser : "", tuser ? "@" : "",
  177. thost, targ);
  178. }
  179. if (ret == -1)
  180. err (1, "malloc");
  181. susystem(bp);
  182. free(bp);
  183. } else { /* local to remote */
  184. if (remin == -1) {
  185. if (asprintf(&bp, "%s -t %s", cmd, targ) == -1)
  186. err (1, "malloc");
  187. host = thost;
  188. if (do_cmd(host, tuser, bp, &remin, &remout) < 0)
  189. exit(1);
  190. if (response() < 0)
  191. exit(1);
  192. free(bp);
  193. }
  194. source(1, argv+i);
  195. }
  196. }
  197. }
  198. void
  199. tolocal(int argc, char **argv)
  200. {
  201. int i;
  202. char *bp, *host, *src, *suser;
  203. for (i = 0; i < argc - 1; i++) {
  204. int ret;
  205. if (!(src = colon(argv[i]))) { /* Local to local. */
  206. ret = asprintf(&bp, "exec %s%s%s %s %s", _PATH_CP,
  207. iamrecursive ? " -PR" : "", pflag ? " -p" : "",
  208. argv[i], argv[argc - 1]);
  209. if (ret == -1)
  210. err (1, "malloc");
  211. if (susystem(bp))
  212. ++errs;
  213. free(bp);
  214. continue;
  215. }
  216. *src++ = 0;
  217. if (*src == 0)
  218. src = ".";
  219. if ((host = strchr(argv[i], '@')) == NULL) {
  220. host = argv[i];
  221. suser = pwd->pw_name;
  222. } else {
  223. *host++ = 0;
  224. suser = argv[i];
  225. if (*suser == '\0')
  226. suser = pwd->pw_name;
  227. else if (!okname(suser))
  228. continue;
  229. }
  230. ret = asprintf(&bp, "%s -f %s", cmd, src);
  231. if (ret == -1)
  232. err (1, "malloc");
  233. if (do_cmd(host, suser, bp, &remin, &remout) < 0) {
  234. free(bp);
  235. ++errs;
  236. continue;
  237. }
  238. free(bp);
  239. sink(1, argv + argc - 1);
  240. close(remin);
  241. remin = remout = -1;
  242. }
  243. }
  244. void
  245. source(int argc, char **argv)
  246. {
  247. struct stat stb;
  248. static BUF buffer;
  249. BUF *bp;
  250. off_t i;
  251. off_t amt;
  252. int fd, haderr, indx, result;
  253. char *last, *name, buf[BUFSIZ];
  254. for (indx = 0; indx < argc; ++indx) {
  255. name = argv[indx];
  256. if ((fd = open(name, O_RDONLY, 0)) < 0)
  257. goto syserr;
  258. if (fstat(fd, &stb)) {
  259. syserr: run_err("%s: %s", name, strerror(errno));
  260. goto next;
  261. }
  262. if (S_ISDIR(stb.st_mode) && iamrecursive) {
  263. rsource(name, &stb);
  264. goto next;
  265. } else if (!S_ISREG(stb.st_mode)) {
  266. run_err("%s: not a regular file", name);
  267. goto next;
  268. }
  269. if ((last = strrchr(name, '/')) == NULL)
  270. last = name;
  271. else
  272. ++last;
  273. if (pflag) {
  274. /*
  275. * Make it compatible with possible future
  276. * versions expecting microseconds.
  277. */
  278. snprintf(buf, sizeof(buf), "T%ld 0 %ld 0\n",
  279. (long)stb.st_mtime,
  280. (long)stb.st_atime);
  281. write(remout, buf, strlen(buf));
  282. if (response() < 0)
  283. goto next;
  284. }
  285. #undef MODEMASK
  286. #define MODEMASK (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)
  287. snprintf(buf, sizeof(buf), "C%04o %lu %s\n",
  288. (unsigned int)(stb.st_mode & MODEMASK),
  289. (unsigned long)stb.st_size,
  290. last);
  291. write(remout, buf, strlen(buf));
  292. if (response() < 0)
  293. goto next;
  294. if ((bp = allocbuf(&buffer, fd, BUFSIZ)) == NULL) {
  295. next: close(fd);
  296. continue;
  297. }
  298. /* Keep writing after an error so that we stay sync'd up. */
  299. for (haderr = i = 0; i < stb.st_size; i += bp->cnt) {
  300. amt = bp->cnt;
  301. if (i + amt > stb.st_size)
  302. amt = stb.st_size - i;
  303. if (!haderr) {
  304. result = read(fd, bp->buf, (size_t)amt);
  305. if (result != amt)
  306. haderr = result >= 0 ? EIO : errno;
  307. }
  308. if (haderr)
  309. write(remout, bp->buf, amt);
  310. else {
  311. result = write(remout, bp->buf, (size_t)amt);
  312. if (result != amt)
  313. haderr = result >= 0 ? EIO : errno;
  314. }
  315. }
  316. if (close(fd) && !haderr)
  317. haderr = errno;
  318. if (!haderr)
  319. write(remout, "", 1);
  320. else
  321. run_err("%s: %s", name, strerror(haderr));
  322. response();
  323. }
  324. }
  325. void
  326. rsource(char *name, struct stat *statp)
  327. {
  328. DIR *dirp;
  329. struct dirent *dp;
  330. char *last, *vect[1], path[MAXPATHLEN];
  331. if (!(dirp = opendir(name))) {
  332. run_err("%s: %s", name, strerror(errno));
  333. return;
  334. }
  335. last = strrchr(name, '/');
  336. if (last == 0)
  337. last = name;
  338. else
  339. last++;
  340. if (pflag) {
  341. snprintf(path, sizeof(path), "T%ld 0 %ld 0\n",
  342. (long)statp->st_mtime,
  343. (long)statp->st_atime);
  344. write(remout, path, strlen(path));
  345. if (response() < 0) {
  346. closedir(dirp);
  347. return;
  348. }
  349. }
  350. snprintf(path, sizeof(path),
  351. "D%04o %d %s\n",
  352. (unsigned int)(statp->st_mode & MODEMASK), 0, last);
  353. write(remout, path, strlen(path));
  354. if (response() < 0) {
  355. closedir(dirp);
  356. return;
  357. }
  358. while ((dp = readdir(dirp)) != NULL) {
  359. if (dp->d_ino == 0)
  360. continue;
  361. if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
  362. continue;
  363. if (strlen(name) + 1 + strlen(dp->d_name) >= MAXPATHLEN - 1) {
  364. run_err("%s/%s: name too long", name, dp->d_name);
  365. continue;
  366. }
  367. snprintf(path, sizeof(path), "%s/%s", name, dp->d_name);
  368. vect[0] = path;
  369. source(1, vect);
  370. }
  371. closedir(dirp);
  372. write(remout, "E\n", 2);
  373. response();
  374. }
  375. void
  376. sink(int argc, char **argv)
  377. {
  378. static BUF buffer;
  379. struct stat stb;
  380. struct timeval tv[2];
  381. enum { YES, NO, DISPLAYED } wrerr;
  382. BUF *bp;
  383. off_t i, j, size;
  384. int amt, count, exists, first, mask, mode, ofd, omode;
  385. int setimes, targisdir, wrerrno = 0;
  386. char ch, *cp, *np, *targ, *why, *vect[1], buf[BUFSIZ];
  387. #define atime tv[0]
  388. #define mtime tv[1]
  389. #define SCREWUP(str) { why = str; goto screwup; }
  390. setimes = targisdir = 0;
  391. mask = umask(0);
  392. if (!pflag)
  393. umask(mask);
  394. if (argc != 1) {
  395. run_err("ambiguous target");
  396. exit(1);
  397. }
  398. targ = *argv;
  399. if (targetshouldbedirectory)
  400. verifydir(targ);
  401. write(remout, "", 1);
  402. if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode))
  403. targisdir = 1;
  404. for (first = 1;; first = 0) {
  405. cp = buf;
  406. if (read(remin, cp, 1) <= 0)
  407. return;
  408. if (*cp++ == '\n')
  409. SCREWUP("unexpected <newline>");
  410. do {
  411. if (read(remin, &ch, sizeof(ch)) != sizeof(ch))
  412. SCREWUP("lost connection");
  413. *cp++ = ch;
  414. } while (cp < &buf[BUFSIZ - 1] && ch != '\n');
  415. *cp = 0;
  416. if (buf[0] == '\01' || buf[0] == '\02') {
  417. if (iamremote == 0)
  418. write(STDERR_FILENO,
  419. buf + 1, strlen(buf + 1));
  420. if (buf[0] == '\02')
  421. exit(1);
  422. ++errs;
  423. continue;
  424. }
  425. if (buf[0] == 'E') {
  426. write(remout, "", 1);
  427. return;
  428. }
  429. if (ch == '\n')
  430. *--cp = 0;
  431. cp = buf;
  432. if (*cp == 'T') {
  433. setimes++;
  434. cp++;
  435. mtime.tv_sec = strtol(cp, &cp, 10);
  436. if (!cp || *cp++ != ' ')
  437. SCREWUP("mtime.sec not delimited");
  438. mtime.tv_usec = strtol(cp, &cp, 10);
  439. if (!cp || *cp++ != ' ')
  440. SCREWUP("mtime.usec not delimited");
  441. atime.tv_sec = strtol(cp, &cp, 10);
  442. if (!cp || *cp++ != ' ')
  443. SCREWUP("atime.sec not delimited");
  444. atime.tv_usec = strtol(cp, &cp, 10);
  445. if (!cp || *cp++ != '\0')
  446. SCREWUP("atime.usec not delimited");
  447. write(remout, "", 1);
  448. continue;
  449. }
  450. if (*cp != 'C' && *cp != 'D') {
  451. /*
  452. * Check for the case "rcp remote:foo\* local:bar".
  453. * In this case, the line "No match." can be returned
  454. * by the shell before the rcp command on the remote is
  455. * executed so the ^Aerror_message convention isn't
  456. * followed.
  457. */
  458. if (first) {
  459. run_err("%s", cp);
  460. exit(1);
  461. }
  462. SCREWUP("expected control record");
  463. }
  464. mode = 0;
  465. for (++cp; cp < buf + 5; cp++) {
  466. if (*cp < '0' || *cp > '7')
  467. SCREWUP("bad mode");
  468. mode = (mode << 3) | (*cp - '0');
  469. }
  470. if (*cp++ != ' ')
  471. SCREWUP("mode not delimited");
  472. for (size = 0; isdigit((unsigned char)*cp);)
  473. size = size * 10 + (*cp++ - '0');
  474. if (*cp++ != ' ')
  475. SCREWUP("size not delimited");
  476. if (targisdir) {
  477. static char *namebuf;
  478. static int cursize;
  479. size_t need;
  480. need = strlen(targ) + strlen(cp) + 250;
  481. if (need > cursize) {
  482. if (!(namebuf = malloc(need)))
  483. run_err("%s", strerror(errno));
  484. }
  485. snprintf(namebuf, need, "%s%s%s", targ,
  486. *targ ? "/" : "", cp);
  487. np = namebuf;
  488. } else
  489. np = targ;
  490. exists = stat(np, &stb) == 0;
  491. if (buf[0] == 'D') {
  492. int mod_flag = pflag;
  493. if (exists) {
  494. if (!S_ISDIR(stb.st_mode)) {
  495. errno = ENOTDIR;
  496. goto bad;
  497. }
  498. if (pflag)
  499. chmod(np, mode);
  500. } else {
  501. /* Handle copying from a read-only directory */
  502. mod_flag = 1;
  503. if (mkdir(np, mode | S_IRWXU) < 0)
  504. goto bad;
  505. }
  506. vect[0] = np;
  507. sink(1, vect);
  508. if (setimes) {
  509. setimes = 0;
  510. if (utimes(np, tv) < 0)
  511. run_err("%s: set times: %s",
  512. np, strerror(errno));
  513. }
  514. if (mod_flag)
  515. chmod(np, mode);
  516. continue;
  517. }
  518. omode = mode;
  519. mode |= S_IWRITE;
  520. if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) {
  521. bad: run_err("%s: %s", np, strerror(errno));
  522. continue;
  523. }
  524. write(remout, "", 1);
  525. if ((bp = allocbuf(&buffer, ofd, BUFSIZ)) == NULL) {
  526. close(ofd);
  527. continue;
  528. }
  529. cp = bp->buf;
  530. wrerr = NO;
  531. for (count = i = 0; i < size; i += BUFSIZ) {
  532. amt = BUFSIZ;
  533. if (i + amt > size)
  534. amt = size - i;
  535. count += amt;
  536. if((j = net_read(remin, cp, amt)) != amt) {
  537. run_err("%s", j ? strerror(errno) :
  538. "dropped connection");
  539. exit(1);
  540. }
  541. amt -= j;
  542. cp += j;
  543. if (count == bp->cnt) {
  544. /* Keep reading so we stay sync'd up. */
  545. if (wrerr == NO) {
  546. j = write(ofd, bp->buf, (size_t)count);
  547. if (j != count) {
  548. wrerr = YES;
  549. wrerrno = j >= 0 ? EIO : errno;
  550. }
  551. }
  552. count = 0;
  553. cp = bp->buf;
  554. }
  555. }
  556. if (count != 0 && wrerr == NO &&
  557. (j = write(ofd, bp->buf, (size_t)count)) != count) {
  558. wrerr = YES;
  559. wrerrno = j >= 0 ? EIO : errno;
  560. }
  561. if (ftruncate(ofd, size)) {
  562. run_err("%s: truncate: %s", np, strerror(errno));
  563. wrerr = DISPLAYED;
  564. }
  565. if (pflag) {
  566. if (exists || omode != mode)
  567. if (fchmod(ofd, omode))
  568. run_err("%s: set mode: %s",
  569. np, strerror(errno));
  570. } else {
  571. if (!exists && omode != mode)
  572. if (fchmod(ofd, omode & ~mask))
  573. run_err("%s: set mode: %s",
  574. np, strerror(errno));
  575. }
  576. close(ofd);
  577. response();
  578. if (setimes && wrerr == NO) {
  579. setimes = 0;
  580. if (utimes(np, tv) < 0) {
  581. run_err("%s: set times: %s",
  582. np, strerror(errno));
  583. wrerr = DISPLAYED;
  584. }
  585. }
  586. switch(wrerr) {
  587. case YES:
  588. run_err("%s: %s", np, strerror(wrerrno));
  589. break;
  590. case NO:
  591. write(remout, "", 1);
  592. break;
  593. case DISPLAYED:
  594. break;
  595. }
  596. }
  597. screwup:
  598. run_err("protocol error: %s", why);
  599. exit(1);
  600. }
  601. int
  602. response(void)
  603. {
  604. char ch, *cp, resp, rbuf[BUFSIZ];
  605. if (read(remin, &resp, sizeof(resp)) != sizeof(resp))
  606. lostconn(0);
  607. cp = rbuf;
  608. switch(resp) {
  609. case 0: /* ok */
  610. return (0);
  611. default:
  612. *cp++ = resp;
  613. /* FALLTHROUGH */
  614. case 1: /* error, followed by error msg */
  615. case 2: /* fatal error, "" */
  616. do {
  617. if (read(remin, &ch, sizeof(ch)) != sizeof(ch))
  618. lostconn(0);
  619. *cp++ = ch;
  620. } while (cp < &rbuf[BUFSIZ] && ch != '\n');
  621. if (!iamremote)
  622. write(STDERR_FILENO, rbuf, cp - rbuf);
  623. ++errs;
  624. if (resp == 1)
  625. return (-1);
  626. exit(1);
  627. }
  628. /* NOTREACHED */
  629. }
  630. #include <stdarg.h>
  631. void
  632. run_err(const char *fmt, ...)
  633. {
  634. static FILE *fp;
  635. va_list ap;
  636. ++errs;
  637. if (fp == NULL && !(fp = fdopen(remout, "w")))
  638. return;
  639. va_start(ap, fmt);
  640. fprintf(fp, "%c", 0x01);
  641. fprintf(fp, "rcp: ");
  642. vfprintf(fp, fmt, ap);
  643. fprintf(fp, "\n");
  644. fflush(fp);
  645. va_end(ap);
  646. if (!iamremote) {
  647. va_start(ap, fmt);
  648. vwarnx(fmt, ap);
  649. va_end(ap);
  650. }
  651. }
  652. /*
  653. * This function executes the given command as the specified user on the
  654. * given host. This returns < 0 if execution fails, and >= 0 otherwise. This
  655. * assigns the input and output file descriptors on success.
  656. *
  657. * If it cannot create necessary pipes it exits with error message.
  658. */
  659. int
  660. do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
  661. {
  662. int pin[2], pout[2], reserved[2];
  663. /*
  664. * Reserve two descriptors so that the real pipes won't get
  665. * descriptors 0 and 1 because that will screw up dup2 below.
  666. */
  667. pipe(reserved);
  668. /* Create a socket pair for communicating with rsh. */
  669. if (pipe(pin) < 0) {
  670. perror("pipe");
  671. exit(255);
  672. }
  673. if (pipe(pout) < 0) {
  674. perror("pipe");
  675. exit(255);
  676. }
  677. /* Free the reserved descriptors. */
  678. close(reserved[0]);
  679. close(reserved[1]);
  680. /* For a child to execute the command on the remote host using rsh. */
  681. if (fork() == 0) {
  682. char *args[100];
  683. unsigned int i;
  684. /* Child. */
  685. close(pin[1]);
  686. close(pout[0]);
  687. dup2(pin[0], 0);
  688. dup2(pout[1], 1);
  689. close(pin[0]);
  690. close(pout[1]);
  691. i = 0;
  692. args[i++] = RSH_PROGRAM;
  693. if (usekrb4)
  694. args[i++] = "-4";
  695. if (usekrb5)
  696. args[i++] = "-5";
  697. if (usebroken)
  698. args[i++] = "-K";
  699. if (doencrypt)
  700. args[i++] = "-x";
  701. if (forwardtkt)
  702. args[i++] = "-F";
  703. if (noencrypt)
  704. args[i++] = "-z";
  705. if (port != NULL) {
  706. args[i++] = "-p";
  707. args[i++] = port;
  708. }
  709. if (eflag)
  710. args[i++] = "-e";
  711. if (remuser != NULL) {
  712. args[i++] = "-l";
  713. args[i++] = remuser;
  714. }
  715. args[i++] = host;
  716. args[i++] = cmd;
  717. args[i++] = NULL;
  718. execvp(RSH_PROGRAM, args);
  719. perror(RSH_PROGRAM);
  720. exit(1);
  721. }
  722. /* Parent. Close the other side, and return the local side. */
  723. close(pin[0]);
  724. *fdout = pin[1];
  725. close(pout[1]);
  726. *fdin = pout[0];
  727. return 0;
  728. }