📄 rcmd.c
字号:
/* * Copyright (c) 1983, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#if defined(LIBC_SCCS) && !defined(lint)static char sccsid[] = "@(#)rcmd.c 8.3 (Berkeley) 3/26/94";#endif /* LIBC_SCCS and not lint */#include <sys/cdefs.h>#include <sys/types.h>#include <time.h>#include <sys/select.h>#include "namespace.h"#include <sys/param.h>#include <sys/socket.h>#include <sys/stat.h>#include <netinet/in.h>#include <arpa/inet.h>#include <signal.h>#include <fcntl.h>#include <netdb.h>#include <stdlib.h>#include <unistd.h>#include <pwd.h>#include <errno.h>#include <stdio.h>#include <ctype.h>#include <string.h>#ifdef YP#include <rpc/rpc.h>#include <rpcsvc/yp_prot.h>#include <rpcsvc/ypclnt.h>#endif#include <arpa/nameser.h>#include "un-namespace.h"/* wrapper for KAME-special getnameinfo() */#ifndef NI_WITHSCOPEID#define NI_WITHSCOPEID 0#endifextern int innetgr( const char *, const char *, const char *, const char * );extern int rcmdsh(char **ahost, int rport, const char *locuser, const char *remuser, const char *cmd, const char *rshprog);int rresvport_af(int *alport, int family);#define max(a, b) ((a > b) ? a : b)int __ivaliduser(FILE *, u_int32_t, const char *, const char *);int __ivaliduser_af(FILE *,const void *, const char *, const char *, int, int);int __ivaliduser_sa(FILE *, const struct sockaddr *, socklen_t, const char *, const char *);static int __icheckhost(const struct sockaddr *, socklen_t, const char *);char paddr[NI_MAXHOST];intrcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, af) char **ahost; u_short rport; const char *locuser, *remuser, *cmd; int *fd2p; int af;{ struct addrinfo hints, *res, *ai; struct sockaddr_storage from; fd_set reads; sigset_t oldmask, newmask; pid_t pid; int s, aport, lport, timo, error; char c, *p; int refused, nres; char num[8]; static char canonnamebuf[MAXDNAME]; /* is it proper here? */ /* call rcmdsh() with specified remote shell if appropriate. */ if (!issetugid() && (p = getenv("RSH"))) { struct servent *sp = getservbyname("shell", "tcp"); if (sp && sp->s_port == rport) return (rcmdsh(ahost, rport, locuser, remuser, cmd, p)); } /* use rsh(1) if non-root and remote port is shell. */ if (geteuid()) { struct servent *sp = getservbyname("shell", "tcp"); if (sp && sp->s_port == rport) return (rcmdsh(ahost, rport, locuser, remuser, cmd, NULL)); } pid = getpid(); memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_CANONNAME; hints.ai_family = af; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = 0; (void)snprintf(num, sizeof(num), "%d", ntohs(rport)); error = getaddrinfo(*ahost, num, &hints, &res); if (error) { fprintf(stderr, "rcmd: getaddrinfo: %s\n", gai_strerror(error)); if (error == EAI_SYSTEM) fprintf(stderr, "rcmd: getaddrinfo: %s\n", strerror(errno)); return (-1); } if (res->ai_canonname && strlen(res->ai_canonname) + 1 < sizeof(canonnamebuf)) { strncpy(canonnamebuf, res->ai_canonname, sizeof(canonnamebuf)); *ahost = canonnamebuf; } nres = 0; for (ai = res; ai; ai = ai->ai_next) nres++; ai = res; refused = 0; sigemptyset(&newmask); sigaddset(&newmask, SIGURG); sigprocmask(SIG_BLOCK, (const sigset_t *)&newmask, &oldmask); for (timo = 1, lport = IPPORT_RESERVED - 1;;) { s = rresvport_af(&lport, ai->ai_family); if (s < 0) { if (errno != EAGAIN && ai->ai_next) { ai = ai->ai_next; continue; } if (errno == EAGAIN) (void)fprintf(stderr, "rcmd: socket: All ports in use\n"); else (void)fprintf(stderr, "rcmd: socket: %s\n", strerror(errno)); freeaddrinfo(res); sigprocmask(SIG_SETMASK, (const sigset_t *)&oldmask, NULL); return (-1); } fcntl(s, F_SETOWN, pid); if (connect(s, ai->ai_addr, ai->ai_addrlen) >= 0) break; (void)close(s); if (errno == EADDRINUSE) { lport--; continue; } if (errno == ECONNREFUSED) refused = 1; if (ai->ai_next == NULL && (!refused || timo > 16)) { (void)fprintf(stderr, "%s: %s\n", *ahost, strerror(errno)); freeaddrinfo(res); sigprocmask(SIG_SETMASK, (const sigset_t *)&oldmask, NULL); return (-1); } if (nres > 1) { int oerrno = errno; getnameinfo(ai->ai_addr, ai->ai_addrlen, paddr, sizeof(paddr), NULL, 0, NI_NUMERICHOST|NI_WITHSCOPEID); (void)fprintf(stderr, "connect to address %s: ", paddr); errno = oerrno; perror(0); } if ((ai = ai->ai_next) == NULL) { /* refused && timo <= 16 */ struct timespec time_to_sleep, time_remaining; time_to_sleep.tv_sec = timo; time_to_sleep.tv_nsec = 0; (void)nanosleep(&time_to_sleep, &time_remaining); timo *= 2; ai = res; refused = 0; } if (nres > 1) { getnameinfo(ai->ai_addr, ai->ai_addrlen, paddr, sizeof(paddr), NULL, 0, NI_NUMERICHOST|NI_WITHSCOPEID); fprintf(stderr, "Trying %s...\n", paddr); } } lport--; if (fd2p == 0) { write(s, "", 1); lport = 0; } else { char num[8]; int s2 = rresvport_af(&lport, ai->ai_family), s3; int len = ai->ai_addrlen; int nfds; if (s2 < 0) goto bad; listen(s2, 1); (void)snprintf(num, sizeof(num), "%d", lport); if (write(s, num, strlen(num)+1) != strlen(num)+1) { (void)fprintf(stderr, "rcmd: write (setting up stderr): %s\n", strerror(errno)); (void)close(s2); goto bad; } nfds = max(s, s2)+1; if(nfds > FD_SETSIZE) { fprintf(stderr, "rcmd: too many files\n"); (void)close(s2); goto bad; }again: FD_ZERO(&reads); FD_SET(s, &reads); FD_SET(s2, &reads); errno = 0; if (select(nfds, &reads, 0, 0, 0) < 1 || !FD_ISSET(s2, &reads)){ if (errno != 0) (void)fprintf(stderr, "rcmd: select (setting up stderr): %s\n", strerror(errno)); else (void)fprintf(stderr, "select: protocol failure in circuit setup\n"); (void)close(s2); goto bad; } s3 = accept(s2, (struct sockaddr *)&from, &len); switch (from.ss_family) { case AF_INET: aport = ntohs(((struct sockaddr_in *)&from)->sin_port); break;#ifdef INET6 case AF_INET6: aport = ntohs(((struct sockaddr_in6 *)&from)->sin6_port); break;#endif default: aport = 0; /* error */ break; } /* * XXX careful for ftp bounce attacks. If discovered, shut them * down and check for the real auxiliary channel to connect. */ if (aport == 20) { close(s3); goto again; } (void)close(s2); if (s3 < 0) { (void)fprintf(stderr, "rcmd: accept: %s\n", strerror(errno)); lport = 0; goto bad; } *fd2p = s3; if (aport >= IPPORT_RESERVED || aport < IPPORT_RESERVED / 2) { (void)fprintf(stderr, "socket: protocol failure in circuit setup.\n"); goto bad2; } } (void)write(s, locuser, strlen(locuser)+1); (void)write(s, remuser, strlen(remuser)+1); (void)write(s, cmd, strlen(cmd)+1); if (read(s, &c, 1) != 1) { (void)fprintf(stderr, "rcmd: %s: %s\n", *ahost, strerror(errno)); goto bad2; } if (c != 0) { while (read(s, &c, 1) == 1) { (void)write(STDERR_FILENO, &c, 1); if (c == '\n') break; } goto bad2; } sigprocmask(SIG_SETMASK, (const sigset_t *)&oldmask, NULL); freeaddrinfo(res); return (s);bad2: if (lport) (void)close(*fd2p);bad: (void)close(s); sigprocmask(SIG_SETMASK, (const sigset_t *)&oldmask, NULL); freeaddrinfo(res); return (-1);}intrcmd(ahost, rport, locuser, remuser, cmd, fd2p) char **ahost; u_short rport; const char *locuser, *remuser, *cmd; int *fd2p;{ return rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, AF_INET);}intrresvport(port) int *port;{ return rresvport_af(port, AF_INET);}intrresvport_af(alport, family) int *alport, family;{ int s; struct sockaddr_storage ss; u_short *sport; memset(&ss, 0, sizeof(ss)); ss.ss_family = family; switch (family) { case AF_INET: sport = &((struct sockaddr_in *)&ss)->sin_port; ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY; break;#ifdef INET6 case AF_INET6: sport = &((struct sockaddr_in6 *)&ss)->sin6_port; ((struct sockaddr_in6 *)&ss)->sin6_addr = in6addr_any; break;#endif default: errno = EAFNOSUPPORT; return -1; } s = socket(ss.ss_family, SOCK_STREAM, 0); if (s < 0) return (-1);#if 0 /* compat_exact_traditional_rresvport_semantics */ sin.sin_port = htons((u_short)*alport); if (_bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0) return (s); if (errno != EADDRINUSE) { (void)close(s); return (-1); }#endif *sport = 0; if (bindresvport_sa(s, (struct sockaddr *)&ss) == -1) { (void)close(s); return (-1); } *alport = (int)ntohs(*sport);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -