diff options
Diffstat (limited to 'inet/rcmd.c')
-rw-r--r-- | inet/rcmd.c | 260 |
1 files changed, 192 insertions, 68 deletions
diff --git a/inet/rcmd.c b/inet/rcmd.c index 51fa34eca8..483e7b389d 100644 --- a/inet/rcmd.c +++ b/inet/rcmd.c @@ -55,8 +55,10 @@ static char sccsid[] = "@(#)rcmd.c 8.3 (Berkeley) 3/26/94"; #include <string.h> -int __ivaliduser __P((FILE *, u_int32_t, const char *, const char *)); -static int __icheckhost __P((u_int32_t, char *)) internal_function; +int __ivaliduser __P ((FILE *, u_int32_t, const char *, const char *)); +static int __ivaliduser2 __P ((FILE *, u_int32_t, const char *, const char *, + const char *)); + int rcmd(ahost, rport, locuser, remuser, cmd, fd2p) @@ -283,7 +285,7 @@ ruserok(rhost, superuser, ruser, luser) for (ap = hp->h_addr_list; *ap; ++ap) { bcopy(*ap, &addr, sizeof(addr)); - if (iruserok(addr, superuser, ruser, luser) == 0) + if (iruserok(addr, superuser, ruser, luser, rhost) == 0) return 0; } return -1; @@ -341,11 +343,11 @@ iruserfopen (char *file, uid_t okuser) * * Returns 0 if ok, -1 if not ok. */ -int -iruserok (raddr, superuser, ruser, luser) +static int +iruserok2 (raddr, superuser, ruser, luser, rhost) u_int32_t raddr; int superuser; - const char *ruser, *luser; + const char *ruser, *luser, *rhost; { FILE *hostf = NULL; int isbad; @@ -355,7 +357,7 @@ iruserok (raddr, superuser, ruser, luser) if (hostf) { - isbad = __ivaliduser (hostf, raddr, luser, ruser); + isbad = __ivaliduser2 (hostf, raddr, luser, ruser, rhost); fclose (hostf); if (!isbad) @@ -388,7 +390,7 @@ iruserok (raddr, superuser, ruser, luser) if (hostf != NULL) { - isbad = __ivaliduser (hostf, raddr, luser, ruser); + isbad = __ivaliduser2 (hostf, raddr, luser, ruser, rhost); fclose (hostf); } @@ -398,10 +400,25 @@ iruserok (raddr, superuser, ruser, luser) return -1; } +/* This is the exported version. */ +int +iruserok (raddr, superuser, ruser, luser) + u_int32_t raddr; + int superuser; + const char *ruser, *luser; +{ + return iruserok2 (raddr, superuser, ruser, luser, "-"); +} + /* * XXX * Don't make static, used by lpd(8). * + * This function is not used anymore. It is only present because lpd(8) + * calls it (!?!). We simply call __invaliduser2() with an illegal rhost + * argument. This means that netgroups won't work in .rhost/hosts.equiv + * files. If you want lpd to work with netgroups, fix lpd to use ruserok() + * or PAM. * Returns 0 if ok, -1 if not ok. */ int @@ -410,87 +427,194 @@ __ivaliduser(hostf, raddr, luser, ruser) u_int32_t raddr; const char *luser, *ruser; { - register char *user, *p; - int ch; - char *buf = NULL; - char *cp; - size_t bufsize = 0; - ssize_t nread; - - while ((nread = __getline (&buf, &bufsize, hostf)) > 0) { - buf[bufsize - 1] = '\0'; /* Make sure it's terminated. */ - /* Because the file format does not know any form of quoting we - can search forward for the next '#' character and if found - make it terminating the line. */ - cp = strchr (buf, '#'); - if (cp != NULL) - *cp = '\0'; - p = buf; - while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') { - *p = isupper(*p) ? tolower(*p) : *p; - p++; - } - if (*p == ' ' || *p == '\t') { - *p++ = '\0'; - while (*p == ' ' || *p == '\t') - p++; - user = p; - while (*p != '\n' && *p != ' ' && - *p != '\t' && *p != '\0') - p++; - } else - user = p; - *p = '\0'; - if (__icheckhost(raddr, buf) && - strcmp(ruser, *user ? user : luser) == 0) { - free (buf); - return 0; - } - } - if (buf != NULL) - free (buf); - return -1; + return __ivaliduser2(hostf, raddr, luser, ruser, "-"); } -/* - * Returns "true" if match, 0 if no match. - */ + +/* Returns 1 on positive match, 0 on no match, -1 on negative match. */ static int internal_function -__icheckhost(raddr, lhost) +__icheckhost (raddr, lhost, rhost) u_int32_t raddr; - register char *lhost; + char *lhost; + const char *rhost; { struct hostent hostbuf, *hp; size_t buflen; char *buffer; - register u_int32_t laddr; - register char **pp; int herr; + int save_errno; + u_int32_t laddr; + int negate=1; /* Multiply return with this to get -1 instead of 1 */ + char **pp, *user; + + /* Check nis netgroup. */ + if (strncmp ("+@", lhost, 2) == 0) + return innetgr (&lhost[2], rhost, NULL, NULL); + + if (strncmp ("-@", lhost, 2) == 0) + return -innetgr (&lhost[2], rhost, NULL, NULL); + + /* -host */ + if (strncmp ("-", lhost,1) == 0) { + negate = -1; + lhost++; + } else if (strcmp ("+",lhost) == 0) { + return 1; /* asking for trouble, but ok.. */ + } /* Try for raw ip address first. */ - if (isdigit(*lhost) && (int32_t)(laddr = inet_addr(lhost)) != -1) - return raddr == laddr; + if (isdigit (*lhost) && (long) (laddr = inet_addr (lhost)) != -1) + return negate * (! (raddr ^ laddr)); /* Better be a hostname. */ buflen = 1024; buffer = __alloca (buflen); + save_errno = errno; while (__gethostbyname_r (lhost, &hostbuf, buffer, buflen, &hp, &herr) < 0) - if (herr != NETDB_INTERNAL || errno != ERANGE) - return 0; - else - { - /* Enlarge the buffer. */ - buflen *= 2; - buffer = __alloca (buflen); - } + if (herr != NETDB_INTERNAL || errno != ERANGE) + return (0); + else { + /* Enlarge the buffer. */ + buflen *= 2; + buffer = __alloca (buflen); + __set_errno (0); + } + __set_errno (save_errno); + if (hp == NULL) + return 0; /* Spin through ip addresses. */ for (pp = hp->h_addr_list; *pp; ++pp) - if (!memcmp(&raddr, *pp, sizeof(u_int32_t))) - return 1; + if (!memcmp (&raddr, *pp, sizeof (u_int32_t))) + return negate; /* No match. */ - return 0; + return (0); +} + +/* Returns 1 on positive match, 0 on no match, -1 on negative match. */ +static int +internal_function +__icheckuser (luser, ruser) + const char *luser, *ruser; +{ + /* + luser is user entry from .rhosts/hosts.equiv file + ruser is user id on remote host + */ + char *user; + + /* [-+]@netgroup */ + if (strncmp ("+@", luser, 2) == 0) + return innetgr (&luser[2], NULL, ruser, NULL); + + if (strncmp ("-@", luser,2) == 0) + return -innetgr (&luser[2], NULL, ruser, NULL); + + /* -user */ + if (strncmp ("-", luser, 1) == 0) + return -(strcmp (&luser[1], ruser) == 0); + + /* + */ + if (strcmp ("+", luser) == 0) + return 1; + + /* simple string match */ + return strcmp (ruser, luser) == 0; +} + +/* + * Returns 1 for blank lines (or only comment lines) and 0 otherwise + */ +static int +__isempty(p) + char *p; +{ + while (*p && isspace (*p)) { + ++p; + } + + return (*p == '\0' || *p == '#') ? 1 : 0 ; +} + +/* + * Returns 0 if positive match, -1 if _not_ ok. + */ +static int +__ivaliduser2(hostf, raddr, luser, ruser, rhost) + FILE *hostf; + u_int32_t raddr; + const char *luser, *ruser, *rhost; +{ + register const char *user; + register char *p; + int hcheck, ucheck; + char *buf = NULL; + size_t bufsize = 0; + + while (__getline (&buf, &bufsize, hostf) > 0) { + buf[bufsize - 1] = '\0'; /* Make sure it's terminated. */ + p = buf; + + /* Skip empty or comment lines */ + if (__isempty (p)) { + continue; + } + + /* Skip lines that are too long. */ + if (strchr (p, '\n') == NULL) { + int ch = getc (hostf); + + while (ch != '\n' && ch != EOF) + ch = getc (hostf); + continue; + } + + for (;*p && !isspace(*p); ++p) { + *p = tolower (*p); + } + + /* Next we want to find the permitted name for the remote user. */ + if (*p == ' ' || *p == '\t') { + /* <nul> terminate hostname and skip spaces */ + for (*p++='\0'; *p && isspace (*p); ++p); + + user = p; /* this is the user's name */ + while (*p && !isspace (*p)) + ++p; /* find end of user's name */ + } else + user = p; + + *p = '\0'; /* <nul> terminate username (+host?) */ + + /* buf -> host(?) ; user -> username(?) */ + + /* First check host part */ + hcheck = __icheckhost (raddr, buf, rhost); + + if (hcheck < 0) + return -1; + + if (hcheck) { + /* Then check user part */ + if (! (*user)) + user = luser; + + ucheck = __icheckuser (user, ruser); + + /* Positive 'host user' match? */ + if (ucheck > 0) + return 0; + + /* Negative 'host -user' match? */ + if (ucheck < 0) + return -1; + + /* Neither, go on looking for match */ + } + } + + return -1; } |