diff --git a/libs/libpam/Makefile b/libs/libpam/Makefile new file mode 100644 index 0000000000..7881c3ef91 --- /dev/null +++ b/libs/libpam/Makefile @@ -0,0 +1,71 @@ +# +# Copyright (C) 2006-2014 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=libpam +PKG_VERSION:=1.1.8 +PKG_RELEASE:=3 + +PKG_SOURCE:=Linux-PAM-$(PKG_VERSION).tar.bz2 +PKG_SOURCE_URL:=http://www.linux-pam.org/library/ +PKG_MD5SUM:=35b6091af95981b1b2cd60d813b5e4ee +PKG_INSTALL:=1 +PKG_FIXUP:=autoreconf +PKG_MAINTAINER:=Nikos Mavrogiannopoulos + +PKG_BUILD_DIR:=$(BUILD_DIR)/Linux-PAM-$(PKG_VERSION) + +include $(INCLUDE_DIR)/package.mk + +define Package/libpam + SECTION:=libs + CATEGORY:=Libraries + TITLE:=the Linux-PAM libraries and modules. + URL:=http://www.kernel.org/pub/linux/libs/pam +endef + +define Package/libpam/description + The Linux-PAM Pluggable Authentication Modules. +endef + +TARGET_CFLAGS += $(FPIC) + +define Build/Configure + $(call Build/Configure/Default, \ + --enable-shared \ + --enable-static \ + --enable-pamlocking \ + --disable-prelude \ + --disable-lckpwdf \ + --disable-selinux \ + --disable-nls \ + --disable-rpath \ + --enable-db=no \ + ) +endef + +define Build/InstallDev + $(INSTALL_DIR) $(1)/lib + $(INSTALL_DIR) $(1)/usr/include + $(CP) $(PKG_INSTALL_DIR)/lib/* $(1)/lib/ + $(CP) $(PKG_INSTALL_DIR)/usr/include/* $(1)/usr/include +endef + +define Package/libpam/install + $(INSTALL_DIR) $(1)/lib $(1)/lib/security $(1)/lib/security/pam_filter + $(INSTALL_DIR) $(1)/etc $(1)/etc/pam.d + $(INSTALL_DIR) $(1)/usr/sbin + $(CP) $(PKG_INSTALL_DIR)/lib/*.so* $(1)/lib/ + $(CP) $(PKG_INSTALL_DIR)/lib/security/*.so* $(1)/lib/security/ + $(CP) $(PKG_INSTALL_DIR)/lib/security/pam_filter/* $(1)/lib/security/pam_filter/ + $(CP) $(PKG_INSTALL_DIR)/etc/* $(1)/etc/ + $(CP) ./files/* $(1)/etc/ + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/* $(1)/usr/sbin/ +endef + +$(eval $(call BuildPackage,libpam)) diff --git a/libs/libpam/files/pam.conf b/libs/libpam/files/pam.conf new file mode 100644 index 0000000000..3eeb72d320 --- /dev/null +++ b/libs/libpam/files/pam.conf @@ -0,0 +1,15 @@ +# ---------------------------------------------------------------------------# +# /etc/pam.conf # +# ---------------------------------------------------------------------------# +# +# NOTE +# ---- +# +# NOTE: Most program use a file under the /etc/pam.d/ directory to setup their +# PAM service modules. This file is used only if that directory does not exist. +# ---------------------------------------------------------------------------# + +# Format: +# serv. module ctrl module [path] ...[args..] # +# name type flag # + diff --git a/libs/libpam/files/pam.d/common-account b/libs/libpam/files/pam.d/common-account new file mode 100644 index 0000000000..7162548ccb --- /dev/null +++ b/libs/libpam/files/pam.d/common-account @@ -0,0 +1,20 @@ +# +# /etc/pam.d/common-account - authorization settings common to all services +# +# This file is included from other service-specific PAM config files, +# and should contain a list of the authorization modules that define +# the central access policy for use on the system. The default is to +# only deny service to users whose accounts are expired in /etc/shadow. +# + +# here are the per-package modules (the "Primary" block) +account [success=1 new_authtok_reqd=done default=ignore] pam_unix.so +# here's the fallback if no module succeeds +account requisite pam_deny.so +# prime the stack with a positive return value if there isn't one already; +# this avoids us returning an error just because nothing sets a success code +# since the modules above will each just jump around +account required pam_permit.so +# and here are more per-package modules (the "Additional" block) + +# end of pam-auth-update config diff --git a/libs/libpam/files/pam.d/common-auth b/libs/libpam/files/pam.d/common-auth new file mode 100644 index 0000000000..8fc529d70f --- /dev/null +++ b/libs/libpam/files/pam.d/common-auth @@ -0,0 +1,21 @@ +# +# /etc/pam.d/common-auth - authentication settings common to all services +# +# This file is included from other service-specific PAM config files, +# and should contain a list of the authentication modules that define +# the central authentication scheme for use on the system +# (e.g., /etc/shadow, LDAP, Kerberos, etc.). The default is to use the +# traditional Unix authentication mechanisms. +# + +# here are the per-package modules (the "Primary" block) +auth [success=1 default=ignore] pam_unix.so nullok_secure +# here's the fallback if no module succeeds +auth requisite pam_deny.so +# prime the stack with a positive return value if there isn't one already; +# this avoids us returning an error just because nothing sets a success code +# since the modules above will each just jump around +auth required pam_permit.so +# and here are more per-package modules (the "Additional" block) + +# end of pam-auth-update config diff --git a/libs/libpam/files/pam.d/common-password b/libs/libpam/files/pam.d/common-password new file mode 100644 index 0000000000..5d0dee0a68 --- /dev/null +++ b/libs/libpam/files/pam.d/common-password @@ -0,0 +1,28 @@ +# +# /etc/pam.d/common-password - password-related modules common to all services +# +# This file is included from other service-specific PAM config files, +# and should contain a list of modules that define the services to be +# used to change user passwords. The default is pam_unix. + +# Explanation of pam_unix options: +# +# The "sha512" option enables salted SHA512 passwords. Without this option, +# the default is Unix crypt. Prior releases used the option "md5". +# +# The "obscure" option replaces the old `OBSCURE_CHECKS_ENAB' option in +# login.defs. +# +# See the pam_unix manpage for other options. + +# here are the per-package modules (the "Primary" block) +password [success=1 default=ignore] pam_unix.so obscure sha512 +# here's the fallback if no module succeeds +password requisite pam_deny.so +# prime the stack with a positive return value if there isn't one already; +# this avoids us returning an error just because nothing sets a success code +# since the modules above will each just jump around +password required pam_permit.so +# and here are more per-package modules (the "Additional" block) + +# end of pam-auth-update config diff --git a/libs/libpam/files/pam.d/common-session b/libs/libpam/files/pam.d/common-session new file mode 100644 index 0000000000..f0d41ccf7d --- /dev/null +++ b/libs/libpam/files/pam.d/common-session @@ -0,0 +1,25 @@ +# +# /etc/pam.d/common-session - session-related modules common to all services +# +# This file is included from other service-specific PAM config files, +# and should contain a list of modules that define tasks to be performed +# at the start and end of sessions of *any* kind (both interactive and +# non-interactive). +# + +# here are the per-package modules (the "Primary" block) +session [default=1] pam_permit.so +# here's the fallback if no module succeeds +session requisite pam_deny.so +# prime the stack with a positive return value if there isn't one already; +# this avoids us returning an error just because nothing sets a success code +# since the modules above will each just jump around +session required pam_permit.so +# The pam_umask module will set the umask according to the system default in +# /etc/login.defs and user settings, solving the problem of different +# umask settings with different shells, display managers, remote sessions etc. +# See "man pam_umask". +session optional pam_umask.so +# and here are more per-package modules (the "Additional" block) +session required pam_unix.so +# end of pam-auth-update config diff --git a/libs/libpam/files/pam.d/common-session-noninteractive b/libs/libpam/files/pam.d/common-session-noninteractive new file mode 100644 index 0000000000..f4943e1b0e --- /dev/null +++ b/libs/libpam/files/pam.d/common-session-noninteractive @@ -0,0 +1,25 @@ +# +# /etc/pam.d/common-session-noninteractive - session-related modules +# common to all non-interactive services +# +# This file is included from other service-specific PAM config files, +# and should contain a list of modules that define tasks to be performed +# at the start and end of all non-interactive sessions. +# + +# here are the per-package modules (the "Primary" block) +session [default=1] pam_permit.so +# here's the fallback if no module succeeds +session requisite pam_deny.so +# prime the stack with a positive return value if there isn't one already; +# this avoids us returning an error just because nothing sets a success code +# since the modules above will each just jump around +session required pam_permit.so +# The pam_umask module will set the umask according to the system default in +# /etc/login.defs and user settings, solving the problem of different +# umask settings with different shells, display managers, remote sessions etc. +# See "man pam_umask". +session optional pam_umask.so +# and here are more per-package modules (the "Additional" block) +session required pam_unix.so +# end of pam-auth-update config diff --git a/libs/libpam/files/pam.d/other b/libs/libpam/files/pam.d/other new file mode 100644 index 0000000000..6679e4f198 --- /dev/null +++ b/libs/libpam/files/pam.d/other @@ -0,0 +1,16 @@ +# +# /etc/pam.d/other - specify the PAM fallback behaviour +# +# Note that this file is used for any unspecified service; for example +#if /etc/pam.d/cron specifies no session modules but cron calls +#pam_open_session, the session module out of /etc/pam.d/other is +#used. If you really want nothing to happen then use pam_permit.so or +#pam_deny.so as appropriate. + +# We fall back to the system default in /etc/pam.d/common-* +# + +auth include common-auth +account include common-account +password include common-password +session include common-session diff --git a/libs/libpam/patches/000-OE-libpam-xtests.patch b/libs/libpam/patches/000-OE-libpam-xtests.patch new file mode 100644 index 0000000000..19fbaa29bd --- /dev/null +++ b/libs/libpam/patches/000-OE-libpam-xtests.patch @@ -0,0 +1,35 @@ +This patch is used to create a new sub package libpam-xtests to do more checks. + +Upstream-Status: Pending + +Signed-off-by: Kang Kai +--- a/xtests/Makefile.am ++++ b/xtests/Makefile.am +@@ -7,7 +7,7 @@ AM_CFLAGS = -DLIBPAM_COMPILE -I$(top_src + LDADD = $(top_builddir)/libpam/libpam.la \ + $(top_builddir)/libpam_misc/libpam_misc.la + +-CLEANFILES = *~ $(XTESTS) ++CLEANFILES = *~ + + EXTRA_DIST = run-xtests.sh tst-pam_dispatch1.pamd tst-pam_dispatch2.pamd \ + tst-pam_dispatch3.pamd tst-pam_dispatch4.pamd \ +@@ -51,3 +51,18 @@ EXTRA_PROGRAMS = $(XTESTS) + + xtests: $(XTESTS) run-xtests.sh + "$(srcdir)"/run-xtests.sh "$(srcdir)" ${XTESTS} ${NOSRCTESTS} ++ ++all: $(XTESTS) ++ ++install: install_xtests ++ ++install_xtests: ++ $(INSTALL) -d $(DESTDIR)$(pkgdatadir)/xtests ++ for file in $(EXTRA_DIST) ; do \ ++ $(INSTALL) $$file $(DESTDIR)$(pkgdatadir)/xtests ; \ ++ done ++ for file in $(XTESTS); do \ ++ $(INSTALL) .libs/$$file $(DESTDIR)$(pkgdatadir)/xtests ; \ ++ done ++ ++.PHONY: all install_xtests diff --git a/libs/libpam/patches/000-OE-pam-no-innetgr.patch b/libs/libpam/patches/000-OE-pam-no-innetgr.patch new file mode 100644 index 0000000000..f7f5b4897e --- /dev/null +++ b/libs/libpam/patches/000-OE-pam-no-innetgr.patch @@ -0,0 +1,85 @@ +innetgr may not be there so make sure that when innetgr is not present +then we inform about it and not use it. + +-Khem +--- a/modules/pam_group/pam_group.c ++++ b/modules/pam_group/pam_group.c +@@ -656,7 +656,11 @@ static int check_account(pam_handle_t *p + } + /* If buffer starts with @, we are using netgroups */ + if (buffer[0] == '@') ++#ifdef HAVE_INNETGR + good &= innetgr (&buffer[1], NULL, user, NULL); ++#else ++ pam_syslog (pamh, LOG_ERR, "pam_group does not have netgroup support"); ++#endif + /* otherwise, if the buffer starts with %, it's a UNIX group */ + else if (buffer[0] == '%') + good &= pam_modutil_user_in_group_nam_nam(pamh, user, &buffer[1]); +--- a/modules/pam_time/pam_time.c ++++ b/modules/pam_time/pam_time.c +@@ -555,9 +555,13 @@ check_account(pam_handle_t *pamh, const + } + /* If buffer starts with @, we are using netgroups */ + if (buffer[0] == '@') +- good &= innetgr (&buffer[1], NULL, user, NULL); ++#ifdef HAVE_INNETGR ++ good &= innetgr (&buffer[1], NULL, user, NULL); ++#else ++ pam_syslog (pamh, LOG_ERR, "pam_time does not have netgroup support"); ++#endif + else +- good &= logic_field(pamh, user, buffer, count, is_same); ++ good &= logic_field(pamh, user, buffer, count, is_same); + D(("with user: %s", good ? "passes":"fails" )); + + /* here we get the time field */ +--- a/modules/pam_succeed_if/pam_succeed_if.c ++++ b/modules/pam_succeed_if/pam_succeed_if.c +@@ -231,18 +231,27 @@ evaluate_notingroup(pam_handle_t *pamh, + } + /* Return PAM_SUCCESS if the (host,user) is in the netgroup. */ + static int +-evaluate_innetgr(const char *host, const char *user, const char *group) ++evaluate_innetgr(const pam_handle_t* pamh, const char *host, const char *user, const char *group) + { ++#ifdef HAVE_INNETGR + if (innetgr(group, host, user, NULL) == 1) + return PAM_SUCCESS; ++#else ++ pam_syslog (pamh, LOG_ERR, "pam_succeed_if does not have netgroup support"); ++#endif ++ + return PAM_AUTH_ERR; + } + /* Return PAM_SUCCESS if the (host,user) is NOT in the netgroup. */ + static int +-evaluate_notinnetgr(const char *host, const char *user, const char *group) ++evaluate_notinnetgr(const pam_handle_t* pamh, const char *host, const char *user, const char *group) + { ++#ifdef HAVE_INNETGR + if (innetgr(group, host, user, NULL) == 0) + return PAM_SUCCESS; ++#else ++ pam_syslog (pamh, LOG_ERR, "pam_succeed_if does not have netgroup support"); ++#endif + return PAM_AUTH_ERR; + } + +@@ -387,14 +396,14 @@ evaluate(pam_handle_t *pamh, int debug, + const void *rhost; + if (pam_get_item(pamh, PAM_RHOST, &rhost) != PAM_SUCCESS) + rhost = NULL; +- return evaluate_innetgr(rhost, user, right); ++ return evaluate_innetgr(pamh, rhost, user, right); + } + /* (Rhost, user) is not in this group. */ + if (strcasecmp(qual, "notinnetgr") == 0) { + const void *rhost; + if (pam_get_item(pamh, PAM_RHOST, &rhost) != PAM_SUCCESS) + rhost = NULL; +- return evaluate_notinnetgr(rhost, user, right); ++ return evaluate_notinnetgr(pamh, rhost, user, right); + } + /* Fail closed. */ + return PAM_SERVICE_ERR; diff --git a/libs/libpam/patches/001-no_nis.patch b/libs/libpam/patches/001-no_nis.patch new file mode 100644 index 0000000000..c9988c7fbd --- /dev/null +++ b/libs/libpam/patches/001-no_nis.patch @@ -0,0 +1,68 @@ +--- a/modules/pam_access/pam_access.c ++++ b/modules/pam_access/pam_access.c +@@ -44,7 +44,7 @@ + #include + #include + #include +-#ifdef HAVE_RPCSVC_YPCLNT_H ++#ifdef HAVE_RPCSVC_YPCLNT_H && USE_NIS + #include + #endif + #ifdef HAVE_LIBAUDIT +--- a/modules/pam_unix/pam_unix_passwd.c ++++ b/modules/pam_unix/pam_unix_passwd.c +@@ -79,18 +79,18 @@ + #include "passverify.h" + #include "bigcrypt.h" + +-#if (HAVE_YP_GET_DEFAULT_DOMAIN || HAVE_GETDOMAINNAME) && HAVE_YP_MASTER ++#if (HAVE_YP_GET_DEFAULT_DOMAIN || HAVE_GETDOMAINNAME) && HAVE_YP_MASTER && USE_NIS + # define HAVE_NIS + #endif + + #ifdef HAVE_NIS + # include + +-# if HAVE_RPCSVC_YP_PROT_H ++# if HAVE_RPCSVC_YP_PROT_H && USE_NIS + # include + # endif + +-# if HAVE_RPCSVC_YPCLNT_H ++# if HAVE_RPCSVC_YPCLNT_H && USE_NIS + # include + # endif + +--- a/modules/pam_unix/support.c ++++ b/modules/pam_unix/support.c +@@ -19,7 +19,7 @@ + #include + #include + #include +-#ifdef HAVE_RPCSVC_YPCLNT_H ++#ifdef HAVE_RPCSVC_YPCLNT_H && USE_NIS + #include + #endif + +@@ -402,7 +402,7 @@ int _unix_getpwnam(pam_handle_t *pamh, c + } + } + +-#if defined(HAVE_YP_GET_DEFAULT_DOMAIN) && defined (HAVE_YP_BIND) && defined (HAVE_YP_MATCH) && defined (HAVE_YP_UNBIND) ++#if defined(HAVE_YP_GET_DEFAULT_DOMAIN) && defined (HAVE_YP_BIND) && defined (HAVE_YP_MATCH) && defined (HAVE_YP_UNBIND) && (USE_NIS) + if (!matched && nis) { + char *userinfo = NULL, *domain = NULL; + int len = 0, i; +--- a/modules/pam_unix/yppasswd_xdr.c ++++ b/modules/pam_unix/yppasswd_xdr.c +@@ -15,6 +15,10 @@ + #ifdef HAVE_RPC_RPC_H + + #include ++#ifdef USE_NIS ++#include ++#include ++#endif + #include "yppasswd.h" + + bool_t diff --git a/libs/libpam/patches/002-no_yywrap.patch b/libs/libpam/patches/002-no_yywrap.patch new file mode 100644 index 0000000000..0d73e4be05 --- /dev/null +++ b/libs/libpam/patches/002-no_yywrap.patch @@ -0,0 +1,26 @@ +--- a/conf/pam_conv1/pam_conv_l.c ++++ b/conf/pam_conv1/pam_conv_l.c +@@ -534,7 +534,9 @@ void yyset_lineno (int line_number ); + #ifdef __cplusplus + extern "C" int yywrap (void ); + #else +-extern int yywrap (void ); ++int yywrap (void ) { ++ return 1; ++} + #endif + #endif + +--- a/doc/specs/parse_l.c ++++ b/doc/specs/parse_l.c +@@ -520,7 +520,9 @@ void yyset_lineno (int line_number ); + #ifdef __cplusplus + extern "C" int yywrap (void ); + #else +-extern int yywrap (void ); ++int yywrap (void ) { ++ return 1; ++} + #endif + #endif + diff --git a/libs/libpam/patches/003-no_doc.patch b/libs/libpam/patches/003-no_doc.patch new file mode 100644 index 0000000000..d36621514f --- /dev/null +++ b/libs/libpam/patches/003-no_doc.patch @@ -0,0 +1,22 @@ +--- a/Makefile.am ++++ b/Makefile.am +@@ -4,7 +4,7 @@ + + AUTOMAKE_OPTIONS = 1.9 gnu dist-bzip2 check-news + +-SUBDIRS = libpam tests libpamc libpam_misc modules po conf doc examples xtests ++SUBDIRS = libpam tests libpamc libpam_misc modules po conf examples xtests + + CLEANFILES = *~ + +--- a/Makefile.in ++++ b/Makefile.in +@@ -288,7 +288,7 @@ top_build_prefix = @top_build_prefix@ + top_builddir = @top_builddir@ + top_srcdir = @top_srcdir@ + AUTOMAKE_OPTIONS = 1.9 gnu dist-bzip2 check-news +-SUBDIRS = libpam tests libpamc libpam_misc modules po conf doc examples xtests ++SUBDIRS = libpam tests libpamc libpam_misc modules po conf examples xtests + CLEANFILES = *~ + EXTRA_DIST = pgp.keys.asc CHANGELOG ChangeLog-CVS Copyright Make.xml.rules + ACLOCAL_AMFLAGS = -I m4 diff --git a/libs/libpam/patches/004-fix_lib64.patch b/libs/libpam/patches/004-fix_lib64.patch new file mode 100644 index 0000000000..5605d8298b --- /dev/null +++ b/libs/libpam/patches/004-fix_lib64.patch @@ -0,0 +1,16 @@ +--- a/configure.in ++++ b/configure.in +@@ -28,12 +28,7 @@ dnl If we use /usr as prefix, use /etc f + fi + if test ${libdir} = '${exec_prefix}/lib' + then +- case "`uname -m`" in +- x86_64|ppc64|s390x|sparc64) +- libdir="/lib64" ;; +- *) +- libdir="/lib" ;; +- esac ++ libdir="/lib" + fi + if test ${sbindir} = '${exec_prefix}/sbin' + then diff --git a/libs/libpam/patches/005-fix_ruserok.patch b/libs/libpam/patches/005-fix_ruserok.patch new file mode 100644 index 0000000000..1f0f463371 --- /dev/null +++ b/libs/libpam/patches/005-fix_ruserok.patch @@ -0,0 +1,364 @@ +--- a/modules/pam_rhosts/pam_rhosts.c ++++ b/modules/pam_rhosts/pam_rhosts.c +@@ -43,6 +43,361 @@ + #include + #include + ++#ifdef __UCLIBC__ ++ ++#include ++#include ++ ++ ++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') { ++ /* 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'; /* 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) diff --git a/libs/libpam/patches/006-fix_xdr.patch b/libs/libpam/patches/006-fix_xdr.patch new file mode 100644 index 0000000000..9769506089 --- /dev/null +++ b/libs/libpam/patches/006-fix_xdr.patch @@ -0,0 +1,271 @@ +--- a/modules/pam_unix/yppasswd_xdr.c ++++ b/modules/pam_unix/yppasswd_xdr.c +@@ -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) + {