193d36fc9SDavid van Moolenbroek /* $NetBSD: rshd.c,v 1.50 2012/07/14 15:06:26 darrenr Exp $ */
293d36fc9SDavid van Moolenbroek
393d36fc9SDavid van Moolenbroek /*
493d36fc9SDavid van Moolenbroek * Copyright (C) 1998 WIDE Project.
593d36fc9SDavid van Moolenbroek * All rights reserved.
693d36fc9SDavid van Moolenbroek *
793d36fc9SDavid van Moolenbroek * Redistribution and use in source and binary forms, with or without
893d36fc9SDavid van Moolenbroek * modification, are permitted provided that the following conditions
993d36fc9SDavid van Moolenbroek * are met:
1093d36fc9SDavid van Moolenbroek * 1. Redistributions of source code must retain the above copyright
1193d36fc9SDavid van Moolenbroek * notice, this list of conditions and the following disclaimer.
1293d36fc9SDavid van Moolenbroek * 2. Redistributions in binary form must reproduce the above copyright
1393d36fc9SDavid van Moolenbroek * notice, this list of conditions and the following disclaimer in the
1493d36fc9SDavid van Moolenbroek * documentation and/or other materials provided with the distribution.
1593d36fc9SDavid van Moolenbroek * 3. All advertising materials mentioning features or use of this software
1693d36fc9SDavid van Moolenbroek * must display the following acknowledgement:
1793d36fc9SDavid van Moolenbroek * This product includes software developed by WIDE Project and
1893d36fc9SDavid van Moolenbroek * its contributors.
1993d36fc9SDavid van Moolenbroek * 4. Neither the name of the project nor the names of its contributors
2093d36fc9SDavid van Moolenbroek * may be used to endorse or promote products derived from this software
2193d36fc9SDavid van Moolenbroek * without specific prior written permission.
2293d36fc9SDavid van Moolenbroek *
2393d36fc9SDavid van Moolenbroek * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2493d36fc9SDavid van Moolenbroek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2593d36fc9SDavid van Moolenbroek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2693d36fc9SDavid van Moolenbroek * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2793d36fc9SDavid van Moolenbroek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2893d36fc9SDavid van Moolenbroek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2993d36fc9SDavid van Moolenbroek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3093d36fc9SDavid van Moolenbroek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3193d36fc9SDavid van Moolenbroek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3293d36fc9SDavid van Moolenbroek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3393d36fc9SDavid van Moolenbroek * SUCH DAMAGE.
3493d36fc9SDavid van Moolenbroek */
3593d36fc9SDavid van Moolenbroek
3693d36fc9SDavid van Moolenbroek /*-
3793d36fc9SDavid van Moolenbroek * Copyright (c) 1988, 1989, 1992, 1993, 1994
3893d36fc9SDavid van Moolenbroek * The Regents of the University of California. All rights reserved.
3993d36fc9SDavid van Moolenbroek *
4093d36fc9SDavid van Moolenbroek * Redistribution and use in source and binary forms, with or without
4193d36fc9SDavid van Moolenbroek * modification, are permitted provided that the following conditions
4293d36fc9SDavid van Moolenbroek * are met:
4393d36fc9SDavid van Moolenbroek * 1. Redistributions of source code must retain the above copyright
4493d36fc9SDavid van Moolenbroek * notice, this list of conditions and the following disclaimer.
4593d36fc9SDavid van Moolenbroek * 2. Redistributions in binary form must reproduce the above copyright
4693d36fc9SDavid van Moolenbroek * notice, this list of conditions and the following disclaimer in the
4793d36fc9SDavid van Moolenbroek * documentation and/or other materials provided with the distribution.
4893d36fc9SDavid van Moolenbroek * 3. Neither the name of the University nor the names of its contributors
4993d36fc9SDavid van Moolenbroek * may be used to endorse or promote products derived from this software
5093d36fc9SDavid van Moolenbroek * without specific prior written permission.
5193d36fc9SDavid van Moolenbroek *
5293d36fc9SDavid van Moolenbroek * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
5393d36fc9SDavid van Moolenbroek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5493d36fc9SDavid van Moolenbroek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5593d36fc9SDavid van Moolenbroek * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
5693d36fc9SDavid van Moolenbroek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5793d36fc9SDavid van Moolenbroek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5893d36fc9SDavid van Moolenbroek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5993d36fc9SDavid van Moolenbroek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
6093d36fc9SDavid van Moolenbroek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
6193d36fc9SDavid van Moolenbroek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6293d36fc9SDavid van Moolenbroek * SUCH DAMAGE.
6393d36fc9SDavid van Moolenbroek */
6493d36fc9SDavid van Moolenbroek
6593d36fc9SDavid van Moolenbroek #include <sys/cdefs.h>
6693d36fc9SDavid van Moolenbroek #ifndef lint
6793d36fc9SDavid van Moolenbroek __COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1992, 1993, 1994\
6893d36fc9SDavid van Moolenbroek The Regents of the University of California. All rights reserved.");
6993d36fc9SDavid van Moolenbroek #if 0
7093d36fc9SDavid van Moolenbroek static char sccsid[] = "@(#)rshd.c 8.2 (Berkeley) 4/6/94";
7193d36fc9SDavid van Moolenbroek #else
7293d36fc9SDavid van Moolenbroek __RCSID("$NetBSD: rshd.c,v 1.50 2012/07/14 15:06:26 darrenr Exp $");
7393d36fc9SDavid van Moolenbroek #endif
7493d36fc9SDavid van Moolenbroek #endif /* not lint */
7593d36fc9SDavid van Moolenbroek
7693d36fc9SDavid van Moolenbroek /*
7793d36fc9SDavid van Moolenbroek * remote shell server:
7893d36fc9SDavid van Moolenbroek * [port]\0
7993d36fc9SDavid van Moolenbroek * remuser\0
8093d36fc9SDavid van Moolenbroek * locuser\0
8193d36fc9SDavid van Moolenbroek * command\0
8293d36fc9SDavid van Moolenbroek * data
8393d36fc9SDavid van Moolenbroek */
8493d36fc9SDavid van Moolenbroek #include <sys/param.h>
8593d36fc9SDavid van Moolenbroek #include <sys/ioctl.h>
8693d36fc9SDavid van Moolenbroek #include <sys/time.h>
8793d36fc9SDavid van Moolenbroek #include <sys/socket.h>
8893d36fc9SDavid van Moolenbroek
8993d36fc9SDavid van Moolenbroek #include <netinet/in_systm.h>
9093d36fc9SDavid van Moolenbroek #include <netinet/in.h>
9193d36fc9SDavid van Moolenbroek #include <netinet/ip.h>
9293d36fc9SDavid van Moolenbroek #include <netinet/tcp.h>
9393d36fc9SDavid van Moolenbroek #include <arpa/inet.h>
9493d36fc9SDavid van Moolenbroek #include <netdb.h>
9593d36fc9SDavid van Moolenbroek
9693d36fc9SDavid van Moolenbroek #include <errno.h>
9793d36fc9SDavid van Moolenbroek #include <fcntl.h>
9893d36fc9SDavid van Moolenbroek #include <paths.h>
9993d36fc9SDavid van Moolenbroek #include <pwd.h>
10093d36fc9SDavid van Moolenbroek #include <signal.h>
10193d36fc9SDavid van Moolenbroek #include <stdio.h>
10293d36fc9SDavid van Moolenbroek #include <stdlib.h>
10393d36fc9SDavid van Moolenbroek #include <string.h>
10493d36fc9SDavid van Moolenbroek #include <syslog.h>
10593d36fc9SDavid van Moolenbroek #include <unistd.h>
10693d36fc9SDavid van Moolenbroek #include <poll.h>
10793d36fc9SDavid van Moolenbroek #ifdef LOGIN_CAP
10893d36fc9SDavid van Moolenbroek #include <login_cap.h>
10993d36fc9SDavid van Moolenbroek #endif
11093d36fc9SDavid van Moolenbroek
11193d36fc9SDavid van Moolenbroek #ifdef USE_PAM
11293d36fc9SDavid van Moolenbroek #include <security/pam_appl.h>
11393d36fc9SDavid van Moolenbroek #include <security/openpam.h>
11493d36fc9SDavid van Moolenbroek #include <sys/wait.h>
11593d36fc9SDavid van Moolenbroek
11693d36fc9SDavid van Moolenbroek static struct pam_conv pamc = { openpam_nullconv, NULL };
11793d36fc9SDavid van Moolenbroek static pam_handle_t *pamh;
11893d36fc9SDavid van Moolenbroek static int pam_err;
11993d36fc9SDavid van Moolenbroek
12093d36fc9SDavid van Moolenbroek #define PAM_END do { \
12193d36fc9SDavid van Moolenbroek if ((pam_err = pam_setcred(pamh, PAM_DELETE_CRED)) != PAM_SUCCESS) \
12293d36fc9SDavid van Moolenbroek syslog(LOG_ERR|LOG_AUTH, "pam_setcred(): %s", \
12393d36fc9SDavid van Moolenbroek pam_strerror(pamh, pam_err)); \
12493d36fc9SDavid van Moolenbroek if ((pam_err = pam_close_session(pamh,0)) != PAM_SUCCESS) \
12593d36fc9SDavid van Moolenbroek syslog(LOG_ERR|LOG_AUTH, "pam_close_session(): %s", \
12693d36fc9SDavid van Moolenbroek pam_strerror(pamh, pam_err)); \
12793d36fc9SDavid van Moolenbroek if ((pam_err = pam_end(pamh, pam_err)) != PAM_SUCCESS) \
12893d36fc9SDavid van Moolenbroek syslog(LOG_ERR|LOG_AUTH, "pam_end(): %s", \
12993d36fc9SDavid van Moolenbroek pam_strerror(pamh, pam_err)); \
13093d36fc9SDavid van Moolenbroek } while (/*CONSTCOND*/0)
13193d36fc9SDavid van Moolenbroek #else
13293d36fc9SDavid van Moolenbroek #define PAM_END
13393d36fc9SDavid van Moolenbroek #endif
13493d36fc9SDavid van Moolenbroek
13593d36fc9SDavid van Moolenbroek static int keepalive = 1;
13693d36fc9SDavid van Moolenbroek static int check_all;
13793d36fc9SDavid van Moolenbroek static int log_success; /* If TRUE, log all successful accesses */
13893d36fc9SDavid van Moolenbroek static int sent_null;
13993d36fc9SDavid van Moolenbroek
14093d36fc9SDavid van Moolenbroek __dead static void doit(struct sockaddr *, struct sockaddr *);
14193d36fc9SDavid van Moolenbroek __dead static void rshd_errx(int, const char *, ...) __printflike(2, 3);
14293d36fc9SDavid van Moolenbroek static void getstr(char *, int, const char *);
14393d36fc9SDavid van Moolenbroek static int local_domain(char *);
14493d36fc9SDavid van Moolenbroek static char *topdomain(char *);
14593d36fc9SDavid van Moolenbroek __dead static void usage(void);
14693d36fc9SDavid van Moolenbroek
14793d36fc9SDavid van Moolenbroek #define OPTIONS "aLln"
14893d36fc9SDavid van Moolenbroek extern int __check_rhosts_file;
14993d36fc9SDavid van Moolenbroek extern char *__rcmd_errstr; /* syslog hook from libc/net/rcmd.c. */
150*0a6a1f1dSLionel Sambuc #if defined(__minix) && defined(USE_PAM)
15193d36fc9SDavid van Moolenbroek static const char incorrect[] = "Login incorrect.";
152*0a6a1f1dSLionel Sambuc #endif /* defined(__minix) && defined(USE_PAM) */
15393d36fc9SDavid van Moolenbroek
15493d36fc9SDavid van Moolenbroek int
main(int argc,char * argv[])15593d36fc9SDavid van Moolenbroek main(int argc, char *argv[])
15693d36fc9SDavid van Moolenbroek {
15793d36fc9SDavid van Moolenbroek struct linger linger;
15893d36fc9SDavid van Moolenbroek int ch, on = 1;
15993d36fc9SDavid van Moolenbroek socklen_t fromlen;
16093d36fc9SDavid van Moolenbroek socklen_t locallen;
16193d36fc9SDavid van Moolenbroek struct sockaddr_storage from;
16293d36fc9SDavid van Moolenbroek struct sockaddr_storage local;
16393d36fc9SDavid van Moolenbroek struct protoent *proto;
16493d36fc9SDavid van Moolenbroek
16593d36fc9SDavid van Moolenbroek openlog("rshd", LOG_PID, LOG_DAEMON);
16693d36fc9SDavid van Moolenbroek
16793d36fc9SDavid van Moolenbroek opterr = 0;
16893d36fc9SDavid van Moolenbroek while ((ch = getopt(argc, argv, OPTIONS)) != -1)
16993d36fc9SDavid van Moolenbroek switch (ch) {
17093d36fc9SDavid van Moolenbroek case 'a':
17193d36fc9SDavid van Moolenbroek check_all = 1;
17293d36fc9SDavid van Moolenbroek break;
17393d36fc9SDavid van Moolenbroek case 'l':
17493d36fc9SDavid van Moolenbroek __check_rhosts_file = 0;
17593d36fc9SDavid van Moolenbroek break;
17693d36fc9SDavid van Moolenbroek case 'n':
17793d36fc9SDavid van Moolenbroek keepalive = 0;
17893d36fc9SDavid van Moolenbroek break;
17993d36fc9SDavid van Moolenbroek case 'L':
18093d36fc9SDavid van Moolenbroek log_success = 1;
18193d36fc9SDavid van Moolenbroek break;
18293d36fc9SDavid van Moolenbroek case '?':
18393d36fc9SDavid van Moolenbroek default:
18493d36fc9SDavid van Moolenbroek usage();
18593d36fc9SDavid van Moolenbroek break;
18693d36fc9SDavid van Moolenbroek }
18793d36fc9SDavid van Moolenbroek
18893d36fc9SDavid van Moolenbroek argc -= optind;
18993d36fc9SDavid van Moolenbroek argv += optind;
19093d36fc9SDavid van Moolenbroek
19193d36fc9SDavid van Moolenbroek fromlen = sizeof(from); /* xxx */
19293d36fc9SDavid van Moolenbroek locallen = sizeof(local); /* xxx */
19393d36fc9SDavid van Moolenbroek if (getpeername(STDIN_FILENO, (struct sockaddr *)&from, &fromlen) < 0) {
19493d36fc9SDavid van Moolenbroek syslog(LOG_ERR, "getpeername: %m");
19593d36fc9SDavid van Moolenbroek return EXIT_FAILURE;
19693d36fc9SDavid van Moolenbroek }
19793d36fc9SDavid van Moolenbroek if (getsockname(STDIN_FILENO, (struct sockaddr *)&local,
19893d36fc9SDavid van Moolenbroek &locallen) < 0) {
19993d36fc9SDavid van Moolenbroek syslog(LOG_ERR, "getsockname: %m");
20093d36fc9SDavid van Moolenbroek return EXIT_FAILURE;
20193d36fc9SDavid van Moolenbroek }
20293d36fc9SDavid van Moolenbroek #if 0
20393d36fc9SDavid van Moolenbroek if (((struct sockaddr *)&from)->sa_family == AF_INET6 &&
20493d36fc9SDavid van Moolenbroek IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&from)->sin6_addr) &&
20593d36fc9SDavid van Moolenbroek sizeof(struct sockaddr_in) <= sizeof(from)) {
20693d36fc9SDavid van Moolenbroek struct sockaddr_in sin;
20793d36fc9SDavid van Moolenbroek struct sockaddr_in6 *sin6;
20893d36fc9SDavid van Moolenbroek const int off = sizeof(struct sockaddr_in6) -
20993d36fc9SDavid van Moolenbroek sizeof(struct sockaddr_in);
21093d36fc9SDavid van Moolenbroek
21193d36fc9SDavid van Moolenbroek sin6 = (struct sockaddr_in6 *)&from;
21293d36fc9SDavid van Moolenbroek (void)memset(&sin, 0, sizeof(sin));
21393d36fc9SDavid van Moolenbroek sin.sin_family = AF_INET;
21493d36fc9SDavid van Moolenbroek sin.sin_len = sizeof(struct sockaddr_in);
21593d36fc9SDavid van Moolenbroek (void)memcpy(&sin.sin_addr, &sin6->sin6_addr.s6_addr[off],
21693d36fc9SDavid van Moolenbroek sizeof(sin.sin_addr));
21793d36fc9SDavid van Moolenbroek (void)memcpy(&from, &sin, sizeof(sin));
21893d36fc9SDavid van Moolenbroek fromlen = sin.sin_len;
21993d36fc9SDavid van Moolenbroek }
22093d36fc9SDavid van Moolenbroek #else
22193d36fc9SDavid van Moolenbroek if (((struct sockaddr *)&from)->sa_family == AF_INET6 &&
22293d36fc9SDavid van Moolenbroek IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&from)->sin6_addr)) {
22393d36fc9SDavid van Moolenbroek char hbuf[NI_MAXHOST];
22493d36fc9SDavid van Moolenbroek if (getnameinfo((struct sockaddr *)&from, fromlen, hbuf,
22593d36fc9SDavid van Moolenbroek sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) {
22693d36fc9SDavid van Moolenbroek strlcpy(hbuf, "invalid", sizeof(hbuf));
22793d36fc9SDavid van Moolenbroek }
22893d36fc9SDavid van Moolenbroek syslog(LOG_ERR, "malformed \"from\" address (v4 mapped, %s)",
22993d36fc9SDavid van Moolenbroek hbuf);
23093d36fc9SDavid van Moolenbroek return EXIT_FAILURE;
23193d36fc9SDavid van Moolenbroek }
23293d36fc9SDavid van Moolenbroek #endif
23393d36fc9SDavid van Moolenbroek if (keepalive &&
23493d36fc9SDavid van Moolenbroek setsockopt(STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
23593d36fc9SDavid van Moolenbroek sizeof(on)) < 0)
23693d36fc9SDavid van Moolenbroek syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
23793d36fc9SDavid van Moolenbroek linger.l_onoff = 1;
23893d36fc9SDavid van Moolenbroek linger.l_linger = 60; /* XXX */
23993d36fc9SDavid van Moolenbroek if (setsockopt(STDIN_FILENO, SOL_SOCKET, SO_LINGER, (char *)&linger,
24093d36fc9SDavid van Moolenbroek sizeof (linger)) < 0)
24193d36fc9SDavid van Moolenbroek syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m");
24293d36fc9SDavid van Moolenbroek proto = getprotobyname("tcp");
24393d36fc9SDavid van Moolenbroek (void)setsockopt(STDIN_FILENO, proto->p_proto, TCP_NODELAY, &on,
24493d36fc9SDavid van Moolenbroek sizeof(on));
24593d36fc9SDavid van Moolenbroek doit((struct sockaddr *)&from, (struct sockaddr *)&local);
24693d36fc9SDavid van Moolenbroek }
24793d36fc9SDavid van Moolenbroek
24893d36fc9SDavid van Moolenbroek extern char **environ;
24993d36fc9SDavid van Moolenbroek
25093d36fc9SDavid van Moolenbroek static void
doit(struct sockaddr * fromp,struct sockaddr * localp)25193d36fc9SDavid van Moolenbroek doit(struct sockaddr *fromp, struct sockaddr *localp)
25293d36fc9SDavid van Moolenbroek {
25393d36fc9SDavid van Moolenbroek struct passwd *pwd, pwres;
25493d36fc9SDavid van Moolenbroek in_port_t port;
25593d36fc9SDavid van Moolenbroek struct pollfd set[2];
25693d36fc9SDavid van Moolenbroek int cc, pv[2], pid, s = -1; /* XXX gcc */
25793d36fc9SDavid van Moolenbroek int one = 1;
25893d36fc9SDavid van Moolenbroek char *hostname, *errorhost = NULL; /* XXX gcc */
25993d36fc9SDavid van Moolenbroek const char *cp;
26093d36fc9SDavid van Moolenbroek char sig, buf[BUFSIZ];
26193d36fc9SDavid van Moolenbroek char cmdbuf[NCARGS+1], locuser[16], remuser[16];
26293d36fc9SDavid van Moolenbroek char remotehost[2 * MAXHOSTNAMELEN + 1];
26393d36fc9SDavid van Moolenbroek char hostnamebuf[2 * MAXHOSTNAMELEN + 1];
26493d36fc9SDavid van Moolenbroek #ifdef LOGIN_CAP
26593d36fc9SDavid van Moolenbroek login_cap_t *lc;
26693d36fc9SDavid van Moolenbroek #endif
26793d36fc9SDavid van Moolenbroek char naddr[NI_MAXHOST];
26893d36fc9SDavid van Moolenbroek char saddr[NI_MAXHOST];
26993d36fc9SDavid van Moolenbroek char raddr[NI_MAXHOST];
27093d36fc9SDavid van Moolenbroek char pbuf[NI_MAXSERV];
27193d36fc9SDavid van Moolenbroek int af = fromp->sa_family;
27293d36fc9SDavid van Moolenbroek u_int16_t *portp;
27393d36fc9SDavid van Moolenbroek struct addrinfo hints, *res, *res0;
27493d36fc9SDavid van Moolenbroek int gaierror;
27593d36fc9SDavid van Moolenbroek const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
27693d36fc9SDavid van Moolenbroek const char *errormsg = NULL, *errorstr = NULL;
27793d36fc9SDavid van Moolenbroek char pwbuf[1024];
27893d36fc9SDavid van Moolenbroek
27993d36fc9SDavid van Moolenbroek (void)signal(SIGINT, SIG_DFL);
28093d36fc9SDavid van Moolenbroek (void)signal(SIGQUIT, SIG_DFL);
28193d36fc9SDavid van Moolenbroek (void)signal(SIGTERM, SIG_DFL);
28293d36fc9SDavid van Moolenbroek #ifdef DEBUG
28393d36fc9SDavid van Moolenbroek {
28493d36fc9SDavid van Moolenbroek int t = open(_PATH_TTY, O_RDWR);
28593d36fc9SDavid van Moolenbroek if (t >= 0) {
28693d36fc9SDavid van Moolenbroek ioctl(t, TIOCNOTTY, NULL);
28793d36fc9SDavid van Moolenbroek (void)close(t);
28893d36fc9SDavid van Moolenbroek }
28993d36fc9SDavid van Moolenbroek }
29093d36fc9SDavid van Moolenbroek #endif
29193d36fc9SDavid van Moolenbroek switch (af) {
29293d36fc9SDavid van Moolenbroek case AF_INET:
29393d36fc9SDavid van Moolenbroek portp = &((struct sockaddr_in *)fromp)->sin_port;
29493d36fc9SDavid van Moolenbroek break;
29593d36fc9SDavid van Moolenbroek #ifdef INET6
29693d36fc9SDavid van Moolenbroek case AF_INET6:
29793d36fc9SDavid van Moolenbroek portp = &((struct sockaddr_in6 *)fromp)->sin6_port;
29893d36fc9SDavid van Moolenbroek break;
29993d36fc9SDavid van Moolenbroek #endif
30093d36fc9SDavid van Moolenbroek default:
30193d36fc9SDavid van Moolenbroek syslog(LOG_ERR, "malformed \"from\" address (af %d)", af);
30293d36fc9SDavid van Moolenbroek exit(EXIT_FAILURE);
30393d36fc9SDavid van Moolenbroek }
30493d36fc9SDavid van Moolenbroek if (getnameinfo(fromp, fromp->sa_len, naddr, sizeof(naddr),
30593d36fc9SDavid van Moolenbroek pbuf, sizeof(pbuf), niflags) != 0) {
30693d36fc9SDavid van Moolenbroek syslog(LOG_ERR, "malformed \"from\" address (af %d)", af);
30793d36fc9SDavid van Moolenbroek exit(EXIT_FAILURE);
30893d36fc9SDavid van Moolenbroek }
30993d36fc9SDavid van Moolenbroek #ifdef IP_OPTIONS
31093d36fc9SDavid van Moolenbroek if (af == AF_INET) {
31193d36fc9SDavid van Moolenbroek
31293d36fc9SDavid van Moolenbroek u_char optbuf[BUFSIZ/3];
31393d36fc9SDavid van Moolenbroek socklen_t optsize = sizeof(optbuf);
31493d36fc9SDavid van Moolenbroek int ipproto;
31593d36fc9SDavid van Moolenbroek unsigned int i;
31693d36fc9SDavid van Moolenbroek struct protoent *ip;
31793d36fc9SDavid van Moolenbroek
31893d36fc9SDavid van Moolenbroek if ((ip = getprotobyname("ip")) != NULL)
31993d36fc9SDavid van Moolenbroek ipproto = ip->p_proto;
32093d36fc9SDavid van Moolenbroek else
32193d36fc9SDavid van Moolenbroek ipproto = IPPROTO_IP;
32293d36fc9SDavid van Moolenbroek if (!getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, &optsize) &&
32393d36fc9SDavid van Moolenbroek optsize != 0) {
32493d36fc9SDavid van Moolenbroek for (i = 0; i < optsize;) {
32593d36fc9SDavid van Moolenbroek u_char c = optbuf[i];
32693d36fc9SDavid van Moolenbroek if (c == IPOPT_LSRR || c == IPOPT_SSRR) {
32793d36fc9SDavid van Moolenbroek syslog(LOG_NOTICE,
32893d36fc9SDavid van Moolenbroek "Connection refused from %s "
32993d36fc9SDavid van Moolenbroek "with IP option %s",
33093d36fc9SDavid van Moolenbroek inet_ntoa((
33193d36fc9SDavid van Moolenbroek (struct sockaddr_in *)fromp)->sin_addr),
33293d36fc9SDavid van Moolenbroek c == IPOPT_LSRR ? "LSRR" : "SSRR");
33393d36fc9SDavid van Moolenbroek exit(EXIT_FAILURE);
33493d36fc9SDavid van Moolenbroek }
33593d36fc9SDavid van Moolenbroek if (c == IPOPT_EOL)
33693d36fc9SDavid van Moolenbroek break;
33793d36fc9SDavid van Moolenbroek i += (c == IPOPT_NOP) ? 1 : optbuf[i + 1];
33893d36fc9SDavid van Moolenbroek }
33993d36fc9SDavid van Moolenbroek }
34093d36fc9SDavid van Moolenbroek }
34193d36fc9SDavid van Moolenbroek #endif
34293d36fc9SDavid van Moolenbroek if (ntohs(*portp) >= IPPORT_RESERVED
34393d36fc9SDavid van Moolenbroek || ntohs(*portp) < IPPORT_RESERVED / 2) {
34493d36fc9SDavid van Moolenbroek syslog(LOG_NOTICE|LOG_AUTH,
34593d36fc9SDavid van Moolenbroek "Connection from %s on illegal port %u",
34693d36fc9SDavid van Moolenbroek naddr, ntohs(*portp));
34793d36fc9SDavid van Moolenbroek exit(EXIT_FAILURE);
34893d36fc9SDavid van Moolenbroek }
34993d36fc9SDavid van Moolenbroek
35093d36fc9SDavid van Moolenbroek (void) alarm(60);
35193d36fc9SDavid van Moolenbroek port = 0;
35293d36fc9SDavid van Moolenbroek for (;;) {
35393d36fc9SDavid van Moolenbroek char c;
35493d36fc9SDavid van Moolenbroek
35593d36fc9SDavid van Moolenbroek if ((cc = read(STDIN_FILENO, &c, 1)) != 1) {
35693d36fc9SDavid van Moolenbroek if (cc < 0)
35793d36fc9SDavid van Moolenbroek syslog(LOG_ERR, "read: %m");
35893d36fc9SDavid van Moolenbroek (void)shutdown(0, SHUT_RDWR);
35993d36fc9SDavid van Moolenbroek exit(EXIT_FAILURE);
36093d36fc9SDavid van Moolenbroek }
36193d36fc9SDavid van Moolenbroek if (c == 0)
36293d36fc9SDavid van Moolenbroek break;
36393d36fc9SDavid van Moolenbroek port = port * 10 + c - '0';
36493d36fc9SDavid van Moolenbroek }
36593d36fc9SDavid van Moolenbroek
36693d36fc9SDavid van Moolenbroek (void) alarm(0);
36793d36fc9SDavid van Moolenbroek if (port != 0) {
36893d36fc9SDavid van Moolenbroek int lport = IPPORT_RESERVED - 1;
36993d36fc9SDavid van Moolenbroek s = rresvport_af_addr(&lport, af, localp);
37093d36fc9SDavid van Moolenbroek if (s < 0) {
37193d36fc9SDavid van Moolenbroek syslog(LOG_ERR, "can't get stderr port: %m");
37293d36fc9SDavid van Moolenbroek exit(EXIT_FAILURE);
37393d36fc9SDavid van Moolenbroek }
37493d36fc9SDavid van Moolenbroek if (port >= IPPORT_RESERVED) {
37593d36fc9SDavid van Moolenbroek syslog(LOG_ERR, "2nd port not reserved");
37693d36fc9SDavid van Moolenbroek exit(EXIT_FAILURE);
37793d36fc9SDavid van Moolenbroek }
37893d36fc9SDavid van Moolenbroek *portp = htons(port);
37993d36fc9SDavid van Moolenbroek if (connect(s, fromp, fromp->sa_len) < 0) {
38093d36fc9SDavid van Moolenbroek syslog(LOG_ERR, "connect second port %d: %m", port);
38193d36fc9SDavid van Moolenbroek exit(EXIT_FAILURE);
38293d36fc9SDavid van Moolenbroek }
38393d36fc9SDavid van Moolenbroek }
38493d36fc9SDavid van Moolenbroek
38593d36fc9SDavid van Moolenbroek
38693d36fc9SDavid van Moolenbroek #ifdef notdef
38793d36fc9SDavid van Moolenbroek /* from inetd, socket is already on 0, 1, 2 */
38893d36fc9SDavid van Moolenbroek (void)dup2(f, STDIN_FILENO);
38993d36fc9SDavid van Moolenbroek (void)dup2(f, STDOUT_FILENO);
39093d36fc9SDavid van Moolenbroek (void)dup2(f, STDERR_FILENO);
39193d36fc9SDavid van Moolenbroek #endif
39293d36fc9SDavid van Moolenbroek if (getnameinfo(fromp, fromp->sa_len, saddr, sizeof(saddr),
39393d36fc9SDavid van Moolenbroek NULL, 0, NI_NAMEREQD) == 0) {
39493d36fc9SDavid van Moolenbroek /*
39593d36fc9SDavid van Moolenbroek * If name returned by getnameinfo is in our domain,
39693d36fc9SDavid van Moolenbroek * attempt to verify that we haven't been fooled by someone
39793d36fc9SDavid van Moolenbroek * in a remote net; look up the name and check that this
39893d36fc9SDavid van Moolenbroek * address corresponds to the name.
39993d36fc9SDavid van Moolenbroek */
40093d36fc9SDavid van Moolenbroek hostname = saddr;
40193d36fc9SDavid van Moolenbroek res0 = NULL;
40293d36fc9SDavid van Moolenbroek if (check_all || local_domain(saddr)) {
40393d36fc9SDavid van Moolenbroek (void)strlcpy(remotehost, saddr, sizeof(remotehost));
40493d36fc9SDavid van Moolenbroek errorhost = remotehost;
40593d36fc9SDavid van Moolenbroek (void)memset(&hints, 0, sizeof(hints));
40693d36fc9SDavid van Moolenbroek hints.ai_family = fromp->sa_family;
40793d36fc9SDavid van Moolenbroek hints.ai_socktype = SOCK_STREAM;
40893d36fc9SDavid van Moolenbroek hints.ai_flags = AI_CANONNAME;
40993d36fc9SDavid van Moolenbroek gaierror = getaddrinfo(remotehost, pbuf, &hints, &res0);
41093d36fc9SDavid van Moolenbroek if (gaierror) {
41193d36fc9SDavid van Moolenbroek syslog(LOG_NOTICE,
41293d36fc9SDavid van Moolenbroek "Couldn't look up address for %s: %s",
41393d36fc9SDavid van Moolenbroek remotehost, gai_strerror(gaierror));
41493d36fc9SDavid van Moolenbroek errorstr =
41593d36fc9SDavid van Moolenbroek "Couldn't look up address for your host (%s)\n";
41693d36fc9SDavid van Moolenbroek hostname = naddr;
41793d36fc9SDavid van Moolenbroek } else {
41893d36fc9SDavid van Moolenbroek for (res = res0; res; res = res->ai_next) {
41993d36fc9SDavid van Moolenbroek if (res->ai_family != fromp->sa_family)
42093d36fc9SDavid van Moolenbroek continue;
42193d36fc9SDavid van Moolenbroek if (res->ai_addrlen != fromp->sa_len)
42293d36fc9SDavid van Moolenbroek continue;
42393d36fc9SDavid van Moolenbroek if (getnameinfo(res->ai_addr,
42493d36fc9SDavid van Moolenbroek res->ai_addrlen,
42593d36fc9SDavid van Moolenbroek raddr, sizeof(raddr), NULL, 0,
42693d36fc9SDavid van Moolenbroek niflags) == 0
42793d36fc9SDavid van Moolenbroek && strcmp(naddr, raddr) == 0) {
42893d36fc9SDavid van Moolenbroek hostname = res->ai_canonname
42993d36fc9SDavid van Moolenbroek ? res->ai_canonname
43093d36fc9SDavid van Moolenbroek : saddr;
43193d36fc9SDavid van Moolenbroek break;
43293d36fc9SDavid van Moolenbroek }
43393d36fc9SDavid van Moolenbroek }
43493d36fc9SDavid van Moolenbroek if (res == NULL) {
43593d36fc9SDavid van Moolenbroek syslog(LOG_NOTICE,
43693d36fc9SDavid van Moolenbroek "Host addr %s not listed for host %s",
43793d36fc9SDavid van Moolenbroek naddr, res0->ai_canonname
43893d36fc9SDavid van Moolenbroek ? res0->ai_canonname
43993d36fc9SDavid van Moolenbroek : saddr);
44093d36fc9SDavid van Moolenbroek errorstr =
44193d36fc9SDavid van Moolenbroek "Host address mismatch for %s\n";
44293d36fc9SDavid van Moolenbroek hostname = naddr;
44393d36fc9SDavid van Moolenbroek }
44493d36fc9SDavid van Moolenbroek }
44593d36fc9SDavid van Moolenbroek }
44693d36fc9SDavid van Moolenbroek (void)strlcpy(hostnamebuf, hostname, sizeof(hostnamebuf));
44793d36fc9SDavid van Moolenbroek hostname = hostnamebuf;
44893d36fc9SDavid van Moolenbroek if (res0)
44993d36fc9SDavid van Moolenbroek freeaddrinfo(res0);
45093d36fc9SDavid van Moolenbroek } else {
45193d36fc9SDavid van Moolenbroek (void)strlcpy(hostnamebuf, naddr, sizeof(hostnamebuf));
45293d36fc9SDavid van Moolenbroek errorhost = hostname = hostnamebuf;
45393d36fc9SDavid van Moolenbroek }
45493d36fc9SDavid van Moolenbroek
45593d36fc9SDavid van Moolenbroek (void)alarm(60);
45693d36fc9SDavid van Moolenbroek getstr(remuser, sizeof(remuser), "remuser");
45793d36fc9SDavid van Moolenbroek getstr(locuser, sizeof(locuser), "locuser");
45893d36fc9SDavid van Moolenbroek getstr(cmdbuf, sizeof(cmdbuf), "command");
45993d36fc9SDavid van Moolenbroek (void)alarm(0);
46093d36fc9SDavid van Moolenbroek
46193d36fc9SDavid van Moolenbroek #ifdef USE_PAM
46293d36fc9SDavid van Moolenbroek pam_err = pam_start("rsh", locuser, &pamc, &pamh);
46393d36fc9SDavid van Moolenbroek if (pam_err != PAM_SUCCESS) {
46493d36fc9SDavid van Moolenbroek syslog(LOG_ERR|LOG_AUTH, "pam_start(): %s",
46593d36fc9SDavid van Moolenbroek pam_strerror(pamh, pam_err));
46693d36fc9SDavid van Moolenbroek rshd_errx(EXIT_FAILURE, incorrect);
46793d36fc9SDavid van Moolenbroek }
46893d36fc9SDavid van Moolenbroek
46993d36fc9SDavid van Moolenbroek if ((pam_err = pam_set_item(pamh, PAM_RUSER, remuser)) != PAM_SUCCESS ||
47093d36fc9SDavid van Moolenbroek (pam_err = pam_set_item(pamh, PAM_RHOST, hostname)) != PAM_SUCCESS){
47193d36fc9SDavid van Moolenbroek syslog(LOG_ERR|LOG_AUTH, "pam_set_item(): %s",
47293d36fc9SDavid van Moolenbroek pam_strerror(pamh, pam_err));
47393d36fc9SDavid van Moolenbroek rshd_errx(EXIT_FAILURE, incorrect);
47493d36fc9SDavid van Moolenbroek }
47593d36fc9SDavid van Moolenbroek
47693d36fc9SDavid van Moolenbroek pam_err = pam_authenticate(pamh, 0);
47793d36fc9SDavid van Moolenbroek if (pam_err == PAM_SUCCESS) {
47893d36fc9SDavid van Moolenbroek if ((pam_err = pam_get_user(pamh, &cp, NULL)) == PAM_SUCCESS) {
47993d36fc9SDavid van Moolenbroek (void)strlcpy(locuser, cp, sizeof(locuser));
48093d36fc9SDavid van Moolenbroek /* XXX truncation! */
48193d36fc9SDavid van Moolenbroek }
48293d36fc9SDavid van Moolenbroek pam_err = pam_acct_mgmt(pamh, 0);
48393d36fc9SDavid van Moolenbroek }
48493d36fc9SDavid van Moolenbroek if (pam_err != PAM_SUCCESS) {
48593d36fc9SDavid van Moolenbroek errorstr = incorrect;
48693d36fc9SDavid van Moolenbroek errormsg = pam_strerror(pamh, pam_err);
48793d36fc9SDavid van Moolenbroek goto badlogin;
48893d36fc9SDavid van Moolenbroek }
48993d36fc9SDavid van Moolenbroek #endif /* USE_PAM */
49093d36fc9SDavid van Moolenbroek setpwent();
49193d36fc9SDavid van Moolenbroek if (getpwnam_r(locuser, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0 ||
49293d36fc9SDavid van Moolenbroek pwd == NULL) {
49393d36fc9SDavid van Moolenbroek syslog(LOG_INFO|LOG_AUTH,
49493d36fc9SDavid van Moolenbroek "%s@%s as %s: unknown login. cmd='%.80s'",
49593d36fc9SDavid van Moolenbroek remuser, hostname, locuser, cmdbuf);
49693d36fc9SDavid van Moolenbroek if (errorstr == NULL)
49793d36fc9SDavid van Moolenbroek errorstr = "Permission denied.";
49893d36fc9SDavid van Moolenbroek rshd_errx(EXIT_FAILURE, errorstr, errorhost);
49993d36fc9SDavid van Moolenbroek }
50093d36fc9SDavid van Moolenbroek #ifdef LOGIN_CAP
50193d36fc9SDavid van Moolenbroek lc = login_getclass(pwd ? pwd->pw_class : NULL);
50293d36fc9SDavid van Moolenbroek #endif
50393d36fc9SDavid van Moolenbroek
50493d36fc9SDavid van Moolenbroek if (chdir(pwd->pw_dir) < 0) {
50593d36fc9SDavid van Moolenbroek if (chdir("/") < 0
50693d36fc9SDavid van Moolenbroek #ifdef LOGIN_CAP
50793d36fc9SDavid van Moolenbroek || login_getcapbool(lc, "requirehome", pwd->pw_uid ? 1 : 0)
50893d36fc9SDavid van Moolenbroek #endif
50993d36fc9SDavid van Moolenbroek ) {
51093d36fc9SDavid van Moolenbroek syslog(LOG_INFO|LOG_AUTH,
51193d36fc9SDavid van Moolenbroek "%s@%s as %s: no home directory. cmd='%.80s'",
51293d36fc9SDavid van Moolenbroek remuser, hostname, locuser, cmdbuf);
51393d36fc9SDavid van Moolenbroek rshd_errx(EXIT_SUCCESS, "No remote home directory.");
51493d36fc9SDavid van Moolenbroek }
51593d36fc9SDavid van Moolenbroek }
51693d36fc9SDavid van Moolenbroek
51793d36fc9SDavid van Moolenbroek #ifndef USE_PAM
51893d36fc9SDavid van Moolenbroek if (errorstr ||
51993d36fc9SDavid van Moolenbroek (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' &&
52093d36fc9SDavid van Moolenbroek iruserok_sa(fromp, fromp->sa_len, pwd->pw_uid == 0, remuser,
52193d36fc9SDavid van Moolenbroek locuser) < 0)) {
52293d36fc9SDavid van Moolenbroek errormsg = __rcmd_errstr ? __rcmd_errstr : "unknown error";
52393d36fc9SDavid van Moolenbroek if (errorstr == NULL)
52493d36fc9SDavid van Moolenbroek errorstr = "Permission denied.";
52593d36fc9SDavid van Moolenbroek goto badlogin;
52693d36fc9SDavid van Moolenbroek }
52793d36fc9SDavid van Moolenbroek
52893d36fc9SDavid van Moolenbroek if (pwd->pw_uid && !access(_PATH_NOLOGIN, F_OK))
52993d36fc9SDavid van Moolenbroek rshd_errx(EXIT_FAILURE, "Logins currently disabled.");
53093d36fc9SDavid van Moolenbroek #endif
53193d36fc9SDavid van Moolenbroek
53293d36fc9SDavid van Moolenbroek #ifdef LOGIN_CAP
53393d36fc9SDavid van Moolenbroek /*
53493d36fc9SDavid van Moolenbroek * PAM modules might add supplementary groups in
53593d36fc9SDavid van Moolenbroek * pam_setcred(), so initialize them first.
53693d36fc9SDavid van Moolenbroek * But we need to open the session as root.
53793d36fc9SDavid van Moolenbroek */
53893d36fc9SDavid van Moolenbroek if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) != 0) {
53993d36fc9SDavid van Moolenbroek syslog(LOG_ERR, "setusercontext: %m");
54093d36fc9SDavid van Moolenbroek exit(EXIT_FAILURE);
54193d36fc9SDavid van Moolenbroek }
54293d36fc9SDavid van Moolenbroek #else
54393d36fc9SDavid van Moolenbroek initgroups(pwd->pw_name, pwd->pw_gid);
54493d36fc9SDavid van Moolenbroek #endif
54593d36fc9SDavid van Moolenbroek
54693d36fc9SDavid van Moolenbroek #ifdef USE_PAM
54793d36fc9SDavid van Moolenbroek if ((pam_err = pam_open_session(pamh, 0)) != PAM_SUCCESS) {
54893d36fc9SDavid van Moolenbroek syslog(LOG_ERR, "pam_open_session: %s",
54993d36fc9SDavid van Moolenbroek pam_strerror(pamh, pam_err));
55093d36fc9SDavid van Moolenbroek } else if ((pam_err = pam_setcred(pamh, PAM_ESTABLISH_CRED))
55193d36fc9SDavid van Moolenbroek != PAM_SUCCESS) {
55293d36fc9SDavid van Moolenbroek syslog(LOG_ERR, "pam_setcred: %s", pam_strerror(pamh, pam_err));
55393d36fc9SDavid van Moolenbroek }
55493d36fc9SDavid van Moolenbroek #endif
55593d36fc9SDavid van Moolenbroek
55693d36fc9SDavid van Moolenbroek (void)write(STDERR_FILENO, "\0", 1);
55793d36fc9SDavid van Moolenbroek sent_null = 1;
55893d36fc9SDavid van Moolenbroek
55993d36fc9SDavid van Moolenbroek if (port) {
56093d36fc9SDavid van Moolenbroek if (pipe(pv) < 0)
56193d36fc9SDavid van Moolenbroek rshd_errx(EXIT_FAILURE, "Can't make pipe. (%s)",
56293d36fc9SDavid van Moolenbroek strerror(errno));
56393d36fc9SDavid van Moolenbroek pid = fork();
56493d36fc9SDavid van Moolenbroek if (pid == -1)
56593d36fc9SDavid van Moolenbroek rshd_errx(EXIT_FAILURE, "Can't fork. (%s)",
56693d36fc9SDavid van Moolenbroek strerror(errno));
56793d36fc9SDavid van Moolenbroek if (pid) {
56893d36fc9SDavid van Moolenbroek (void)close(STDIN_FILENO);
56993d36fc9SDavid van Moolenbroek (void)close(STDOUT_FILENO);
57093d36fc9SDavid van Moolenbroek (void)close(STDERR_FILENO);
57193d36fc9SDavid van Moolenbroek (void)close(pv[1]);
57293d36fc9SDavid van Moolenbroek
57393d36fc9SDavid van Moolenbroek set[0].fd = s;
57493d36fc9SDavid van Moolenbroek set[0].events = POLLIN;
57593d36fc9SDavid van Moolenbroek set[1].fd = pv[0];
57693d36fc9SDavid van Moolenbroek set[1].events = POLLIN;
57793d36fc9SDavid van Moolenbroek ioctl(pv[0], FIONBIO, (char *)&one);
57893d36fc9SDavid van Moolenbroek
57993d36fc9SDavid van Moolenbroek /* should set s nbio! */
58093d36fc9SDavid van Moolenbroek do {
581*0a6a1f1dSLionel Sambuc #if defined(__minix)
58293d36fc9SDavid van Moolenbroek if (set[0].events == 0 && set[1].events == 0)
58393d36fc9SDavid van Moolenbroek break;
584*0a6a1f1dSLionel Sambuc #endif /* defined(__minix) */
58593d36fc9SDavid van Moolenbroek if (poll(set, 2, INFTIM) < 0)
58693d36fc9SDavid van Moolenbroek break;
58793d36fc9SDavid van Moolenbroek if (set[0].revents & POLLIN) {
58893d36fc9SDavid van Moolenbroek int ret;
58993d36fc9SDavid van Moolenbroek
59093d36fc9SDavid van Moolenbroek ret = read(s, &sig, 1);
59193d36fc9SDavid van Moolenbroek if (ret <= 0)
59293d36fc9SDavid van Moolenbroek set[0].events = 0;
59393d36fc9SDavid van Moolenbroek else
59493d36fc9SDavid van Moolenbroek killpg(pid, sig);
59593d36fc9SDavid van Moolenbroek }
59693d36fc9SDavid van Moolenbroek if (set[1].revents & POLLIN) {
59793d36fc9SDavid van Moolenbroek errno = 0;
59893d36fc9SDavid van Moolenbroek cc = read(pv[0], buf, sizeof(buf));
59993d36fc9SDavid van Moolenbroek if (cc <= 0) {
60093d36fc9SDavid van Moolenbroek shutdown(s, SHUT_RDWR);
60193d36fc9SDavid van Moolenbroek set[1].events = 0;
60293d36fc9SDavid van Moolenbroek } else {
60393d36fc9SDavid van Moolenbroek (void)write(s, buf, cc);
60493d36fc9SDavid van Moolenbroek }
60593d36fc9SDavid van Moolenbroek }
60693d36fc9SDavid van Moolenbroek
60793d36fc9SDavid van Moolenbroek } while ((set[0].revents | set[1].revents) & POLLIN);
60893d36fc9SDavid van Moolenbroek PAM_END;
60993d36fc9SDavid van Moolenbroek exit(EXIT_SUCCESS);
61093d36fc9SDavid van Moolenbroek }
61193d36fc9SDavid van Moolenbroek (void)close(s);
61293d36fc9SDavid van Moolenbroek (void)close(pv[0]);
61393d36fc9SDavid van Moolenbroek (void)dup2(pv[1], STDERR_FILENO);
61493d36fc9SDavid van Moolenbroek close(pv[1]);
61593d36fc9SDavid van Moolenbroek }
61693d36fc9SDavid van Moolenbroek #ifdef USE_PAM
61793d36fc9SDavid van Moolenbroek else {
61893d36fc9SDavid van Moolenbroek pid = fork();
61993d36fc9SDavid van Moolenbroek if (pid == -1)
62093d36fc9SDavid van Moolenbroek rshd_errx(EXIT_FAILURE, "Can't fork. (%s)",
62193d36fc9SDavid van Moolenbroek strerror(errno));
62293d36fc9SDavid van Moolenbroek if (pid) {
62393d36fc9SDavid van Moolenbroek pid_t xpid;
62493d36fc9SDavid van Moolenbroek int status;
62593d36fc9SDavid van Moolenbroek if ((xpid = waitpid(pid, &status, 0)) != pid) {
62693d36fc9SDavid van Moolenbroek pam_err = pam_close_session(pamh, 0);
62793d36fc9SDavid van Moolenbroek if (pam_err != PAM_SUCCESS) {
62893d36fc9SDavid van Moolenbroek syslog(LOG_ERR,
62993d36fc9SDavid van Moolenbroek "pam_close_session: %s",
63093d36fc9SDavid van Moolenbroek pam_strerror(pamh, pam_err));
63193d36fc9SDavid van Moolenbroek }
63293d36fc9SDavid van Moolenbroek PAM_END;
63393d36fc9SDavid van Moolenbroek if (xpid != -1)
63493d36fc9SDavid van Moolenbroek syslog(LOG_WARNING,
63593d36fc9SDavid van Moolenbroek "wrong PID: %d != %d", pid, xpid);
63693d36fc9SDavid van Moolenbroek else
63793d36fc9SDavid van Moolenbroek syslog(LOG_WARNING,
63893d36fc9SDavid van Moolenbroek "wait pid=%d failed %m", pid);
63993d36fc9SDavid van Moolenbroek exit(EXIT_FAILURE);
64093d36fc9SDavid van Moolenbroek }
64193d36fc9SDavid van Moolenbroek exit(EXIT_SUCCESS);
64293d36fc9SDavid van Moolenbroek }
64393d36fc9SDavid van Moolenbroek }
64493d36fc9SDavid van Moolenbroek #endif
64593d36fc9SDavid van Moolenbroek
64693d36fc9SDavid van Moolenbroek #ifdef F_CLOSEM
64793d36fc9SDavid van Moolenbroek (void)fcntl(STDERR_FILENO + 1, F_CLOSEM, 0);
64893d36fc9SDavid van Moolenbroek #else
64993d36fc9SDavid van Moolenbroek for (fd = getdtablesize(); fd > STDERR_FILENO; fd--)
65093d36fc9SDavid van Moolenbroek (void)close(fd);
65193d36fc9SDavid van Moolenbroek #endif
65293d36fc9SDavid van Moolenbroek if (setsid() == -1)
65393d36fc9SDavid van Moolenbroek syslog(LOG_ERR, "setsid() failed: %m");
65493d36fc9SDavid van Moolenbroek #ifdef USE_PAM
65593d36fc9SDavid van Moolenbroek if (setlogin(pwd->pw_name) < 0)
65693d36fc9SDavid van Moolenbroek syslog(LOG_ERR, "setlogin() failed: %m");
65793d36fc9SDavid van Moolenbroek
65893d36fc9SDavid van Moolenbroek if (*pwd->pw_shell == '\0')
65993d36fc9SDavid van Moolenbroek pwd->pw_shell = __UNCONST(_PATH_BSHELL);
66093d36fc9SDavid van Moolenbroek
66193d36fc9SDavid van Moolenbroek (void)pam_setenv(pamh, "HOME", pwd->pw_dir, 1);
66293d36fc9SDavid van Moolenbroek (void)pam_setenv(pamh, "SHELL", pwd->pw_shell, 1);
66393d36fc9SDavid van Moolenbroek (void)pam_setenv(pamh, "USER", pwd->pw_name, 1);
66493d36fc9SDavid van Moolenbroek (void)pam_setenv(pamh, "PATH", _PATH_DEFPATH, 1);
66593d36fc9SDavid van Moolenbroek environ = pam_getenvlist(pamh);
66693d36fc9SDavid van Moolenbroek (void)pam_end(pamh, pam_err);
66793d36fc9SDavid van Moolenbroek #else
66893d36fc9SDavid van Moolenbroek #ifdef LOGIN_CAP
66993d36fc9SDavid van Moolenbroek {
67093d36fc9SDavid van Moolenbroek char *sh;
67193d36fc9SDavid van Moolenbroek if ((sh = login_getcapstr(lc, "shell", NULL, NULL))) {
67293d36fc9SDavid van Moolenbroek if(!(sh = strdup(sh))) {
67393d36fc9SDavid van Moolenbroek syslog(LOG_ERR, "Cannot alloc mem");
67493d36fc9SDavid van Moolenbroek exit(EXIT_FAILURE);
67593d36fc9SDavid van Moolenbroek }
67693d36fc9SDavid van Moolenbroek pwd->pw_shell = sh;
67793d36fc9SDavid van Moolenbroek }
67893d36fc9SDavid van Moolenbroek }
67993d36fc9SDavid van Moolenbroek #endif
68093d36fc9SDavid van Moolenbroek {
68193d36fc9SDavid van Moolenbroek static char *envinit[] = { NULL };
68293d36fc9SDavid van Moolenbroek environ = envinit;
68393d36fc9SDavid van Moolenbroek }
68493d36fc9SDavid van Moolenbroek setenv("PATH", _PATH_DEFPATH, 1);
68593d36fc9SDavid van Moolenbroek setenv("HOME", pwd->pw_dir, 1);
68693d36fc9SDavid van Moolenbroek setenv("SHELL", pwd->pw_shell, 1);
68793d36fc9SDavid van Moolenbroek setenv("USER", pwd->pw_name, 1);
68893d36fc9SDavid van Moolenbroek #endif
68993d36fc9SDavid van Moolenbroek
69093d36fc9SDavid van Moolenbroek cp = strrchr(pwd->pw_shell, '/');
69193d36fc9SDavid van Moolenbroek if (cp)
69293d36fc9SDavid van Moolenbroek cp++;
69393d36fc9SDavid van Moolenbroek else
69493d36fc9SDavid van Moolenbroek cp = pwd->pw_shell;
69593d36fc9SDavid van Moolenbroek
69693d36fc9SDavid van Moolenbroek #ifdef LOGIN_CAP
69793d36fc9SDavid van Moolenbroek if (setusercontext(lc, pwd, pwd->pw_uid,
69893d36fc9SDavid van Moolenbroek LOGIN_SETALL & ~LOGIN_SETGROUP) < 0) {
69993d36fc9SDavid van Moolenbroek syslog(LOG_ERR, "setusercontext(): %m");
70093d36fc9SDavid van Moolenbroek exit(EXIT_FAILURE);
70193d36fc9SDavid van Moolenbroek }
70293d36fc9SDavid van Moolenbroek login_close(lc);
70393d36fc9SDavid van Moolenbroek #else
70493d36fc9SDavid van Moolenbroek (void)setgid((gid_t)pwd->pw_gid);
70593d36fc9SDavid van Moolenbroek (void)setuid((uid_t)pwd->pw_uid);
70693d36fc9SDavid van Moolenbroek #endif
70793d36fc9SDavid van Moolenbroek endpwent();
70893d36fc9SDavid van Moolenbroek if (log_success || pwd->pw_uid == 0) {
70993d36fc9SDavid van Moolenbroek syslog(LOG_INFO|LOG_AUTH, "%s@%s as %s: cmd='%.80s'",
71093d36fc9SDavid van Moolenbroek remuser, hostname, locuser, cmdbuf);
71193d36fc9SDavid van Moolenbroek }
71293d36fc9SDavid van Moolenbroek (void)execl(pwd->pw_shell, cp, "-c", cmdbuf, NULL);
71393d36fc9SDavid van Moolenbroek rshd_errx(EXIT_FAILURE, "%s: %s", pwd->pw_shell, strerror(errno));
71493d36fc9SDavid van Moolenbroek badlogin:
71593d36fc9SDavid van Moolenbroek syslog(LOG_INFO|LOG_AUTH,
71693d36fc9SDavid van Moolenbroek "%s@%s as %s: permission denied (%s). cmd='%.80s'",
71793d36fc9SDavid van Moolenbroek remuser, hostname, locuser, errormsg, cmdbuf);
71893d36fc9SDavid van Moolenbroek rshd_errx(EXIT_FAILURE, errorstr, errorhost);
71993d36fc9SDavid van Moolenbroek }
72093d36fc9SDavid van Moolenbroek
72193d36fc9SDavid van Moolenbroek /*
72293d36fc9SDavid van Moolenbroek * Report error to client. Note: can't be used until second socket has
72393d36fc9SDavid van Moolenbroek * connected to client, or older clients will hang waiting for that
72493d36fc9SDavid van Moolenbroek * connection first.
72593d36fc9SDavid van Moolenbroek */
72693d36fc9SDavid van Moolenbroek
72793d36fc9SDavid van Moolenbroek #include <stdarg.h>
72893d36fc9SDavid van Moolenbroek
72993d36fc9SDavid van Moolenbroek static void
rshd_errx(int error,const char * fmt,...)73093d36fc9SDavid van Moolenbroek rshd_errx(int error, const char *fmt, ...)
73193d36fc9SDavid van Moolenbroek {
73293d36fc9SDavid van Moolenbroek va_list ap;
73393d36fc9SDavid van Moolenbroek int len, rv;
73493d36fc9SDavid van Moolenbroek char *bp, buf[BUFSIZ];
73593d36fc9SDavid van Moolenbroek va_start(ap, fmt);
73693d36fc9SDavid van Moolenbroek bp = buf;
73793d36fc9SDavid van Moolenbroek if (sent_null == 0) {
73893d36fc9SDavid van Moolenbroek *bp++ = 1;
73993d36fc9SDavid van Moolenbroek len = 1;
74093d36fc9SDavid van Moolenbroek } else
74193d36fc9SDavid van Moolenbroek len = 0;
74293d36fc9SDavid van Moolenbroek rv = vsnprintf(bp, sizeof(buf) - 2, fmt, ap);
74393d36fc9SDavid van Moolenbroek bp[rv++] = '\n';
74493d36fc9SDavid van Moolenbroek (void)write(STDERR_FILENO, buf, len + rv);
74593d36fc9SDavid van Moolenbroek va_end(ap);
74693d36fc9SDavid van Moolenbroek exit(error);
74793d36fc9SDavid van Moolenbroek }
74893d36fc9SDavid van Moolenbroek
74993d36fc9SDavid van Moolenbroek static void
getstr(char * buf,int cnt,const char * err)75093d36fc9SDavid van Moolenbroek getstr(char *buf, int cnt, const char *err)
75193d36fc9SDavid van Moolenbroek {
75293d36fc9SDavid van Moolenbroek char c;
75393d36fc9SDavid van Moolenbroek
75493d36fc9SDavid van Moolenbroek do {
75593d36fc9SDavid van Moolenbroek if (read(STDIN_FILENO, &c, 1) != 1)
75693d36fc9SDavid van Moolenbroek exit(EXIT_FAILURE);
75793d36fc9SDavid van Moolenbroek *buf++ = c;
75893d36fc9SDavid van Moolenbroek if (--cnt == 0)
75993d36fc9SDavid van Moolenbroek rshd_errx(EXIT_FAILURE, "%s too long", err);
76093d36fc9SDavid van Moolenbroek } while (c != 0);
76193d36fc9SDavid van Moolenbroek }
76293d36fc9SDavid van Moolenbroek
76393d36fc9SDavid van Moolenbroek /*
76493d36fc9SDavid van Moolenbroek * Check whether host h is in our local domain,
76593d36fc9SDavid van Moolenbroek * defined as sharing the last two components of the domain part,
76693d36fc9SDavid van Moolenbroek * or the entire domain part if the local domain has only one component.
76793d36fc9SDavid van Moolenbroek * If either name is unqualified (contains no '.'),
76893d36fc9SDavid van Moolenbroek * assume that the host is local, as it will be
76993d36fc9SDavid van Moolenbroek * interpreted as such.
77093d36fc9SDavid van Moolenbroek */
77193d36fc9SDavid van Moolenbroek static int
local_domain(char * h)77293d36fc9SDavid van Moolenbroek local_domain(char *h)
77393d36fc9SDavid van Moolenbroek {
77493d36fc9SDavid van Moolenbroek char localhost[MAXHOSTNAMELEN + 1];
77593d36fc9SDavid van Moolenbroek char *p1, *p2;
77693d36fc9SDavid van Moolenbroek
77793d36fc9SDavid van Moolenbroek localhost[0] = 0;
77893d36fc9SDavid van Moolenbroek (void)gethostname(localhost, sizeof(localhost));
77993d36fc9SDavid van Moolenbroek localhost[sizeof(localhost) - 1] = '\0';
78093d36fc9SDavid van Moolenbroek p1 = topdomain(localhost);
78193d36fc9SDavid van Moolenbroek p2 = topdomain(h);
78293d36fc9SDavid van Moolenbroek if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2))
78393d36fc9SDavid van Moolenbroek return (1);
78493d36fc9SDavid van Moolenbroek return (0);
78593d36fc9SDavid van Moolenbroek }
78693d36fc9SDavid van Moolenbroek
78793d36fc9SDavid van Moolenbroek static char *
topdomain(char * h)78893d36fc9SDavid van Moolenbroek topdomain(char *h)
78993d36fc9SDavid van Moolenbroek {
79093d36fc9SDavid van Moolenbroek char *p, *maybe = NULL;
79193d36fc9SDavid van Moolenbroek int dots = 0;
79293d36fc9SDavid van Moolenbroek
79393d36fc9SDavid van Moolenbroek for (p = h + strlen(h); p >= h; p--) {
79493d36fc9SDavid van Moolenbroek if (*p == '.') {
79593d36fc9SDavid van Moolenbroek if (++dots == 2)
79693d36fc9SDavid van Moolenbroek return (p);
79793d36fc9SDavid van Moolenbroek maybe = p;
79893d36fc9SDavid van Moolenbroek }
79993d36fc9SDavid van Moolenbroek }
80093d36fc9SDavid van Moolenbroek return (maybe);
80193d36fc9SDavid van Moolenbroek }
80293d36fc9SDavid van Moolenbroek
80393d36fc9SDavid van Moolenbroek static void
usage(void)80493d36fc9SDavid van Moolenbroek usage(void)
80593d36fc9SDavid van Moolenbroek {
80693d36fc9SDavid van Moolenbroek
80793d36fc9SDavid van Moolenbroek syslog(LOG_ERR, "Usage: %s [-%s]", getprogname(), OPTIONS);
80893d36fc9SDavid van Moolenbroek exit(EXIT_FAILURE);
80993d36fc9SDavid van Moolenbroek }
810