Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 5 Sep 1996 01:06:56 -0400 (EDT)
From:      Bill Paul <wpaul@skynet.ctr.columbia.edu>
To:        pst@jnx.com (Paul Traina)
Cc:        bugs@freebsd.org
Subject:   Re: proper entry for /etc/groups override?
Message-ID:  <199609050506.BAA16389@skynet.ctr.columbia.edu>
In-Reply-To: <199609050048.RAA12235@base.jnx.com> from "Paul Traina" at Sep 4, 96 05:48:04 pm

next in thread | previous in thread | raw e-mail | index | archive | help
Of all the gin joints in all the towns in all the world, Paul Traina had 
to walk into mine and say:
 
> Bill,
> 
> I'm having problems with YP in /etc/group and I'm wondering what I'm doing
> wrong.

You're not doing anything wrong. The code is just busted. I've been
waiting for an excuse to fix this. Thanks for prodding me.

I've got a patch for getgrent.c for you to try at the end of this
message. This should work on both -current and 2.1.x. First, some
discussion.

> With the following program:
> 
> ------
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> #include <unistd.h>
> #include <grp.h>
> 
> main(int argc, char **argv)
> {
> 	char **g;
> 	struct group *gr;
> 
> 	gr = getgrgid((gid_t) 0);
> 	if (!gr)
> 		perror("no gr");

You should bail here if gr == NULL, otherwise you'll SEGV at the
next line.

Also, use warn() or err() rather than perror(); it's more BSDish. :)
 
> 	for (g = gr->gr_mem; ; ++g) {
> 		if (!*g) {
> 			printf(" -- done\n");
> 			exit(0);
> 		}
> 		printf("%s ", *g);
> 	}
> }
> ----------
> 
> and a YP group entry with:
> 
> pst@base$ ypmatch wheel group
> wheel:*:0:root,pst,tli,dennis,dock,pusateri,krishna,shermis

Looks ok.
 
> and no "wheel" entry in /etc/group, but +::: at the end, I get:
> 
> pst@base$ ./foo
> root pst tli dennis dock pusateri krishna shermis -- done
> 
> which is correct... we match the wheel group out of YP.

Yep.
 
> However, I want to specify that getgr* should get wheel group membership
> out of YP,  not have it work "by default".
> 
> I read the man page, and I think it wants me to put "+wheel" in my group file.

Hm. I have to think about this. Because of the way we use Berkeley DB
databases for the password system, /etc/master.passwd entries must
stick to the proper format, otherwise pwd_mkdb would get very confused.
So you can't have things like + or +:, which are legal to use in
/etc/passwd on other systems.

We don't use databases for groups though. I'm not sure I like this
syntax, but I've endeavoured to make it work right -- this time.

> When I do that, I get:
> 
> pst@base$ ./foo
> daemon  -- done
> 
> This is very bogus.  Daemon is certainly not in the wheel group, and the
> other stuff is missing.

Bug in grscan(): the _ypfound flag was being initialized to 0, but
it wasn't being cleared on each iteration of the for(;;) loop (so
it remained set incorrectly during a second pass through the loop
and caused the code to falsely select the next group in /etc/group,
daemon, of which daemon is a member. Fixed.

> With an /etc/group entry for wheel reading:
> 
> +wheel:::
> 
> I get
> 
> pst@base$ ./foo
>  -- done

