--- /dev/null
+--- 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)
--- /dev/null
+--- a/modules/pam_unix/yppasswd_xdr.c
++++ b/modules/pam_unix/yppasswd_xdr.c
+2011-10-01 13:46:21.599443197 +0300
+@@ -21,6 +21,268 @@
+ #endif
+ #include "yppasswd.h"
+
++#ifdef __UCLIBC__
++
++static const char xdr_zero[BYTES_PER_XDR_UNIT] = {0, 0, 0, 0};
++
++/*
++ * XDR integers
++ */
++bool_t
++xdr_int (XDR *xdrs, int *ip)
++{
++
++#if INT_MAX < LONG_MAX
++ long l;
++
++ switch (xdrs->x_op)
++ {
++ case XDR_ENCODE:
++ l = (long) *ip;
++ return XDR_PUTLONG (xdrs, &l);
++
++ case XDR_DECODE:
++ if (!XDR_GETLONG (xdrs, &l))
++ {
++ return FALSE;
++ }
++ *ip = (int) l;
++ case XDR_FREE:
++ return TRUE;
++ }
++ return FALSE;
++#elif INT_MAX == LONG_MAX
++ return xdr_long (xdrs, (long *) ip);
++#elif INT_MAX == SHRT_MAX
++ return xdr_short (xdrs, (short *) ip);
++#else
++#error unexpected integer sizes in xdr_int()
++#endif
++}
++
++/*
++ * XDR null terminated ASCII strings
++ * xdr_string deals with "C strings" - arrays of bytes that are
++ * terminated by a NULL character. The parameter cpp references a
++ * pointer to storage; If the pointer is null, then the necessary
++ * storage is allocated. The last parameter is the max allowed length
++ * of the string as specified by a protocol.
++ */
++bool_t
++xdr_string (XDR *xdrs, char **cpp, u_int maxsize)
++{
++ char *sp = *cpp; /* sp is the actual string pointer */
++ u_int size;
++ u_int nodesize;
++
++ /*
++ * first deal with the length since xdr strings are counted-strings
++ */
++ switch (xdrs->x_op)
++ {
++ case XDR_FREE:
++ if (sp == NULL)
++ {
++ return TRUE; /* already free */
++ }
++ /* fall through... */
++ case XDR_ENCODE:
++ if (sp == NULL)
++ return FALSE;
++ size = strlen (sp);
++ break;
++ case XDR_DECODE:
++ break;
++ }
++ if (!xdr_u_int (xdrs, &size))
++ {
++ return FALSE;
++ }
++ if (size > maxsize)
++ {
++ return FALSE;
++ }
++ nodesize = size + 1;
++
++ /*
++ * now deal with the actual bytes
++ */
++ switch (xdrs->x_op)
++ {
++ case XDR_DECODE:
++ if (nodesize == 0)
++ {
++ return TRUE;
++ }
++ if (sp == NULL)
++ *cpp = sp = (char *) mem_alloc (nodesize);
++ if (sp == NULL)
++ {
++#ifdef USE_IN_LIBIO
++ if (_IO_fwide (stderr, 0) > 0)
++ (void) fwprintf (stderr, L"%s",
++ _("xdr_string: out of memory\n"));
++ else
++#endif
++ (void) fputs (_("xdr_string: out of memory\n"), stderr);
++ return FALSE;
++ }
++ sp[size] = 0;
++ /* fall into ... */
++
++ case XDR_ENCODE:
++ return xdr_opaque (xdrs, sp, size);
++
++ case XDR_FREE:
++ mem_free (sp, nodesize);
++ *cpp = NULL;
++ return TRUE;
++ }
++ return FALSE;
++}
++
++/*
++ * XDR long integers
++ * The definition of xdr_long() is kept for backward
++ * compatibility. Instead xdr_int() should be used.
++ */
++bool_t
++xdr_long (XDR *xdrs, long *lp)
++{
++ if (xdrs->x_op == XDR_ENCODE
++ && (sizeof (int32_t) == sizeof (long)
++ || (int32_t) *lp == *lp))
++ return XDR_PUTLONG (xdrs, lp);
++
++ if (xdrs->x_op == XDR_DECODE)
++ return XDR_GETLONG (xdrs, lp);
++
++ if (xdrs->x_op == XDR_FREE)
++ return TRUE;
++
++ return FALSE;
++}
++
++/*
++ * XDR unsigned integers
++ */
++bool_t
++xdr_u_int (XDR *xdrs, u_int *up)
++{
++#if UINT_MAX < ULONG_MAX
++ u_long l;
++
++ switch (xdrs->x_op)
++ {
++ case XDR_ENCODE:
++ l = (u_long) * up;
++ return XDR_PUTLONG (xdrs, (long *) &l);
++
++ case XDR_DECODE:
++ if (!XDR_GETLONG (xdrs, (long *) &l))
++ {
++ return FALSE;
++ }
++ *up = (u_int) l;
++ case XDR_FREE:
++ return TRUE;
++ }
++ return FALSE;
++#elif UINT_MAX == ULONG_MAX
++ return xdr_u_long (xdrs, (u_long *) up);
++#elif UINT_MAX == USHRT_MAX
++ return xdr_short (xdrs, (short *) up);
++#else
++#error unexpected integer sizes in xdr_u_int()
++#endif
++}
++
++/*
++ * XDR opaque data
++ * Allows the specification of a fixed size sequence of opaque bytes.
++ * cp points to the opaque object and cnt gives the byte length.
++ */
++bool_t
++xdr_opaque (XDR *xdrs, caddr_t cp, u_int cnt)
++{
++ u_int rndup;
++ static char crud[BYTES_PER_XDR_UNIT];
++
++ /*
++ * if no data we are done
++ */
++ if (cnt == 0)
++ return TRUE;
++
++ /*
++ * round byte count to full xdr units
++ */
++ rndup = cnt % BYTES_PER_XDR_UNIT;
++ if (rndup > 0)
++ rndup = BYTES_PER_XDR_UNIT - rndup;
++
++ switch (xdrs->x_op)
++ {
++ case XDR_DECODE:
++ if (!XDR_GETBYTES (xdrs, cp, cnt))
++ {
++ return FALSE;
++ }
++ if (rndup == 0)
++ return TRUE;
++ return XDR_GETBYTES (xdrs, (caddr_t)crud, rndup);
++
++ case XDR_ENCODE:
++ if (!XDR_PUTBYTES (xdrs, cp, cnt))
++ {
++ return FALSE;
++ }
++ if (rndup == 0)
++ return TRUE;
++ return XDR_PUTBYTES (xdrs, xdr_zero, rndup);
++
++ case XDR_FREE:
++ return TRUE;
++ }
++ return FALSE;
++}
++
++/*
++ * XDR unsigned long integers
++ * The definition of xdr_u_long() is kept for backward
++ * compatibility. Instead xdr_u_int() should be used.
++ */
++bool_t
++xdr_u_long (XDR *xdrs, u_long *ulp)
++{
++ switch (xdrs->x_op)
++ {
++ case XDR_DECODE:
++ {
++ long int tmp;
++
++ if (XDR_GETLONG (xdrs, &tmp) == FALSE)
++ return FALSE;
++
++ *ulp = (uint32_t) tmp;
++ return TRUE;
++ }
++
++ case XDR_ENCODE:
++ if (sizeof (uint32_t) != sizeof (u_long)
++ && (uint32_t) *ulp != *ulp)
++ return FALSE;
++
++ return XDR_PUTLONG (xdrs, (long *) ulp);
++
++ case XDR_FREE:
++ return TRUE;
++ }
++ return FALSE;
++}
++
++#endif /* UCLIBC */
++
+ bool_t
+ xdr_xpasswd(XDR * xdrs, xpasswd * objp)
+ {