libs/libpam: make KanjiMonster happy
authoracoul <acoul@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Thu, 29 Sep 2011 12:03:36 +0000 (12:03 +0000)
committeracoul <acoul@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Thu, 29 Sep 2011 12:03:36 +0000 (12:03 +0000)
git-svn-id: svn://svn.openwrt.org/openwrt/packages@28317 3c298f89-4303-0410-b956-a3cf2f4a3e73

libs/libpam/patches/005-fix_ruserok.patch

index 91a4741..1abd2d1 100644 (file)
 --- a/modules/pam_rhosts/pam_rhosts.c
 +++ b/modules/pam_rhosts/pam_rhosts.c
-@@ -111,11 +111,13 @@ int pam_sm_authenticate (pam_handle_t *p
-       as_root = (lpwd->pw_uid == 0);
-     }
+@@ -34,8 +34,10 @@
  
-+#if   0
- #ifdef HAVE_RUSEROK_AF
-     retval = ruserok_af (rhost, as_root, ruser, luser, PF_UNSPEC);
- #else
-     retval = ruserok (rhost, as_root, ruser, luser);
- #endif
+ #include <pwd.h>
+ #include <netdb.h>
++#include <stdio.h>
+ #include <string.h>
+ #include <syslog.h>
++#include <sys/stat.h>
+ #define PAM_SM_AUTH  /* only defines this management group */
+@@ -43,6 +45,353 @@
+ #include <security/pam_modutil.h>
+ #include <security/pam_ext.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
-     if (retval != 0) {
-       if (!opt_silent || opt_debug)
-       pam_syslog(pamh, LOG_WARNING, "denied access to %s@%s as %s",
++      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;
++}
++
+ PAM_EXTERN
+ int pam_sm_authenticate (pam_handle_t *pamh, int flags, int argc,
+                        const char **argv)