Newsgroup: comp.os.minix


Path: icdoc!mvax.cc.ic.ac.uk!dds
From: dds@cc.ic.ac.uk (Diomidis Spinellis)
Newsgroups: comp.os.minix
Subject: Group commands for Minix
Keywords: Minix, groups
Message-ID: <1988Mar3.220039.5819@mvax.cc.ic.ac.uk>
Date: 3 Mar 88 20:00:38 GMT
Reply-To: dds@cc.ic.ac.uk (Diomidis Spinellis)
Organization: Computer Center, Imperial College, London, England
Lines: 450
Content-Length: 9876

Support for the shell newgrp builtin. See the README file and the newgrp
source.

------8<-----CUT-HERE-----------------------------------------------------------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	README
#	chgrp.c
#	getgrent.c
#	grp.h
#	id.c
#	newgrp.c
# This archive created: Thu Mar  3 19:08:39 WET 1988
export PATH; PATH=/bin:$PATH
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
cat << \SHAR_EOF > 'README'
     Here is group support for Minix.  It  consists  of  the
newgrp  and  chgrp commands, a modified getgrent.c and grp.h
that support group members  and  the  id  command  used  for
debugging.

     Newgrp is a shell built in. No change is needed to  the
shell  as  the  shell  already  knows  about it. When a user
enters  the  newgrp  command  the  shell  does  an  exec  on
/bin/newgrp  or /usr/bin/newgrp which should be installed as
setuid root. This checks if the user is  allowed  to  change
group  and  changes the real and effective group id. It then
execs another shell.

     Chgrp works like the  chown  command.   The  format  of
/etc/group file needed is :

     groupname:passwd:gid:user,user ...

     The password can be an  encrypted  password,  empty  or
``*''.  The  optional  list of users are users who belong to
that group without it being their default one.

     In order to change group you  enter  newgrp  optionally
followed  by  a group name. Newgrp without groupname returns
yyou to your default group.

     If the group has a password and the user has not or  if
the  group  has a password and the user is not in the member
list of the group the user is prompted for the  group  pass-
word.

     The user always gets a new shell no matter if  he  gets
into a new group or not.

BUGS

The - option in newgrp is not supported.

AUTHOR

Diomidis D. Spinellis (dds@cc.ic.ac.uk)

SHAR_EOF
fi # end of overwriting check
if test -f 'chgrp.c'
then
	echo shar: will not over-write existing file "'chgrp.c'"
else
cat << \SHAR_EOF > 'chgrp.c'
/*
 * chgrp username file ...
 * 
 * By Diomidis D. Spinellis
 * Heavilly based on chown by Patrick van Kleef
 *
 */

#include "grp.h"
#include "../h/type.h"
#include "stat.h"
#include "stdio.h"

