/crypto/heimdal/appl/rsh/rsh.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 1032 lines · 854 code · 121 blank · 57 comment · 243 complexity · adf7a9c7026ec7417e83d5146f65110a MD5 · raw file

  1. /*
  2. * Copyright (c) 1997 - 2004 Kungliga Tekniska Hรถgskolan
  3. * (Royal Institute of Technology, Stockholm, Sweden).
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. *
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. *
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. *
  17. * 3. Neither the name of the Institute nor the names of its contributors
  18. * may be used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
  22. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24. * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
  25. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. * SUCH DAMAGE.
  32. */
  33. #include "rsh_locl.h"
  34. RCSID("$Id$");
  35. enum auth_method auth_method;
  36. #if defined(KRB5)
  37. int do_encrypt = -1;
  38. #endif
  39. #ifdef KRB5
  40. int do_unique_tkfile = 0;
  41. char *unique_tkfile = NULL;
  42. char tkfile[MAXPATHLEN];
  43. int do_forward = -1;
  44. int do_forwardable = -1;
  45. krb5_context context;
  46. krb5_keyblock *keyblock;
  47. krb5_crypto crypto;
  48. #endif
  49. int sock_debug = 0;
  50. #ifdef KRB5
  51. static int use_v5 = -1;
  52. #endif
  53. #if defined(KRB5)
  54. static int use_only_broken = 0;
  55. #else
  56. static int use_only_broken = 1;
  57. #endif
  58. static int use_broken = 1;
  59. static char *port_str;
  60. static const char *user;
  61. static int do_version;
  62. static int do_help;
  63. static int do_errsock = 1;
  64. #ifdef KRB5
  65. static char *protocol_version_str;
  66. static int protocol_version = 2;
  67. #endif
  68. /*
  69. *
  70. */
  71. static int input = 1; /* Read from stdin */
  72. static int
  73. rsh_loop (int s, int errsock)
  74. {
  75. fd_set real_readset;
  76. int count = 1;
  77. #ifdef KRB5
  78. if(auth_method == AUTH_KRB5 && protocol_version == 2)
  79. init_ivecs(1, errsock != -1);
  80. #endif
  81. if (s >= FD_SETSIZE || (errsock != -1 && errsock >= FD_SETSIZE))
  82. errx (1, "fd too large");
  83. FD_ZERO(&real_readset);
  84. FD_SET(s, &real_readset);
  85. if (errsock != -1) {
  86. FD_SET(errsock, &real_readset);
  87. ++count;
  88. }
  89. if(input)
  90. FD_SET(STDIN_FILENO, &real_readset);
  91. for (;;) {
  92. int ret;
  93. fd_set readset;
  94. char buf[RSH_BUFSIZ];
  95. readset = real_readset;
  96. ret = select (max(s, errsock) + 1, &readset, NULL, NULL, NULL);
  97. if (ret < 0) {
  98. if (errno == EINTR)
  99. continue;
  100. else
  101. err (1, "select");
  102. }
  103. if (FD_ISSET(s, &readset)) {
  104. ret = do_read (s, buf, sizeof(buf), ivec_in[0]);
  105. if (ret < 0)
  106. err (1, "read");
  107. else if (ret == 0) {
  108. close (s);
  109. FD_CLR(s, &real_readset);
  110. if (--count == 0)
  111. return 0;
  112. } else
  113. net_write (STDOUT_FILENO, buf, ret);
  114. }
  115. if (errsock != -1 && FD_ISSET(errsock, &readset)) {
  116. ret = do_read (errsock, buf, sizeof(buf), ivec_in[1]);
  117. if (ret < 0)
  118. err (1, "read");
  119. else if (ret == 0) {
  120. close (errsock);
  121. FD_CLR(errsock, &real_readset);
  122. if (--count == 0)
  123. return 0;
  124. } else
  125. net_write (STDERR_FILENO, buf, ret);
  126. }
  127. if (FD_ISSET(STDIN_FILENO, &readset)) {
  128. ret = read (STDIN_FILENO, buf, sizeof(buf));
  129. if (ret < 0)
  130. err (1, "read");
  131. else if (ret == 0) {
  132. close (STDIN_FILENO);
  133. FD_CLR(STDIN_FILENO, &real_readset);
  134. shutdown (s, SHUT_WR);
  135. } else
  136. do_write (s, buf, ret, ivec_out[0]);
  137. }
  138. }
  139. }
  140. #ifdef KRB5
  141. /*
  142. * Send forward information on `s' for host `hostname', them being
  143. * forwardable themselves if `forwardable'
  144. */
  145. static int
  146. krb5_forward_cred (krb5_auth_context auth_context,
  147. int s,
  148. const char *hostname,
  149. int forwardable)
  150. {
  151. krb5_error_code ret;
  152. krb5_ccache ccache;
  153. krb5_creds creds;
  154. krb5_kdc_flags flags;
  155. krb5_data out_data;
  156. krb5_principal principal;
  157. memset (&creds, 0, sizeof(creds));
  158. ret = krb5_cc_default (context, &ccache);
  159. if (ret) {
  160. warnx ("could not forward creds: krb5_cc_default: %s",
  161. krb5_get_err_text (context, ret));
  162. return 1;
  163. }
  164. ret = krb5_cc_get_principal (context, ccache, &principal);
  165. if (ret) {
  166. warnx ("could not forward creds: krb5_cc_get_principal: %s",
  167. krb5_get_err_text (context, ret));
  168. return 1;
  169. }
  170. creds.client = principal;
  171. ret = krb5_make_principal(context,
  172. &creds.server,
  173. principal->realm,
  174. "krbtgt",
  175. principal->realm,
  176. NULL);
  177. if (ret) {
  178. warnx ("could not forward creds: krb5_make_principal: %s",
  179. krb5_get_err_text (context, ret));
  180. return 1;
  181. }
  182. creds.times.endtime = 0;
  183. flags.i = 0;
  184. flags.b.forwarded = 1;
  185. flags.b.forwardable = forwardable;
  186. ret = krb5_get_forwarded_creds (context,
  187. auth_context,
  188. ccache,
  189. flags.i,
  190. hostname,
  191. &creds,
  192. &out_data);
  193. if (ret) {
  194. warnx ("could not forward creds: krb5_get_forwarded_creds: %s",
  195. krb5_get_err_text (context, ret));
  196. return 1;
  197. }
  198. ret = krb5_write_message (context,
  199. (void *)&s,
  200. &out_data);
  201. krb5_data_free (&out_data);
  202. if (ret)
  203. warnx ("could not forward creds: krb5_write_message: %s",
  204. krb5_get_err_text (context, ret));
  205. return 0;
  206. }
  207. static int sendauth_version_error;
  208. static int
  209. send_krb5_auth(int s,
  210. struct sockaddr *thisaddr,
  211. struct sockaddr *thataddr,
  212. const char *hostname,
  213. const char *remote_user,
  214. const char *local_user,
  215. size_t cmd_len,
  216. const char *cmd)
  217. {
  218. krb5_principal server;
  219. krb5_data cksum_data;
  220. int status;
  221. size_t len;
  222. krb5_auth_context auth_context = NULL;
  223. const char *protocol_string = NULL;
  224. krb5_flags ap_opts;
  225. char *str;
  226. status = krb5_sname_to_principal(context,
  227. hostname,
  228. "host",
  229. KRB5_NT_SRV_HST,
  230. &server);
  231. if (status) {
  232. warnx ("%s: %s", hostname, krb5_get_err_text(context, status));
  233. return 1;
  234. }
  235. if(do_encrypt == -1) {
  236. krb5_appdefault_boolean(context, NULL,
  237. krb5_principal_get_realm(context, server),
  238. "encrypt",
  239. FALSE,
  240. &do_encrypt);
  241. }
  242. cksum_data.length = asprintf (&str,
  243. "%u:%s%s%s",
  244. ntohs(socket_get_port(thataddr)),
  245. do_encrypt ? "-x " : "",
  246. cmd,
  247. remote_user);
  248. if (str == NULL) {
  249. warnx ("%s: failed to allocate command", hostname);
  250. return 1;
  251. }
  252. cksum_data.data = str;
  253. ap_opts = 0;
  254. if(do_encrypt)
  255. ap_opts |= AP_OPTS_MUTUAL_REQUIRED;
  256. switch(protocol_version) {
  257. case 2:
  258. ap_opts |= AP_OPTS_USE_SUBKEY;
  259. protocol_string = KCMD_NEW_VERSION;
  260. break;
  261. case 1:
  262. protocol_string = KCMD_OLD_VERSION;
  263. key_usage = KRB5_KU_OTHER_ENCRYPTED;
  264. break;
  265. default:
  266. abort();
  267. }
  268. status = krb5_sendauth (context,
  269. &auth_context,
  270. &s,
  271. protocol_string,
  272. NULL,
  273. server,
  274. ap_opts,
  275. &cksum_data,
  276. NULL,
  277. NULL,
  278. NULL,
  279. NULL,
  280. NULL);
  281. /* do this while we have a principal */
  282. if(do_forward == -1 || do_forwardable == -1) {
  283. krb5_const_realm realm = krb5_principal_get_realm(context, server);
  284. if (do_forwardable == -1)
  285. krb5_appdefault_boolean(context, NULL, realm,
  286. "forwardable", FALSE,
  287. &do_forwardable);
  288. if (do_forward == -1)
  289. krb5_appdefault_boolean(context, NULL, realm,
  290. "forward", FALSE,
  291. &do_forward);
  292. }
  293. krb5_free_principal(context, server);
  294. krb5_data_free(&cksum_data);
  295. if (status) {
  296. if(status == KRB5_SENDAUTH_REJECTED &&
  297. protocol_version == 2 && protocol_version_str == NULL)
  298. sendauth_version_error = 1;
  299. else
  300. krb5_warn(context, status, "%s", hostname);
  301. return 1;
  302. }
  303. status = krb5_auth_con_getlocalsubkey (context, auth_context, &keyblock);
  304. if(keyblock == NULL)
  305. status = krb5_auth_con_getkey (context, auth_context, &keyblock);
  306. if (status) {
  307. warnx ("krb5_auth_con_getkey: %s", krb5_get_err_text(context, status));
  308. return 1;
  309. }
  310. status = krb5_auth_con_setaddrs_from_fd (context,
  311. auth_context,
  312. &s);
  313. if (status) {
  314. warnx("krb5_auth_con_setaddrs_from_fd: %s",
  315. krb5_get_err_text(context, status));
  316. return(1);
  317. }
  318. status = krb5_crypto_init(context, keyblock, 0, &crypto);
  319. if(status) {
  320. warnx ("krb5_crypto_init: %s", krb5_get_err_text(context, status));
  321. return 1;
  322. }
  323. len = strlen(remote_user) + 1;
  324. if (net_write (s, remote_user, len) != len) {
  325. warn ("write");
  326. return 1;
  327. }
  328. if (do_encrypt && net_write (s, "-x ", 3) != 3) {
  329. warn ("write");
  330. return 1;
  331. }
  332. if (net_write (s, cmd, cmd_len) != cmd_len) {
  333. warn ("write");
  334. return 1;
  335. }
  336. if (do_unique_tkfile) {
  337. if (net_write (s, tkfile, strlen(tkfile)) != strlen(tkfile)) {
  338. warn ("write");
  339. return 1;
  340. }
  341. }
  342. len = strlen(local_user) + 1;
  343. if (net_write (s, local_user, len) != len) {
  344. warn ("write");
  345. return 1;
  346. }
  347. if (!do_forward
  348. || krb5_forward_cred (auth_context, s, hostname, do_forwardable)) {
  349. /* Empty forwarding info */
  350. u_char zero[4] = {0, 0, 0, 0};
  351. write (s, &zero, 4);
  352. }
  353. krb5_auth_con_free (context, auth_context);
  354. return 0;
  355. }
  356. #endif /* KRB5 */
  357. static int
  358. send_broken_auth(int s,
  359. struct sockaddr *thisaddr,
  360. struct sockaddr *thataddr,
  361. const char *hostname,
  362. const char *remote_user,
  363. const char *local_user,
  364. size_t cmd_len,
  365. const char *cmd)
  366. {
  367. size_t len;
  368. len = strlen(local_user) + 1;
  369. if (net_write (s, local_user, len) != len) {
  370. warn ("write");
  371. return 1;
  372. }
  373. len = strlen(remote_user) + 1;
  374. if (net_write (s, remote_user, len) != len) {
  375. warn ("write");
  376. return 1;
  377. }
  378. if (net_write (s, cmd, cmd_len) != cmd_len) {
  379. warn ("write");
  380. return 1;
  381. }
  382. return 0;
  383. }
  384. static int
  385. proto (int s, int errsock,
  386. const char *hostname, const char *local_user, const char *remote_user,
  387. const char *cmd, size_t cmd_len,
  388. int (*auth_func)(int s,
  389. struct sockaddr *this, struct sockaddr *that,
  390. const char *hostname, const char *remote_user,
  391. const char *local_user, size_t cmd_len,
  392. const char *cmd))
  393. {
  394. int errsock2;
  395. char buf[BUFSIZ];
  396. char *p;
  397. size_t len;
  398. char reply;
  399. struct sockaddr_storage thisaddr_ss;
  400. struct sockaddr *thisaddr = (struct sockaddr *)&thisaddr_ss;
  401. struct sockaddr_storage thataddr_ss;
  402. struct sockaddr *thataddr = (struct sockaddr *)&thataddr_ss;
  403. struct sockaddr_storage erraddr_ss;
  404. struct sockaddr *erraddr = (struct sockaddr *)&erraddr_ss;
  405. socklen_t addrlen;
  406. int ret;
  407. addrlen = sizeof(thisaddr_ss);
  408. if (getsockname (s, thisaddr, &addrlen) < 0) {
  409. warn ("getsockname(%s)", hostname);
  410. return 1;
  411. }
  412. addrlen = sizeof(thataddr_ss);
  413. if (getpeername (s, thataddr, &addrlen) < 0) {
  414. warn ("getpeername(%s)", hostname);
  415. return 1;
  416. }
  417. if (errsock != -1) {
  418. addrlen = sizeof(erraddr_ss);
  419. if (getsockname (errsock, erraddr, &addrlen) < 0) {
  420. warn ("getsockname");
  421. return 1;
  422. }
  423. if (listen (errsock, 1) < 0) {
  424. warn ("listen");
  425. return 1;
  426. }
  427. p = buf;
  428. snprintf (p, sizeof(buf), "%u",
  429. ntohs(socket_get_port(erraddr)));
  430. len = strlen(buf) + 1;
  431. if(net_write (s, buf, len) != len) {
  432. warn ("write");
  433. close (errsock);
  434. return 1;
  435. }
  436. for (;;) {
  437. fd_set fdset;
  438. if (errsock >= FD_SETSIZE || s >= FD_SETSIZE)
  439. errx (1, "fd too large");
  440. FD_ZERO(&fdset);
  441. FD_SET(errsock, &fdset);
  442. FD_SET(s, &fdset);
  443. ret = select (max(errsock, s) + 1, &fdset, NULL, NULL, NULL);
  444. if (ret < 0) {
  445. if (errno == EINTR)
  446. continue;
  447. warn ("select");
  448. close (errsock);
  449. return 1;
  450. }
  451. if (FD_ISSET(errsock, &fdset)) {
  452. errsock2 = accept (errsock, NULL, NULL);
  453. close (errsock);
  454. if (errsock2 < 0) {
  455. warn ("accept");
  456. return 1;
  457. }
  458. break;
  459. }
  460. /*
  461. * there should not arrive any data on this fd so if it's
  462. * readable it probably indicates that the other side when
  463. * away.
  464. */
  465. if (FD_ISSET(s, &fdset)) {
  466. warnx ("socket closed");
  467. close (errsock);
  468. errsock2 = -1;
  469. break;
  470. }
  471. }
  472. } else {
  473. if (net_write (s, "0", 2) != 2) {
  474. warn ("write");
  475. return 1;
  476. }
  477. errsock2 = -1;
  478. }
  479. if ((*auth_func)(s, thisaddr, thataddr, hostname,
  480. remote_user, local_user,
  481. cmd_len, cmd)) {
  482. close (errsock2);
  483. return 1;
  484. }
  485. ret = net_read (s, &reply, 1);
  486. if (ret < 0) {
  487. warn ("read");
  488. close (errsock2);
  489. return 1;
  490. } else if (ret == 0) {
  491. warnx ("unexpected EOF from %s", hostname);
  492. close (errsock2);
  493. return 1;
  494. }
  495. if (reply != 0) {
  496. warnx ("Error from rshd at %s:", hostname);
  497. while ((ret = read (s, buf, sizeof(buf))) > 0)
  498. write (STDOUT_FILENO, buf, ret);
  499. write (STDOUT_FILENO,"\n",1);
  500. close (errsock2);
  501. return 1;
  502. }
  503. if (sock_debug) {
  504. int one = 1;
  505. if (setsockopt(s, SOL_SOCKET, SO_DEBUG, (void *)&one, sizeof(one)) < 0)
  506. warn("setsockopt remote");
  507. if (errsock2 != -1 &&
  508. setsockopt(errsock2, SOL_SOCKET, SO_DEBUG,
  509. (void *)&one, sizeof(one)) < 0)
  510. warn("setsockopt stderr");
  511. }
  512. return rsh_loop (s, errsock2);
  513. }
  514. /*
  515. * Return in `res' a copy of the concatenation of `argc, argv' into
  516. * malloced space. */
  517. static size_t
  518. construct_command (char **res, int argc, char **argv)
  519. {
  520. int i;
  521. size_t len = 0;
  522. char *tmp;
  523. for (i = 0; i < argc; ++i)
  524. len += strlen(argv[i]) + 1;
  525. len = max (1, len);
  526. tmp = malloc (len);
  527. if (tmp == NULL)
  528. errx (1, "malloc %lu failed", (unsigned long)len);
  529. *tmp = '\0';
  530. for (i = 0; i < argc - 1; ++i) {
  531. strlcat (tmp, argv[i], len);
  532. strlcat (tmp, " ", len);
  533. }
  534. if (argc > 0)
  535. strlcat (tmp, argv[argc-1], len);
  536. *res = tmp;
  537. return len;
  538. }
  539. static char *
  540. print_addr (const struct sockaddr *sa)
  541. {
  542. char addr_str[256];
  543. char *res;
  544. const char *as = NULL;
  545. if(sa->sa_family == AF_INET)
  546. as = inet_ntop (sa->sa_family, &((struct sockaddr_in*)sa)->sin_addr,
  547. addr_str, sizeof(addr_str));
  548. #ifdef HAVE_INET6
  549. else if(sa->sa_family == AF_INET6)
  550. as = inet_ntop (sa->sa_family, &((struct sockaddr_in6*)sa)->sin6_addr,
  551. addr_str, sizeof(addr_str));
  552. #endif
  553. if(as == NULL)
  554. return NULL;
  555. res = strdup(as);
  556. if (res == NULL)
  557. errx (1, "malloc: out of memory");
  558. return res;
  559. }
  560. static int
  561. doit_broken (int argc,
  562. char **argv,
  563. int hostindex,
  564. struct addrinfo *ai,
  565. const char *remote_user,
  566. const char *local_user,
  567. int priv_socket1,
  568. int priv_socket2,
  569. const char *cmd,
  570. size_t cmd_len)
  571. {
  572. struct addrinfo *a;
  573. if (connect (priv_socket1, ai->ai_addr, ai->ai_addrlen) < 0) {
  574. int save_errno = errno;
  575. close(priv_socket1);
  576. close(priv_socket2);
  577. for (a = ai->ai_next; a != NULL; a = a->ai_next) {
  578. pid_t pid;
  579. char *adr = print_addr(a->ai_addr);
  580. if(adr == NULL)
  581. continue;
  582. pid = fork();
  583. if (pid < 0)
  584. err (1, "fork");
  585. else if(pid == 0) {
  586. char **new_argv;
  587. int i = 0;
  588. new_argv = malloc((argc + 2) * sizeof(*new_argv));
  589. if (new_argv == NULL)
  590. errx (1, "malloc: out of memory");
  591. new_argv[i] = argv[i];
  592. ++i;
  593. if (hostindex == i)
  594. new_argv[i++] = adr;
  595. new_argv[i++] = "-K";
  596. for(; i <= argc; ++i)
  597. new_argv[i] = argv[i - 1];
  598. if (hostindex > 1)
  599. new_argv[hostindex + 1] = adr;
  600. new_argv[argc + 1] = NULL;
  601. execv(PATH_RSH, new_argv);
  602. err(1, "execv(%s)", PATH_RSH);
  603. } else {
  604. int status;
  605. free(adr);
  606. while(waitpid(pid, &status, 0) < 0)
  607. ;
  608. if(WIFEXITED(status) && WEXITSTATUS(status) == 0)
  609. return 0;
  610. }
  611. }
  612. errno = save_errno;
  613. warn("%s", argv[hostindex]);
  614. return 1;
  615. } else {
  616. int ret;
  617. ret = proto (priv_socket1, priv_socket2,
  618. argv[hostindex],
  619. local_user, remote_user,
  620. cmd, cmd_len,
  621. send_broken_auth);
  622. return ret;
  623. }
  624. }
  625. #if defined(KRB5)
  626. static int
  627. doit (const char *hostname,
  628. struct addrinfo *ai,
  629. const char *remote_user,
  630. const char *local_user,
  631. const char *cmd,
  632. size_t cmd_len,
  633. int (*auth_func)(int s,
  634. struct sockaddr *this, struct sockaddr *that,
  635. const char *hostname, const char *remote_user,
  636. const char *local_user, size_t cmd_len,
  637. const char *cmd))
  638. {
  639. int error;
  640. struct addrinfo *a;
  641. int socketfailed = 1;
  642. int ret;
  643. for (a = ai; a != NULL; a = a->ai_next) {
  644. int s;
  645. int errsock;
  646. s = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
  647. if (s < 0)
  648. continue;
  649. socketfailed = 0;
  650. if (connect (s, a->ai_addr, a->ai_addrlen) < 0) {
  651. char addr[128];
  652. if(getnameinfo(a->ai_addr, a->ai_addrlen,
  653. addr, sizeof(addr), NULL, 0, NI_NUMERICHOST) == 0)
  654. warn ("connect(%s [%s])", hostname, addr);
  655. else
  656. warn ("connect(%s)", hostname);
  657. close (s);
  658. continue;
  659. }
  660. if (do_errsock) {
  661. struct addrinfo *ea, *eai;
  662. struct addrinfo hints;
  663. memset (&hints, 0, sizeof(hints));
  664. hints.ai_socktype = a->ai_socktype;
  665. hints.ai_protocol = a->ai_protocol;
  666. hints.ai_family = a->ai_family;
  667. hints.ai_flags = AI_PASSIVE;
  668. errsock = -1;
  669. error = getaddrinfo (NULL, "0", &hints, &eai);
  670. if (error)
  671. errx (1, "getaddrinfo: %s", gai_strerror(error));
  672. for (ea = eai; ea != NULL; ea = ea->ai_next) {
  673. errsock = socket (ea->ai_family, ea->ai_socktype,
  674. ea->ai_protocol);
  675. if (errsock < 0)
  676. continue;
  677. if (bind (errsock, ea->ai_addr, ea->ai_addrlen) < 0)
  678. err (1, "bind");
  679. break;
  680. }
  681. if (errsock < 0)
  682. err (1, "socket");
  683. freeaddrinfo (eai);
  684. } else
  685. errsock = -1;
  686. ret = proto (s, errsock,
  687. hostname,
  688. local_user, remote_user,
  689. cmd, cmd_len, auth_func);
  690. close (s);
  691. return ret;
  692. }
  693. if(socketfailed)
  694. warnx ("failed to contact %s", hostname);
  695. return -1;
  696. }
  697. #endif /* KRB5 */
  698. struct getargs args[] = {
  699. #ifdef KRB5
  700. { "krb5", '5', arg_flag, &use_v5, "Use Kerberos V5" },
  701. { "forward", 'f', arg_flag, &do_forward, "Forward credentials [krb5]"},
  702. { "forwardable", 'F', arg_flag, &do_forwardable,
  703. "Forward forwardable credentials [krb5]" },
  704. { NULL, 'G', arg_negative_flag,&do_forward, "Don't forward credentials" },
  705. { "unique", 'u', arg_flag, &do_unique_tkfile,
  706. "Use unique remote credentials cache [krb5]" },
  707. { "tkfile", 'U', arg_string, &unique_tkfile,
  708. "Specifies remote credentials cache [krb5]" },
  709. { "protocol", 'P', arg_string, &protocol_version_str,
  710. "Protocol version [krb5]", "protocol" },
  711. #endif
  712. { "broken", 'K', arg_flag, &use_only_broken, "Use only priv port" },
  713. #if defined(KRB5)
  714. { "encrypt", 'x', arg_flag, &do_encrypt, "Encrypt connection" },
  715. { NULL, 'z', arg_negative_flag, &do_encrypt,
  716. "Don't encrypt connection", NULL },
  717. #endif
  718. { NULL, 'd', arg_flag, &sock_debug, "Enable socket debugging" },
  719. { "input", 'n', arg_negative_flag, &input, "Close stdin" },
  720. { "port", 'p', arg_string, &port_str, "Use this port",
  721. "port" },
  722. { "user", 'l', arg_string, &user, "Run as this user", "login" },
  723. { "stderr", 'e', arg_negative_flag, &do_errsock, "Don't open stderr"},
  724. #ifdef KRB5
  725. #endif
  726. { "version", 0, arg_flag, &do_version, NULL },
  727. { "help", 0, arg_flag, &do_help, NULL }
  728. };
  729. static void
  730. usage (int ret)
  731. {
  732. arg_printusage (args,
  733. sizeof(args) / sizeof(args[0]),
  734. NULL,
  735. "[login@]host [command]");
  736. exit (ret);
  737. }
  738. /*
  739. *
  740. */
  741. int
  742. main(int argc, char **argv)
  743. {
  744. int priv_port1, priv_port2;
  745. int priv_socket1, priv_socket2;
  746. int argindex = 0;
  747. int error;
  748. struct addrinfo hints, *ai;
  749. int ret = 1;
  750. char *cmd;
  751. char *tmp;
  752. size_t cmd_len;
  753. const char *local_user;
  754. char *host = NULL;
  755. int host_index = -1;
  756. #ifdef KRB5
  757. int status;
  758. #endif
  759. uid_t uid;
  760. priv_port1 = priv_port2 = IPPORT_RESERVED-1;
  761. priv_socket1 = rresvport(&priv_port1);
  762. priv_socket2 = rresvport(&priv_port2);
  763. uid = getuid ();
  764. if (setuid (uid) || (uid != 0 && setuid(0) == 0))
  765. err (1, "setuid");
  766. setprogname (argv[0]);
  767. if (argc >= 2 && argv[1][0] != '-') {
  768. host = argv[host_index = 1];
  769. argindex = 1;
  770. }
  771. if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv,
  772. &argindex))
  773. usage (1);
  774. if (do_help)
  775. usage (0);
  776. if (do_version) {
  777. print_version (NULL);
  778. return 0;
  779. }
  780. #ifdef KRB5
  781. if(protocol_version_str != NULL) {
  782. if(strcasecmp(protocol_version_str, "N") == 0)
  783. protocol_version = 2;
  784. else if(strcasecmp(protocol_version_str, "O") == 0)
  785. protocol_version = 1;
  786. else {
  787. char *end;
  788. int v;
  789. v = strtol(protocol_version_str, &end, 0);
  790. if(*end != '\0' || (v != 1 && v != 2)) {
  791. errx(1, "unknown protocol version \"%s\"",
  792. protocol_version_str);
  793. }
  794. protocol_version = v;
  795. }
  796. }
  797. status = krb5_init_context (&context);
  798. if (status) {
  799. if(use_v5 == 1)
  800. errx(1, "krb5_init_context failed: %d", status);
  801. else
  802. use_v5 = 0;
  803. }
  804. /* request for forwardable on the command line means we should
  805. also forward */
  806. if (do_forwardable == 1)
  807. do_forward = 1;
  808. #endif
  809. if (use_only_broken) {
  810. #ifdef KRB5
  811. use_v5 = 0;
  812. #endif
  813. }
  814. if(priv_socket1 < 0) {
  815. if (use_only_broken)
  816. errx (1, "unable to bind reserved port: is rsh setuid root?");
  817. use_broken = 0;
  818. }
  819. #if defined(KRB5)
  820. if (do_encrypt == 1 && use_only_broken)
  821. errx (1, "encryption not supported with old style authentication");
  822. #endif
  823. #ifdef KRB5
  824. if (do_unique_tkfile && unique_tkfile != NULL)
  825. errx (1, "Only one of -u and -U allowed.");
  826. if (do_unique_tkfile)
  827. strlcpy(tkfile,"-u ", sizeof(tkfile));
  828. else if (unique_tkfile != NULL) {
  829. if (strchr(unique_tkfile,' ') != NULL) {
  830. warnx("Space is not allowed in tkfilename");
  831. usage(1);
  832. }
  833. do_unique_tkfile = 1;
  834. snprintf (tkfile, sizeof(tkfile), "-U %s ", unique_tkfile);
  835. }
  836. #endif
  837. if (host == NULL) {
  838. if (argc - argindex < 1)
  839. usage (1);
  840. else
  841. host = argv[host_index = argindex++];
  842. }
  843. if((tmp = strchr(host, '@')) != NULL) {
  844. *tmp++ = '\0';
  845. user = host;
  846. host = tmp;
  847. }
  848. if (argindex == argc) {
  849. close (priv_socket1);
  850. close (priv_socket2);
  851. argv[0] = "rlogin";
  852. execvp ("rlogin", argv);
  853. err (1, "execvp rlogin");
  854. }
  855. local_user = get_default_username ();
  856. if (local_user == NULL)
  857. errx (1, "who are you?");
  858. if (user == NULL)
  859. user = local_user;
  860. cmd_len = construct_command(&cmd, argc - argindex, argv + argindex);
  861. /*
  862. * Try all different authentication methods
  863. */
  864. #ifdef KRB5
  865. if (ret && use_v5) {
  866. memset (&hints, 0, sizeof(hints));
  867. hints.ai_socktype = SOCK_STREAM;
  868. hints.ai_protocol = IPPROTO_TCP;
  869. if(port_str == NULL) {
  870. error = getaddrinfo(host, "kshell", &hints, &ai);
  871. if(error == EAI_NONAME)
  872. error = getaddrinfo(host, "544", &hints, &ai);
  873. } else
  874. error = getaddrinfo(host, port_str, &hints, &ai);
  875. if(error)
  876. errx (1, "getaddrinfo: %s", gai_strerror(error));
  877. auth_method = AUTH_KRB5;
  878. again:
  879. ret = doit (host, ai, user, local_user, cmd, cmd_len,
  880. send_krb5_auth);
  881. if(ret != 0 && sendauth_version_error &&
  882. protocol_version == 2) {
  883. protocol_version = 1;
  884. goto again;
  885. }
  886. freeaddrinfo(ai);
  887. }
  888. #endif
  889. if (ret && use_broken) {
  890. memset (&hints, 0, sizeof(hints));
  891. hints.ai_socktype = SOCK_STREAM;
  892. hints.ai_protocol = IPPROTO_TCP;
  893. if(port_str == NULL) {
  894. error = getaddrinfo(host, "shell", &hints, &ai);
  895. if(error == EAI_NONAME)
  896. error = getaddrinfo(host, "514", &hints, &ai);
  897. } else
  898. error = getaddrinfo(host, port_str, &hints, &ai);
  899. if(error)
  900. errx (1, "getaddrinfo: %s", gai_strerror(error));
  901. auth_method = AUTH_BROKEN;
  902. ret = doit_broken (argc, argv, host_index, ai,
  903. user, local_user,
  904. priv_socket1,
  905. do_errsock ? priv_socket2 : -1,
  906. cmd, cmd_len);
  907. freeaddrinfo(ai);
  908. }
  909. free(cmd);
  910. return ret;
  911. }