NetBSD Problem Report #40728

From root@nagler-company.com  Mon Feb 23 12:46:30 2009
Return-Path: <root@nagler-company.com>
Received: from mail.netbsd.org (mail.netbsd.org [204.152.190.11])
	by www.NetBSD.org (Postfix) with ESMTP id 3710263B8C3
	for <gnats-bugs@gnats.NetBSD.org>; Mon, 23 Feb 2009 12:46:30 +0000 (UTC)
Message-Id: <20090223124608.F32634EA9F9@s012.nagler-company.com>
Date: Mon, 23 Feb 2009 13:46:08 +0100 (CET)
From: Wolfgang.Stukenbrock@nagler-company.com
Reply-To: Wolfgang.Stukenbrock@nagler-company.com
To: gnats-bugs@gnats.NetBSD.org
Subject: expanding NIS-Netgroups for users and groups is very slow
X-Send-Pr-Version: 3.95

>Number:         40728
>Category:       lib
>Synopsis:       expanding NIS-Netgroups for users and groups is very slow
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    lib-bug-people
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Mon Feb 23 12:50:00 +0000 2009
>Last-Modified:  Thu Mar 29 09:25:00 +0000 2012
>Originator:     W. Stukenbrock
>Release:        NetBSD 4.0
>Organization:
Dr. Nagler & Company GmbH

>Environment:


System: NetBSD s012 4.0 NetBSD 4.0 (NSW-S012) #1: Thu Sep 11 12:21:03 CEST 2008 root@s012:/usr/src/sys/arch/amd64/compile/NSW-S012 amd64
Architecture: x86_64
Machine: amd64
>Description:
	The problem has been recognized while running "ls -l" as root and as non-root-user.
	When running as root the statement takes significant longer (something around 20 seconds) as running as non-root-user on
	the same directory. The call for the non-root-user takes less than 2 seconds.
	The system is a YP-client with no local ypserv and setup in passwd and group compat mode with compat-nis.
	I've analysed the problem by tracing the network and found a lot of repeated YP-request to check the existens of
	passwd.adjunct and passwd.master.byname.
	A look into the ls-command sources shows, that it uses the pwcache-module - user_from_uid().
	The pwcache-module tries to minimize the lookup-effort of the getpwent-routines by setting stayopen to 1.
	Dooing this should keep all possible fd's etc. active in order to avoid redundant requests etc.
	In the getpwent (or getgrent) routines the ns-switch is used.
	The pwcache calls now getpwuid() to solve the user_from_uid() call.
	This call will go though _compat_getpwuid() in getpwent.c, will find the included netgroup (e.g. "+@NU_USER_FOR_HOST") in the
	password file and starts netgroup processing (setnetgrent(), getnetgrent(), endnetgrent()).
	It will call the ns-switch for passwd_compat for every member in the netgroup with the function getpwnam_r.
	This will call _nis_getpwnam_r() - we have compat set to NIS - and is here the problem.
	Even if we have set stayopen - _nis_getpwnam_r() uses a local state information and ignores the global stayopen condition.
	So it will start over with determining the domainname and for the user root check if there are passwd.adjunct or passwd.master.byname
	maps on the server.
	The same happens to the group lookup stuff.
	The problem gets gets bigger and bigger with the member count of the included netgroup. Each lookup will take up to 3 times the required
	time for each member of the group. And if you are out of luck, the pwcache module is not able to cache a lot due to the simple
	hash mechanism there.
	A look the implementation of _nis_getpwnam_r() and _nis_getpwuid_r() shows, that they are just callint ypmatch(...) and don't touch
	any other state information than the domainname and the cached information for passwd.adjunct or passwd.master.byname maps..
	So it is easy to avoid the repeated lookups by useing the global state buffer for NIS if stayopen is set there.
	No additional synchronisation is needed for the current implementation, because all calls enter a module-monitor prior the first call
	to the ns-switch stuff. If this will be changed in the future, the current state information should be copied to the local state info
	in theese routines with an adequate mutex aquired, but this is a possbile todo for the future.

	With the following patch the run time of ls -l" as user root is much faster as before and reaches the time of a non-root-user,
	if there are no passwd.adjunct and passwd.master.byname maps.

	An analog problem may be in the HESIOD code part, but we are not useing HESIOD-maps here, so I cannot test anything and therefore
	I haven't changed the code there.
