#!/usr/bin/perl -w # -*- perl -*- # # $Id: we_user,v 1.18 2005/05/10 12:02:04 eserte Exp $ # Author: Slaven Rezic # # Copyright (C) 2002,2004,2005 Slaven Rezic. # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, see the file COPYING. # # Mail: slaven@rezic.de # WWW: http://we-framework.sourceforge.net # use strict; use Getopt::Long; use vars qw($VERSION); $VERSION = sprintf("%d.%02d", q$Revision: 1.18 $ =~ /(\d+)\.(\d+)/); my @args; my $class = "WE::DB::ComplexUser"; my $contained_in; my $force_dd; my $rootdir = "."; my $userdb_file; my $onlineuserdb_file; my $need_rw = 1; my $show_version; my @inc; use WE::DB::Info; my $info = WE::DB::Info->new; $info->load; my %opt = $info->getopt; $class = $opt{userdbclass} if defined $opt{userdbclass}; $contained_in = $opt{userdbclass_file} if defined $opt{userdbclass_file}; @inc = @{ $opt{inc} } if defined $opt{inc}; Getopt::Long::config('pass_through', 'no_auto_abbrev'); GetOptions("class=s" => \$class, "containedin=s" => \$contained_in, "forcedd|forcedatadumper!" => \$force_dd, "rootdir=s" => \$rootdir, "userdb=s" => \$userdb_file, "onlineuserdb=s" => \$onlineuserdb_file, 'inc=s@' => \@inc, 'version' => \$show_version, ); Getopt::Long::config('no_pass_through'); if ($show_version) { print "$0 version $VERSION\n"; exit 0; } if (@inc) { unshift @INC, @inc; } my $command = shift @ARGV; my %cmdarg; if ($command =~ /^-/) { usage("Wrong command line option $command"); } elsif ($command eq 'show') { $need_rw = 0; } elsif ($command =~ /^(add|add-if-not-exists)$/) { if (!GetOptions('u|user=s' => \$cmdarg{User}, 'p|pw|password=s' => \$cmdarg{Password}, 'n|name|fullname=s' => \$cmdarg{Fullname}, 'g|groups=s' => \$cmdarg{GroupString}, 'email=s' => \$cmdarg{Email}, )) { usage("wrong arguments for $command"); } } elsif ($command =~ /^(add-group|add-group-if-not-exists)$/) { if (!GetOptions("g|group=s" => \$cmdarg{Group}, "desc|description=s" => \$cmdarg{Description}, )) { usage("wrong arguments for $command"); } } elsif ($command =~ /^user-exists$/) { if (!GetOptions('u|user=s' => \$cmdarg{User}, )) { usage("Wrong argument for user-exists"); } if (!defined $cmdarg{User}) { usage("user-exists needs the -u argument"); } } elsif ($command =~ /^(del|delete)$/) { if (!GetOptions('u|user=s' => \$cmdarg{User}, )) { usage("wrong arguments for del"); } $command = "del"; } elsif ($command eq 'passwd') { if (!GetOptions('u|user=s' => \$cmdarg{User}, 'p|pw|password=s' => \$cmdarg{Password}, )) { usage("wrong arguments for passwd"); } } elsif ($command =~ /^(update|change)$/) { if (!GetOptions('u|user=s' => \$cmdarg{User}, 'p|pw|password=s' => \$cmdarg{Password}, 'n|name|fullname=s' => \$cmdarg{Fullname}, 'g|groups=s' => \$cmdarg{GroupString}, 'k|key=s' => \$cmdarg{Key}, 'v|val|value=s' => \$cmdarg{Value}, 'email=s' => \$cmdarg{Email}, )) { usage("wrong arguments for update"); } $command = "update"; } elsif ($command =~ /^(dbinfo|meta)$/) { if (!GetOptions('k|key=s' => \$cmdarg{Key}, 'v|val|value=s' => \$cmdarg{Value}, )) { usage("wrong arguments for dbinfo"); } $command = "dbinfo"; } elsif ($command =~ /^show(?:dbinfo|meta)$/) { if (!GetOptions('k|key=s' => \$cmdarg{Key}, )) { usage("wrong arguments for showdbinfo"); } $command = "showdbinfo"; } else { usage("Invalid command $command"); } if (!defined $userdb_file) { if (-d $rootdir) { $userdb_file = "$rootdir/userdb.db"; } else { die "$rootdir is not a directory"; } } if (@ARGV) { die "Extra arguments: @ARGV"; } my $module = $class; if ($contained_in) { $module = $contained_in; } eval 'require ' . $module; die $@ if $@; # Check if the file exists already and has the correct format if (-e $userdb_file) { my $db; # XXX why is this eval not quiet??? eval { $db = $class->new(undef, $userdb_file, -connect => 1, -readonly => 1); }; if ($@ || !$db) { #warn $@; } else { die "Wrong class for $userdb_file?" if !$db->check_data_format; } } my $db = get_db(); if ($onlineuserdb_file) { require WE::DB::OnlineUser; my $online_db = WE::DB::OnlineUser->new(undef, $onlineuserdb_file); die "Can't open/create WE::DB::OnlineUser database from $onlineuserdb_file" if !$online_db; } if ($command eq 'show') { if (!$force_dd && eval { require YAML }) { print YAML::Dump($db->{DB}), "\n"; } else { require Data::Dumper; print Data::Dumper->new([$db->{DB}],[])->Indent(1)->Useqq(1)->Dump; } } elsif ($command eq 'add-if-not-exists') { if (!defined $cmdarg{User}) { die "Username necessary!"; } if (!$db->user_exists($cmdarg{User})) { add_user(); } } elsif ($command eq 'add') { add_user(); } elsif ($command eq 'add-group-if-not-exists' || $command eq 'add-group') { if (!defined $cmdarg{Group}) { die "Groupname necessary!"; } my $group_obj = $db->GroupObjClass->new; $group_obj->Groupname($cmdarg{Group}); if (defined $cmdarg{Description}) { $group_obj->Description($cmdarg{Description}); } my $ret = $db->add_group_definition($group_obj); if ($command eq 'add-group-if-not-exists' && $ret eq $db->ERROR_GROUP_EXISTS) { # ignore } elsif ($ret ne $db->ERROR_OK) { die "Cannot add group $cmdarg{Group}, error code: $ret"; } } elsif ($command eq 'user-exists') { if ($db->user_exists($cmdarg{User})) { exit 0; } else { exit 1; } } elsif ($command eq 'del') { if (!defined $cmdarg{User}) { die "Username necessary!"; } $db->delete_user($cmdarg{User}); } elsif ($command eq 'passwd') { if (!defined $cmdarg{User}) { die "Username necessary!"; } $cmdarg{Password} = get_password($cmdarg{User}) if !defined $cmdarg{Password}; $db->update_user($cmdarg{User}, $cmdarg{Password}, undef, undef); } elsif ($command eq 'update') { if (!defined $cmdarg{User}) { die "Username necessary!"; } $db->update_user($cmdarg{User}, $cmdarg{Password}, $cmdarg{Fullname}, undef); if (defined $cmdarg{GroupString}) { foreach my $group ($db->get_groups($cmdarg{User})) { $db->delete_group($cmdarg{User}, $group); } foreach my $group (split /,/, $cmdarg{GroupString}) { if ((my $err = $db->add_group($cmdarg{User}, $group)) != $db->ERROR_OK) { die "Error $err while adding group $group for $cmdarg{User}"; } } } my %user_args; if (defined $cmdarg{Key}) { $user_args{$cmdarg{Key}} = $cmdarg{Value}; } if (defined $cmdarg{Email}) { $user_args{Email} = $cmdarg{Email}; } if (%user_args) { my $u = $db->get_user_object($cmdarg{User}); if (!$u) { die "Can't get user object"; } while(my($k,$v) = each %user_args) { $u->{$k} = $v; } $db->set_user_object($u); } } elsif ($command eq 'dbinfo') { # XXX Should not poke in the internals! my $dbinfo = $db->DB->{__DBINFO__}; my $dbinfo_usage = <$method($cmdarg{Value}); $db->DB->{__DBINFO__} = $dbinfo; } elsif ($command eq 'showdbinfo') { # XXX Should not poke in the internals! my $dbinfo = $db->DB->{__DBINFO__}; my $dbinfo_usage = <$method, "\n"; } sub add_user { if (!defined $cmdarg{User}) { die "Username necessary!"; } my %user_args = (Username => $cmdarg{User}, Password => $cmdarg{Password}, Realname => $cmdarg{Fullname}, ); if ($cmdarg{Email}) { $user_args{Email} = $cmdarg{Email}; } my $userobj = $db->UserObjClass->new(%user_args); if ((my $err = $db->add_user_object($userobj)) != $db->ERROR_OK) { die "Error (code=$err) while adding user $cmdarg{User}"; } if ($cmdarg{GroupString}) { foreach my $group (split /,/, $cmdarg{GroupString}) { if ((my $err = $db->add_group($cmdarg{User}, $group)) != $db->ERROR_OK) { die "Error (code=$err) while adding group $group for $cmdarg{User}"; } } } } sub get_db { my(%args) = @_; my $db = $class->new(undef, $userdb_file, -readonly => !$need_rw); die "Can't open $class database from $userdb_file" if !$db; $db; } sub usage { my($error) = @_; require Pod::Usage; print STDERR $error, "\n"; Pod::Usage::pod2usage(1); } sub get_password { my $user = shift; my $password; if (eval { require Term::ReadKey; 1 }) { while (1) { print STDERR "Password for $user: "; Term::ReadKey::ReadMode('noecho'); chomp($password = Term::ReadKey::ReadLine(0)); Term::ReadKey::ReadMode(0); print STDERR "\nRetype password for $user: "; Term::ReadKey::ReadMode('noecho'); chomp(my $retype_password = Term::ReadKey::ReadLine(0)); Term::ReadKey::ReadMode(0); print STDERR "\n"; last if $password eq $retype_password; print STDERR "Password mismatch. Please retry again.\n"; }; } else { print STDERR "WARNING: Term::ReadKey could not be loaded, therefore the password will be visible on the screen. Password for $user: "; chomp($password = ); } $password; } sub normalize_dbinfo_key { my($key) = @_; if ($key =~ /^(CryptMode|crypt)$/i) { "CryptMode"; } elsif ($key =~ /^InvalidChars$/i) { "InvalidChars"; } elsif ($key =~ /^InvalidGroupChars$/i) { "InvalidGroupChars"; } else { undef; } } __END__ =head1 NAME we_user - manipulate the web.editor user database =head1 SYNOPSIS we_user [-class classname] [-containedin modulename] [-rootdir dir | -userdb file -onlineuserdb file] command options ... =head1 DESCRIPTION =head2 COMMANDS Valid commands are: =over =item show Show the whole database =item add -u I -p I [-n "I"] [-g I,I,...] [-email I] Add a new user with a password and optionaly a real name and groups. =item add-if-not-exists -u I -p I [-n "I"] [-g I,I,...] [-email I] Like C, but do not fail if user already exists. =item del -u I Delete the named user (by username). =item passwd -u I -p I Change the password for I. The C<-p I> option may be omitted, in this case the password is queried in the terminal (recommended). =item update -u I [-p I] [-n "I"] [-g I,I,...] [-email I] Change attributes for I. =item dbinfo -k I -v I Change database meta data. =item showdbinfo -k I Print the value of the named key. =item user-exists -u I Exit with 0 if the named user exists and with 1 if the user does not exist. =back =head2 OPTIONS =over =item -class I WE_Framework UserDB class e.g. L or L. Default is C. =item -containedin I Set this if the UserDB class is contained in another module =item -rootdir I The root directory of the database (can be used instead of specifying C<-userdb>). By default the current directory is used. =item -userdb I The user database file. =item -onlineuserdb The online user database file =back =head1 AUTHOR Slaven Rezic =head1 SEE ALSO L, L. =cut