1 1.51 ryo /* $NetBSD: rshd.c,v 1.51 2017/10/07 19:23:02 ryo Exp $ */ 2 1.18 itojun 3 1.18 itojun /* 4 1.18 itojun * Copyright (C) 1998 WIDE Project. 5 1.18 itojun * All rights reserved. 6 1.18 itojun * 7 1.18 itojun * Redistribution and use in source and binary forms, with or without 8 1.18 itojun * modification, are permitted provided that the following conditions 9 1.18 itojun * are met: 10 1.18 itojun * 1. Redistributions of source code must retain the above copyright 11 1.18 itojun * notice, this list of conditions and the following disclaimer. 12 1.18 itojun * 2. Redistributions in binary form must reproduce the above copyright 13 1.18 itojun * notice, this list of conditions and the following disclaimer in the 14 1.18 itojun * documentation and/or other materials provided with the distribution. 15 1.18 itojun * 3. All advertising materials mentioning features or use of this software 16 1.18 itojun * must display the following acknowledgement: 17 1.18 itojun * This product includes software developed by WIDE Project and 18 1.18 itojun * its contributors. 19 1.18 itojun * 4. Neither the name of the project nor the names of its contributors 20 1.18 itojun * may be used to endorse or promote products derived from this software 21 1.18 itojun * without specific prior written permission. 22 1.18 itojun * 23 1.18 itojun * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 24 1.18 itojun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 1.18 itojun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 1.18 itojun * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 27 1.18 itojun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 1.18 itojun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 1.18 itojun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 1.18 itojun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 1.18 itojun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 1.18 itojun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 1.18 itojun * SUCH DAMAGE. 34 1.18 itojun */ 35 1.10 mrg 36 1.1 cgd /*- 37 1.7 cgd * Copyright (c) 1988, 1989, 1992, 1993, 1994 38 1.7 cgd * The Regents of the University of California. All rights reserved. 39 1.1 cgd * 40 1.1 cgd * Redistribution and use in source and binary forms, with or without 41 1.1 cgd * modification, are permitted provided that the following conditions 42 1.1 cgd * are met: 43 1.1 cgd * 1. Redistributions of source code must retain the above copyright 44 1.1 cgd * notice, this list of conditions and the following disclaimer. 45 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 46 1.1 cgd * notice, this list of conditions and the following disclaimer in the 47 1.1 cgd * documentation and/or other materials provided with the distribution. 48 1.32 agc * 3. Neither the name of the University nor the names of its contributors 49 1.1 cgd * may be used to endorse or promote products derived from this software 50 1.1 cgd * without specific prior written permission. 51 1.1 cgd * 52 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 53 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 56 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62 1.1 cgd * SUCH DAMAGE. 63 1.1 cgd */ 64 1.1 cgd 65 1.10 mrg #include <sys/cdefs.h> 66 1.1 cgd #ifndef lint 67 1.46 lukem __COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1992, 1993, 1994\ 68 1.46 lukem The Regents of the University of California. All rights reserved."); 69 1.10 mrg #if 0 70 1.10 mrg static char sccsid[] = "@(#)rshd.c 8.2 (Berkeley) 4/6/94"; 71 1.10 mrg #else 72 1.51 ryo __RCSID("$NetBSD: rshd.c,v 1.51 2017/10/07 19:23:02 ryo Exp $"); 73 1.10 mrg #endif 74 1.1 cgd #endif /* not lint */ 75 1.1 cgd 76 1.1 cgd /* 77 1.1 cgd * remote shell server: 78 1.1 cgd * [port]\0 79 1.1 cgd * remuser\0 80 1.1 cgd * locuser\0 81 1.1 cgd * command\0 82 1.1 cgd * data 83 1.1 cgd */ 84 1.1 cgd #include <sys/param.h> 85 1.1 cgd #include <sys/ioctl.h> 86 1.1 cgd #include <sys/time.h> 87 1.7 cgd #include <sys/socket.h> 88 1.1 cgd 89 1.36 christos #include <netinet/in_systm.h> 90 1.1 cgd #include <netinet/in.h> 91 1.36 christos #include <netinet/ip.h> 92 1.31 joff #include <netinet/tcp.h> 93 1.1 cgd #include <arpa/inet.h> 94 1.1 cgd #include <netdb.h> 95 1.1 cgd 96 1.7 cgd #include <errno.h> 97 1.7 cgd #include <fcntl.h> 98 1.7 cgd #include <paths.h> 99 1.1 cgd #include <pwd.h> 100 1.7 cgd #include <signal.h> 101 1.1 cgd #include <stdio.h> 102 1.1 cgd #include <stdlib.h> 103 1.1 cgd #include <string.h> 104 1.7 cgd #include <syslog.h> 105 1.7 cgd #include <unistd.h> 106 1.27 itojun #include <poll.h> 107 1.17 mjl #ifdef LOGIN_CAP 108 1.17 mjl #include <login_cap.h> 109 1.17 mjl #endif 110 1.1 cgd 111 1.34 christos #ifdef USE_PAM 112 1.34 christos #include <security/pam_appl.h> 113 1.34 christos #include <security/openpam.h> 114 1.34 christos #include <sys/wait.h> 115 1.34 christos 116 1.34 christos static struct pam_conv pamc = { openpam_nullconv, NULL }; 117 1.34 christos static pam_handle_t *pamh; 118 1.34 christos static int pam_err; 119 1.34 christos 120 1.39 christos #define PAM_END do { \ 121 1.34 christos if ((pam_err = pam_setcred(pamh, PAM_DELETE_CRED)) != PAM_SUCCESS) \ 122 1.34 christos syslog(LOG_ERR|LOG_AUTH, "pam_setcred(): %s", \ 123 1.34 christos pam_strerror(pamh, pam_err)); \ 124 1.34 christos if ((pam_err = pam_close_session(pamh,0)) != PAM_SUCCESS) \ 125 1.34 christos syslog(LOG_ERR|LOG_AUTH, "pam_close_session(): %s", \ 126 1.34 christos pam_strerror(pamh, pam_err)); \ 127 1.34 christos if ((pam_err = pam_end(pamh, pam_err)) != PAM_SUCCESS) \ 128 1.34 christos syslog(LOG_ERR|LOG_AUTH, "pam_end(): %s", \ 129 1.34 christos pam_strerror(pamh, pam_err)); \ 130 1.39 christos } while (/*CONSTCOND*/0) 131 1.34 christos #else 132 1.34 christos #define PAM_END 133 1.34 christos #endif 134 1.34 christos 135 1.48 joerg static int keepalive = 1; 136 1.48 joerg static int check_all; 137 1.48 joerg static int log_success; /* If TRUE, log all successful accesses */ 138 1.48 joerg static int sent_null; 139 1.48 joerg 140 1.50 darrenr __dead static void doit(struct sockaddr *, struct sockaddr *); 141 1.48 joerg __dead static void rshd_errx(int, const char *, ...) __printflike(2, 3); 142 1.48 joerg static void getstr(char *, int, const char *); 143 1.48 joerg static int local_domain(char *); 144 1.48 joerg static char *topdomain(char *); 145 1.48 joerg __dead static void usage(void); 146 1.7 cgd 147 1.37 wiz #define OPTIONS "aLln" 148 1.23 christos extern int __check_rhosts_file; 149 1.23 christos extern char *__rcmd_errstr; /* syslog hook from libc/net/rcmd.c. */ 150 1.51 ryo #ifdef USE_PAM 151 1.34 christos static const char incorrect[] = "Login incorrect."; 152 1.51 ryo #endif 153 1.1 cgd 154 1.7 cgd int 155 1.25 mjl main(int argc, char *argv[]) 156 1.1 cgd { 157 1.1 cgd struct linger linger; 158 1.44 mrg int ch, on = 1; 159 1.44 mrg socklen_t fromlen; 160 1.50 darrenr socklen_t locallen; 161 1.18 itojun struct sockaddr_storage from; 162 1.50 darrenr struct sockaddr_storage local; 163 1.31 joff struct protoent *proto; 164 1.1 cgd 165 1.22 lukem openlog("rshd", LOG_PID, LOG_DAEMON); 166 1.1 cgd 167 1.1 cgd opterr = 0; 168 1.11 enami while ((ch = getopt(argc, argv, OPTIONS)) != -1) 169 1.1 cgd switch (ch) { 170 1.1 cgd case 'a': 171 1.1 cgd check_all = 1; 172 1.1 cgd break; 173 1.1 cgd case 'l': 174 1.6 pk __check_rhosts_file = 0; 175 1.1 cgd break; 176 1.1 cgd case 'n': 177 1.1 cgd keepalive = 0; 178 1.1 cgd break; 179 1.3 cgd case 'L': 180 1.7 cgd log_success = 1; 181 1.3 cgd break; 182 1.1 cgd case '?': 183 1.1 cgd default: 184 1.1 cgd usage(); 185 1.7 cgd break; 186 1.1 cgd } 187 1.1 cgd 188 1.1 cgd argc -= optind; 189 1.1 cgd argv += optind; 190 1.1 cgd 191 1.41 christos fromlen = sizeof(from); /* xxx */ 192 1.50 darrenr locallen = sizeof(local); /* xxx */ 193 1.41 christos if (getpeername(STDIN_FILENO, (struct sockaddr *)&from, &fromlen) < 0) { 194 1.1 cgd syslog(LOG_ERR, "getpeername: %m"); 195 1.41 christos return EXIT_FAILURE; 196 1.1 cgd } 197 1.50 darrenr if (getsockname(STDIN_FILENO, (struct sockaddr *)&local, 198 1.50 darrenr &locallen) < 0) { 199 1.50 darrenr syslog(LOG_ERR, "getsockname: %m"); 200 1.50 darrenr return EXIT_FAILURE; 201 1.50 darrenr } 202 1.19 itojun #if 0 203 1.19 itojun if (((struct sockaddr *)&from)->sa_family == AF_INET6 && 204 1.19 itojun IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&from)->sin6_addr) && 205 1.19 itojun sizeof(struct sockaddr_in) <= sizeof(from)) { 206 1.19 itojun struct sockaddr_in sin; 207 1.19 itojun struct sockaddr_in6 *sin6; 208 1.19 itojun const int off = sizeof(struct sockaddr_in6) - 209 1.19 itojun sizeof(struct sockaddr_in); 210 1.19 itojun 211 1.19 itojun sin6 = (struct sockaddr_in6 *)&from; 212 1.41 christos (void)memset(&sin, 0, sizeof(sin)); 213 1.19 itojun sin.sin_family = AF_INET; 214 1.19 itojun sin.sin_len = sizeof(struct sockaddr_in); 215 1.41 christos (void)memcpy(&sin.sin_addr, &sin6->sin6_addr.s6_addr[off], 216 1.19 itojun sizeof(sin.sin_addr)); 217 1.41 christos (void)memcpy(&from, &sin, sizeof(sin)); 218 1.19 itojun fromlen = sin.sin_len; 219 1.19 itojun } 220 1.19 itojun #else 221 1.19 itojun if (((struct sockaddr *)&from)->sa_family == AF_INET6 && 222 1.19 itojun IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&from)->sin6_addr)) { 223 1.19 itojun char hbuf[NI_MAXHOST]; 224 1.19 itojun if (getnameinfo((struct sockaddr *)&from, fromlen, hbuf, 225 1.19 itojun sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) { 226 1.30 itojun strlcpy(hbuf, "invalid", sizeof(hbuf)); 227 1.19 itojun } 228 1.25 mjl syslog(LOG_ERR, "malformed \"from\" address (v4 mapped, %s)", 229 1.19 itojun hbuf); 230 1.41 christos return EXIT_FAILURE; 231 1.19 itojun } 232 1.19 itojun #endif 233 1.1 cgd if (keepalive && 234 1.41 christos setsockopt(STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, 235 1.1 cgd sizeof(on)) < 0) 236 1.1 cgd syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 237 1.1 cgd linger.l_onoff = 1; 238 1.1 cgd linger.l_linger = 60; /* XXX */ 239 1.41 christos if (setsockopt(STDIN_FILENO, SOL_SOCKET, SO_LINGER, (char *)&linger, 240 1.1 cgd sizeof (linger)) < 0) 241 1.1 cgd syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m"); 242 1.31 joff proto = getprotobyname("tcp"); 243 1.41 christos (void)setsockopt(STDIN_FILENO, proto->p_proto, TCP_NODELAY, &on, 244 1.41 christos sizeof(on)); 245 1.50 darrenr doit((struct sockaddr *)&from, (struct sockaddr *)&local); 246 1.1 cgd } 247 1.1 cgd 248 1.48 joerg extern char **environ; 249 1.1 cgd 250 1.48 joerg static void 251 1.50 darrenr doit(struct sockaddr *fromp, struct sockaddr *localp) 252 1.1 cgd { 253 1.42 christos struct passwd *pwd, pwres; 254 1.14 mrg in_port_t port; 255 1.26 mycroft struct pollfd set[2]; 256 1.26 mycroft int cc, pv[2], pid, s = -1; /* XXX gcc */ 257 1.1 cgd int one = 1; 258 1.34 christos char *hostname, *errorhost = NULL; /* XXX gcc */ 259 1.15 mycroft const char *cp; 260 1.15 mycroft char sig, buf[BUFSIZ]; 261 1.7 cgd char cmdbuf[NCARGS+1], locuser[16], remuser[16]; 262 1.1 cgd char remotehost[2 * MAXHOSTNAMELEN + 1]; 263 1.9 christos char hostnamebuf[2 * MAXHOSTNAMELEN + 1]; 264 1.17 mjl #ifdef LOGIN_CAP 265 1.17 mjl login_cap_t *lc; 266 1.17 mjl #endif 267 1.18 itojun char naddr[NI_MAXHOST]; 268 1.18 itojun char saddr[NI_MAXHOST]; 269 1.18 itojun char raddr[NI_MAXHOST]; 270 1.18 itojun char pbuf[NI_MAXSERV]; 271 1.18 itojun int af = fromp->sa_family; 272 1.18 itojun u_int16_t *portp; 273 1.18 itojun struct addrinfo hints, *res, *res0; 274 1.18 itojun int gaierror; 275 1.18 itojun const int niflags = NI_NUMERICHOST | NI_NUMERICSERV; 276 1.34 christos const char *errormsg = NULL, *errorstr = NULL; 277 1.42 christos char pwbuf[1024]; 278 1.1 cgd 279 1.41 christos (void)signal(SIGINT, SIG_DFL); 280 1.41 christos (void)signal(SIGQUIT, SIG_DFL); 281 1.41 christos (void)signal(SIGTERM, SIG_DFL); 282 1.1 cgd #ifdef DEBUG 283 1.36 christos { 284 1.41 christos int t = open(_PATH_TTY, O_RDWR); 285 1.36 christos if (t >= 0) { 286 1.41 christos ioctl(t, TIOCNOTTY, NULL); 287 1.36 christos (void)close(t); 288 1.36 christos } 289 1.1 cgd } 290 1.1 cgd #endif 291 1.18 itojun switch (af) { 292 1.18 itojun case AF_INET: 293 1.18 itojun portp = &((struct sockaddr_in *)fromp)->sin_port; 294 1.18 itojun break; 295 1.18 itojun #ifdef INET6 296 1.18 itojun case AF_INET6: 297 1.18 itojun portp = &((struct sockaddr_in6 *)fromp)->sin6_port; 298 1.18 itojun break; 299 1.18 itojun #endif 300 1.18 itojun default: 301 1.25 mjl syslog(LOG_ERR, "malformed \"from\" address (af %d)", af); 302 1.41 christos exit(EXIT_FAILURE); 303 1.18 itojun } 304 1.18 itojun if (getnameinfo(fromp, fromp->sa_len, naddr, sizeof(naddr), 305 1.18 itojun pbuf, sizeof(pbuf), niflags) != 0) { 306 1.25 mjl syslog(LOG_ERR, "malformed \"from\" address (af %d)", af); 307 1.41 christos exit(EXIT_FAILURE); 308 1.1 cgd } 309 1.1 cgd #ifdef IP_OPTIONS 310 1.36 christos if (af == AF_INET) { 311 1.36 christos 312 1.36 christos u_char optbuf[BUFSIZ/3]; 313 1.44 mrg socklen_t optsize = sizeof(optbuf); 314 1.47 lukem int ipproto; 315 1.47 lukem unsigned int i; 316 1.1 cgd struct protoent *ip; 317 1.1 cgd 318 1.1 cgd if ((ip = getprotobyname("ip")) != NULL) 319 1.1 cgd ipproto = ip->p_proto; 320 1.1 cgd else 321 1.1 cgd ipproto = IPPROTO_IP; 322 1.1 cgd if (!getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, &optsize) && 323 1.1 cgd optsize != 0) { 324 1.36 christos for (i = 0; i < optsize;) { 325 1.36 christos u_char c = optbuf[i]; 326 1.36 christos if (c == IPOPT_LSRR || c == IPOPT_SSRR) { 327 1.36 christos syslog(LOG_NOTICE, 328 1.36 christos "Connection refused from %s " 329 1.36 christos "with IP option %s", 330 1.36 christos inet_ntoa(( 331 1.36 christos (struct sockaddr_in *)fromp)->sin_addr), 332 1.36 christos c == IPOPT_LSRR ? "LSRR" : "SSRR"); 333 1.41 christos exit(EXIT_FAILURE); 334 1.36 christos } 335 1.36 christos if (c == IPOPT_EOL) 336 1.36 christos break; 337 1.36 christos i += (c == IPOPT_NOP) ? 1 : optbuf[i + 1]; 338 1.1 cgd } 339 1.1 cgd } 340 1.36 christos } 341 1.1 cgd #endif 342 1.18 itojun if (ntohs(*portp) >= IPPORT_RESERVED 343 1.41 christos || ntohs(*portp) < IPPORT_RESERVED / 2) { 344 1.13 enami syslog(LOG_NOTICE|LOG_AUTH, 345 1.13 enami "Connection from %s on illegal port %u", 346 1.18 itojun naddr, ntohs(*portp)); 347 1.41 christos exit(EXIT_FAILURE); 348 1.13 enami } 349 1.1 cgd 350 1.1 cgd (void) alarm(60); 351 1.1 cgd port = 0; 352 1.1 cgd for (;;) { 353 1.1 cgd char c; 354 1.13 enami 355 1.7 cgd if ((cc = read(STDIN_FILENO, &c, 1)) != 1) { 356 1.1 cgd if (cc < 0) 357 1.22 lukem syslog(LOG_ERR, "read: %m"); 358 1.41 christos (void)shutdown(0, SHUT_RDWR); 359 1.41 christos exit(EXIT_FAILURE); 360 1.1 cgd } 361 1.13 enami if (c == 0) 362 1.1 cgd break; 363 1.1 cgd port = port * 10 + c - '0'; 364 1.1 cgd } 365 1.1 cgd 366 1.1 cgd (void) alarm(0); 367 1.1 cgd if (port != 0) { 368 1.1 cgd int lport = IPPORT_RESERVED - 1; 369 1.50 darrenr s = rresvport_af_addr(&lport, af, localp); 370 1.1 cgd if (s < 0) { 371 1.1 cgd syslog(LOG_ERR, "can't get stderr port: %m"); 372 1.41 christos exit(EXIT_FAILURE); 373 1.1 cgd } 374 1.12 lukem if (port >= IPPORT_RESERVED) { 375 1.25 mjl syslog(LOG_ERR, "2nd port not reserved"); 376 1.41 christos exit(EXIT_FAILURE); 377 1.12 lukem } 378 1.18 itojun *portp = htons(port); 379 1.38 ginsbach if (connect(s, fromp, fromp->sa_len) < 0) { 380 1.22 lukem syslog(LOG_ERR, "connect second port %d: %m", port); 381 1.41 christos exit(EXIT_FAILURE); 382 1.1 cgd } 383 1.1 cgd } 384 1.1 cgd 385 1.1 cgd 386 1.1 cgd #ifdef notdef 387 1.1 cgd /* from inetd, socket is already on 0, 1, 2 */ 388 1.41 christos (void)dup2(f, STDIN_FILENO); 389 1.41 christos (void)dup2(f, STDOUT_FILENO); 390 1.41 christos (void)dup2(f, STDERR_FILENO); 391 1.1 cgd #endif 392 1.18 itojun if (getnameinfo(fromp, fromp->sa_len, saddr, sizeof(saddr), 393 1.18 itojun NULL, 0, NI_NAMEREQD) == 0) { 394 1.1 cgd /* 395 1.18 itojun * If name returned by getnameinfo is in our domain, 396 1.1 cgd * attempt to verify that we haven't been fooled by someone 397 1.1 cgd * in a remote net; look up the name and check that this 398 1.1 cgd * address corresponds to the name. 399 1.1 cgd */ 400 1.18 itojun hostname = saddr; 401 1.21 itojun res0 = NULL; 402 1.18 itojun if (check_all || local_domain(saddr)) { 403 1.41 christos (void)strlcpy(remotehost, saddr, sizeof(remotehost)); 404 1.1 cgd errorhost = remotehost; 405 1.41 christos (void)memset(&hints, 0, sizeof(hints)); 406 1.18 itojun hints.ai_family = fromp->sa_family; 407 1.18 itojun hints.ai_socktype = SOCK_STREAM; 408 1.18 itojun hints.ai_flags = AI_CANONNAME; 409 1.18 itojun gaierror = getaddrinfo(remotehost, pbuf, &hints, &res0); 410 1.18 itojun if (gaierror) { 411 1.22 lukem syslog(LOG_NOTICE, 412 1.18 itojun "Couldn't look up address for %s: %s", 413 1.18 itojun remotehost, gai_strerror(gaierror)); 414 1.1 cgd errorstr = 415 1.1 cgd "Couldn't look up address for your host (%s)\n"; 416 1.18 itojun hostname = naddr; 417 1.18 itojun } else { 418 1.18 itojun for (res = res0; res; res = res->ai_next) { 419 1.18 itojun if (res->ai_family != fromp->sa_family) 420 1.18 itojun continue; 421 1.18 itojun if (res->ai_addrlen != fromp->sa_len) 422 1.18 itojun continue; 423 1.18 itojun if (getnameinfo(res->ai_addr, 424 1.18 itojun res->ai_addrlen, 425 1.18 itojun raddr, sizeof(raddr), NULL, 0, 426 1.18 itojun niflags) == 0 427 1.18 itojun && strcmp(naddr, raddr) == 0) { 428 1.18 itojun hostname = res->ai_canonname 429 1.18 itojun ? res->ai_canonname 430 1.18 itojun : saddr; 431 1.18 itojun break; 432 1.18 itojun } 433 1.18 itojun } 434 1.18 itojun if (res == NULL) { 435 1.1 cgd syslog(LOG_NOTICE, 436 1.1 cgd "Host addr %s not listed for host %s", 437 1.18 itojun naddr, res0->ai_canonname 438 1.18 itojun ? res0->ai_canonname 439 1.18 itojun : saddr); 440 1.1 cgd errorstr = 441 1.1 cgd "Host address mismatch for %s\n"; 442 1.18 itojun hostname = naddr; 443 1.1 cgd } 444 1.1 cgd } 445 1.1 cgd } 446 1.41 christos (void)strlcpy(hostnamebuf, hostname, sizeof(hostnamebuf)); 447 1.25 mjl hostname = hostnamebuf; 448 1.21 itojun if (res0) 449 1.21 itojun freeaddrinfo(res0); 450 1.18 itojun } else { 451 1.41 christos (void)strlcpy(hostnamebuf, naddr, sizeof(hostnamebuf)); 452 1.25 mjl errorhost = hostname = hostnamebuf; 453 1.18 itojun } 454 1.1 cgd 455 1.34 christos (void)alarm(60); 456 1.9 christos getstr(remuser, sizeof(remuser), "remuser"); 457 1.1 cgd getstr(locuser, sizeof(locuser), "locuser"); 458 1.1 cgd getstr(cmdbuf, sizeof(cmdbuf), "command"); 459 1.34 christos (void)alarm(0); 460 1.34 christos 461 1.34 christos #ifdef USE_PAM 462 1.34 christos pam_err = pam_start("rsh", locuser, &pamc, &pamh); 463 1.34 christos if (pam_err != PAM_SUCCESS) { 464 1.34 christos syslog(LOG_ERR|LOG_AUTH, "pam_start(): %s", 465 1.34 christos pam_strerror(pamh, pam_err)); 466 1.41 christos rshd_errx(EXIT_FAILURE, incorrect); 467 1.34 christos } 468 1.34 christos 469 1.34 christos if ((pam_err = pam_set_item(pamh, PAM_RUSER, remuser)) != PAM_SUCCESS || 470 1.49 christos (pam_err = pam_set_item(pamh, PAM_RHOST, hostname)) != PAM_SUCCESS){ 471 1.34 christos syslog(LOG_ERR|LOG_AUTH, "pam_set_item(): %s", 472 1.34 christos pam_strerror(pamh, pam_err)); 473 1.41 christos rshd_errx(EXIT_FAILURE, incorrect); 474 1.34 christos } 475 1.34 christos 476 1.34 christos pam_err = pam_authenticate(pamh, 0); 477 1.34 christos if (pam_err == PAM_SUCCESS) { 478 1.34 christos if ((pam_err = pam_get_user(pamh, &cp, NULL)) == PAM_SUCCESS) { 479 1.41 christos (void)strlcpy(locuser, cp, sizeof(locuser)); 480 1.34 christos /* XXX truncation! */ 481 1.34 christos } 482 1.34 christos pam_err = pam_acct_mgmt(pamh, 0); 483 1.34 christos } 484 1.34 christos if (pam_err != PAM_SUCCESS) { 485 1.34 christos errorstr = incorrect; 486 1.34 christos errormsg = pam_strerror(pamh, pam_err); 487 1.34 christos goto badlogin; 488 1.34 christos } 489 1.34 christos #endif /* USE_PAM */ 490 1.1 cgd setpwent(); 491 1.43 christos if (getpwnam_r(locuser, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0 || 492 1.43 christos pwd == NULL) { 493 1.7 cgd syslog(LOG_INFO|LOG_AUTH, 494 1.7 cgd "%s@%s as %s: unknown login. cmd='%.80s'", 495 1.7 cgd remuser, hostname, locuser, cmdbuf); 496 1.1 cgd if (errorstr == NULL) 497 1.34 christos errorstr = "Permission denied."; 498 1.41 christos rshd_errx(EXIT_FAILURE, errorstr, errorhost); 499 1.1 cgd } 500 1.17 mjl #ifdef LOGIN_CAP 501 1.17 mjl lc = login_getclass(pwd ? pwd->pw_class : NULL); 502 1.17 mjl #endif 503 1.17 mjl 504 1.1 cgd if (chdir(pwd->pw_dir) < 0) { 505 1.34 christos if (chdir("/") < 0 506 1.17 mjl #ifdef LOGIN_CAP 507 1.34 christos || login_getcapbool(lc, "requirehome", pwd->pw_uid ? 1 : 0) 508 1.34 christos #endif 509 1.34 christos ) { 510 1.17 mjl syslog(LOG_INFO|LOG_AUTH, 511 1.17 mjl "%s@%s as %s: no home directory. cmd='%.80s'", 512 1.17 mjl remuser, hostname, locuser, cmdbuf); 513 1.41 christos rshd_errx(EXIT_SUCCESS, "No remote home directory."); 514 1.17 mjl } 515 1.1 cgd } 516 1.1 cgd 517 1.34 christos #ifndef USE_PAM 518 1.13 enami if (errorstr || 519 1.13 enami (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' && 520 1.18 itojun iruserok_sa(fromp, fromp->sa_len, pwd->pw_uid == 0, remuser, 521 1.18 itojun locuser) < 0)) { 522 1.34 christos errormsg = __rcmd_errstr ? __rcmd_errstr : "unknown error"; 523 1.13 enami if (errorstr == NULL) 524 1.34 christos errorstr = "Permission denied."; 525 1.35 christos goto badlogin; 526 1.13 enami } 527 1.1 cgd 528 1.34 christos if (pwd->pw_uid && !access(_PATH_NOLOGIN, F_OK)) 529 1.41 christos rshd_errx(EXIT_FAILURE, "Logins currently disabled."); 530 1.39 christos #endif 531 1.39 christos 532 1.39 christos #ifdef LOGIN_CAP 533 1.39 christos /* 534 1.39 christos * PAM modules might add supplementary groups in 535 1.39 christos * pam_setcred(), so initialize them first. 536 1.39 christos * But we need to open the session as root. 537 1.39 christos */ 538 1.39 christos if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) != 0) { 539 1.39 christos syslog(LOG_ERR, "setusercontext: %m"); 540 1.41 christos exit(EXIT_FAILURE); 541 1.39 christos } 542 1.39 christos #else 543 1.39 christos initgroups(pwd->pw_name, pwd->pw_gid); 544 1.39 christos #endif 545 1.39 christos 546 1.39 christos #ifdef USE_PAM 547 1.39 christos if ((pam_err = pam_open_session(pamh, 0)) != PAM_SUCCESS) { 548 1.39 christos syslog(LOG_ERR, "pam_open_session: %s", 549 1.39 christos pam_strerror(pamh, pam_err)); 550 1.39 christos } else if ((pam_err = pam_setcred(pamh, PAM_ESTABLISH_CRED)) 551 1.39 christos != PAM_SUCCESS) { 552 1.39 christos syslog(LOG_ERR, "pam_setcred: %s", pam_strerror(pamh, pam_err)); 553 1.39 christos } 554 1.39 christos #endif 555 1.1 cgd 556 1.41 christos (void)write(STDERR_FILENO, "\0", 1); 557 1.1 cgd sent_null = 1; 558 1.1 cgd 559 1.1 cgd if (port) { 560 1.34 christos if (pipe(pv) < 0) 561 1.41 christos rshd_errx(EXIT_FAILURE, "Can't make pipe. (%s)", 562 1.41 christos strerror(errno)); 563 1.1 cgd pid = fork(); 564 1.34 christos if (pid == -1) 565 1.41 christos rshd_errx(EXIT_FAILURE, "Can't fork. (%s)", 566 1.41 christos strerror(errno)); 567 1.1 cgd if (pid) { 568 1.41 christos (void)close(STDIN_FILENO); 569 1.41 christos (void)close(STDOUT_FILENO); 570 1.41 christos (void)close(STDERR_FILENO); 571 1.41 christos (void)close(pv[1]); 572 1.1 cgd 573 1.26 mycroft set[0].fd = s; 574 1.26 mycroft set[0].events = POLLIN; 575 1.26 mycroft set[1].fd = pv[0]; 576 1.26 mycroft set[1].events = POLLIN; 577 1.13 enami ioctl(pv[0], FIONBIO, (char *)&one); 578 1.1 cgd 579 1.1 cgd /* should set s nbio! */ 580 1.1 cgd do { 581 1.26 mycroft if (poll(set, 2, INFTIM) < 0) 582 1.13 enami break; 583 1.26 mycroft if (set[0].revents & POLLIN) { 584 1.1 cgd int ret; 585 1.13 enami 586 1.13 enami ret = read(s, &sig, 1); 587 1.1 cgd if (ret <= 0) 588 1.26 mycroft set[0].events = 0; 589 1.1 cgd else 590 1.1 cgd killpg(pid, sig); 591 1.1 cgd } 592 1.26 mycroft if (set[1].revents & POLLIN) { 593 1.1 cgd errno = 0; 594 1.1 cgd cc = read(pv[0], buf, sizeof(buf)); 595 1.1 cgd if (cc <= 0) { 596 1.22 lukem shutdown(s, SHUT_RDWR); 597 1.26 mycroft set[1].events = 0; 598 1.1 cgd } else { 599 1.41 christos (void)write(s, buf, cc); 600 1.1 cgd } 601 1.1 cgd } 602 1.1 cgd 603 1.26 mycroft } while ((set[0].revents | set[1].revents) & POLLIN); 604 1.39 christos PAM_END; 605 1.41 christos exit(EXIT_SUCCESS); 606 1.1 cgd } 607 1.41 christos (void)close(s); 608 1.41 christos (void)close(pv[0]); 609 1.41 christos (void)dup2(pv[1], STDERR_FILENO); 610 1.1 cgd close(pv[1]); 611 1.1 cgd } 612 1.34 christos #ifdef USE_PAM 613 1.34 christos else { 614 1.34 christos pid = fork(); 615 1.34 christos if (pid == -1) 616 1.41 christos rshd_errx(EXIT_FAILURE, "Can't fork. (%s)", 617 1.41 christos strerror(errno)); 618 1.34 christos if (pid) { 619 1.39 christos pid_t xpid; 620 1.39 christos int status; 621 1.39 christos if ((xpid = waitpid(pid, &status, 0)) != pid) { 622 1.39 christos pam_err = pam_close_session(pamh, 0); 623 1.39 christos if (pam_err != PAM_SUCCESS) { 624 1.39 christos syslog(LOG_ERR, 625 1.39 christos "pam_close_session: %s", 626 1.39 christos pam_strerror(pamh, pam_err)); 627 1.39 christos } 628 1.39 christos PAM_END; 629 1.39 christos if (xpid != -1) 630 1.39 christos syslog(LOG_WARNING, 631 1.39 christos "wrong PID: %d != %d", pid, xpid); 632 1.39 christos else 633 1.39 christos syslog(LOG_WARNING, 634 1.39 christos "wait pid=%d failed %m", pid); 635 1.41 christos exit(EXIT_FAILURE); 636 1.39 christos } 637 1.41 christos exit(EXIT_SUCCESS); 638 1.39 christos } 639 1.34 christos } 640 1.34 christos #endif 641 1.17 mjl 642 1.34 christos #ifdef F_CLOSEM 643 1.41 christos (void)fcntl(STDERR_FILENO + 1, F_CLOSEM, 0); 644 1.34 christos #else 645 1.41 christos for (fd = getdtablesize(); fd > STDERR_FILENO; fd--) 646 1.34 christos (void)close(fd); 647 1.34 christos #endif 648 1.34 christos if (setsid() == -1) 649 1.34 christos syslog(LOG_ERR, "setsid() failed: %m"); 650 1.34 christos #ifdef USE_PAM 651 1.34 christos if (setlogin(pwd->pw_name) < 0) 652 1.34 christos syslog(LOG_ERR, "setlogin() failed: %m"); 653 1.34 christos 654 1.39 christos if (*pwd->pw_shell == '\0') 655 1.41 christos pwd->pw_shell = __UNCONST(_PATH_BSHELL); 656 1.39 christos 657 1.34 christos (void)pam_setenv(pamh, "HOME", pwd->pw_dir, 1); 658 1.34 christos (void)pam_setenv(pamh, "SHELL", pwd->pw_shell, 1); 659 1.34 christos (void)pam_setenv(pamh, "USER", pwd->pw_name, 1); 660 1.34 christos (void)pam_setenv(pamh, "PATH", _PATH_DEFPATH, 1); 661 1.34 christos environ = pam_getenvlist(pamh); 662 1.34 christos (void)pam_end(pamh, pam_err); 663 1.39 christos #else 664 1.17 mjl #ifdef LOGIN_CAP 665 1.39 christos { 666 1.39 christos char *sh; 667 1.39 christos if ((sh = login_getcapstr(lc, "shell", NULL, NULL))) { 668 1.39 christos if(!(sh = strdup(sh))) { 669 1.39 christos syslog(LOG_ERR, "Cannot alloc mem"); 670 1.41 christos exit(EXIT_FAILURE); 671 1.39 christos } 672 1.39 christos pwd->pw_shell = sh; 673 1.17 mjl } 674 1.17 mjl } 675 1.17 mjl #endif 676 1.48 joerg { 677 1.48 joerg static char *envinit[] = { NULL }; 678 1.1 cgd environ = envinit; 679 1.48 joerg } 680 1.48 joerg setenv("PATH", _PATH_DEFPATH, 1); 681 1.48 joerg setenv("HOME", pwd->pw_dir, 1); 682 1.48 joerg setenv("SHELL", pwd->pw_shell, 1); 683 1.48 joerg setenv("USER", pwd->pw_name, 1); 684 1.34 christos #endif 685 1.34 christos 686 1.7 cgd cp = strrchr(pwd->pw_shell, '/'); 687 1.1 cgd if (cp) 688 1.1 cgd cp++; 689 1.1 cgd else 690 1.1 cgd cp = pwd->pw_shell; 691 1.34 christos 692 1.34 christos #ifdef LOGIN_CAP 693 1.34 christos if (setusercontext(lc, pwd, pwd->pw_uid, 694 1.34 christos LOGIN_SETALL & ~LOGIN_SETGROUP) < 0) { 695 1.34 christos syslog(LOG_ERR, "setusercontext(): %m"); 696 1.41 christos exit(EXIT_FAILURE); 697 1.34 christos } 698 1.34 christos login_close(lc); 699 1.34 christos #else 700 1.34 christos (void)setgid((gid_t)pwd->pw_gid); 701 1.34 christos (void)setuid((uid_t)pwd->pw_uid); 702 1.34 christos #endif 703 1.34 christos endpwent(); 704 1.34 christos if (log_success || pwd->pw_uid == 0) { 705 1.34 christos syslog(LOG_INFO|LOG_AUTH, "%s@%s as %s: cmd='%.80s'", 706 1.34 christos remuser, hostname, locuser, cmdbuf); 707 1.34 christos } 708 1.41 christos (void)execl(pwd->pw_shell, cp, "-c", cmdbuf, NULL); 709 1.41 christos rshd_errx(EXIT_FAILURE, "%s: %s", pwd->pw_shell, strerror(errno)); 710 1.34 christos badlogin: 711 1.34 christos syslog(LOG_INFO|LOG_AUTH, 712 1.34 christos "%s@%s as %s: permission denied (%s). cmd='%.80s'", 713 1.34 christos remuser, hostname, locuser, errormsg, cmdbuf); 714 1.41 christos rshd_errx(EXIT_FAILURE, errorstr, errorhost); 715 1.1 cgd } 716 1.1 cgd 717 1.1 cgd /* 718 1.7 cgd * Report error to client. Note: can't be used until second socket has 719 1.7 cgd * connected to client, or older clients will hang waiting for that 720 1.7 cgd * connection first. 721 1.1 cgd */ 722 1.25 mjl 723 1.7 cgd #include <stdarg.h> 724 1.7 cgd 725 1.48 joerg static void 726 1.34 christos rshd_errx(int error, const char *fmt, ...) 727 1.1 cgd { 728 1.7 cgd va_list ap; 729 1.34 christos int len, rv; 730 1.7 cgd char *bp, buf[BUFSIZ]; 731 1.7 cgd va_start(ap, fmt); 732 1.7 cgd bp = buf; 733 1.7 cgd if (sent_null == 0) { 734 1.1 cgd *bp++ = 1; 735 1.7 cgd len = 1; 736 1.7 cgd } else 737 1.7 cgd len = 0; 738 1.34 christos rv = vsnprintf(bp, sizeof(buf) - 2, fmt, ap); 739 1.34 christos bp[rv++] = '\n'; 740 1.34 christos (void)write(STDERR_FILENO, buf, len + rv); 741 1.24 wiz va_end(ap); 742 1.34 christos exit(error); 743 1.1 cgd } 744 1.1 cgd 745 1.48 joerg static void 746 1.41 christos getstr(char *buf, int cnt, const char *err) 747 1.1 cgd { 748 1.1 cgd char c; 749 1.1 cgd 750 1.1 cgd do { 751 1.7 cgd if (read(STDIN_FILENO, &c, 1) != 1) 752 1.41 christos exit(EXIT_FAILURE); 753 1.1 cgd *buf++ = c; 754 1.34 christos if (--cnt == 0) 755 1.41 christos rshd_errx(EXIT_FAILURE, "%s too long", err); 756 1.1 cgd } while (c != 0); 757 1.1 cgd } 758 1.1 cgd 759 1.1 cgd /* 760 1.1 cgd * Check whether host h is in our local domain, 761 1.1 cgd * defined as sharing the last two components of the domain part, 762 1.1 cgd * or the entire domain part if the local domain has only one component. 763 1.1 cgd * If either name is unqualified (contains no '.'), 764 1.1 cgd * assume that the host is local, as it will be 765 1.1 cgd * interpreted as such. 766 1.1 cgd */ 767 1.48 joerg static int 768 1.25 mjl local_domain(char *h) 769 1.1 cgd { 770 1.14 mrg char localhost[MAXHOSTNAMELEN + 1]; 771 1.7 cgd char *p1, *p2; 772 1.1 cgd 773 1.1 cgd localhost[0] = 0; 774 1.14 mrg (void)gethostname(localhost, sizeof(localhost)); 775 1.14 mrg localhost[sizeof(localhost) - 1] = '\0'; 776 1.1 cgd p1 = topdomain(localhost); 777 1.1 cgd p2 = topdomain(h); 778 1.1 cgd if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) 779 1.7 cgd return (1); 780 1.7 cgd return (0); 781 1.1 cgd } 782 1.1 cgd 783 1.48 joerg static char * 784 1.25 mjl topdomain(char *h) 785 1.1 cgd { 786 1.7 cgd char *p, *maybe = NULL; 787 1.1 cgd int dots = 0; 788 1.1 cgd 789 1.1 cgd for (p = h + strlen(h); p >= h; p--) { 790 1.1 cgd if (*p == '.') { 791 1.1 cgd if (++dots == 2) 792 1.1 cgd return (p); 793 1.1 cgd maybe = p; 794 1.1 cgd } 795 1.1 cgd } 796 1.1 cgd return (maybe); 797 1.1 cgd } 798 1.1 cgd 799 1.48 joerg static void 800 1.25 mjl usage(void) 801 1.1 cgd { 802 1.7 cgd 803 1.41 christos syslog(LOG_ERR, "Usage: %s [-%s]", getprogname(), OPTIONS); 804 1.41 christos exit(EXIT_FAILURE); 805 1.1 cgd } 806