>How-To-Repeat:
	Setup a large netgroup and add it to /etc/passwd and/or /etc/group.
	Run agains a server without passwd.master (and passwd.adjunct) maps.
	Try "ls -l" as root and trace the network trafic. You will see two request for passwd.adjunct and passwd.master.byname
	for each member in the netgroup and they report all the time, that the maps are not present.
>Fix:
	The following patches will use the global state buffer in getpwent.c and getgrent.c if stayopen has been set.

--- getgrent.c	2009/02/23 10:50:32	1.1
+++ getgrent.c	2009/02/23 12:45:45
@@ -1194,9 +1194,17 @@
 	_DIAGASSERT(result != NULL);

 	*result = NULL;
-	memset(&state, 0, sizeof(state));
-	rv = __grscan_nis(retval, grp, buffer, buflen, &state, 1, NULL, gid);
-	__grend_nis(&state);
+/* remark: we run under a global mutex inside of this module ... */
+	if (_nis_state.stayopen)
+	  { /* use global state only if stayopen is set - otherwiese we would blow up getgrent_r() ... */
+	     rv = __grscan_nis(retval, grp, buffer, buflen, &_nis_state, 1, NULL, gid);
+	  }
+	else
+	  {
+	    memset(&state, 0, sizeof(state));
+	    rv = __grscan_nis(retval, grp, buffer, buflen, &state, 1, NULL, gid);
+	    __grend_nis(&state);
+	  }
 	if (rv == NS_SUCCESS)
 		*result = grp;
 	return rv;
@@ -1246,9 +1254,17 @@
 	_DIAGASSERT(result != NULL);

 	*result = NULL;
-	memset(&state, 0, sizeof(state));
-	rv = __grscan_nis(retval, grp, buffer, buflen, &state, 1, name, 0);
-	__grend_nis(&state);
+/* remark: we run under a global mutex inside of this module ... */
+	if (_nis_state.stayopen)
+	  { /* use global state only if stayopen is set - otherwiese we would blow up getgrent_r() ... */
+	     rv = __grscan_nis(retval, grp, buffer, buflen, &_nis_state, 1, name, 0);
+	  }
+	else
+	  {
+	    memset(&state, 0, sizeof(state));
+	    rv = __grscan_nis(retval, grp, buffer, buflen, &state, 1, name, 0);
+	    __grend_nis(&state);
+	  }
 	if (rv == NS_SUCCESS)
 		*result = grp;
 	return rv;
--- getpwent.c	2009/02/23 10:50:32	1.1
+++ getpwent.c	2009/02/23 11:09:31
@@ -1529,14 +1529,21 @@
 	_DIAGASSERT(result != NULL);

 	*result = NULL;
-	memset(&state, 0, sizeof(state));
-	rv = _nis_start(&state);
-	if (rv != NS_SUCCESS)
-		return rv;
 	snprintf(buffer, buflen, "%u", (unsigned int)uid);
