2007-11-05 18:42:38 +03:00
#!/usr/bin/perl
#
use strict ;
use Getopt::Long ;
use Cwd qw( abs_path ) ;
my $ opt_help = 0 ;
2009-05-28 00:35:14 +04:00
my $ opt_passwd_path = undef ;
my $ opt_group_path = undef ;
2007-11-05 18:42:38 +03:00
my $ opt_action = undef ;
my $ opt_type = undef ;
my $ opt_name = undef ;
2009-05-28 12:39:37 +04:00
my $ opt_member = undef ;
2010-03-19 11:50:56 +03:00
my $ opt_gid = 65534 ; # nogroup gid
2007-11-05 18:42:38 +03:00
my $ passwdfn = undef ;
my $ groupfn = undef ;
2009-05-28 12:39:37 +04:00
my $ memberfn = undef ;
2007-11-05 18:42:38 +03:00
my $ actionfn = undef ;
2010-03-19 11:50:56 +03:00
sub passwd_add ($$$$$) ;
sub passwd_delete ($$$$$) ;
sub group_add ($$$$$) ;
sub group_delete ($$$$$) ;
sub member_add ($$$$$) ;
sub member_delete ($$$$$) ;
2009-05-28 12:39:37 +04:00
sub check_path ($$) ;
2007-11-05 18:42:38 +03:00
my $ result = GetOptions (
'help|h|?' = > \ $ opt_help ,
2009-05-28 00:35:14 +04:00
'passwd_path=s' = > \ $ opt_passwd_path ,
'group_path=s' = > \ $ opt_group_path ,
2007-11-05 18:42:38 +03:00
'action=s' = > \ $ opt_action ,
'type=s' = > \ $ opt_type ,
2009-05-28 12:39:37 +04:00
'name=s' = > \ $ opt_name ,
2010-03-19 11:50:56 +03:00
'member=s' = > \ $ opt_member ,
'gid=i' = > \ $ opt_gid
2007-11-05 18:42:38 +03:00
) ;
sub usage ( $ ; $ )
{
my ( $ ret , $ msg ) = @ _ ;
print $ msg . "\n\n" if defined ( $ msg ) ;
print " usage:
- - help | - h | - ? Show this help .
2009-05-28 00:35:14 +04:00
- - passwd_path <path> Path of the 'passwd' file .
- - group_path <path> Path of the 'group' file .
2007-11-05 18:42:38 +03:00
2009-05-28 12:39:37 +04:00
- - type <type> 'passwd' , 'group' and 'member' are supported .
2007-11-05 18:42:38 +03:00
- - action <action> 'add' or 'delete' .
- - name <name> The name of the object .
2009-05-28 12:39:37 +04:00
- - member <member> The name of the member .
2010-03-19 11:50:56 +03:00
- - gid <gid> Primary Group ID for new users .
2007-11-05 18:42:38 +03:00
" ;
exit ( $ ret ) ;
}
usage ( 1 ) if ( not $ result ) ;
usage ( 0 ) if ( $ opt_help ) ;
if ( not defined ( $ opt_action ) ) {
usage ( 1 , "missing: --action [add|delete]" ) ;
}
if ( $ opt_action eq "add" ) {
$ passwdfn = \ & passwd_add ;
$ groupfn = \ & group_add ;
2009-05-28 12:39:37 +04:00
$ memberfn = \ & member_add ;
2007-11-05 18:42:38 +03:00
} elsif ( $ opt_action eq "delete" ) {
$ passwdfn = \ & passwd_delete ;
$ groupfn = \ & group_delete ;
2009-05-28 12:39:37 +04:00
$ memberfn = \ & member_delete ;
2007-11-05 18:42:38 +03:00
} else {
usage ( 1 , "invalid: --action [add|delete]: '$opt_action'" ) ;
}
if ( not defined ( $ opt_type ) ) {
2009-05-28 12:39:37 +04:00
usage ( 1 , "missing: --type [passwd|group|member]" ) ;
2007-11-05 18:42:38 +03:00
}
2009-05-28 12:39:37 +04:00
if ( $ opt_type eq "member" and not defined ( $ opt_member ) ) {
usage ( 1 , "missing: --member <member>" ) ;
}
my $ opt_fullpath_passwd ;
my $ opt_fullpath_group ;
2007-11-05 18:42:38 +03:00
if ( $ opt_type eq "passwd" ) {
$ actionfn = $ passwdfn ;
2009-05-28 12:39:37 +04:00
$ opt_fullpath_passwd = check_path ( $ opt_passwd_path , $ opt_type ) ;
2007-11-05 18:42:38 +03:00
} elsif ( $ opt_type eq "group" ) {
$ actionfn = $ groupfn ;
2009-05-28 12:39:37 +04:00
$ opt_fullpath_group = check_path ( $ opt_group_path , $ opt_type ) ;
} elsif ( $ opt_type eq "member" ) {
$ actionfn = $ memberfn ;
$ opt_fullpath_passwd = check_path ( $ opt_passwd_path , "passwd" ) ;
$ opt_fullpath_group = check_path ( $ opt_group_path , "group" ) ;
2007-11-05 18:42:38 +03:00
} else {
usage ( 1 , "invalid: --type [passwd|group]: '$opt_type'" )
}
if ( not defined ( $ opt_name ) ) {
usage ( 1 , "missing: --name <name>" ) ;
}
if ( $ opt_name eq "" ) {
usage ( 1 , "invalid: --name <name>" ) ;
}
2010-03-19 11:50:56 +03:00
exit $ actionfn - > ( $ opt_fullpath_passwd , $ opt_member , $ opt_fullpath_group , $ opt_name , $ opt_gid ) ;
2007-11-05 18:42:38 +03:00
2009-05-28 00:35:14 +04:00
sub check_path ($$)
{
my ( $ path , $ type ) = @ _ ;
if ( not defined ( $ path ) ) {
usage ( 1 , "missing: --$type\_path <path>" ) ;
}
if ( $ path eq "" or $ path eq "/" ) {
usage ( 1 , "invalid: --$type\_path <path>: '$path'" ) ;
}
my $ fullpath = abs_path ( $ path ) ;
if ( not defined ( $ fullpath ) ) {
usage ( 1 , "invalid: --$type\_path <path>: '$path'" ) ;
}
return $ fullpath ;
}
2007-11-05 18:42:38 +03:00
sub passwd_add_entry ($$) ;
sub passwd_load ($)
{
my ( $ path ) = @ _ ;
my @ lines ;
my $ passwd = undef ;
open ( PWD , "<$path" ) or die ( "Unable to open '$path' for read" ) ;
@ lines = <PWD> ;
close ( PWD ) ;
$ passwd - > { array } = ( ) ;
$ passwd - > { name } = { } ;
$ passwd - > { uid } = { } ;
$ passwd - > { path } = $ path ;
foreach my $ line ( @ lines ) {
passwd_add_entry ( $ passwd , $ line ) ;
}
return $ passwd ;
}
2009-05-20 04:06:22 +04:00
sub group_add_entry ($$) ;
sub group_load ($)
{
my ( $ path ) = @ _ ;
my @ lines ;
my $ group = undef ;
open ( GROUP , "<$path" ) or die ( "Unable to open '$path' for read" ) ;
@ lines = <GROUP> ;
close ( GROUP ) ;
$ group - > { array } = ( ) ;
$ group - > { name } = { } ;
$ group - > { gid } = { } ;
$ group - > { path } = $ path ;
foreach my $ line ( @ lines ) {
group_add_entry ( $ group , $ line ) ;
}
return $ group ;
}
2007-11-05 18:42:38 +03:00
sub passwd_lookup_name ($$)
{
my ( $ passwd , $ name ) = @ _ ;
return undef unless defined ( $ passwd - > { name } { $ name } ) ;
return $ passwd - > { name } { $ name } ;
}
2009-05-20 04:06:22 +04:00
sub group_lookup_name ($$)
{
my ( $ group , $ name ) = @ _ ;
return undef unless defined ( $ group - > { name } { $ name } ) ;
return $ group - > { name } { $ name } ;
}
2007-11-05 18:42:38 +03:00
sub passwd_lookup_uid ($$)
{
my ( $ passwd , $ uid ) = @ _ ;
return undef unless defined ( $ passwd - > { uid } { $ uid } ) ;
return $ passwd - > { uid } { $ uid } ;
}
2009-05-20 04:06:22 +04:00
sub group_lookup_gid ($$)
{
my ( $ group , $ gid ) = @ _ ;
return undef unless defined ( $ group - > { gid } { $ gid } ) ;
return $ group - > { gid } { $ gid } ;
}
2007-11-05 18:42:38 +03:00
sub passwd_get_free_uid ($)
{
my ( $ passwd ) = @ _ ;
my $ uid = 1000 ;
while ( passwd_lookup_uid ( $ passwd , $ uid ) ) {
$ uid + + ;
}
return $ uid ;
}
2009-05-20 04:06:22 +04:00
sub group_get_free_gid ($)
{
my ( $ group ) = @ _ ;
my $ gid = 1000 ;
while ( group_lookup_gid ( $ group , $ gid ) ) {
$ gid + + ;
}
return $ gid ;
}
2007-11-05 18:42:38 +03:00
sub passwd_add_entry ($$)
{
my ( $ passwd , $ str ) = @ _ ;
chomp $ str ;
my @ e = split ( ':' , $ str ) ;
push ( @ { $ passwd - > { array } } , \ @ e ) ;
$ passwd - > { name } { $ e [ 0 ] } = \ @ e ;
$ passwd - > { uid } { $ e [ 2 ] } = \ @ e ;
}
2009-05-20 04:06:22 +04:00
sub group_add_entry ($$)
{
my ( $ group , $ str ) = @ _ ;
chomp $ str ;
my @ e = split ( ':' , $ str ) ;
push ( @ { $ group - > { array } } , \ @ e ) ;
$ group - > { name } { $ e [ 0 ] } = \ @ e ;
$ group - > { gid } { $ e [ 2 ] } = \ @ e ;
}
2007-11-05 18:42:38 +03:00
sub passwd_remove_entry ($$)
{
my ( $ passwd , $ eref ) = @ _ ;
2009-01-12 15:04:40 +03:00
for ( my $ i = 0 ; defined ( $ passwd - > { array } [ $ i ] ) ; $ i + + ) {
2007-11-05 18:42:38 +03:00
if ( $ eref == $ passwd - > { array } [ $ i ] ) {
$ passwd - > { array } [ $ i ] = undef ;
}
}
delete $ passwd - > { name } { $ { $ eref } [ 0 ] } ;
delete $ passwd - > { uid } { $ { $ eref } [ 2 ] } ;
}
2009-05-20 04:10:12 +04:00
sub group_remove_entry ($$)
{
my ( $ group , $ eref ) = @ _ ;
for ( my $ i = 0 ; defined ( $ group - > { array } [ $ i ] ) ; $ i + + ) {
if ( $ eref == $ group - > { array } [ $ i ] ) {
$ group - > { array } [ $ i ] = undef ;
}
}
delete $ group - > { name } { $ { $ eref } [ 0 ] } ;
delete $ group - > { gid } { $ { $ eref } [ 2 ] } ;
}
2009-05-28 12:39:37 +04:00
sub group_add_member ($$$)
{
my ( $ group , $ eref , $ username ) = @ _ ;
my @ members ;
my $ str = @$ eref [ 3 ] || undef ;
if ( $ str ) {
@ members = split ( "," , $ str ) ;
}
foreach my $ member ( @ members ) {
if ( $ member and $ member eq $ username ) {
die ( "account[$username] is already member of '@$eref[0]'" ) ;
}
}
push ( @ members , $ username ) ;
my $ gwent = @$ eref [ 0 ] . ":x:" . @$ eref [ 2 ] . ":" . join ( "," , @ members ) ;
group_remove_entry ( $ group , $ eref ) ;
group_add_entry ( $ group , $ gwent ) ;
}
sub group_delete_member ($$$)
{
my ( $ group , $ eref , $ username ) = @ _ ;
my @ members = undef ;
my $ str = @$ eref [ 3 ] || undef ;
if ( $ str ) {
@ members = split ( "," , $ str ) ;
}
my @ new_members ;
my $ removed = 0 ;
foreach my $ member ( @ members ) {
if ( $ member and $ member ne $ username ) {
push ( @ new_members , $ member ) ;
} else {
$ removed = 1 ;
}
}
if ( $ removed != 1 ) {
die ( "account[$username] is not member of '@$eref[0]'" ) ;
}
my $ gwent = @$ eref [ 0 ] . ":x:" . @$ eref [ 2 ] . ":" . join ( "," , @ new_members ) ;
group_remove_entry ( $ group , $ eref ) ;
group_add_entry ( $ group , $ gwent ) ;
}
2007-11-05 18:42:38 +03:00
sub passwd_save ($)
{
my ( $ passwd ) = @ _ ;
my @ lines = ( ) ;
my $ path = $ passwd - > { path } ;
my $ tmppath = $ path . $$ ;
foreach my $ eref ( @ { $ passwd - > { array } } ) {
next unless defined ( $ eref ) ;
my $ line = join ( ':' , @ { $ eref } ) ;
push ( @ lines , $ line ) ;
}
open ( PWD , ">$tmppath" ) or die ( "Unable to open '$tmppath' for write" ) ;
print PWD join ( "\n" , @ lines ) . "\n" ;
close ( PWD ) ;
rename ( $ tmppath , $ path ) or die ( "Unable to rename $tmppath => $path" ) ;
}
2009-05-20 04:06:22 +04:00
sub group_save ($)
{
my ( $ group ) = @ _ ;
my @ lines = ( ) ;
my $ path = $ group - > { path } ;
my $ tmppath = $ path . $$ ;
foreach my $ eref ( @ { $ group - > { array } } ) {
next unless defined ( $ eref ) ;
my $ line = join ( ':' , @ { $ eref } ) ;
if ( scalar ( @ { $ eref } ) == 3 ) {
$ line . = ":" ;
}
push ( @ lines , $ line ) ;
}
open ( GROUP , ">$tmppath" ) or die ( "Unable to open '$tmppath' for write" ) ;
print GROUP join ( "\n" , @ lines ) . "\n" ;
close ( GROUP ) ;
rename ( $ tmppath , $ path ) or die ( "Unable to rename $tmppath => $path" ) ;
}
2010-03-19 11:50:56 +03:00
sub passwd_add ($$$$$)
2007-11-05 18:42:38 +03:00
{
2010-03-19 11:50:56 +03:00
my ( $ path , $ dummy , $ dummy2 , $ name , $ gid ) = @ _ ;
2007-11-05 18:42:38 +03:00
#print "passwd_add: '$name' in '$path'\n";
my $ passwd = passwd_load ( $ path ) ;
my $ e = passwd_lookup_name ( $ passwd , $ name ) ;
die ( "account[$name] already exists in '$path'" ) if defined ( $ e ) ;
my $ uid = passwd_get_free_uid ( $ passwd ) ;
my $ pwent = $ name . ":x:" . $ uid . ":" . $ gid . ":" . $ name . " gecos:/nodir:/bin/false" ;
passwd_add_entry ( $ passwd , $ pwent ) ;
passwd_save ( $ passwd ) ;
return 0 ;
}
2010-03-19 11:50:56 +03:00
sub passwd_delete ($$$$$)
2007-11-05 18:42:38 +03:00
{
2010-03-19 11:50:56 +03:00
my ( $ path , $ dummy , $ dummy2 , $ name , $ dummy3 ) = @ _ ;
2007-11-05 18:42:38 +03:00
#print "passwd_delete: '$name' in '$path'\n";
my $ passwd = passwd_load ( $ path ) ;
my $ e = passwd_lookup_name ( $ passwd , $ name ) ;
die ( "account[$name] does not exists in '$path'" ) unless defined ( $ e ) ;
passwd_remove_entry ( $ passwd , $ e ) ;
passwd_save ( $ passwd ) ;
return 0 ;
}
2010-03-19 11:50:56 +03:00
sub group_add ($$$$$)
2007-11-05 18:42:38 +03:00
{
2010-03-19 11:50:56 +03:00
my ( $ dummy , $ dummy2 , $ path , $ name , $ dummy3 ) = @ _ ;
2007-11-05 18:42:38 +03:00
#print "group_add: '$name' in '$path'\n";
2009-05-20 04:06:22 +04:00
my $ group = group_load ( $ path ) ;
my $ e = group_lookup_name ( $ group , $ name ) ;
die ( "group[$name] already exists in '$path'" ) if defined ( $ e ) ;
my $ gid = group_get_free_gid ( $ group ) ;
2009-05-28 12:39:37 +04:00
my $ gwent = $ name . ":x:" . $ gid . ":" . "" ;
2009-05-20 04:06:22 +04:00
group_add_entry ( $ group , $ gwent ) ;
group_save ( $ group ) ;
#printf("%d\n", $gid);
2007-11-05 18:42:38 +03:00
return 0 ;
}
2010-03-19 11:50:56 +03:00
sub group_delete ($$$$$)
2007-11-05 18:42:38 +03:00
{
2010-03-19 11:50:56 +03:00
my ( $ dummy , $ dummy2 , $ path , $ name , $ dummy3 ) = @ _ ;
2007-11-05 18:42:38 +03:00
#print "group_delete: '$name' in '$path'\n";
2009-05-20 04:10:12 +04:00
my $ group = group_load ( $ path ) ;
my $ e = group_lookup_name ( $ group , $ name ) ;
die ( "group[$name] does not exists in '$path'" ) unless defined ( $ e ) ;
group_remove_entry ( $ group , $ e ) ;
group_save ( $ group ) ;
2007-11-05 18:42:38 +03:00
return 0 ;
}
2009-05-28 12:39:37 +04:00
2010-03-19 11:50:56 +03:00
sub member_add ($$$$$)
2009-05-28 12:39:37 +04:00
{
2010-03-19 11:50:56 +03:00
my ( $ passwd_path , $ username , $ group_path , $ groupname , $ dummy ) = @ _ ;
2009-05-28 12:39:37 +04:00
#print "member_add: adding '$username' in '$passwd_path' to '$groupname' in '$group_path'\n";
my $ group = group_load ( $ group_path ) ;
my $ g = group_lookup_name ( $ group , $ groupname ) ;
die ( "group[$groupname] does not exists in '$group_path'" ) unless defined ( $ g ) ;
my $ passwd = passwd_load ( $ passwd_path ) ;
my $ u = passwd_lookup_name ( $ passwd , $ username ) ;
die ( "account[$username] does not exists in '$passwd_path'" ) unless defined ( $ u ) ;
group_add_member ( $ group , $ g , $ username ) ;
group_save ( $ group ) ;
return 0 ;
}
2010-03-19 11:50:56 +03:00
sub member_delete ($$$$$)
2009-05-28 12:39:37 +04:00
{
2010-03-19 11:50:56 +03:00
my ( $ passwd_path , $ username , $ group_path , $ groupname , $ dummy ) = @ _ ;
2009-05-28 12:39:37 +04:00
#print "member_delete: removing '$username' in '$passwd_path' from '$groupname' in '$group_path'\n";
my $ group = group_load ( $ group_path ) ;
my $ g = group_lookup_name ( $ group , $ groupname ) ;
die ( "group[$groupname] does not exists in '$group_path'" ) unless defined ( $ g ) ;
my $ passwd = passwd_load ( $ passwd_path ) ;
my $ u = passwd_lookup_name ( $ passwd , $ username ) ;
die ( "account[$username] does not exists in '$passwd_path'" ) unless defined ( $ u ) ;
group_delete_member ( $ group , $ g , $ username ) ;
group_save ( $ group ) ;
return 0 ;
}