1df930be7Sderaadt /* 28ffd66b8Sderaadt * Copyright (c) 1995, 1996 Theo de Raadt. All rights reserved. 3df930be7Sderaadt * Copyright (c) 1983, 1993, 1994 4df930be7Sderaadt * The Regents of the University of California. All rights reserved. 5df930be7Sderaadt * 6df930be7Sderaadt * Redistribution and use in source and binary forms, with or without 7df930be7Sderaadt * modification, are permitted provided that the following conditions 8df930be7Sderaadt * are met: 9df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright 10df930be7Sderaadt * notice, this list of conditions and the following disclaimer. 11df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright 12df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the 13df930be7Sderaadt * documentation and/or other materials provided with the distribution. 14df930be7Sderaadt * 3. All advertising materials mentioning features or use of this software 15df930be7Sderaadt * must display the following acknowledgement: 16df930be7Sderaadt * This product includes software developed by the University of 17df930be7Sderaadt * California, Berkeley and its contributors. 188ffd66b8Sderaadt * This product includes software developed by Theo de Raadt. 19df930be7Sderaadt * 4. Neither the name of the University nor the names of its contributors 20df930be7Sderaadt * may be used to endorse or promote products derived from this software 21df930be7Sderaadt * without specific prior written permission. 22df930be7Sderaadt * 23df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33df930be7Sderaadt * SUCH DAMAGE. 34df930be7Sderaadt */ 35df930be7Sderaadt 36df930be7Sderaadt #if defined(LIBC_SCCS) && !defined(lint) 37*d4b79a24Sderaadt static char *rcsid = "$OpenBSD: rcmd.c,v 1.17 1996/09/03 10:53:37 deraadt Exp $"; 38df930be7Sderaadt #endif /* LIBC_SCCS and not lint */ 39df930be7Sderaadt 40df930be7Sderaadt #include <sys/param.h> 41df930be7Sderaadt #include <sys/socket.h> 42df930be7Sderaadt #include <sys/stat.h> 43df930be7Sderaadt 44df930be7Sderaadt #include <netinet/in.h> 45df930be7Sderaadt #include <arpa/inet.h> 46df930be7Sderaadt 47df930be7Sderaadt #include <signal.h> 48df930be7Sderaadt #include <fcntl.h> 49df930be7Sderaadt #include <netdb.h> 50df930be7Sderaadt #include <unistd.h> 51df930be7Sderaadt #include <pwd.h> 52df930be7Sderaadt #include <errno.h> 53df930be7Sderaadt #include <stdio.h> 54df930be7Sderaadt #include <ctype.h> 55df930be7Sderaadt #include <string.h> 566bd11984Sderaadt #include <syslog.h> 57*d4b79a24Sderaadt #include <stdlib.h> 58df930be7Sderaadt 59df930be7Sderaadt int __ivaliduser __P((FILE *, u_long, const char *, const char *)); 606bd11984Sderaadt static int __icheckhost __P((u_int32_t, const char *)); 616bd11984Sderaadt static char *__gethostloop __P((u_int32_t)); 62df930be7Sderaadt 63df930be7Sderaadt int 64df930be7Sderaadt rcmd(ahost, rport, locuser, remuser, cmd, fd2p) 65df930be7Sderaadt char **ahost; 66df930be7Sderaadt u_short rport; 67df930be7Sderaadt const char *locuser, *remuser, *cmd; 68df930be7Sderaadt int *fd2p; 69df930be7Sderaadt { 70df930be7Sderaadt struct hostent *hp; 71df930be7Sderaadt struct sockaddr_in sin, from; 72df930be7Sderaadt fd_set reads; 738f6952f5Sderaadt int oldmask; 74df930be7Sderaadt pid_t pid; 75df930be7Sderaadt int s, lport, timo; 76542c8643Smillert char c, *p; 77542c8643Smillert 78542c8643Smillert /* call rcmdsh() with specified remote shell if appropriate. */ 79542c8643Smillert if ((p = getenv("RSH"))) { 80542c8643Smillert struct servent *sp = getservbyname("shell", "tcp"); 81542c8643Smillert 82542c8643Smillert if (sp && sp->s_port == rport) 83542c8643Smillert return (rcmdsh(ahost, rport, locuser, remuser, 84542c8643Smillert cmd, p)); 85542c8643Smillert } 86df930be7Sderaadt 871437b3aeSmillert /* use rsh(1) if non-root and remote port is shell. */ 881437b3aeSmillert if (geteuid()) { 891437b3aeSmillert struct servent *sp = getservbyname("shell", "tcp"); 9022c1ec3fSderaadt 911437b3aeSmillert if (sp && sp->s_port == rport) 9222c1ec3fSderaadt return (rcmdsh(ahost, rport, locuser, remuser, 9322c1ec3fSderaadt cmd, NULL)); 941437b3aeSmillert } 951437b3aeSmillert 96df930be7Sderaadt pid = getpid(); 97df930be7Sderaadt hp = gethostbyname(*ahost); 98df930be7Sderaadt if (hp == NULL) { 99df930be7Sderaadt herror(*ahost); 100df930be7Sderaadt return (-1); 101df930be7Sderaadt } 102df930be7Sderaadt *ahost = hp->h_name; 1031437b3aeSmillert 104df930be7Sderaadt oldmask = sigblock(sigmask(SIGURG)); 105df930be7Sderaadt for (timo = 1, lport = IPPORT_RESERVED - 1;;) { 106df930be7Sderaadt s = rresvport(&lport); 107df930be7Sderaadt if (s < 0) { 108df930be7Sderaadt if (errno == EAGAIN) 109df930be7Sderaadt (void)fprintf(stderr, 110df930be7Sderaadt "rcmd: socket: All ports in use\n"); 111df930be7Sderaadt else 112df930be7Sderaadt (void)fprintf(stderr, "rcmd: socket: %s\n", 113df930be7Sderaadt strerror(errno)); 114df930be7Sderaadt sigsetmask(oldmask); 115df930be7Sderaadt return (-1); 116df930be7Sderaadt } 117df930be7Sderaadt fcntl(s, F_SETOWN, pid); 1182817004dSderaadt bzero(&sin, sizeof sin); 119df930be7Sderaadt sin.sin_len = sizeof(struct sockaddr_in); 120df930be7Sderaadt sin.sin_family = hp->h_addrtype; 121df930be7Sderaadt sin.sin_port = rport; 122df930be7Sderaadt bcopy(hp->h_addr_list[0], &sin.sin_addr, hp->h_length); 123df930be7Sderaadt if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0) 124df930be7Sderaadt break; 125df930be7Sderaadt (void)close(s); 126df930be7Sderaadt if (errno == EADDRINUSE) { 127df930be7Sderaadt lport--; 128df930be7Sderaadt continue; 129df930be7Sderaadt } 130df930be7Sderaadt if (errno == ECONNREFUSED && timo <= 16) { 131df930be7Sderaadt (void)sleep(timo); 132df930be7Sderaadt timo *= 2; 133df930be7Sderaadt continue; 134df930be7Sderaadt } 135df930be7Sderaadt if (hp->h_addr_list[1] != NULL) { 136df930be7Sderaadt int oerrno = errno; 137df930be7Sderaadt 138df930be7Sderaadt (void)fprintf(stderr, "connect to address %s: ", 139df930be7Sderaadt inet_ntoa(sin.sin_addr)); 140df930be7Sderaadt errno = oerrno; 141df930be7Sderaadt perror(0); 142df930be7Sderaadt hp->h_addr_list++; 143df930be7Sderaadt bcopy(hp->h_addr_list[0], &sin.sin_addr, hp->h_length); 144df930be7Sderaadt (void)fprintf(stderr, "Trying %s...\n", 145df930be7Sderaadt inet_ntoa(sin.sin_addr)); 146df930be7Sderaadt continue; 147df930be7Sderaadt } 148df930be7Sderaadt (void)fprintf(stderr, "%s: %s\n", hp->h_name, strerror(errno)); 149df930be7Sderaadt sigsetmask(oldmask); 150df930be7Sderaadt return (-1); 151df930be7Sderaadt } 1524c98b448Sderaadt #if 0 1534c98b448Sderaadt /* 1544c98b448Sderaadt * try to rresvport() to the same port. This will make rresvport() 1554c98b448Sderaadt * fail it's first bind, resulting in it choosing a random port. 1564c98b448Sderaadt */ 157df930be7Sderaadt lport--; 1584c98b448Sderaadt #endif 159df930be7Sderaadt if (fd2p == 0) { 160df930be7Sderaadt write(s, "", 1); 161df930be7Sderaadt lport = 0; 162df930be7Sderaadt } else { 163df930be7Sderaadt char num[8]; 164df930be7Sderaadt int s2 = rresvport(&lport), s3; 165df930be7Sderaadt int len = sizeof(from); 166df930be7Sderaadt 167df930be7Sderaadt if (s2 < 0) 168df930be7Sderaadt goto bad; 169df930be7Sderaadt listen(s2, 1); 170df930be7Sderaadt (void)snprintf(num, sizeof(num), "%d", lport); 171df930be7Sderaadt if (write(s, num, strlen(num)+1) != strlen(num)+1) { 172df930be7Sderaadt (void)fprintf(stderr, 173df930be7Sderaadt "rcmd: write (setting up stderr): %s\n", 174df930be7Sderaadt strerror(errno)); 175df930be7Sderaadt (void)close(s2); 176df930be7Sderaadt goto bad; 177df930be7Sderaadt } 178efa7ea8eSderaadt again: 179df930be7Sderaadt FD_ZERO(&reads); 180df930be7Sderaadt FD_SET(s, &reads); 181df930be7Sderaadt FD_SET(s2, &reads); 182df930be7Sderaadt errno = 0; 183df930be7Sderaadt if (select(MAX(s, s2) + 1, &reads, 0, 0, 0) < 1 || 184df930be7Sderaadt !FD_ISSET(s2, &reads)) { 185df930be7Sderaadt if (errno != 0) 186df930be7Sderaadt (void)fprintf(stderr, 187df930be7Sderaadt "rcmd: select (setting up stderr): %s\n", 188df930be7Sderaadt strerror(errno)); 189df930be7Sderaadt else 190df930be7Sderaadt (void)fprintf(stderr, 191df930be7Sderaadt "select: protocol failure in circuit setup\n"); 192df930be7Sderaadt (void)close(s2); 193df930be7Sderaadt goto bad; 194df930be7Sderaadt } 195df930be7Sderaadt s3 = accept(s2, (struct sockaddr *)&from, &len); 196efa7ea8eSderaadt /* 197efa7ea8eSderaadt * XXX careful for ftp bounce attacks. If discovered, shut them 198efa7ea8eSderaadt * down and check for the real auxiliary channel to connect. 199efa7ea8eSderaadt */ 200efa7ea8eSderaadt if (from.sin_family == AF_INET && from.sin_port == htons(20)) { 201efa7ea8eSderaadt close(s3); 202efa7ea8eSderaadt goto again; 203efa7ea8eSderaadt } 204df930be7Sderaadt (void)close(s2); 205df930be7Sderaadt if (s3 < 0) { 206df930be7Sderaadt (void)fprintf(stderr, 207df930be7Sderaadt "rcmd: accept: %s\n", strerror(errno)); 208df930be7Sderaadt lport = 0; 209df930be7Sderaadt goto bad; 210df930be7Sderaadt } 211df930be7Sderaadt *fd2p = s3; 212df930be7Sderaadt from.sin_port = ntohs(from.sin_port); 213df930be7Sderaadt if (from.sin_family != AF_INET || 214df930be7Sderaadt from.sin_port >= IPPORT_RESERVED || 215df930be7Sderaadt from.sin_port < IPPORT_RESERVED / 2) { 216df930be7Sderaadt (void)fprintf(stderr, 217df930be7Sderaadt "socket: protocol failure in circuit setup.\n"); 218df930be7Sderaadt goto bad2; 219df930be7Sderaadt } 220df930be7Sderaadt } 221df930be7Sderaadt (void)write(s, locuser, strlen(locuser)+1); 222df930be7Sderaadt (void)write(s, remuser, strlen(remuser)+1); 223df930be7Sderaadt (void)write(s, cmd, strlen(cmd)+1); 224df930be7Sderaadt if (read(s, &c, 1) != 1) { 225df930be7Sderaadt (void)fprintf(stderr, 226df930be7Sderaadt "rcmd: %s: %s\n", *ahost, strerror(errno)); 227df930be7Sderaadt goto bad2; 228df930be7Sderaadt } 229df930be7Sderaadt if (c != 0) { 230df930be7Sderaadt while (read(s, &c, 1) == 1) { 231df930be7Sderaadt (void)write(STDERR_FILENO, &c, 1); 232df930be7Sderaadt if (c == '\n') 233df930be7Sderaadt break; 234df930be7Sderaadt } 235df930be7Sderaadt goto bad2; 236df930be7Sderaadt } 237df930be7Sderaadt sigsetmask(oldmask); 238df930be7Sderaadt return (s); 239df930be7Sderaadt bad2: 240df930be7Sderaadt if (lport) 241df930be7Sderaadt (void)close(*fd2p); 242df930be7Sderaadt bad: 243df930be7Sderaadt (void)close(s); 244df930be7Sderaadt sigsetmask(oldmask); 245df930be7Sderaadt return (-1); 246df930be7Sderaadt } 247df930be7Sderaadt 248df930be7Sderaadt int 249df930be7Sderaadt rresvport(alport) 250df930be7Sderaadt int *alport; 251df930be7Sderaadt { 252df930be7Sderaadt struct sockaddr_in sin; 253df930be7Sderaadt int s; 254df930be7Sderaadt 2552233f5a3Sderaadt bzero(&sin, sizeof sin); 256df930be7Sderaadt sin.sin_len = sizeof(struct sockaddr_in); 257df930be7Sderaadt sin.sin_family = AF_INET; 258df930be7Sderaadt sin.sin_addr.s_addr = INADDR_ANY; 259df930be7Sderaadt s = socket(AF_INET, SOCK_STREAM, 0); 260df930be7Sderaadt if (s < 0) 261df930be7Sderaadt return (-1); 262df930be7Sderaadt sin.sin_port = htons((u_short)*alport); 263304caed9Sderaadt if (*alport != IPPORT_RESERVED - 1) { 264df930be7Sderaadt if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0) 265df930be7Sderaadt return (s); 266df930be7Sderaadt if (errno != EADDRINUSE) { 267df930be7Sderaadt (void)close(s); 268df930be7Sderaadt return (-1); 269df930be7Sderaadt } 27022c1ec3fSderaadt } 271e3bf207fSderaadt sin.sin_port = 0; 27216ef94eeSderaadt if (bindresvport(s, &sin) == -1) { 273df930be7Sderaadt (void)close(s); 274df930be7Sderaadt return (-1); 275df930be7Sderaadt } 27616ef94eeSderaadt *alport = (int)ntohs(sin.sin_port); 27716ef94eeSderaadt return (s); 278df930be7Sderaadt } 279df930be7Sderaadt 280df930be7Sderaadt int __check_rhosts_file = 1; 281df930be7Sderaadt char *__rcmd_errstr; 282df930be7Sderaadt 283df930be7Sderaadt int 284df930be7Sderaadt ruserok(rhost, superuser, ruser, luser) 285df930be7Sderaadt const char *rhost, *ruser, *luser; 286df930be7Sderaadt int superuser; 287df930be7Sderaadt { 288df930be7Sderaadt struct hostent *hp; 289df930be7Sderaadt char **ap; 290df930be7Sderaadt int i; 291df930be7Sderaadt #define MAXADDRS 35 2926bd11984Sderaadt u_int32_t addrs[MAXADDRS + 1]; 293df930be7Sderaadt 294df930be7Sderaadt if ((hp = gethostbyname(rhost)) == NULL) 295df930be7Sderaadt return (-1); 296df930be7Sderaadt for (i = 0, ap = hp->h_addr_list; *ap && i < MAXADDRS; ++ap, ++i) 297df930be7Sderaadt bcopy(*ap, &addrs[i], sizeof(addrs[i])); 298df930be7Sderaadt addrs[i] = 0; 299df930be7Sderaadt 300df930be7Sderaadt for (i = 0; i < MAXADDRS && addrs[i]; i++) 3016bd11984Sderaadt if (iruserok((u_long)addrs[i], superuser, ruser, luser) == 0) 302df930be7Sderaadt return (0); 303df930be7Sderaadt return (-1); 304df930be7Sderaadt } 305df930be7Sderaadt 306df930be7Sderaadt /* 307df930be7Sderaadt * New .rhosts strategy: We are passed an ip address. We spin through 308df930be7Sderaadt * hosts.equiv and .rhosts looking for a match. When the .rhosts only 309df930be7Sderaadt * has ip addresses, we don't have to trust a nameserver. When it 310df930be7Sderaadt * contains hostnames, we spin through the list of addresses the nameserver 311df930be7Sderaadt * gives us and look for a match. 312df930be7Sderaadt * 313df930be7Sderaadt * Returns 0 if ok, -1 if not ok. 314df930be7Sderaadt */ 315df930be7Sderaadt int 316df930be7Sderaadt iruserok(raddr, superuser, ruser, luser) 3178f6952f5Sderaadt u_int32_t raddr; 318df930be7Sderaadt int superuser; 319df930be7Sderaadt const char *ruser, *luser; 320df930be7Sderaadt { 321df930be7Sderaadt register char *cp; 322df930be7Sderaadt struct stat sbuf; 323df930be7Sderaadt struct passwd *pwd; 324df930be7Sderaadt FILE *hostf; 325df930be7Sderaadt uid_t uid; 326df930be7Sderaadt int first; 327df930be7Sderaadt char pbuf[MAXPATHLEN]; 328df930be7Sderaadt 329df930be7Sderaadt first = 1; 330df930be7Sderaadt hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "r"); 331df930be7Sderaadt again: 332df930be7Sderaadt if (hostf) { 333df930be7Sderaadt if (__ivaliduser(hostf, raddr, luser, ruser) == 0) { 334df930be7Sderaadt (void)fclose(hostf); 335df930be7Sderaadt return (0); 336df930be7Sderaadt } 337df930be7Sderaadt (void)fclose(hostf); 338df930be7Sderaadt } 339df930be7Sderaadt if (first == 1 && (__check_rhosts_file || superuser)) { 340df930be7Sderaadt first = 0; 341df930be7Sderaadt if ((pwd = getpwnam(luser)) == NULL) 342df930be7Sderaadt return (-1); 343df930be7Sderaadt (void)strcpy(pbuf, pwd->pw_dir); 344df930be7Sderaadt (void)strcat(pbuf, "/.rhosts"); 345df930be7Sderaadt 346df930be7Sderaadt /* 347df930be7Sderaadt * Change effective uid while opening .rhosts. If root and 348df930be7Sderaadt * reading an NFS mounted file system, can't read files that 349df930be7Sderaadt * are protected read/write owner only. 350df930be7Sderaadt */ 351df930be7Sderaadt uid = geteuid(); 352df930be7Sderaadt (void)seteuid(pwd->pw_uid); 353df930be7Sderaadt hostf = fopen(pbuf, "r"); 354df930be7Sderaadt (void)seteuid(uid); 355df930be7Sderaadt 356df930be7Sderaadt if (hostf == NULL) 357df930be7Sderaadt return (-1); 358df930be7Sderaadt /* 359df930be7Sderaadt * If not a regular file, or is owned by someone other than 360df930be7Sderaadt * user or root or if writeable by anyone but the owner, quit. 361df930be7Sderaadt */ 362df930be7Sderaadt cp = NULL; 363df930be7Sderaadt if (lstat(pbuf, &sbuf) < 0) 364df930be7Sderaadt cp = ".rhosts lstat failed"; 365df930be7Sderaadt else if (!S_ISREG(sbuf.st_mode)) 366df930be7Sderaadt cp = ".rhosts not regular file"; 367df930be7Sderaadt else if (fstat(fileno(hostf), &sbuf) < 0) 368df930be7Sderaadt cp = ".rhosts fstat failed"; 369df930be7Sderaadt else if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid) 370df930be7Sderaadt cp = "bad .rhosts owner"; 371df930be7Sderaadt else if (sbuf.st_mode & (S_IWGRP|S_IWOTH)) 372df930be7Sderaadt cp = ".rhosts writeable by other than owner"; 373df930be7Sderaadt /* If there were any problems, quit. */ 374df930be7Sderaadt if (cp) { 375df930be7Sderaadt __rcmd_errstr = cp; 376df930be7Sderaadt (void)fclose(hostf); 377df930be7Sderaadt return (-1); 378df930be7Sderaadt } 379df930be7Sderaadt goto again; 380df930be7Sderaadt } 381df930be7Sderaadt return (-1); 382df930be7Sderaadt } 383df930be7Sderaadt 384df930be7Sderaadt /* 385df930be7Sderaadt * XXX 386df930be7Sderaadt * Don't make static, used by lpd(8). 387df930be7Sderaadt * 388df930be7Sderaadt * Returns 0 if ok, -1 if not ok. 389df930be7Sderaadt */ 390df930be7Sderaadt int 3916bd11984Sderaadt __ivaliduser(hostf, raddrl, luser, ruser) 392df930be7Sderaadt FILE *hostf; 3936bd11984Sderaadt u_long raddrl; 394df930be7Sderaadt const char *luser, *ruser; 395df930be7Sderaadt { 396df930be7Sderaadt register char *user, *p; 397df930be7Sderaadt int ch; 398df930be7Sderaadt char buf[MAXHOSTNAMELEN + 128]; /* host + login */ 399df930be7Sderaadt const char *auser, *ahost; 400df930be7Sderaadt int hostok, userok; 4016bd11984Sderaadt char *rhost = (char *)-1; 402df930be7Sderaadt char domain[MAXHOSTNAMELEN]; 4036bd11984Sderaadt u_int32_t raddr = (u_int32_t)raddrl; 404df930be7Sderaadt 405df930be7Sderaadt getdomainname(domain, sizeof(domain)); 406df930be7Sderaadt 407df930be7Sderaadt while (fgets(buf, sizeof(buf), hostf)) { 408df930be7Sderaadt p = buf; 409df930be7Sderaadt /* Skip lines that are too long. */ 410df930be7Sderaadt if (strchr(p, '\n') == NULL) { 4116bd11984Sderaadt while ((ch = getc(hostf)) != '\n' && ch != EOF) 4126bd11984Sderaadt ; 413df930be7Sderaadt continue; 414df930be7Sderaadt } 4159983e72cSderaadt if (*p == '#') 4169983e72cSderaadt continue; 417df930be7Sderaadt while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') { 418df930be7Sderaadt *p = isupper(*p) ? tolower(*p) : *p; 419df930be7Sderaadt p++; 420df930be7Sderaadt } 421df930be7Sderaadt if (*p == ' ' || *p == '\t') { 422df930be7Sderaadt *p++ = '\0'; 423df930be7Sderaadt while (*p == ' ' || *p == '\t') 424df930be7Sderaadt p++; 425df930be7Sderaadt user = p; 426df930be7Sderaadt while (*p != '\n' && *p != ' ' && 427df930be7Sderaadt *p != '\t' && *p != '\0') 428df930be7Sderaadt p++; 429df930be7Sderaadt } else 430df930be7Sderaadt user = p; 431df930be7Sderaadt *p = '\0'; 432df930be7Sderaadt 433df930be7Sderaadt if (p == buf) 434df930be7Sderaadt continue; 435df930be7Sderaadt 436df930be7Sderaadt auser = *user ? user : luser; 437df930be7Sderaadt ahost = buf; 438df930be7Sderaadt 4396bd11984Sderaadt /* 4406bd11984Sderaadt * innetgr() must lookup a hostname (we do not attempt 4416bd11984Sderaadt * to change the semantics so that netgroups may have 4426bd11984Sderaadt * #.#.#.# addresses in the list.) 4436bd11984Sderaadt */ 444df930be7Sderaadt if (ahost[0] == '+') 445df930be7Sderaadt switch (ahost[1]) { 446df930be7Sderaadt case '\0': 447df930be7Sderaadt hostok = 1; 448df930be7Sderaadt break; 449df930be7Sderaadt case '@': 4506bd11984Sderaadt if (rhost == (char *)-1) 4516bd11984Sderaadt rhost = __gethostloop(raddr); 4526bd11984Sderaadt hostok = 0; 4536bd11984Sderaadt if (rhost) 4546bd11984Sderaadt hostok = innetgr(&ahost[2], rhost, 4556bd11984Sderaadt NULL, domain); 456df930be7Sderaadt break; 457df930be7Sderaadt default: 458df930be7Sderaadt hostok = __icheckhost(raddr, &ahost[1]); 459df930be7Sderaadt break; 460df930be7Sderaadt } 461df930be7Sderaadt else if (ahost[0] == '-') 462df930be7Sderaadt switch (ahost[1]) { 463df930be7Sderaadt case '\0': 464df930be7Sderaadt hostok = -1; 465df930be7Sderaadt break; 466df930be7Sderaadt case '@': 4676bd11984Sderaadt if (rhost == (char *)-1) 4686bd11984Sderaadt rhost = __gethostloop(raddr); 4696bd11984Sderaadt hostok = 0; 4706bd11984Sderaadt if (rhost) 4716bd11984Sderaadt hostok = -innetgr(&ahost[2], rhost, 4726bd11984Sderaadt NULL, domain); 473df930be7Sderaadt break; 474df930be7Sderaadt default: 475df930be7Sderaadt hostok = -__icheckhost(raddr, &ahost[1]); 476df930be7Sderaadt break; 477df930be7Sderaadt } 478df930be7Sderaadt else 479df930be7Sderaadt hostok = __icheckhost(raddr, ahost); 480df930be7Sderaadt 481df930be7Sderaadt 482df930be7Sderaadt if (auser[0] == '+') 483df930be7Sderaadt switch (auser[1]) { 484df930be7Sderaadt case '\0': 485df930be7Sderaadt userok = 1; 486df930be7Sderaadt break; 487df930be7Sderaadt case '@': 488df930be7Sderaadt userok = innetgr(&auser[2], NULL, ruser, 489df930be7Sderaadt domain); 490df930be7Sderaadt break; 491df930be7Sderaadt default: 4926bd11984Sderaadt userok = strcmp(ruser, &auser[1]) ? 0 : 1; 493df930be7Sderaadt break; 494df930be7Sderaadt } 495df930be7Sderaadt else if (auser[0] == '-') 496df930be7Sderaadt switch (auser[1]) { 497df930be7Sderaadt case '\0': 498df930be7Sderaadt userok = -1; 499df930be7Sderaadt break; 500df930be7Sderaadt case '@': 501df930be7Sderaadt userok = -innetgr(&auser[2], NULL, ruser, 502df930be7Sderaadt domain); 503df930be7Sderaadt break; 504df930be7Sderaadt default: 5056bd11984Sderaadt userok = strcmp(ruser, &auser[1]) ? 0 : -1; 506df930be7Sderaadt break; 507df930be7Sderaadt } 508df930be7Sderaadt else 5096bd11984Sderaadt userok = strcmp(ruser, auser) ? 0 : 1; 510df930be7Sderaadt 511df930be7Sderaadt /* Check if one component did not match */ 512df930be7Sderaadt if (hostok == 0 || userok == 0) 513df930be7Sderaadt continue; 514df930be7Sderaadt 515df930be7Sderaadt /* Check if we got a forbidden pair */ 5166bd11984Sderaadt if (userok <= -1 || hostok <= -1) 5176bd11984Sderaadt return (-1); 518df930be7Sderaadt 519df930be7Sderaadt /* Check if we got a valid pair */ 5206bd11984Sderaadt if (hostok >= 1 && userok >= 1) 5216bd11984Sderaadt return (0); 522df930be7Sderaadt } 5236bd11984Sderaadt return (-1); 524df930be7Sderaadt } 525df930be7Sderaadt 526df930be7Sderaadt /* 5276bd11984Sderaadt * Returns "true" if match, 0 if no match. If we do not find any 5286bd11984Sderaadt * semblance of an A->PTR->A loop, allow a simple #.#.#.# match to work. 529df930be7Sderaadt */ 530df930be7Sderaadt static int 531df930be7Sderaadt __icheckhost(raddr, lhost) 5326bd11984Sderaadt u_int32_t raddr; 533df930be7Sderaadt const char *lhost; 534df930be7Sderaadt { 535df930be7Sderaadt register struct hostent *hp; 536df930be7Sderaadt register char **pp; 5376bd11984Sderaadt struct in_addr in; 538df930be7Sderaadt 5396bd11984Sderaadt hp = gethostbyname(lhost); 5406bd11984Sderaadt if (hp != NULL) { 541df930be7Sderaadt /* Spin through ip addresses. */ 542df930be7Sderaadt for (pp = hp->h_addr_list; *pp; ++pp) 5436bd11984Sderaadt if (!bcmp(&raddr, *pp, sizeof(raddr))) 544df930be7Sderaadt return (1); 5456bd11984Sderaadt } 546df930be7Sderaadt 5476bd11984Sderaadt in.s_addr = raddr; 5486bd11984Sderaadt if (strcmp(lhost, inet_ntoa(in)) == 0) 5496bd11984Sderaadt return (1); 550df930be7Sderaadt return (0); 551df930be7Sderaadt } 5526bd11984Sderaadt 5536bd11984Sderaadt /* 5546bd11984Sderaadt * Return the hostname associated with the supplied address. 5556bd11984Sderaadt * Do a reverse lookup as well for security. If a loop cannot 5566bd11984Sderaadt * be found, pack the result of inet_ntoa() into the string. 5576bd11984Sderaadt */ 5586bd11984Sderaadt static char * 5596bd11984Sderaadt __gethostloop(raddr) 5606bd11984Sderaadt u_int32_t raddr; 5616bd11984Sderaadt { 5626bd11984Sderaadt static char remotehost[MAXHOSTNAMELEN]; 5636bd11984Sderaadt struct hostent *hp; 5646bd11984Sderaadt struct in_addr in; 5656bd11984Sderaadt 5666bd11984Sderaadt hp = gethostbyaddr((char *) &raddr, sizeof(raddr), AF_INET); 5676bd11984Sderaadt if (hp == NULL) 5686bd11984Sderaadt return (NULL); 5696bd11984Sderaadt 5706bd11984Sderaadt /* 5716bd11984Sderaadt * Look up the name and check that the supplied 5726bd11984Sderaadt * address is in the list 5736bd11984Sderaadt */ 5746bd11984Sderaadt strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1); 5756bd11984Sderaadt remotehost[sizeof(remotehost) - 1] = '\0'; 5766bd11984Sderaadt hp = gethostbyname(remotehost); 5776bd11984Sderaadt if (hp == NULL) 5786bd11984Sderaadt return (NULL); 5796bd11984Sderaadt 5806bd11984Sderaadt for (; hp->h_addr_list[0] != NULL; hp->h_addr_list++) 5816bd11984Sderaadt if (!bcmp(hp->h_addr_list[0], (caddr_t)&raddr, sizeof(raddr))) 5826bd11984Sderaadt return (remotehost); 5836bd11984Sderaadt 5846bd11984Sderaadt /* 5856bd11984Sderaadt * either the DNS adminstrator has made a configuration 5866bd11984Sderaadt * mistake, or someone has attempted to spoof us 5876bd11984Sderaadt */ 5886bd11984Sderaadt in.s_addr = raddr; 5896bd11984Sderaadt syslog(LOG_NOTICE, "rcmd: address %s not listed for host %s", 5906bd11984Sderaadt inet_ntoa(in), hp->h_name); 5916bd11984Sderaadt return (NULL); 5926bd11984Sderaadt } 593