/* * XXX * Don't make static, used by lpd(8). * * Returns 0 if ok, -1 if not ok. */ int __ivaliduser(FILE *hostf, u_int32_t raddr, const char *luser, const char *ruser) { struct sockaddr_in sin; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_len = sizeof(struct sockaddr_in); memcpy(&sin.sin_addr, &raddr, sizeof(sin.sin_addr)); return __ivaliduser_sa(hostf, (struct sockaddr *)&sin, sin.sin_len, luser, ruser); }
/* * Returns 0 if ok, -1 if not ok. * * XXX obsolete API. */ int __ivaliduser_af(FILE *hostf, const void *raddr, const char *luser, const char *ruser, int af, int len) { struct sockaddr *sa = NULL; struct sockaddr_in *sin = NULL; #ifdef INET6 struct sockaddr_in6 *sin6 = NULL; #endif struct sockaddr_storage ss; memset(&ss, 0, sizeof(ss)); switch (af) { case AF_INET: if (len != sizeof(sin->sin_addr)) return -1; sin = (struct sockaddr_in *)&ss; sin->sin_family = AF_INET; sin->sin_len = sizeof(struct sockaddr_in); memcpy(&sin->sin_addr, raddr, sizeof(sin->sin_addr)); break; #ifdef INET6 case AF_INET6: if (len != sizeof(sin6->sin6_addr)) return -1; /* you will lose scope info */ sin6 = (struct sockaddr_in6 *)&ss; sin6->sin6_family = AF_INET6; sin6->sin6_len = sizeof(struct sockaddr_in6); memcpy(&sin6->sin6_addr, raddr, sizeof(sin6->sin6_addr)); break; #endif default: return -1; } sa = (struct sockaddr *)&ss; return __ivaliduser_sa(hostf, sa, sa->sa_len, luser, ruser); }
int iruserok_sa(const void *raddr, int rlen, int superuser, const char *ruser, const char *luser) { struct sockaddr *sa; char *cp; struct stat sbuf; struct passwd pwstore, *pwd; FILE *hostf; uid_t uid; int first; char pbuf[PATH_MAX], pwbuf[_PW_BUF_LEN]; sa = (struct sockaddr *)raddr; first = 1; hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "re"); again: if (hostf) { if (__ivaliduser_sa(hostf, sa, rlen, luser, ruser) == 0) { (void)fclose(hostf); return (0); } (void)fclose(hostf); } if (first == 1) { int len; first = 0; pwd = NULL; getpwnam_r(luser, &pwstore, pwbuf, sizeof(pwbuf), &pwd); if (pwd == NULL) return (-1); len = snprintf(pbuf, sizeof pbuf, "%s/.rhosts", pwd->pw_dir); if (len < 0 || len >= sizeof pbuf) return (-1); /* * Change effective uid while opening .rhosts. If root and * reading an NFS mounted file system, can't read files that * are protected read/write owner only. */ uid = geteuid(); (void)seteuid(pwd->pw_uid); hostf = fopen(pbuf, "re"); (void)seteuid(uid); if (hostf == NULL) return (-1); /* * If not a regular file, or is owned by someone other than * user or root or if writeable by anyone but the owner, quit. */ cp = NULL; if (lstat(pbuf, &sbuf) < 0) cp = ".rhosts lstat failed"; else if (!S_ISREG(sbuf.st_mode)) cp = ".rhosts not regular file"; else if (fstat(fileno(hostf), &sbuf) < 0) cp = ".rhosts fstat failed"; else if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid) cp = "bad .rhosts owner"; else if (sbuf.st_mode & (S_IWGRP|S_IWOTH)) cp = ".rhosts writable by other than owner"; /* If there were any problems, quit. */ if (cp) { (void)fclose(hostf); return (-1); } goto again; } return (-1); }
/* * AF independent extension of iruserok. * * Returns 0 if ok, -1 if not ok. */ int iruserok_sa(const void *ra, int rlen, int superuser, const char *ruser, const char *luser) { char *cp; struct stat sbuf; struct passwd *pwd; FILE *hostf; uid_t uid; int first; char pbuf[MAXPATHLEN]; const struct sockaddr *raddr; struct sockaddr_storage ss; /* avoid alignment issue */ if (rlen > sizeof(ss)) return(-1); memcpy(&ss, ra, rlen); raddr = (struct sockaddr *)&ss; first = 1; hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "r"); again: if (hostf) { if (__ivaliduser_sa(hostf, raddr, rlen, luser, ruser) == 0) { fclose(hostf); return (0); } fclose(hostf); } if (first == 1 && (__check_rhosts_file || superuser)) { first = 0; if ((pwd = getpwnam(luser)) == NULL) return (-1); strcpy(pbuf, pwd->pw_dir); strcat(pbuf, "/.rhosts"); /* * Change effective uid while opening .rhosts. If root and * reading an NFS mounted file system, can't read files that * are protected read/write owner only. */ uid = geteuid(); seteuid(pwd->pw_uid); hostf = fopen(pbuf, "r"); seteuid(uid); if (hostf == NULL) return (-1); /* * If not a regular file, or is owned by someone other than * user or root or if writeable by anyone but the owner, quit. */ cp = NULL; if (lstat(pbuf, &sbuf) < 0) cp = ".rhosts lstat failed"; else if (!S_ISREG(sbuf.st_mode)) cp = ".rhosts not regular file"; else if (_fstat(fileno(hostf), &sbuf) < 0) cp = ".rhosts fstat failed"; else if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid) cp = "bad .rhosts owner"; else if (sbuf.st_mode & (S_IWGRP|S_IWOTH)) cp = ".rhosts writeable by other than owner"; /* If there were any problems, quit. */ if (cp) { __rcmd_errstr = cp; fclose(hostf); return (-1); } goto again; } return (-1); }
/* * Check to see if the host connecting to this host has access to any * lpd services on this host. */ static void chkhost(struct sockaddr *f, int ch_opts) { struct addrinfo hints, *res, *r; register FILE *hostf; char hostbuf[NI_MAXHOST], ip[NI_MAXHOST]; char serv[NI_MAXSERV]; char *syserr, *usererr; int error, errsav, fpass, good, wantsl; wantsl = 0; if (ch_opts & LPD_LOGCONNERR) wantsl = 1; /* also syslog the errors */ from_host = ".na."; /* Need real hostname for temporary filenames */ error = getnameinfo(f, f->sa_len, hostbuf, sizeof(hostbuf), NULL, 0, NI_NAMEREQD); if (error) { errsav = error; error = getnameinfo(f, f->sa_len, hostbuf, sizeof(hostbuf), NULL, 0, NI_NUMERICHOST); if (error) { asprintf(&syserr, "can not determine hostname for remote host (%d,%d)", errsav, error); asprintf(&usererr, "Host name for your address is not known"); fhosterr(ch_opts, syserr, usererr); /* NOTREACHED */ } asprintf(&syserr, "Host name for remote host (%s) not known (%d)", hostbuf, errsav); asprintf(&usererr, "Host name for your address (%s) is not known", hostbuf); fhosterr(ch_opts, syserr, usererr); /* NOTREACHED */ } strlcpy(frombuf, hostbuf, sizeof(frombuf)); from_host = frombuf; ch_opts |= LPD_ADDFROMLINE; /* Need address in stringform for comparison (no DNS lookup here) */ error = getnameinfo(f, f->sa_len, hostbuf, sizeof(hostbuf), NULL, 0, NI_NUMERICHOST); if (error) { asprintf(&syserr, "Cannot print IP address (error %d)", error); asprintf(&usererr, "Cannot print IP address for your host"); fhosterr(ch_opts, syserr, usererr); /* NOTREACHED */ } from_ip = strdup(hostbuf); /* Reject numeric addresses */ memset(&hints, 0, sizeof(hints)); hints.ai_family = family; hints.ai_socktype = SOCK_DGRAM; /*dummy*/ hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; if (getaddrinfo(from_host, NULL, &hints, &res) == 0) { freeaddrinfo(res); /* This syslog message already includes from_host */ ch_opts &= ~LPD_ADDFROMLINE; asprintf(&syserr, "reverse lookup results in non-FQDN %s", from_host); /* same message to both syslog and remote user */ fhosterr(ch_opts, syserr, syserr); /* NOTREACHED */ } /* Check for spoof, ala rlogind */ memset(&hints, 0, sizeof(hints)); hints.ai_family = family; hints.ai_socktype = SOCK_DGRAM; /*dummy*/ error = getaddrinfo(from_host, NULL, &hints, &res); if (error) { asprintf(&syserr, "dns lookup for address %s failed: %s", from_ip, gai_strerror(error)); asprintf(&usererr, "hostname for your address (%s) unknown: %s", from_ip, gai_strerror(error)); fhosterr(ch_opts, syserr, usererr); /* NOTREACHED */ } good = 0; for (r = res; good == 0 && r; r = r->ai_next) { error = getnameinfo(r->ai_addr, r->ai_addrlen, ip, sizeof(ip), NULL, 0, NI_NUMERICHOST); if (!error && !strcmp(from_ip, ip)) good = 1; } if (res) freeaddrinfo(res); if (good == 0) { asprintf(&syserr, "address for remote host (%s) not matched", from_ip); asprintf(&usererr, "address for your hostname (%s) not matched", from_ip); fhosterr(ch_opts, syserr, usererr); /* NOTREACHED */ } fpass = 1; hostf = fopen(_PATH_HOSTSEQUIV, "r"); again: if (hostf) { if (__ivaliduser_sa(hostf, f, f->sa_len, DUMMY, DUMMY) == 0) { (void) fclose(hostf); goto foundhost; } (void) fclose(hostf); } if (fpass == 1) { fpass = 2; hostf = fopen(_PATH_HOSTSLPD, "r"); goto again; } /* This syslog message already includes from_host */ ch_opts &= ~LPD_ADDFROMLINE; asprintf(&syserr, "refused connection from %s, sip=%s", from_host, from_ip); asprintf(&usererr, "Print-services are not available to your host (%s).", from_host); fhosterr(ch_opts, syserr, usererr); /* NOTREACHED */ foundhost: if (ch_opts & LPD_NOPORTCHK) return; /* skip the reserved-port check */ error = getnameinfo(f, f->sa_len, NULL, 0, serv, sizeof(serv), NI_NUMERICSERV); if (error) { /* same message to both syslog and remote user */ asprintf(&syserr, "malformed from-address (%d)", error); fhosterr(ch_opts, syserr, syserr); /* NOTREACHED */ } if (atoi(serv) >= IPPORT_RESERVED) { /* same message to both syslog and remote user */ asprintf(&syserr, "connected from invalid port (%s)", serv); fhosterr(ch_opts, syserr, syserr); /* NOTREACHED */ } }