dds@cc.ic.ac.uk (Diomidis Spinellis) (03/04/88)
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 |