Another bug in grscan(): after filling in the grp struct from YP,
the members were thrown away unconditionally to prepare for local
overriding which never happened (you didn't specify any local members).

In getpwent.c, this is handled using the pw_fields member of the
passwd struct: _pw_breakout_yp() can tell if it needs to preserve
local data for a particular field since pwd_mkdb sets a flag for
each non-empty field. If the breakout function sees that the flag
for a given field is set, it treats the field as being locally
overridden and tosses out the corresponding YP data. (The exception
is for the username: we always want the YP username.)

In getgrent.c, _gr_breakout_yp() has no such nifty mechanism, so we
do things backwards: we fetch the YP data first, fill in the whole
grp struct, then we read the local data and override fields only
if local data for a field exists.

Bleah.

> showing no entries.
> 
> with
> 
> +wheel:*
> 
> the libc function core dumps. :-(  Yet another bug.

Yes, though this one isn't strictly due to YP, I don't think.
This entry is actually invalid, and getgrent(3) is within its
rights to ignore it, though it should not blow up because of it.
The problem is that the code does not test for a potential NULL
pointer before diving into the member parsing code. Also fixed.

Note that this one fix is also outside of #ifdef YP since it looks
like it can happen even with YP turned off. If the code encounters
an entry like this, which leads to the NULL pointer condition, it
considers the entry to be bogus (which it is) and skips it.

I _think_ I got this mess behaving correctly now. Please test this
patch for me and let me know how things turn out. I also fixed
what I think was a memory leak in _getypgroup() while I was in
the area.

You should now be able to use the following syntaxes:

+wheel		Insert just the wheel group from YP, no overrides.
+wheel:::	Ditto.
+wheel:*::	Insert just the wheel group, override password to '*'.
+wheel:::foo    Insert just the wheel group, override members to foo.
+		Insert all YP entries, no overrides.
+::		Ditto
+:::		Ditto
+:*::		Ditto

You can't do global overrides such as +:*::foo,bar since it really
doesn't make much sense. Note that you also can't override GIDs
for the same reason (though it would be fairly easy to allow it).

-Bill

-- 
=============================================================================
-Bill Paul            (212) 854-6020 | System Manager, Master of Unix-Fu
Work:         wpaul@ctr.columbia.edu | Center for Telecommunications Research
Home:  wpaul@skynet.ctr.columbia.edu | Columbia University, New York City
=============================================================================
 "If you're ever in trouble, go to the CTR. Ask for Bill. He will help you."
=============================================================================

*** getgrent.c.orig	Wed Sep  4 23:33:52 1996
--- getgrent.c	Thu Sep  5 00:56:24 1996
***************
*** 165,171 ****
  		_gr_yp_enabled = 0;
  		while((line = fgetln(_gr_fp, &linelen)) != NULL) {
  			if(line[0] == '+') {
! 				if(line[1] && !_gr_yp_enabled) {
  					_gr_yp_enabled = 1;
  				} else {
  					_gr_yp_enabled = -1;
--- 165,171 ----
  		_gr_yp_enabled = 0;
  		while((line = fgetln(_gr_fp, &linelen)) != NULL) {
  			if(line[0] == '+') {
! 				if(line[1] && line[1] != ':' && !_gr_yp_enabled) {
  					_gr_yp_enabled = 1;
  				} else {
  					_gr_yp_enabled = -1;
***************
*** 218,226 ****
  	register char *cp, **m;
  	char *bp;
  #ifdef YP
! 	int _ypfound = 0;
  #endif;
  	for (;;) {
  		if (!fgets(line, sizeof(line), _gr_fp))
  			return(0);
  		bp = line;
--- 218,229 ----
  	register char *cp, **m;
  	char *bp;
  #ifdef YP
! 	int _ypfound;
  #endif;
  	for (;;) {
+ #ifdef YP
+ 		_ypfound = 0;
+ #endif
  		if (!fgets(line, sizeof(line), _gr_fp))
  			return(0);
  		bp = line;
***************
*** 251,261 ****
  					return(0);
  				}
  			} else {
! 				if (!_getypgroup(&_gr_group, &_gr_group.gr_name[1],
  						"group.byname"))
  					continue;
  			/* We're going to override -- tell the world. */
- 				members[0] = NULL;
  				_ypfound++;
  			}
  		}
--- 254,270 ----
  					return(0);
  				}
  			} else {
! 				cp = &_gr_group.gr_name[1];
! 				if (search && name != NULL)
! 					if (strcmp(cp, name))
! 						continue;
! 				if (!_getypgroup(&_gr_group, cp,
  						"group.byname"))
  					continue;
+ 				if (search && name == NULL)
+ 					if (gid != _gr_group.gr_gid)
+ 						continue;
  			/* We're going to override -- tell the world. */
  				_ypfound++;
  			}
  		}
***************
*** 268,284 ****
  				continue;
  			}
  		}
  		if ((_gr_group.gr_passwd = strsep(&bp, ":\n")) == NULL)
! 			break;;
  		if (!(cp = strsep(&bp, ":\n")))
! 			continue;
  #ifdef YP
  		if (!_ypfound)
  #endif
  		_gr_group.gr_gid = atoi(cp);
  		if (search && name == NULL && _gr_group.gr_gid != gid)
  			continue;
  		cp = NULL;
  		for (m = _gr_group.gr_mem = members;; bp++) {
  			if (m == &members[MAXGRP - 1])
  				break;
--- 277,323 ----
  				continue;
  			}
  		}
+ #ifdef YP
+ 		if ((cp = strsep(&bp, ":\n")) == NULL)
+ 			if (_ypfound)
+ 				return(1);
+ 			else
+ 				break;
+ 		if (strlen(cp) || !_ypfound)
+ 			_gr_group.gr_passwd = cp;
+ #else
  		if ((_gr_group.gr_passwd = strsep(&bp, ":\n")) == NULL)
! 			break;
! #endif
  		if (!(cp = strsep(&bp, ":\n")))
! 			if (_ypfound)
! 				return(1);
! 			else
! 				continue;
  #ifdef YP
+ 		/*
+ 		 * Hurm. Should we be doing this? We allow UIDs to
+ 		 * be overridden -- what about GIDs?
+ 		 */
  		if (!_ypfound)
  #endif
  		_gr_group.gr_gid = atoi(cp);
  		if (search && name == NULL && _gr_group.gr_gid != gid)
  			continue;
  		cp = NULL;
+ 		if (bp == NULL) /* !!! Must check for this! */
+ 			break;
+ #ifdef YP
+ 		if ((cp = strsep(&bp, ":\n")) == NULL)
+ 			break;
+ 
+ 		if (!strlen(cp) && _ypfound)
+ 			return(1);
+ 		else
+ 			members[0] = NULL;
+ 		bp = cp;
+ 		cp = NULL;
+ #endif
  		for (m = _gr_group.gr_mem = members;; bp++) {
  			if (m == &members[MAXGRP - 1])
  				break;
***************
*** 376,383 ****
  	if(s) *s = '\0';
  
  	if(resultlen >= sizeof resultbuf) return 0;
! 	strcpy(resultbuf, result);
! 	result = resultbuf;
  	return(_gr_breakout_yp(gr, resultbuf));
  
  }
--- 415,422 ----
  	if(s) *s = '\0';
  
  	if(resultlen >= sizeof resultbuf) return 0;
! 	strncpy(resultbuf, result, resultlen);
! 	free(result);
  	return(_gr_breakout_yp(gr, resultbuf));
  
  }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199609050506.BAA16389>