Sync getnetgrent with FreeBSD:
authorPeter Avalos <pavalos@theshell.com>
Tue, 10 Mar 2009 08:30:28 +0000 (22:30 -1000)
committerPeter Avalos <pavalos@theshell.com>
Tue, 7 Apr 2009 07:09:38 +0000 (21:09 -1000)
* Fix innetgr() returning false positives and negatives when reverse
netgroup matching is used.

* Remember to reset nextgrp in getnetgrent(), so that subsequent calls
to getnetgrent() doesn't return bogus information.

lib/libc/gen/getnetgrent.c

index 76746b3..08fd6ca 100644 (file)
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
  * 4. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/lib/libc/gen/getnetgrent.c,v 1.26 1999/11/04 04:16:27 ache Exp $
- * $DragonFly: src/lib/libc/gen/getnetgrent.c,v 1.5 2005/04/25 19:03:46 joerg Exp $
- *
  * @(#)getnetgrent.c   8.2 (Berkeley) 4/27/95
+ * $FreeBSD: src/lib/libc/gen/getnetgrent.c,v 1.35 2007/01/09 00:27:54 imp Exp $
+ * $DragonFly: src/lib/libc/gen/getnetgrent.c,v 1.5 2005/04/25 19:03:46 joerg Exp $
  */
 
 #include <ctype.h>
 #include <netdb.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <strings.h>
+#include <string.h>
 #include <unistd.h>
 
 #ifdef YP
@@ -136,6 +131,7 @@ static struct {
        NULL,
 };
 static FILE *netf = (FILE *)0;
+
 static int parse_netgrp(const char *);
 static struct linelist *read_for_group(const char *);
 
@@ -268,6 +264,7 @@ endnetgrent(void)
                free((char *)ogp);
        }
        grouphead.gr = (struct netgrp *)0;
+       nextgrp = (struct netgrp *)0;
 #ifdef YP
        _netgr_yp_enabled = 0;
 #endif
@@ -277,7 +274,8 @@ endnetgrent(void)
 static int
 _listmatch(const char *list, const char *group, int len)
 {
-       const char *ptr = list, *cptr;
+       const char *ptr = list;
+       const char *cptr;
        int glen = strlen(group);
 
        /* skip possible leading whitespace */
@@ -298,27 +296,44 @@ _listmatch(const char *list, const char *group, int len)
 }
 
 static int
-_buildkey(char **key, const char *str, const char *dom, int *rotation)
+_revnetgr_lookup(char *lookupdom, char *map, const char *str,
+                const char *dom, const char *group)
 {
-       if (key != NULL)
-               free(key);
-       key = NULL;
-       (*rotation)++;
-       if (*rotation > 4)
-               return(0);
-       switch(*rotation) {
-               case(1): asprintf(key, "%s.%s", str, dom ? dom : "*");
-                        break;
-               case(2): asprintf(key, "%s.*", str);
-                        break;
-               case(3): asprintf(key, "*.%s", dom ? dom : "*");
-                        break;
-               case(4): asprintf(key, "*.*");
-                        break;
+       int y, rv, rot;
+       char key[MAXHOSTNAMELEN];
+       char *result;
+       int resultlen;
+
+       for (rot = 0; ; rot++) {
+               switch (rot) {
+                       case(0): snprintf(key, MAXHOSTNAMELEN, "%s.%s",
+                                         str, dom?dom:lookupdom);
+                                break;
+                       case(1): snprintf(key, MAXHOSTNAMELEN, "%s.*",
+                                         str);
+                                break;
+                       case(2): snprintf(key, MAXHOSTNAMELEN, "*.%s",
+                                         dom?dom:lookupdom);
+                                break;
+                       case(3): snprintf(key, MAXHOSTNAMELEN, "*.*");
+                                break;
+                       default: return(0);
+               }
+               y = yp_match(lookupdom, map, key, strlen(key), &result,
+                            &resultlen);
+               if (y == 0) {
+                       rv = _listmatch(result, group, resultlen);
+                       free(result);
+                       if (rv) return(1);
+               } else if (y != YPERR_KEY) {
+                       /*
+                        * If we get an error other than 'no
+                        * such key in map' then something is
+                        * wrong and we should stop the search.
+                        */
+                       return(-1);
+               }
        }
-       if (key == NULL)
-               return(0);
-       return(1);
 }
 #endif
 
@@ -329,11 +344,6 @@ int
 innetgr(const char *group, const char *host, const char *user, const char *dom)
 {
        char *hst, *usr, *dm;
-#ifdef YP
-       char *result;
-       int resultlen;
-       int rv;
-#endif
        /* Sanity check */
        
        if (group == NULL || !strlen(group))
@@ -348,48 +358,36 @@ innetgr(const char *group, const char *host, const char *user, const char *dom)
        /*
         * If we're in NIS-only mode, do the search using
         * NIS 'reverse netgroup' lookups.
+        *
+        * What happens with 'reverse netgroup' lookups:
+        *
+        * 1) try 'reverse netgroup' lookup
+        *    1.a) if host is specified and user is null:
+        *         look in netgroup.byhost
+        *         (try host.domain, host.*, *.domain or *.*)
+        *         if found, return yes
+        *    1.b) if user is specified and host is null:
+        *         look in netgroup.byuser
+        *         (try host.domain, host.*, *.domain or *.*)
+        *         if found, return yes
+        *    1.c) if both host and user are specified,
+        *         don't do 'reverse netgroup' lookup.  It won't work.
+        *    1.d) if neither host ane user are specified (why?!?)
+        *         don't do 'reverse netgroup' lookup either.
+        * 2) if domain is specified and 'reverse lookup' is done:
+        *    'reverse lookup' was authoritative.  bye bye.
+        * 3) otherwise, too bad, try it the slow way.
         */
-       if (_use_only_yp) {
-               char *_key = NULL;
-               int rot = 0, y = 0;
-
+       if (_use_only_yp && (host == NULL) != (user == NULL)) {
+               int ret;
                if(yp_get_default_domain(&_netgr_yp_domain))
                        return(0);
-               while(_buildkey(&_key, user ? user : host, dom, &rot)) {
-                       y = yp_match(_netgr_yp_domain, user? "netgroup.byuser":
-                           "netgroup.byhost", _key, strlen(_key), &result,
-                               &resultlen);
-                       if (y) {
-                               /*
-                                * If we get an error other than 'no
-                                * such key in map' then something is
-                                * wrong and we should stop the search.
-                                */
-                               if (y != YPERR_KEY)
-                                       break;
-                       } else {
-                               rv = _listmatch(result, group, resultlen);
-                               free(result);
-                               if (_key != NULL)
-                                       free(_key);
-                               if (rv)
-                                       return(1);
-                               else
-                                       return(0);
-                       }
-               }
-               /*
-                * Couldn't match using NIS-exclusive mode. If the error
-                * was YPERR_MAP, then the failure happened because there
-                * was no netgroup.byhost or netgroup.byuser map. The odds
-                * are we are talking to an Sun NIS+ server in YP emulation
-                * mode; if this is the case, then we have to do the check
-                * the 'old-fashioned' way by grovelling through the netgroup
-                * map and resolving memberships on the fly.
-                */
-               if (_key != NULL)
-                       free(_key);
-               if (y != YPERR_MAP)
+               ret = _revnetgr_lookup(_netgr_yp_domain,
+                                     host?"netgroup.byhost":"netgroup.byuser",
+                                     host?host:user, dom, group);
+               if (ret == 1)
+                       return(1);
+               else if (ret == 0 && dom != NULL)
                        return(0);
        }