-	rv = _nis_pwscan(retval, pw, buffer, buflen,
-	    &state, PASSWD_BYUID(&state));
-	_nis_end(&state);
+/* remark: we run under a global mutex inside of this module ... */
+	if (_nis_state.stayopen)
+	  { /* use global state only if stayopen is set - otherwiese we would blow up getpwent_r() ... */
+	    rv = _nis_pwscan(retval, pw, buffer, buflen,
+		&_nis_state, PASSWD_BYUID(&_nis_state));
+	  }
+	else
+	  { /* keep old semantic if no stayopen set - no need to call _nis_start() here - _nis_pwscan() will do it for us ... */
+	    /* use same way as in getgrent.c ... */
+	    memset(&state, 0, sizeof(state));
+	    rv = _nis_pwscan(retval, pw, buffer, buflen,
+		&state, PASSWD_BYUID(&state));
+	    _nis_end(&state);
+	  }
 	if (rv != NS_SUCCESS)
 		return rv;
 	if (uid == pw->pw_uid) {
@@ -1593,13 +1600,20 @@

 	*result = NULL;
 	snprintf(buffer, buflen, "%s", name);
-	memset(&state, 0, sizeof(state));
-	rv = _nis_start(&state);
-	if (rv != NS_SUCCESS)
-		return rv;
-	rv = _nis_pwscan(retval, pw, buffer, buflen,
-	    &state, PASSWD_BYNAME(&state));
-	_nis_end(&state);
+/* remark: we run under a global mutex inside of this module ... */
+	if (_nis_state.stayopen)
+	  { /* use global state only if stayopen is set - otherwiese we would blow up getpwent_r() ... */
+	    rv = _nis_pwscan(retval, pw, buffer, buflen,
+		&_nis_state, PASSWD_BYNAME(&_nis_state));
+	  }
+	else
+	  { /* keep old semantic if no stayopen set - no need to call _nis_start() here - _nis_pwscan() will do it for us ... */
+	    /* use same way as in getgrent.c ... */
+	    memset(&state, 0, sizeof(state));
+	    rv = _nis_pwscan(retval, pw, buffer, buflen,
+		&state, PASSWD_BYNAME(&state));
+	    _nis_end(&state);
+	  }
 	if (rv != NS_SUCCESS)
 		return rv;
 	if (strcmp(name, pw->pw_name) == 0) {

>Audit-Trail:
From: Wolfgang Stukenbrock <Wolfgang.Stukenbrock@nagler-company.com>
To: gnats-bugs@NetBSD.org
Cc: 
Subject: Re: lib/40728: expanding NIS-Netgroups for users and groups is very slow
Date: Mon, 23 Feb 2009 16:49:07 +0100

 Hi, again,

 additional testing has chown, that I missed to enter the folloing part 
 of the patch to getpwent.c.

 Without this change, "+" lines will drop the stayopen state and loop 
 with requesting the "master.passwd" map again

 Sorry my fault.

 here the missing patch part.

 @@ -2054,7 +2068,7 @@
                                 state->mode = COMPAT_FULL;
                                                 /* reset passwd_compat 
 search */
  /* XXXREENTRANT: setpassent is not thread safe ? */
 -                               (void) _passwdcompat_setpassent(0);
 +                               (void) 
 _passwdcompat_setpassent(_compat_state.stayopen);
                                 break;
                         case '@':               /* `+@netgroup' */
                                 state->mode = COMPAT_NETGROUP;


 gnats-admin@NetBSD.org wrote:

 >Thank you very much for your problem report.
 >It has the internal identification `lib/40728'.
 >The individual assigned to look at your
 >report is: lib-bug-people. 
 >
 >>Category:       lib
 >>Responsible:    lib-bug-people
 >>Synopsis:       expanding NIS-Netgroups for users and groups is very slow
 >>Arrival-Date:   Mon Feb 23 12:50:00 +0000 2009
 >>
 >


From: Wolfgang Stukenbrock <wolfgang.stukenbrock@nagler-company.com>
To: gnats-bugs@NetBSD.org
Cc: 
Subject: Re: lib/40728: expanding NIS-Netgroups for users and groups is very slow
Date: Thu, 29 Mar 2012 11:24:31 +0200

 This is a multi-part message in MIME format.
 --------------040207020604010308030301
 Content-Type: text/plain; charset=us-ascii; format=flowed
 Content-Transfer-Encoding: 7bit

 Hi again,

 I've now switched my passwd database setup from passwd to master.passwd
 YP-maps and recognised a bug in my patch.

 Due to the fact that _nis_start() is no longer called prior calling
 _nis_pwscan in any case, we may fail to select the master.passwd map
 correctly.

 Due to the fact that we should not call _nis_start() if we reuse the
 state, there is no easy way to add this call again.
 The better sollution - from my point of view - is to delay the
 map-selection in _nis_pwscan() after the (optional) build-in call to
 _nis_start.

 The following patch will solve this problem by passing an array instead
 of the map name and take the correct map from there after the optional
 _nis_start() call in _nis_pwscan:

 --- getpwent.c  2010/05/03 12:54:18     1.2
 +++ getpwent.c  2012/03/28 11:29:48
 @@ -1099,7 +1099,7 @@
           char            *current;       /* current first/next match */
           int              currentlen;    /* length of _nis_current */
           enum {                          /* shadow map type */
 -               NISMAP_UNKNOWN,         /*  unknown ... */
 +               NISMAP_UNKNOWN = 0,     /*  unknown ... */
                   NISMAP_NONE,            /*  none: use "passwd.by*" */
                   NISMAP_ADJUNCT,         /*  pw_passwd from
 "passwd.adjunct.*" */
                   NISMAP_MASTER           /*  all from 
 "master.passwd.by*" */
 @@ -1111,11 +1111,17 @@
    static struct passwd           _nis_passwd;
    static char                    _nis_passwdbuf[_GETPW_R_SIZE_MAX];

 +static const char __nis_pw_n_1[] = "master.passwd.byname";
 +static const char __nis_pw_n_2[] = "passwd.byname";
 +static const char __nis_pw_u_1[] = "master.passwd.byuid";
 +static const char __nis_pw_u_2[] = "passwd.byuid";
 +
 +static const char * const __nis_pw_n_map[4] = { __nis_pw_n_2,
 __nis_pw_n_2, __nis_pw_n_2, __nis_pw_n_1 };
 +static const char * const __nis_pw_u_map[4] = { __nis_pw_u_2,
 __nis_pw_u_2, __nis_pw_u_2, __nis_pw_u_1 };
 +
           /* macros for deciding which NIS maps to use. */
 -#define        PASSWD_BYNAME(x)        ((x)->maptype == NISMAP_MASTER \
 -                                   ? "master.passwd.byname" :
 "passwd.byname")
 -#define        PASSWD_BYUID(x)         ((x)->maptype == NISMAP_MASTER \
 -                                   ? "master.passwd.byuid" :
 "passwd.byuid")
 +#define        PASSWD_BYNAME(x)        ((x)->maptype == NISMAP_MASTER ?
 __nis_pw_n_1 : __nis_pw_n_2)
 +#define        PASSWD_BYUID(x)         ((x)->maptype == NISMAP_MASTER ?
 __nis_pw_u_1 : __nis_pw_u_2)

    static int
    _nis_start(struct nis_state *state)
 @@ -1236,7 +1242,7 @@
     */
    static int
    _nis_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen,
 -       struct nis_state *state, const char *map)
 +       struct nis_state *state, const char * const *map_arr)
    {
           char    *data;
           int     nisr, rv, datalen;
 @@ -1245,7 +1251,7 @@
           _DIAGASSERT(pw != NULL);
           _DIAGASSERT(buffer != NULL);
           _DIAGASSERT(state != NULL);
 -       _DIAGASSERT(map != NULL);
 +       _DIAGASSERT(map_arr != NULL);

           *retval = 0;

 @@ -1257,9 +1263,10 @@

           data = NULL;
           rv = NS_NOTFOUND;
 +       _DIAGASSERT(state->maptype > 0 && state->maptype <
 sizeof(map_arr)/sizeof(const char*));

                                                           /* search map */
 -       nisr = yp_match(state->domain, map, buffer, (int)strlen(buffer),
 +       nisr = yp_match(state->domain, map_arr[state->maptype], buffer,
 (int)strlen(buffer),
               &data, &datalen);
           switch (nisr) {
           case 0:
 @@ -1494,7 +1501,7 @@
           snprintf(_nis_passwdbuf, sizeof(_nis_passwdbuf), "%u",
 (unsigned int)uid);
           rv = _nis_pwscan(&rerror, &_nis_passwd,
               _nis_passwdbuf, sizeof(_nis_passwdbuf),
 -           &_nis_state, PASSWD_BYUID(&_nis_state));
 +           &_nis_state, __nis_pw_u_map);
           if (!_nis_state.stayopen)
                   _nis_end(&_nis_state);
           if (rv == NS_SUCCESS && uid == _nis_passwd.pw_uid)
 @@ -1527,14 +1534,14 @@
           if (_nis_state.stayopen)
             { /* use global state only if stayopen is set - otherwiese we
 would blow up getpwent_r() ... */
               rv = _nis_pwscan(retval, pw, buffer, buflen,
 -               &_nis_state, PASSWD_BYUID(&_nis_state));
 +               &_nis_state, __nis_pw_u_map);
             }
           else
             { /* keep old semantic if no stayopen set - no need to call
 _nis_start() here - _nis_pwscan() will do it for us ... */
               /* use same way as in getgrent.c ... */
               memset(&state, 0, sizeof(state));
               rv = _nis_pwscan(retval, pw, buffer, buflen,
 -               &state, PASSWD_BYUID(&state));
 +               &state, __nis_pw_u_map);
               _nis_end(&state);
             }
           if (rv != NS_SUCCESS)
 @@ -1564,7 +1571,7 @@
           snprintf(_nis_passwdbuf, sizeof(_nis_passwdbuf), "%s", name);
           rv = _nis_pwscan(&rerror, &_nis_passwd,
               _nis_passwdbuf, sizeof(_nis_passwdbuf),
 -           &_nis_state, PASSWD_BYNAME(&_nis_state));
 +           &_nis_state, __nis_pw_n_map);
           if (!_nis_state.stayopen)
                   _nis_end(&_nis_state);
           if (rv == NS_SUCCESS && strcmp(name, _nis_passwd.pw_name) == 0)
 @@ -1597,14 +1604,14 @@
           if (_nis_state.stayopen)
             { /* use global state only if stayopen is set - otherwiese we
 would blow up getpwent_r() ... */
               rv = _nis_pwscan(retval, pw, buffer, buflen,
 -               &_nis_state, PASSWD_BYNAME(&_nis_state));
 +               &_nis_state, __nis_pw_n_map);
             }
           else
             { /* keep old semantic if no stayopen set - no need to call
 _nis_start() here - _nis_pwscan() will do it for us ... */
               /* use same way as in getgrent.c ... */
               memset(&state, 0, sizeof(state));
               rv = _nis_pwscan(retval, pw, buffer, buflen,
 -               &state, PASSWD_BYNAME(&state));
 +               &state, __nis_pw_n_map);
               _nis_end(&state);
             }
           if (rv != NS_SUCCESS)



 ###### end of additional patch ##########


 And for more easy integration the complete patch for getpwent.c against
 5.1-release again as attachment ....



 --------------040207020604010308030301
 Content-Type: text/plain;
  name="getpwent-1.c-patch"
 Content-Transfer-Encoding: 7bit
 Content-Disposition: inline;
  filename="getpwent-1.c-patch"

 --- getpwent.c	2010/05/03 12:50:13	1.1
 +++ getpwent.c	2012/03/28 11:29:48
 @@ -1099,7 +1099,7 @@
  	char		*current;	/* current first/next match */
  	int		 currentlen;	/* length of _nis_current */
  	enum {				/* shadow map type */
 -		NISMAP_UNKNOWN,		/*  unknown ... */
 +		NISMAP_UNKNOWN = 0,	/*  unknown ... */
  		NISMAP_NONE,		/*  none: use "passwd.by*" */
  		NISMAP_ADJUNCT,		/*  pw_passwd from "passwd.adjunct.*" */
  		NISMAP_MASTER		/*  all from "master.passwd.by*" */
 @@ -1111,11 +1111,17 @@
  static struct passwd		_nis_passwd;
  static char			_nis_passwdbuf[_GETPW_R_SIZE_MAX];

 +static const char __nis_pw_n_1[] = "master.passwd.byname";
 +static const char __nis_pw_n_2[] = "passwd.byname";
 +static const char __nis_pw_u_1[] = "master.passwd.byuid";
 +static const char __nis_pw_u_2[] = "passwd.byuid";
 +
 +static const char * const __nis_pw_n_map[4] = { __nis_pw_n_2, __nis_pw_n_2, __nis_pw_n_2, __nis_pw_n_1 };
 +static const char * const __nis_pw_u_map[4] = { __nis_pw_u_2, __nis_pw_u_2, __nis_pw_u_2, __nis_pw_u_1 };
 +
  	/* macros for deciding which NIS maps to use. */
 -#define	PASSWD_BYNAME(x)	((x)->maptype == NISMAP_MASTER \
 -				    ? "master.passwd.byname" : "passwd.byname")
 -#define	PASSWD_BYUID(x)		((x)->maptype == NISMAP_MASTER \
 -				    ? "master.passwd.byuid" : "passwd.byuid")
 +#define	PASSWD_BYNAME(x)	((x)->maptype == NISMAP_MASTER ? __nis_pw_n_1 : __nis_pw_n_2)
 +#define	PASSWD_BYUID(x)		((x)->maptype == NISMAP_MASTER ? __nis_pw_u_1 : __nis_pw_u_2)

  static int
  _nis_start(struct nis_state *state)
 @@ -1236,7 +1242,7 @@
   */
  static int
  _nis_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen,
 -	struct nis_state *state, const char *map)
 +	struct nis_state *state, const char * const *map_arr)
  {
  	char	*data;
  	int	nisr, rv, datalen;
 @@ -1245,7 +1251,7 @@
  	_DIAGASSERT(pw != NULL);
  	_DIAGASSERT(buffer != NULL);
  	_DIAGASSERT(state != NULL);
 -	_DIAGASSERT(map != NULL);
 +	_DIAGASSERT(map_arr != NULL);

  	*retval = 0;

 @@ -1257,9 +1263,10 @@

  	data = NULL;
  	rv = NS_NOTFOUND;
 +	_DIAGASSERT(state->maptype > 0 && state->maptype < sizeof(map_arr)/sizeof(const char*));

  							/* search map */
 -	nisr = yp_match(state->domain, map, buffer, (int)strlen(buffer),
 +	nisr = yp_match(state->domain, map_arr[state->maptype], buffer, (int)strlen(buffer),
  	    &data, &datalen);
  	switch (nisr) {
  	case 0:
 @@ -1494,7 +1501,7 @@
  	snprintf(_nis_passwdbuf, sizeof(_nis_passwdbuf), "%u", (unsigned int)uid);
  	rv = _nis_pwscan(&rerror, &_nis_passwd,
  	    _nis_passwdbuf, sizeof(_nis_passwdbuf),
 -	    &_nis_state, PASSWD_BYUID(&_nis_state));
 +	    &_nis_state, __nis_pw_u_map);
  	if (!_nis_state.stayopen)
  		_nis_end(&_nis_state);
  	if (rv == NS_SUCCESS && uid == _nis_passwd.pw_uid)
 @@ -1522,14 +1529,21 @@
  	_DIAGASSERT(result != NULL);

  	*result = NULL;
 -	memset(&state, 0, sizeof(state));
 -	rv = _nis_start(&state);
 -	if (rv != NS_SUCCESS)
 -		return rv;
  	snprintf(buffer, buflen, "%u", (unsigned int)uid);
 -	rv = _nis_pwscan(retval, pw, buffer, buflen,
 -	    &state, PASSWD_BYUID(&state));
 -	_nis_end(&state);
 +/* remark: we run under a global mutex inside of this module ... */
 +	if (_nis_state.stayopen)
 +	  { /* use global state only if stayopen is set - otherwiese we would blow up getpwent_r() ... */
 +	    rv = _nis_pwscan(retval, pw, buffer, buflen,
 +		&_nis_state, __nis_pw_u_map);
 +	  }
 +	else
 +	  { /* keep old semantic if no stayopen set - no need to call _nis_start() here - _nis_pwscan() will do it for us ... */
 +	    /* use same way as in getgrent.c ... */
 +	    memset(&state, 0, sizeof(state));
 +	    rv = _nis_pwscan(retval, pw, buffer, buflen,
 +		&state, __nis_pw_u_map);
 +	    _nis_end(&state);
 +	  }
  	if (rv != NS_SUCCESS)
  		return rv;
  	if (uid == pw->pw_uid) {
 @@ -1557,7 +1571,7 @@
  	snprintf(_nis_passwdbuf, sizeof(_nis_passwdbuf), "%s", name);
  	rv = _nis_pwscan(&rerror, &_nis_passwd,
  	    _nis_passwdbuf, sizeof(_nis_passwdbuf),
 -	    &_nis_state, PASSWD_BYNAME(&_nis_state));
 +	    &_nis_state, __nis_pw_n_map);
  	if (!_nis_state.stayopen)
  		_nis_end(&_nis_state);
  	if (rv == NS_SUCCESS && strcmp(name, _nis_passwd.pw_name) == 0)
 @@ -1586,13 +1600,20 @@

  	*result = NULL;
  	snprintf(buffer, buflen, "%s", name);
 -	memset(&state, 0, sizeof(state));
 -	rv = _nis_start(&state);
 -	if (rv != NS_SUCCESS)
 -		return rv;
 -	rv = _nis_pwscan(retval, pw, buffer, buflen,
 -	    &state, PASSWD_BYNAME(&state));
 -	_nis_end(&state);
 +/* remark: we run under a global mutex inside of this module ... */
 +	if (_nis_state.stayopen)
 +	  { /* use global state only if stayopen is set - otherwiese we would blow up getpwent_r() ... */
 +	    rv = _nis_pwscan(retval, pw, buffer, buflen,
 +		&_nis_state, __nis_pw_n_map);
 +	  }
 +	else
 +	  { /* keep old semantic if no stayopen set - no need to call _nis_start() here - _nis_pwscan() will do it for us ... */
 +	    /* use same way as in getgrent.c ... */
 +	    memset(&state, 0, sizeof(state));
 +	    rv = _nis_pwscan(retval, pw, buffer, buflen,
 +		&state, __nis_pw_n_map);
 +	    _nis_end(&state);
 +	  }
  	if (rv != NS_SUCCESS)
  		return rv;
  	if (strcmp(name, pw->pw_name) == 0) {
 @@ -2048,7 +2069,7 @@
  				state->mode = COMPAT_FULL;
  						/* reset passwd_compat search */
  /* XXXREENTRANT: setpassent is not thread safe ? */
 -				(void) _passwdcompat_setpassent(0);
 +				(void) _passwdcompat_setpassent(_compat_state.stayopen);
  				break;
  			case '@':		/* `+@netgroup' */
  				state->mode = COMPAT_NETGROUP;


 --------------040207020604010308030301--

>Unformatted:

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2007 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.