main (argc, argv)
int   argc;
char *argv[];
{
	int     i,
	status = 0;
	struct group  *grp, *getgrnam ();
	struct stat stbuf;

	if (argc < 3) {
		fprintf (stderr,"Usage: chgrp gid file ...\n");
		exit (1);
	}

	if ((grp = getgrnam (argv[1])) == 0) {
		fprintf (stderr,"Unknown group id: %s\n", argv[1]);
		exit (4);
	}

	for (i = 2; i < argc; i++) {
		if (stat (argv[i], &stbuf) < 0) {
			perror (argv[i]);
			status++;
		}
		else
			if (chown (argv[i], stbuf.st_uid, grp -> gr_gid) < 0) {
				fprintf (stderr,"%s: not changed\n", argv[i]);
				status++;
			}
	}
	exit (status);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'getgrent.c'
then
	echo shar: will not over-write existing file "'getgrent.c'"
else
cat << \SHAR_EOF > 'getgrent.c'
/*
 * get entry from group file
 * 
 * By: Patrick van Kleef
 * Modified by Diomidis Spinellis.
 */

#include "../include/grp.h"

#define PRIVATE static

PRIVATE char _gr_file[] = "/etc/group";
PRIVATE char _grbuf[256];
PRIVATE char _buffer[1024];
PRIVATE char *_membuf[32];
PRIVATE char *_pnt;
PRIVATE char *_buf;
PRIVATE int  _gfd = -1;
PRIVATE int  _bufcnt;
PRIVATE struct group grp;

setgrent ()
{
        if (_gfd >= 0)
	        lseek (_gfd, 0L, 0);
        else
	        _gfd = open (_gr_file, 0);

        _bufcnt = 0;
        return (_gfd);
}


endgrent () 
{
        if (_gfd >= 0)
	        close (_gfd);

        _gfd = -1;
        _bufcnt = 0;
}


static getline () 
{
        if (_gfd < 0 && setgrent () < 0)
	        return (0);

        _buf = _grbuf;
        do {
	        if (--_bufcnt <= 0){
	                if ((_bufcnt = read (_gfd, _buffer, 1024)) <= 0)
		                return (0);
	                else
		                _pnt = _buffer;
		}
	        *_buf++ = *_pnt++;
        } while (*_pnt != '\n');
        _pnt++;
        _bufcnt--;
        *_buf = 0;
        _buf = _grbuf;
        return (1);
}

static skip_period () 
{
        while (*_buf != ':')
	        _buf++;
        *_buf++ = '\0';
}

struct group   *getgrent () 
{
	register i ;
        if (getline () == 0)
               return (0);

        grp.gr_name = _buf;
        skip_period ();
        grp.gr_passwd = _buf;
        skip_period ();
        grp.gr_gid = atoi (_buf);
        skip_period ();
	for( i = 0 ; *_buf ; i++ ){
		_membuf[i] = _buf ;
		while( *_buf && *_buf != ',' )
			_buf++ ;
		if( *_buf ) 
			*_buf++ = '\0' ;
	}
	_membuf[i] = (char *) 0 ;
	grp.gr_mem = &_membuf[0] ;
        return (&grp);
}

struct group   *getgrnam (name)
char   *name;
{
        struct group *grp;

        setgrent ();
        while ((grp = getgrent ()) != 0)
	        if (!strcmp (grp -> gr_name, name))
	                break;
        endgrent ();
        if (grp != 0)
	        return (grp);
        else
	        return (0);
}

struct group   *getgrgid (gid)
int     gid;
{
        struct group   *grp;

        setgrent ();
        while ((grp = getgrent ()) != 0)
	        if (grp -> gr_gid == gid)
	                break;
        endgrent ();
        if (grp != 0)
	        return (grp);
        else
	        return (0);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'grp.h'
then
	echo shar: will not over-write existing file "'grp.h'"
else
cat << \SHAR_EOF > 'grp.h'
struct	group { 
	char	*gr_name;
	char	*gr_passwd;
	int	gr_gid;
	char	**gr_mem;
};
SHAR_EOF
fi # end of overwriting check
if test -f 'id.c'
then
	echo shar: will not over-write existing file "'id.c'"
else
cat << \SHAR_EOF > 'id.c'
/*
 * id - Print the real and effective user and group id
 *
 * By Diomidis D. Spinellis
 */

#include <stdio.h>
#include <pwd.h>
#include <grp.h>

main()
{
	printf("Real      : ") ;
	idprint( getuid(), getgid() ) ;
	printf("Effective : ") ;
	idprint( geteuid(), getegid() ) ;
	_cleanup() ;
	exit( 0 ) ;
}

idprint( uid, gid)
int uid, gid ;
{
	struct passwd *pw, *getpwuid() ;
	struct group *gr, *getgrgid() ;
	pw = getpwuid( uid ) ;
	gr = getgrgid( gid ) ;
	printf("user=%d (%s)    group=%d (%s)\n", 
		uid, 
		pw ? pw->pw_name : "unknown",
		gid,
		gr ? gr->gr_name : "unknown"
	) ;
	return ;
}
SHAR_EOF
fi # end of overwriting check
if test -f 'newgrp.c'
then
	echo shar: will not over-write existing file "'newgrp.c'"
else
cat << \SHAR_EOF > 'newgrp.c'
/*
 * newgrp - Change current group
 *
 * By Diomidis D. Spinellis
 *
 */

#include <grp.h>
#include <pwd.h>
#include <sgtty.h>

/* Error messages */
#define E_USAGE "Usage : newgrp [ group ]\n"
#define E_UNKNOWN "Unknown group\n"
#define E_SORRY "Sorry !\n"
#define E_NOSHELL "You have no shell\n"

/* This is needed globaly */
struct passwd *pw ;

main(argc, argv)
	int argc ;
	char *argv[] ;
{
	char    password[14];
	struct group *gr ;
	struct sgttyb   args;
	struct passwd *getpwuid ();
	struct group *getgrnam ();
	char   *crypt ();
	int    nr ;	

	switch( argc ){
	default :
		std_err( E_USAGE ) ;
		newshell( -2 ) ;
	case 1 :
		/* Change to the users default group */
		pw = getpwuid( getuid() ) ;
		newshell( pw->pw_gid ) ;
	case 2 :
		/* Change to the group specified */
		if( ! (gr = getgrnam( argv[1] ) ) ){
			std_err( E_UNKNOWN ) ;
			newshell( -2 ) ;
		}
		pw = getpwuid( getuid() ) ;
		/* A user may change group if :
		 * He is root OR
		 * the group has an empty password OR
		 * 	the user is a member of the group AND 
		 *	the user has a non empty password OR
		 * the group has a password and the user enters it correctly
		 */
		if( getuid() == 0 || *gr->gr_passwd == '\0' )
			newshell( gr->gr_gid ) ;
		if( ismember( pw->pw_name, gr->gr_mem ) && *pw->pw_passwd != '\0' )
			newshell( gr->gr_gid ) ;
		if( isequal( gr->gr_passwd, "*" ) )
			newshell( -1 ) ;
		/* 
		 * Ask for password
		 * (Code copied from su.c)
		 */
		std_err("Password: ");
		ioctl (0, TIOCGETP, &args);	/* get parameters */
		args.sg_flags = args.sg_flags & (~ECHO);
		ioctl (0, TIOCSETP, &args); 
		nr = read (0, password, 14);
		password[nr - 1] = '\0';
		std_err("\n") ;
		args.sg_flags = args.sg_flags | ECHO;
		ioctl (0, TIOCSETP, &args); 
		if( isequal(gr->gr_passwd, crypt (password, gr->gr_passwd) ) )
			newshell( gr->gr_gid ) ;
		else
			newshell( -1 ) ;
	}
}

/*
 * Give the user a new shell with a specified gid.
 * If the gid is -1 say you are sorry.
 */
newshell( gid )
	int gid ;
{
	char *shell = "/bin/sh" ;

	if( gid >= 0 )
		setgid( gid ) ;
	else if( gid == -1 )
		std_err( E_SORRY ) ;
	setuid( pw->pw_uid ) ;
	if( pw->pw_shell[0] )
		shell = pw->pw_shell ;
	execn( shell ) ;
	execn( "/bin/sh" ) ;
	execn( "/usr/bin/sh" ) ;
	std_err( E_NOSHELL ) ;
	exit(3);
}

/*
 * Return true if the two strings are equal
 */
int 
isequal( s1, s2 )
char *s1, *s2 ;
{
	while( *s1 && *s2 )
		if( *s1++ != *s2++ )
			return 0 ;
	return *s1 == *s2 ;
}

/*
 * Return true if name n is in the null terminated array of groups g
 */
int 
ismember(n, g)
char *n, **g ;
{
	register i ;
	for( i = 0 ; g[i] ; i++ )
		if( isequal(n, g[i] ) )
			return 1 ;
	return 0 ;
}
SHAR_EOF
fi # end of overwriting check
#	End of shell archive
exit 0

-- 
Diomidis D. Spinellis, Imperial College |  echo `/usr/games/fortune -o`
dds@cc.ic.ac.uk                         |



Newsgroup comp.os.minix contents
Newsgroup list
Diomidis Spinellis home page

Creative Commons License Unless otherwise expressly stated, all original material on this page created by Diomidis Spinellis is licensed under a Creative Commons Attribution-Share Alike 3.0 Greece License.