|
|
- --- a/modules/pam_rhosts/pam_rhosts.c
- +++ b/modules/pam_rhosts/pam_rhosts.c
- @@ -43,6 +43,361 @@
- #include <security/pam_modutil.h>
- #include <security/pam_ext.h>
-
- +#ifdef __UCLIBC__
- +
- +#include <stdio.h>
- +#include <sys/stat.h>
- +
- +
- +int __check_rhosts_file = 1;
- +
- +/* Extremely paranoid file open function. */
- +static FILE *
- +iruserfopen (const char *file, uid_t okuser)
- +{
- + struct stat st;
- + char *cp = NULL;
- + FILE *res = NULL;
- +
- + /* If not a regular file, if owned by someone other than user or
- + root, if writeable by anyone but the owner, or if hardlinked
- + anywhere, quit. */
- + if (lstat (file, &st))
- + cp = "lstat failed";
- + else if (!S_ISREG (st.st_mode))
- + cp = "not regular file";
- + else
- + {
- + res = fopen (file, "r");
- + if (!res)
- + cp = "cannot open";
- + else if (fstat (fileno (res), &st) < 0)
- + cp = "fstat failed";
- + else if (st.st_uid && st.st_uid != okuser)
- + cp = "bad owner";
- + else if (st.st_mode & (S_IWGRP|S_IWOTH))
- + cp = "writeable by other than owner";
- + else if (st.st_nlink > 1)
- + cp = "hard linked somewhere";
- + }
- +
- + /* If there were any problems, quit. */
- + if (cp != NULL)
- + {
- + if (res)
- + fclose (res);
- + return NULL;
- + }
- +
- + return res;
- +}
- +
- +/*
- + * Returns 1 for blank lines (or only comment lines) and 0 otherwise
- + */
- +static int
- +__isempty(char *p)
- +{
- + while (*p && isspace (*p)) {
- + ++p;
- + }
- +
- + return (*p == '\0' || *p == '#') ? 1 : 0 ;
- +}
- +
- +/* Returns 1 on positive match, 0 on no match, -1 on negative match. */
- +static int
- +__icheckhost (u_int32_t raddr, char *lhost, const char *rhost)
- +{
- + struct hostent *hp;
- + u_int32_t laddr;
- + int negate=1; /* Multiply return with this to get -1 instead of 1 */
- + char **pp;
- +
- +#ifdef __UCLIBC_HAS_REENTRANT_RPC__
- + int save_errno;
- + size_t buflen;
- + char *buffer;
- + struct hostent hostbuf;
- + int herr;
- +#endif
- +
- +#ifdef HAVE_NETGROUP
- + /* 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);
- +#endif /* HAVE_NETGROUP */
- +
- + /* -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) && (laddr = inet_addr (lhost)) != INADDR_NONE)
- + return negate * (! (raddr ^ laddr));
- +
- + /* Better be a hostname. */
- +#ifdef __UCLIBC_HAS_REENTRANT_RPC__
- + buflen = 1024;
- + buffer = malloc(buflen);
- + save_errno = errno;
- +
- + while (gethostbyname_r (lhost, &hostbuf, buffer, buflen, &hp, &herr)
- + != 0) {
- + free(buffer);
- + return (0);
- + }
- + free(buffer);
- + __set_errno (save_errno);
- +#else
- + hp = gethostbyname(lhost);
- +#endif /* __UCLIBC_HAS_REENTRANT_RPC__ */
- +
- + 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 negate;
- +
- + /* No match. */
- + return (0);
- +}
- +
- +/* Returns 1 on positive match, 0 on no match, -1 on negative match. */
- +static int
- +__icheckuser (const char *luser, const char *ruser)
- +{
- +
- + /*
- + luser is user entry from .rhosts/hosts.equiv file
- + ruser is user id on remote host
- + */
- +
- +#ifdef HAVE_NETGROUP
- + /* [-+]@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);
- +#endif /* HAVE_NETGROUP */
- +
- + /* -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 0 if positive match, -1 if _not_ ok.
- + */
- +static int
- +__ivaliduser2(FILE *hostf, u_int32_t raddr, const char *luser,
- + const char *ruser, const char *rhost)
- +{
- + register const char *user;
- + register char *p;
- + int hcheck, ucheck;
- + char *buf = NULL;
- + size_t bufsize = 0;
- + int retval = -1;
- +
- + 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_unlocked (hostf);
- +
- + while (ch != '\n' && ch != EOF)
- + ch = getc_unlocked (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)
- + break;
- +
- + if (hcheck) {
- + /* Then check user part */
- + if (! (*user))
- + user = luser;
- +
- + ucheck = __icheckuser (user, ruser);
- +
- + /* Positive 'host user' match? */
- + if (ucheck > 0) {
- + retval = 0;
- + break;
- + }
- +
- + /* Negative 'host -user' match? */
- + if (ucheck < 0)
- + break;
- +
- + /* Neither, go on looking for match */
- + }
- + }
- +
- + free (buf);
- +
- + return retval;
- +}
- +
- +static int
- +iruserok2 (u_int32_t raddr, int superuser, const char *ruser, const char *luser,
- + const char *rhost)
- +{
- + FILE *hostf = NULL;
- + int isbad = -1;
- +
- + if (!superuser)
- + hostf = iruserfopen (_PATH_HEQUIV, 0);
- +
- + if (hostf) {
- + isbad = __ivaliduser2 (hostf, raddr, luser, ruser, rhost);
- + fclose (hostf);
- +
- + if (!isbad)
- + return 0;
- + }
- +
- + if (__check_rhosts_file || superuser) {
- + char *pbuf;
- + struct passwd *pwd;
- + size_t dirlen;
- + uid_t uid;
- +
- +#ifdef __UCLIBC_HAS_REENTRANT_RPC__
- + size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX);
- + struct passwd pwdbuf;
- + char *buffer = stack_heap_alloc(buflen);
- +
- + if (getpwnam_r (luser, &pwdbuf, buffer,
- + buflen, &pwd) != 0 || pwd == NULL)
- + {
- + stack_heap_free(buffer);
- + return -1;
- + }
- + stack_heap_free(buffer);
- +#else
- + if ((pwd = getpwnam(luser)) == NULL)
- + return -1;
- +#endif
- +
- + dirlen = strlen (pwd->pw_dir);
- + pbuf = malloc (dirlen + sizeof "/.rhosts");
- + strcpy (pbuf, pwd->pw_dir);
- + strcat (pbuf, "/.rhosts");
- +
- + /* Change effective uid while reading .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 = iruserfopen (pbuf, pwd->pw_uid);
- + free(pbuf);
- +
- + if (hostf != NULL) {
- + isbad = __ivaliduser2 (hostf, raddr, luser, ruser, rhost);
- + fclose (hostf);
- + }
- +
- + seteuid (uid);
- + return isbad;
- + }
- + return -1;
- +}
- +
- +int ruserok(const char *rhost, int superuser, const char *ruser,
- + const char *luser)
- +{
- + struct hostent *hp;
- + u_int32_t addr;
- + char **ap;
- +#ifdef __UCLIBC_HAS_REENTRANT_RPC__
- + size_t buflen;
- + char *buffer;
- + int herr;
- + struct hostent hostbuf;
- +#endif
- +
- +#ifdef __UCLIBC_HAS_REENTRANT_RPC__
- + buflen = 1024;
- + buffer = stack_heap_alloc(buflen);
- +
- + while (gethostbyname_r (rhost, &hostbuf, buffer,
- + buflen, &hp, &herr) != 0 || hp == NULL)
- + {
- + if (herr != NETDB_INTERNAL || errno != ERANGE) {
- + stack_heap_free(buffer);
- + return -1;
- + } else
- + {
- + /* Enlarge the buffer. */
- + buflen *= 2;
- + stack_heap_free(buffer);
- + buffer = stack_heap_alloc(buflen);
- + }
- + }
- + stack_heap_free(buffer);
- +#else
- + if ((hp = gethostbyname(rhost)) == NULL) {
- + return -1;
- + }
- +#endif
- + for (ap = hp->h_addr_list; *ap; ++ap) {
- + memmove(&addr, *ap, sizeof(addr));
- + if (iruserok2(addr, superuser, ruser, luser, rhost) == 0)
- + return 0;
- + }
- + return -1;
- +}
- +
- +#endif /* __UCLIBC__ */
- +
- PAM_EXTERN
- int pam_sm_authenticate (pam_handle_t *pamh, int flags, int argc,
- const char **argv)
|