Hi,
while finalizing IPv6 support for the Linux NIS implementation,
I found a problem with pam_unix.so. pam_unix.so can also only
change NIS passwords, if IPv4 is used, but not with IPv6.
My suggested patch would be (and yes, there is no simple TIRPC
variant of SunRPC getrpcport :( ):
diff --git a/configure.ac b/configure.ac
index f33b959..bf00de5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -475,9 +475,12 @@ AS_IF([test "x$enable_nis" != "xno"], [
LIBS="$LIBS $libtirpc_LIBS"
], [:;])
- AC_SEARCH_LIBS([yp_get_default_domain], [nsl])
+ PKG_CHECK_MODULES([NSL], [libnsl], [],
[AC_CHECK_LIB([nsl],[yp_match],[NSL_LIBS="-lnsl"],[NSL_LIBS=""])])
+ CFLAGS="$CFLAGS $NSL_CFLAGS"
+ LIBS="$LIBS $NSL_LIBS"
AC_CHECK_FUNCS([yp_get_default_domain yperr_string yp_master yp_bind yp_match
yp_unbind])
+ AC_CHECK_FUNCS([getrpcport rpcb_getaddr])
AC_CHECK_HEADERS([rpc/rpc.h rpcsvc/ypclnt.h rpcsvc/yp_prot.h])
AC_CHECK_DECLS([getrpcport], , , [
#if HAVE_RPC_RPC_H
@@ -485,16 +488,10 @@ AS_IF([test "x$enable_nis" != "xno"], [
#endif
])
- NIS_CFLAGS="${CFLAGS%${old_CFLAGS}}"
- NIS_LIBS="${LIBS%${old_LIBS}}"
-
CFLAGS="$old_CFLAGS"
LIBS="$old_LIBS"
])
-AC_SUBST([NIS_CFLAGS])
-AC_SUBST([NIS_LIBS])
-
AC_ARG_ENABLE([selinux],
AS_HELP_STRING([--disable-selinux],[do not use SELinux]),
WITH_SELINUX=$enableval, WITH_SELINUX=yes)
diff --git a/modules/pam_unix/Makefile.am b/modules/pam_unix/Makefile.am
index 56ed591..2dc2bd1 100644
--- a/modules/pam_unix/Makefile.am
+++ b/modules/pam_unix/Makefile.am
@@ -19,7 +19,7 @@ secureconfdir = $(SCONFIGDIR)
AM_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include \
-DCHKPWD_HELPER=\"$(sbindir)/unix_chkpwd\" \
-DUPDATE_HELPER=\"$(sbindir)/unix_update\" \
- $(NIS_CFLAGS)
+ @libtirpc_CFLAGS@ @NSL_CFLAGS@
if HAVE_LIBSELINUX
AM_CFLAGS += -D"WITH_SELINUX"
@@ -30,7 +30,7 @@ if HAVE_VERSIONING
pam_unix_la_LDFLAGS += -Wl,--version-script=$(srcdir)/../modules.map
endif
pam_unix_la_LIBADD = $(top_builddir)/libpam/libpam.la \
- @LIBCRYPT@ @LIBSELINUX@ $(NIS_LIBS)
+ @LIBCRYPT@ @LIBSELINUX@ @libtirpc_LIBS@ @NSL_LIBS@
securelib_LTLIBRARIES = pam_unix.la
diff --git a/modules/pam_unix/pam_unix_passwd.c b/modules/pam_unix/pam_unix_passwd.c
index c2e5de5..f7791b1 100644
--- a/modules/pam_unix/pam_unix_passwd.c
+++ b/modules/pam_unix/pam_unix_passwd.c
@@ -96,7 +96,7 @@
# include "yppasswd.h"
-# if !HAVE_DECL_GETRPCPORT
+# if !HAVE_DECL_GETRPCPORT &&!HAVE_RPCB_GETADDR
extern int getrpcport(const char *host, unsigned long prognum,
unsigned long versnum, unsigned int proto);
# endif /* GNU libc 2.1 */
@@ -118,11 +118,48 @@ extern int getrpcport(const char *host, unsigned long prognum,
#define MAX_PASSWD_TRIES 3
#ifdef HAVE_NIS
+#ifdef HAVE_RPCB_GETADDR
+static unsigned short
+__taddr2port (const struct netconfig *nconf, const struct netbuf *nbuf)
+{
+ unsigned short port = 0;
+ struct __rpc_sockinfo si;
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
+ if (!__rpc_nconf2sockinfo(nconf, &si))
+ return 0;
+
+ switch (si.si_af)
+ {
+ case AF_INET:
+ sin = nbuf->buf;
+ port = sin->sin_port;
+ break;
+ case AF_INET6:
+ sin6 = nbuf->buf;
+ port = sin6->sin6_port;
+ break;
+ default:
+ break;
+ }
+
+ return htons (port);
+}
+#endif
+
static char *getNISserver(pam_handle_t *pamh, unsigned int ctrl)
{
char *master;
char *domainname;
int port, err;
+#if defined(HAVE_RPCB_GETADDR)
+ struct netconfig *nconf;
+ struct netbuf svcaddr;
+ char addrbuf[INET6_ADDRSTRLEN];
+ void *handle;
+ int found;
+#endif
+
#ifdef HAVE_YP_GET_DEFAULT_DOMAIN
if ((err = yp_get_default_domain(&domainname)) != 0) {
@@ -150,7 +187,41 @@ static char *getNISserver(pam_handle_t *pamh, unsigned int ctrl)
yperr_string(err));
return NULL;
}
+#ifdef HAVE_RPCB_GETADDR
+ svcaddr.len = 0;
+ svcaddr.maxlen = sizeof (addrbuf);
+ svcaddr.buf = addrbuf;
+ port = 0;
+ found = 0;
+
+ handle = setnetconfig();
+ while ((nconf = getnetconfig(handle)) != NULL) {
+ if (!strcmp(nconf->nc_proto, "udp")) {
+ if (rpcb_getaddr(YPPASSWDPROG, YPPASSWDPROC_UPDATE,
+ nconf, &svcaddr, master)) {
+ port = __taddr2port (nconf, &svcaddr);
+ endnetconfig (handle);
+ found=1;
+ break;
+ }
+
+ if (rpc_createerr.cf_stat != RPC_UNKNOWNHOST) {
+ clnt_pcreateerror (master);
+ pam_syslog (pamh, LOG_ERR,
+ "rpcb_getaddr (%s) failed!", master);
+ return NULL;
+ }
+ }
+ }
+
+ if (!found) {
+ pam_syslog (pamh, LOG_ERR,
+ "Cannot find suitable transport for protocol 'udp'");
+ return NULL;
+ }
+#else
port = getrpcport(master, YPPASSWDPROG, YPPASSWDPROC_UPDATE, IPPROTO_UDP);
+#endif
if (port == 0) {
pam_syslog(pamh, LOG_WARNING,
"yppasswdd not running on NIS master host");
--
Thorsten Kukuk, Senior Architect SLES & Common Code Base
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nuernberg, Germany
GF: Felix Imendörffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nürnberg)