PageRenderTime 52ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

lib/libc/net/rcmd.c

http://www.minix3.org/
C | 1047 lines | 829 code | 93 blank | 125 comment | 231 complexity | 9627b74f7878b347705f7f8f7f3663b2 MD5 | raw file
Possible License(s): MIT, WTFPL, AGPL-1.0, BSD-3-Clause, GPL-3.0, LGPL-2.0, JSON, 0BSD
  1. /* $NetBSD: rcmd.c,v 1.65 2007/01/03 11:46:22 ws Exp $ */
  2. /*
  3. * Copyright (c) 1983, 1993, 1994
  4. * The Regents of the University of California. 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. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. Neither the name of the University nor the names of its contributors
  15. * may be used to endorse or promote products derived from this software
  16. * without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  19. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  20. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  21. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  22. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  23. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  24. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  25. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  26. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  27. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  28. * SUCH DAMAGE.
  29. */
  30. #include <sys/cdefs.h>
  31. #if defined(LIBC_SCCS) && !defined(lint)
  32. #if 0
  33. static char sccsid[] = "@(#)rcmd.c 8.3 (Berkeley) 3/26/94";
  34. #else
  35. __RCSID("$NetBSD: rcmd.c,v 1.65 2007/01/03 11:46:22 ws Exp $");
  36. #endif
  37. #endif /* LIBC_SCCS and not lint */
  38. #ifdef _LIBC
  39. #include "namespace.h"
  40. #endif
  41. #include <sys/param.h>
  42. #include <sys/socket.h>
  43. #include <sys/stat.h>
  44. #include <sys/poll.h>
  45. #include <sys/wait.h>
  46. #include <netinet/in.h>
  47. #ifndef __minix
  48. #include <rpc/rpc.h>
  49. #endif
  50. #include <arpa/inet.h>
  51. #include <netgroup.h>
  52. #include <assert.h>
  53. #include <ctype.h>
  54. #include <err.h>
  55. #include <errno.h>
  56. #include <fcntl.h>
  57. #include <grp.h>
  58. #include <netdb.h>
  59. #include <paths.h>
  60. #include <pwd.h>
  61. #include <signal.h>
  62. #include <stdio.h>
  63. #include <stdlib.h>
  64. #include <string.h>
  65. #include <syslog.h>
  66. #include <unistd.h>
  67. #include "pathnames.h"
  68. int orcmd __P((char **, u_int, const char *, const char *, const char *,
  69. int *));
  70. int orcmd_af __P((char **, u_int, const char *, const char *, const char *,
  71. int *, int));
  72. int __ivaliduser __P((FILE *, u_int32_t, const char *, const char *));
  73. int __ivaliduser_sa __P((FILE *, const struct sockaddr *, socklen_t,
  74. const char *, const char *));
  75. static int rshrcmd __P((char **, u_int32_t, const char *, const char *,
  76. const char *, int *, const char *));
  77. static int resrcmd __P((struct addrinfo *, char **, u_int32_t, const char *,
  78. const char *, const char *, int *));
  79. static int __icheckhost __P((const struct sockaddr *, socklen_t,
  80. const char *));
  81. static char *__gethostloop __P((const struct sockaddr *, socklen_t));
  82. int
  83. rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
  84. char **ahost;
  85. u_short rport;
  86. const char *locuser, *remuser, *cmd;
  87. int *fd2p;
  88. {
  89. return rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, AF_INET);
  90. }
  91. int
  92. rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, af)
  93. char **ahost;
  94. u_short rport;
  95. const char *locuser, *remuser, *cmd;
  96. int *fd2p;
  97. int af;
  98. {
  99. static char hbuf[MAXHOSTNAMELEN];
  100. char pbuf[NI_MAXSERV];
  101. struct addrinfo hints, *res;
  102. int error;
  103. struct servent *sp;
  104. _DIAGASSERT(ahost != NULL);
  105. _DIAGASSERT(locuser != NULL);
  106. _DIAGASSERT(remuser != NULL);
  107. _DIAGASSERT(cmd != NULL);
  108. /* fd2p may be NULL */
  109. snprintf(pbuf, sizeof(pbuf), "%u", ntohs(rport));
  110. memset(&hints, 0, sizeof(hints));
  111. hints.ai_family = af;
  112. hints.ai_socktype = SOCK_STREAM;
  113. hints.ai_flags = AI_CANONNAME;
  114. error = getaddrinfo(*ahost, pbuf, &hints, &res);
  115. if (error) {
  116. warnx("%s: %s", *ahost, gai_strerror(error)); /*XXX*/
  117. return (-1);
  118. }
  119. if (res->ai_canonname) {
  120. /*
  121. * Canonicalise hostname.
  122. * XXX: Should we really do this?
  123. */
  124. strlcpy(hbuf, res->ai_canonname, sizeof(hbuf));
  125. *ahost = hbuf;
  126. }
  127. /*
  128. * Check if rport is the same as the shell port, and that the fd2p. If
  129. * it is not, the program isn't expecting 'rsh' and so we can't use the
  130. * RCMD_CMD environment.
  131. */
  132. sp = getservbyname("shell", "tcp");
  133. if (sp != NULL && sp->s_port == rport)
  134. error = rshrcmd(ahost, (u_int32_t)rport,
  135. locuser, remuser, cmd, fd2p, getenv("RCMD_CMD"));
  136. else
  137. error = resrcmd(res, ahost, (u_int32_t)rport,
  138. locuser, remuser, cmd, fd2p);
  139. freeaddrinfo(res);
  140. return (error);
  141. }
  142. /* this is simply a wrapper around hprcmd() that handles ahost first */
  143. int
  144. orcmd(ahost, rport, locuser, remuser, cmd, fd2p)
  145. char **ahost;
  146. u_int rport;
  147. const char *locuser, *remuser, *cmd;
  148. int *fd2p;
  149. {
  150. return orcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, AF_INET);
  151. }
  152. int
  153. orcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, af)
  154. char **ahost;
  155. u_int rport;
  156. const char *locuser, *remuser, *cmd;
  157. int *fd2p;
  158. int af;
  159. {
  160. static char hbuf[MAXHOSTNAMELEN];
  161. char pbuf[NI_MAXSERV];
  162. struct addrinfo hints, *res;
  163. int error;
  164. _DIAGASSERT(ahost != NULL);
  165. _DIAGASSERT(locuser != NULL);
  166. _DIAGASSERT(remuser != NULL);
  167. _DIAGASSERT(cmd != NULL);
  168. /* fd2p may be NULL */
  169. snprintf(pbuf, sizeof(pbuf), "%u", ntohs(rport));
  170. memset(&hints, 0, sizeof(hints));
  171. hints.ai_family = af;
  172. hints.ai_socktype = SOCK_STREAM;
  173. hints.ai_flags = AI_CANONNAME;
  174. error = getaddrinfo(*ahost, pbuf, &hints, &res);
  175. if (error) {
  176. warnx("%s: %s", *ahost, gai_strerror(error)); /*XXX*/
  177. return (-1);
  178. }
  179. if (res->ai_canonname) {
  180. strlcpy(hbuf, res->ai_canonname, sizeof(hbuf));
  181. *ahost = hbuf;
  182. }
  183. error = resrcmd(res, ahost, rport, locuser, remuser, cmd, fd2p);
  184. freeaddrinfo(res);
  185. return (error);
  186. }
  187. /*ARGSUSED*/
  188. static int
  189. resrcmd(res, ahost, rport, locuser, remuser, cmd, fd2p)
  190. struct addrinfo *res;
  191. char **ahost;
  192. u_int32_t rport;
  193. const char *locuser, *remuser, *cmd;
  194. int *fd2p;
  195. {
  196. struct addrinfo *r;
  197. struct sockaddr_storage from;
  198. struct pollfd reads[2];
  199. #ifdef __minix
  200. /* No support for OOB data in Minix. */
  201. #else
  202. sigset_t nmask, omask;
  203. #endif /* !__minix */
  204. pid_t pid;
  205. int s, lport, timo;
  206. int pollr;
  207. char c;
  208. int refused;
  209. _DIAGASSERT(res != NULL);
  210. _DIAGASSERT(ahost != NULL);
  211. _DIAGASSERT(locuser != NULL);
  212. _DIAGASSERT(remuser != NULL);
  213. _DIAGASSERT(cmd != NULL);
  214. /* fd2p may be NULL */
  215. r = res;
  216. refused = 0;
  217. pid = getpid();
  218. #ifndef __minix
  219. /* Minix has no support for OOB data,
  220. no need to block SIGURG. */
  221. sigemptyset(&nmask);
  222. sigaddset(&nmask, SIGURG);
  223. if (sigprocmask(SIG_BLOCK, &nmask, &omask) == -1)
  224. return -1;
  225. #endif /* !__minix */
  226. for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
  227. s = rresvport_af(&lport, r->ai_family);
  228. if (s < 0) {
  229. if (errno == EAGAIN)
  230. warnx("rcmd: socket: All ports in use");
  231. else
  232. warn("rcmd: socket");
  233. if (r->ai_next) {
  234. r = r->ai_next;
  235. continue;
  236. } else {
  237. #ifndef __minix
  238. (void)sigprocmask(SIG_SETMASK, &omask, NULL);
  239. #endif /* !__minix */
  240. return (-1);
  241. }
  242. }
  243. #ifndef __minix
  244. /* No OOB support in Minix. */
  245. fcntl(s, F_SETOWN, pid);
  246. #endif /* !__minix */
  247. if (connect(s, r->ai_addr, r->ai_addrlen) >= 0)
  248. break;
  249. (void)close(s);
  250. if (errno == EADDRINUSE) {
  251. lport--;
  252. continue;
  253. } else if (errno == ECONNREFUSED)
  254. refused++;
  255. if (r->ai_next) {
  256. int oerrno = errno;
  257. char hbuf[NI_MAXHOST];
  258. const int niflags = NI_NUMERICHOST;
  259. hbuf[0] = '\0';
  260. if (getnameinfo(r->ai_addr, r->ai_addrlen,
  261. hbuf, sizeof(hbuf), NULL, 0, niflags) != 0)
  262. strlcpy(hbuf, "(invalid)", sizeof(hbuf));
  263. errno = oerrno;
  264. warn("rcmd: connect to address %s", hbuf);
  265. r = r->ai_next;
  266. hbuf[0] = '\0';
  267. if (getnameinfo(r->ai_addr, r->ai_addrlen,
  268. hbuf, sizeof(hbuf), NULL, 0, niflags) != 0)
  269. strlcpy(hbuf, "(invalid)", sizeof(hbuf));
  270. (void)fprintf(stderr, "Trying %s...\n", hbuf);
  271. continue;
  272. }
  273. if (refused && timo <= 16) {
  274. (void)sleep((unsigned int)timo);
  275. timo *= 2;
  276. r = res;
  277. refused = 0;
  278. continue;
  279. }
  280. (void)fprintf(stderr, "%s: %s\n", res->ai_canonname,
  281. strerror(errno));
  282. #ifndef __minix
  283. /* No OOB support in Minix. */
  284. (void)sigprocmask(SIG_SETMASK, &omask, NULL);
  285. #endif /* !__minix */
  286. return (-1);
  287. }
  288. lport--;
  289. if (fd2p == 0) {
  290. write(s, "", 1);
  291. lport = 0;
  292. } else {
  293. char num[8];
  294. int s2 = rresvport_af(&lport, r->ai_family), s3;
  295. socklen_t len = sizeof(from);
  296. if (s2 < 0)
  297. goto bad;
  298. listen(s2, 1);
  299. (void)snprintf(num, sizeof(num), "%d", lport);
  300. if (write(s, num, strlen(num) + 1) !=
  301. (ssize_t) (strlen(num) + 1)) {
  302. warn("rcmd: write (setting up stderr)");
  303. (void)close(s2);
  304. goto bad;
  305. }
  306. reads[0].fd = s;
  307. reads[0].events = POLLIN;
  308. reads[1].fd = s2;
  309. reads[1].events = POLLIN;
  310. errno = 0;
  311. pollr = poll(reads, 2, INFTIM);
  312. if (pollr < 1 || (reads[1].revents & POLLIN) == 0) {
  313. if (errno != 0)
  314. warn("poll: setting up stderr");
  315. else
  316. warnx("poll: protocol failure in circuit setup");
  317. (void)close(s2);
  318. goto bad;
  319. }
  320. s3 = accept(s2, (struct sockaddr *)(void *)&from, &len);
  321. (void)close(s2);
  322. if (s3 < 0) {
  323. warn("rcmd: accept");
  324. lport = 0;
  325. goto bad;
  326. }
  327. *fd2p = s3;
  328. switch (((struct sockaddr *)(void *)&from)->sa_family) {
  329. case AF_INET:
  330. #ifdef INET6
  331. case AF_INET6:
  332. #endif
  333. if (getnameinfo((struct sockaddr *)(void *)&from, len,
  334. NULL, 0, num, sizeof(num), NI_NUMERICSERV) != 0 ||
  335. (atoi(num) >= IPPORT_RESERVED ||
  336. atoi(num) < IPPORT_RESERVED / 2)) {
  337. warnx("rcmd: protocol failure in circuit setup.");
  338. goto bad2;
  339. }
  340. break;
  341. default:
  342. break;
  343. }
  344. }
  345. (void)write(s, locuser, strlen(locuser)+1);
  346. (void)write(s, remuser, strlen(remuser)+1);
  347. (void)write(s, cmd, strlen(cmd)+1);
  348. if (read(s, &c, 1) != 1) {
  349. warn("%s", *ahost);
  350. goto bad2;
  351. }
  352. if (c != 0) {
  353. while (read(s, &c, 1) == 1) {
  354. (void)write(STDERR_FILENO, &c, 1);
  355. if (c == '\n')
  356. break;
  357. }
  358. goto bad2;
  359. }
  360. #ifndef __minix
  361. (void)sigprocmask(SIG_SETMASK, &omask, NULL);
  362. #endif /* __minix */
  363. return (s);
  364. bad2:
  365. if (lport)
  366. (void)close(*fd2p);
  367. bad:
  368. (void)close(s);
  369. #ifndef __minix
  370. (void)sigprocmask(SIG_SETMASK, &omask, NULL);
  371. #endif /* __minix */
  372. return (-1);
  373. }
  374. /*
  375. * based on code written by Chris Siebenmann <cks@utcc.utoronto.ca>
  376. */
  377. /* ARGSUSED */
  378. static int
  379. rshrcmd(ahost, rport, locuser, remuser, cmd, fd2p, rshcmd)
  380. char **ahost;
  381. u_int32_t rport;
  382. const char *locuser, *remuser, *cmd;
  383. int *fd2p;
  384. const char *rshcmd;
  385. {
  386. pid_t pid;
  387. int sp[2], ep[2];
  388. char *p;
  389. struct passwd *pw, pwres;
  390. char pwbuf[1024];
  391. _DIAGASSERT(ahost != NULL);
  392. _DIAGASSERT(locuser != NULL);
  393. _DIAGASSERT(remuser != NULL);
  394. _DIAGASSERT(cmd != NULL);
  395. /* fd2p may be NULL */
  396. /* What rsh/shell to use. */
  397. if (rshcmd == NULL)
  398. rshcmd = _PATH_BIN_RCMD;
  399. /* locuser must exist on this host. */
  400. if (getpwnam_r(locuser, &pwres, pwbuf, sizeof(pwbuf), &pw) != 0 ||
  401. pw == NULL) {
  402. warnx("rshrcmd: unknown user: %s", locuser);
  403. return(-1);
  404. }
  405. /* get a socketpair we'll use for stdin and stdout. */
  406. if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sp) < 0) {
  407. warn("rshrcmd: socketpair");
  408. return (-1);
  409. }
  410. /* we will use this for the fd2 pointer */
  411. if (fd2p) {
  412. if (socketpair(AF_LOCAL, SOCK_STREAM, 0, ep) < 0) {
  413. warn("rshrcmd: socketpair");
  414. return (-1);
  415. }
  416. *fd2p = ep[0];
  417. }
  418. pid = fork();
  419. if (pid < 0) {
  420. warn("rshrcmd: fork");
  421. return (-1);
  422. }
  423. if (pid == 0) {
  424. /*
  425. * child
  426. * - we use sp[1] to be stdin/stdout, and close sp[0]
  427. * - with fd2p, we use ep[1] for stderr, and close ep[0]
  428. */
  429. (void)close(sp[0]);
  430. if (dup2(sp[1], 0) < 0 || dup2(0, 1) < 0) {
  431. warn("rshrcmd: dup2");
  432. _exit(1);
  433. }
  434. (void)close(sp[1]);
  435. if (fd2p) {
  436. if (dup2(ep[1], 2) < 0) {
  437. warn("rshrcmd: dup2");
  438. _exit(1);
  439. }
  440. (void)close(ep[0]);
  441. (void)close(ep[1]);
  442. } else if (dup2(0, 2) < 0) {
  443. warn("rshrcmd: dup2");
  444. _exit(1);
  445. }
  446. /* fork again to lose parent. */
  447. pid = fork();
  448. if (pid < 0) {
  449. warn("rshrcmd: second fork");
  450. _exit(1);
  451. }
  452. if (pid > 0)
  453. _exit(0);
  454. /* Orphan. Become local user for rshprog. */
  455. if (setuid(pw->pw_uid)) {
  456. warn("rshrcmd: setuid(%lu)", (u_long)pw->pw_uid);
  457. _exit(1);
  458. }
  459. /*
  460. * If we are rcmd'ing to "localhost" as the same user as we are,
  461. * then avoid running remote shell for efficiency.
  462. */
  463. if (strcmp(*ahost, "localhost") == 0 &&
  464. strcmp(locuser, remuser) == 0) {
  465. if (pw->pw_shell[0] == '\0')
  466. rshcmd = _PATH_BSHELL;
  467. else
  468. rshcmd = pw->pw_shell;
  469. p = strrchr(rshcmd, '/');
  470. execlp(rshcmd, p ? p + 1 : rshcmd, "-c", cmd, NULL);
  471. } else {
  472. p = strrchr(rshcmd, '/');
  473. execlp(rshcmd, p ? p + 1 : rshcmd, *ahost, "-l",
  474. remuser, cmd, NULL);
  475. }
  476. warn("rshrcmd: exec %s", rshcmd);
  477. _exit(1);
  478. }
  479. /* Parent */
  480. (void)close(sp[1]);
  481. if (fd2p)
  482. (void)close(ep[1]);
  483. (void)waitpid(pid, NULL, 0);
  484. return (sp[0]);
  485. }
  486. int
  487. rresvport(alport)
  488. int *alport;
  489. {
  490. _DIAGASSERT(alport != NULL);
  491. return rresvport_af(alport, AF_INET);
  492. }
  493. int
  494. rresvport_af(alport, family)
  495. int *alport;
  496. int family;
  497. {
  498. struct sockaddr_storage ss;
  499. struct sockaddr *sa;
  500. int salen;
  501. int s;
  502. u_int16_t *portp;
  503. _DIAGASSERT(alport != NULL);
  504. memset(&ss, 0, sizeof(ss));
  505. sa = (struct sockaddr *)(void *)&ss;
  506. switch (family) {
  507. case AF_INET:
  508. #ifdef BSD4_4
  509. sa->sa_len =
  510. #endif
  511. salen = sizeof(struct sockaddr_in);
  512. portp = &((struct sockaddr_in *)(void *)sa)->sin_port;
  513. break;
  514. #ifdef INET6
  515. case AF_INET6:
  516. #ifdef BSD4_4
  517. sa->sa_len =
  518. #endif
  519. salen = sizeof(struct sockaddr_in6);
  520. portp = &((struct sockaddr_in6 *)(void *)sa)->sin6_port;
  521. break;
  522. #endif
  523. default:
  524. errno = EAFNOSUPPORT;
  525. return (-1);
  526. }
  527. sa->sa_family = family;
  528. s = socket(family, SOCK_STREAM, 0);
  529. if (s < 0)
  530. return (-1);
  531. #ifdef BSD4_4
  532. switch (family) {
  533. case AF_INET:
  534. case AF_INET6:
  535. *portp = 0;
  536. if (bindresvport(s, (struct sockaddr_in *)(void *)sa) < 0) {
  537. int sverr = errno;
  538. (void)close(s);
  539. errno = sverr;
  540. return (-1);
  541. }
  542. *alport = (int)ntohs(*portp);
  543. return (s);
  544. default:
  545. /* is it necessary to try keep code for other AFs? */
  546. break;
  547. }
  548. #endif
  549. for (;;) {
  550. *portp = htons((u_short)*alport);
  551. if (bind(s, sa, (socklen_t)salen) >= 0)
  552. return (s);
  553. if (errno != EADDRINUSE) {
  554. (void)close(s);
  555. return (-1);
  556. }
  557. (*alport)--;
  558. if (*alport == IPPORT_RESERVED/2) {
  559. (void)close(s);
  560. errno = EAGAIN; /* close */
  561. return (-1);
  562. }
  563. }
  564. }
  565. int __check_rhosts_file = 1;
  566. const char *__rcmd_errstr;
  567. int
  568. ruserok(rhost, superuser, ruser, luser)
  569. const char *rhost, *ruser, *luser;
  570. int superuser;
  571. {
  572. struct addrinfo hints, *res, *r;
  573. int error;
  574. _DIAGASSERT(rhost != NULL);
  575. _DIAGASSERT(ruser != NULL);
  576. _DIAGASSERT(luser != NULL);
  577. memset(&hints, 0, sizeof(hints));
  578. hints.ai_family = PF_UNSPEC;
  579. hints.ai_socktype = SOCK_DGRAM; /*dummy*/
  580. error = getaddrinfo(rhost, "0", &hints, &res);
  581. if (error)
  582. return (-1);
  583. for (r = res; r; r = r->ai_next) {
  584. if (iruserok_sa(r->ai_addr, (int)r->ai_addrlen, superuser,
  585. ruser, luser) == 0) {
  586. freeaddrinfo(res);
  587. return (0);
  588. }
  589. }
  590. freeaddrinfo(res);
  591. return (-1);
  592. }
  593. /*
  594. * New .rhosts strategy: We are passed an ip address. We spin through
  595. * hosts.equiv and .rhosts looking for a match. When the .rhosts only
  596. * has ip addresses, we don't have to trust a nameserver. When it
  597. * contains hostnames, we spin through the list of addresses the nameserver
  598. * gives us and look for a match.
  599. *
  600. * Returns 0 if ok, -1 if not ok.
  601. */
  602. int
  603. iruserok(raddr, superuser, ruser, luser)
  604. u_int32_t raddr;
  605. int superuser;
  606. const char *ruser, *luser;
  607. {
  608. struct sockaddr_in irsin;
  609. memset(&irsin, 0, sizeof(irsin));
  610. irsin.sin_family = AF_INET;
  611. #ifdef BSD4_4
  612. irsin.sin_len = sizeof(struct sockaddr_in);
  613. #endif
  614. memcpy(&irsin.sin_addr, &raddr, sizeof(irsin.sin_addr));
  615. return iruserok_sa(&irsin, sizeof(struct sockaddr_in), superuser, ruser,
  616. luser);
  617. }
  618. /*
  619. * 2nd and 3rd arguments are typed like this, to avoid dependency between
  620. * unistd.h and sys/socket.h. There's no better way.
  621. */
  622. int
  623. iruserok_sa(raddr, rlen, superuser, ruser, luser)
  624. const void *raddr;
  625. int rlen;
  626. int superuser;
  627. const char *ruser, *luser;
  628. {
  629. const struct sockaddr *sa;
  630. struct stat sbuf;
  631. struct passwd *pwd, pwres;
  632. FILE *hostf;
  633. uid_t uid;
  634. gid_t gid;
  635. int isvaliduser;
  636. char pbuf[MAXPATHLEN];
  637. char pwbuf[1024];
  638. _DIAGASSERT(raddr != NULL);
  639. _DIAGASSERT(ruser != NULL);
  640. _DIAGASSERT(luser != NULL);
  641. sa = raddr;
  642. __rcmd_errstr = NULL;
  643. hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "r");
  644. if (hostf) {
  645. if (__ivaliduser_sa(hostf, sa, (socklen_t)rlen, luser,
  646. ruser) == 0) {
  647. (void)fclose(hostf);
  648. return (0);
  649. }
  650. (void)fclose(hostf);
  651. }
  652. isvaliduser = -1;
  653. if (__check_rhosts_file || superuser) {
  654. if (getpwnam_r(luser, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0
  655. || pwd == NULL)
  656. return (-1);
  657. (void)strlcpy(pbuf, pwd->pw_dir, sizeof(pbuf));
  658. (void)strlcat(pbuf, "/.rhosts", sizeof(pbuf));
  659. /*
  660. * Change effective uid while opening and reading .rhosts.
  661. * If root and reading an NFS mounted file system, can't
  662. * read files that are protected read/write owner only.
  663. */
  664. uid = geteuid();
  665. gid = getegid();
  666. (void)setegid(pwd->pw_gid);
  667. initgroups(pwd->pw_name, pwd->pw_gid);
  668. (void)seteuid(pwd->pw_uid);
  669. hostf = fopen(pbuf, "r");
  670. if (hostf != NULL) {
  671. /*
  672. * If not a regular file, or is owned by someone other
  673. * than user or root or if writable by anyone but the
  674. * owner, quit.
  675. */
  676. if (lstat(pbuf, &sbuf) < 0)
  677. __rcmd_errstr = ".rhosts lstat failed";
  678. else if (!S_ISREG(sbuf.st_mode))
  679. __rcmd_errstr = ".rhosts not regular file";
  680. else if (fstat(fileno(hostf), &sbuf) < 0)
  681. __rcmd_errstr = ".rhosts fstat failed";
  682. else if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid)
  683. __rcmd_errstr = "bad .rhosts owner";
  684. else if (sbuf.st_mode & (S_IWGRP|S_IWOTH))
  685. __rcmd_errstr =
  686. ".rhosts writable by other than owner";
  687. else
  688. isvaliduser =
  689. __ivaliduser_sa(hostf, sa, (socklen_t)rlen,
  690. luser, ruser);
  691. (void)fclose(hostf);
  692. }
  693. (void)seteuid(uid);
  694. (void)setegid(gid);
  695. }
  696. return (isvaliduser);
  697. }
  698. /*
  699. * XXX
  700. * Don't make static, used by lpd(8). We will be able to change the function
  701. * into static function, when we bump libc major #.
  702. *
  703. * Returns 0 if ok, -1 if not ok.
  704. */
  705. #ifdef notdef /*_LIBC*/
  706. static
  707. #endif
  708. int
  709. __ivaliduser(hostf, raddr, luser, ruser)
  710. FILE *hostf;
  711. u_int32_t raddr;
  712. const char *luser, *ruser;
  713. {
  714. struct sockaddr_in ivusin;
  715. memset(&ivusin, 0, sizeof(ivusin));
  716. ivusin.sin_family = AF_INET;
  717. #ifdef BSD4_4
  718. ivusin.sin_len = sizeof(struct sockaddr_in);
  719. #endif
  720. memcpy(&ivusin.sin_addr, &raddr, sizeof(ivusin.sin_addr));
  721. return __ivaliduser_sa(hostf, (struct sockaddr *)(void *)&ivusin,
  722. sizeof(struct sockaddr_in), luser, ruser);
  723. }
  724. #ifdef notdef /*_LIBC*/
  725. static
  726. #endif
  727. int
  728. __ivaliduser_sa(hostf, raddr, salen, luser, ruser)
  729. FILE *hostf;
  730. const struct sockaddr *raddr;
  731. socklen_t salen;
  732. const char *luser, *ruser;
  733. {
  734. register char *user, *p;
  735. int ch;
  736. char buf[MAXHOSTNAMELEN + 128]; /* host + login */
  737. const char *auser, *ahost;
  738. int hostok, userok;
  739. char *rhost = NULL;
  740. int firsttime = 1;
  741. char domain[MAXHOSTNAMELEN];
  742. getdomainname(domain, sizeof(domain));
  743. _DIAGASSERT(hostf != NULL);
  744. _DIAGASSERT(luser != NULL);
  745. _DIAGASSERT(ruser != NULL);
  746. while (fgets(buf, sizeof(buf), hostf)) {
  747. p = buf;
  748. /* Skip lines that are too long. */
  749. if (strchr(p, '\n') == NULL) {
  750. while ((ch = getc(hostf)) != '\n' && ch != EOF)
  751. ;
  752. continue;
  753. }
  754. while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') {
  755. *p = isupper((unsigned char)*p) ?
  756. tolower((unsigned char)*p) : *p;
  757. p++;
  758. }
  759. if (*p == ' ' || *p == '\t') {
  760. *p++ = '\0';
  761. while (*p == ' ' || *p == '\t')
  762. p++;
  763. user = p;
  764. while (*p != '\n' && *p != ' ' &&
  765. *p != '\t' && *p != '\0')
  766. p++;
  767. } else
  768. user = p;
  769. *p = '\0';
  770. if (p == buf)
  771. continue;
  772. auser = *user ? user : luser;
  773. ahost = buf;
  774. if (ahost[0] == '+')
  775. switch (ahost[1]) {
  776. case '\0':
  777. hostok = 1;
  778. break;
  779. case '@':
  780. if (firsttime) {
  781. rhost = __gethostloop(raddr, salen);
  782. firsttime = 0;
  783. }
  784. if (rhost)
  785. hostok = innetgr(&ahost[2], rhost,
  786. NULL, domain);
  787. else
  788. hostok = 0;
  789. break;
  790. default:
  791. hostok = __icheckhost(raddr, salen, &ahost[1]);
  792. break;
  793. }
  794. else if (ahost[0] == '-')
  795. switch (ahost[1]) {
  796. case '\0':
  797. hostok = -1;
  798. break;
  799. case '@':
  800. if (firsttime) {
  801. rhost = __gethostloop(raddr, salen);
  802. firsttime = 0;
  803. }
  804. if (rhost)
  805. hostok = -innetgr(&ahost[2], rhost,
  806. NULL, domain);
  807. else
  808. hostok = 0;
  809. break;
  810. default:
  811. hostok = -__icheckhost(raddr, salen, &ahost[1]);
  812. break;
  813. }
  814. else
  815. hostok = __icheckhost(raddr, salen, ahost);
  816. if (auser[0] == '+')
  817. switch (auser[1]) {
  818. case '\0':
  819. userok = 1;
  820. break;
  821. case '@':
  822. userok = innetgr(&auser[2], NULL, ruser,
  823. domain);
  824. break;
  825. default:
  826. userok = strcmp(ruser, &auser[1]) == 0;
  827. break;
  828. }
  829. else if (auser[0] == '-')
  830. switch (auser[1]) {
  831. case '\0':
  832. userok = -1;
  833. break;
  834. case '@':
  835. userok = -innetgr(&auser[2], NULL, ruser,
  836. domain);
  837. break;
  838. default:
  839. userok =
  840. -(strcmp(ruser, &auser[1]) == 0 ? 1 : 0);
  841. break;
  842. }
  843. else
  844. userok = strcmp(ruser, auser) == 0;
  845. /* Check if one component did not match */
  846. if (hostok == 0 || userok == 0)
  847. continue;
  848. /* Check if we got a forbidden pair */
  849. if (userok == -1 || hostok == -1)
  850. return -1;
  851. /* Check if we got a valid pair */
  852. if (hostok == 1 && userok == 1)
  853. return 0;
  854. }
  855. return -1;
  856. }
  857. /*
  858. * Returns "true" if match, 0 if no match.
  859. */
  860. static int
  861. __icheckhost(raddr, salen, lhost)
  862. const struct sockaddr *raddr;
  863. socklen_t salen;
  864. const char *lhost;
  865. {
  866. struct addrinfo hints, *res, *r;
  867. char h1[NI_MAXHOST], h2[NI_MAXHOST];
  868. int error;
  869. const int niflags = NI_NUMERICHOST;
  870. _DIAGASSERT(raddr != NULL);
  871. _DIAGASSERT(lhost != NULL);
  872. h1[0] = '\0';
  873. if (getnameinfo(raddr, salen, h1, sizeof(h1), NULL, 0,
  874. niflags) != 0)
  875. return (0);
  876. /* Resolve laddr into sockaddr */
  877. memset(&hints, 0, sizeof(hints));
  878. hints.ai_family = raddr->sa_family;
  879. hints.ai_socktype = SOCK_DGRAM; /*dummy*/
  880. res = NULL;
  881. error = getaddrinfo(lhost, "0", &hints, &res);
  882. if (error)
  883. return (0);
  884. /*
  885. * Try string comparisons between raddr and laddr.
  886. */
  887. for (r = res; r; r = r->ai_next) {
  888. h2[0] = '\0';
  889. if (getnameinfo(r->ai_addr, r->ai_addrlen, h2, sizeof(h2),
  890. NULL, 0, niflags) != 0)
  891. continue;
  892. if (strcmp(h1, h2) == 0) {
  893. freeaddrinfo(res);
  894. return (1);
  895. }
  896. }
  897. /* No match. */
  898. freeaddrinfo(res);
  899. return (0);
  900. }
  901. /*
  902. * Return the hostname associated with the supplied address.
  903. * Do a reverse lookup as well for security. If a loop cannot
  904. * be found, pack the numeric IP address into the string.
  905. */
  906. static char *
  907. __gethostloop(raddr, salen)
  908. const struct sockaddr *raddr;
  909. socklen_t salen;
  910. {
  911. static char remotehost[NI_MAXHOST];
  912. char h1[NI_MAXHOST], h2[NI_MAXHOST];
  913. struct addrinfo hints, *res, *r;
  914. int error;
  915. const int niflags = NI_NUMERICHOST;
  916. _DIAGASSERT(raddr != NULL);
  917. h1[0] = remotehost[0] = '\0';
  918. if (getnameinfo(raddr, salen, remotehost, sizeof(remotehost),
  919. NULL, 0, NI_NAMEREQD) != 0)
  920. return (NULL);
  921. if (getnameinfo(raddr, salen, h1, sizeof(h1), NULL, 0,
  922. niflags) != 0)
  923. return (NULL);
  924. /*
  925. * Look up the name and check that the supplied
  926. * address is in the list
  927. */
  928. memset(&hints, 0, sizeof(hints));
  929. hints.ai_family = raddr->sa_family;
  930. hints.ai_socktype = SOCK_DGRAM; /*dummy*/
  931. hints.ai_flags = AI_CANONNAME;
  932. res = NULL;
  933. error = getaddrinfo(remotehost, "0", &hints, &res);
  934. if (error)
  935. return (NULL);
  936. for (r = res; r; r = r->ai_next) {
  937. h2[0] = '\0';
  938. if (getnameinfo(r->ai_addr, r->ai_addrlen, h2, sizeof(h2),
  939. NULL, 0, niflags) != 0)
  940. continue;
  941. if (strcmp(h1, h2) == 0) {
  942. freeaddrinfo(res);
  943. return (remotehost);
  944. }
  945. }
  946. /*
  947. * either the DNS adminstrator has made a configuration
  948. * mistake, or someone has attempted to spoof us
  949. */
  950. syslog(LOG_NOTICE, "rcmd: address %s not listed for host %s",
  951. h1, res->ai_canonname ? res->ai_canonname : remotehost);
  952. freeaddrinfo(res);
  953. return (NULL);
  954. }