#!/usr/local/bin/perl # ==================================================================== # The Apache Software License, Version 1.1 # # Copyright (c) 2000 The Apache Software Foundation. All rights # reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # 3. The end-user documentation included with the redistribution, # if any, must include the following acknowledgment: # "This product includes software developed by the # Apache Software Foundation (http://www.apache.org/)." # Alternately, this acknowledgment may appear in the software itself, # if and wherever such third-party acknowledgments normally appear. # # 4. The names "Apache" and "Apache Software Foundation" must # not be used to endorse or promote products derived from this # software without prior written permission. For written # permission, please contact apache@apache.org. # # 5. Products derived from this software may not be called "Apache", # nor may "Apache" appear in their name, without prior written # permission of the Apache Software Foundation. # # THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR # ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # ==================================================================== # # This software consists of voluntary contributions made by many # individuals on behalf of the Apache Software Foundation. For more # information on the Apache Software Foundation, please see # . # # Portions of this software are based upon public domain software # originally written at the National Center for Supercomputing Applications, # University of Illinois, Urbana-Champaign. # #for more functionality see the HTTPD::UserAdmin module: # http://www.perl.com/CPAN/modules/by-module/HTTPD/HTTPD-Tools-x.xx.tar.gz # # usage: dbmmanage package dbmmanage; # -ldb -lndbm -lgdbm BEGIN { @AnyDBM_File::ISA = qw(DB_File NDBM_File GDBM_File) } use strict; use Fcntl; use AnyDBM_File (); my($file,$command,$key,$crypted_pwd) = @ARGV; usage() unless $file and $command and defined &{$dbmc::{$command}}; # if your osname is in $newstyle_salt, then use new style salt (starts with '_' and contains # four bytes of iteration count and four bytes of salt). Otherwise, just use # the traditional two-byte salt. # see the man page on your system to decide if you have a newer crypt() lib. # I believe that 4.4BSD derived systems do (at least BSD/OS 2.0 does). # The new style crypt() allows up to 20 characters of the password to be # significant rather than only 8. my $newstyle_salt = join '|', qw{bsdos}; #others? # remove extension if any my $chop = join '|', qw{db.? pag dir}; $file =~ s/\.($chop)$//; my $is_update = $command eq "update"; my $Is_Win32 = $^O eq "MSWin32"; my %DB = (); my @range = (); my($mode, $flags) = $command =~ /^(?:view|check)$/ ? (0644, O_RDONLY) : (0644, O_RDWR|O_CREAT); tie %DB, "AnyDBM_File", $file, $flags, $mode || die "Can't tie $file: $!"; dbmc->$command(); untie %DB; sub usage { my $cmds = join "|", sort keys %dbmc::; die "usage: $0 filename [$cmds] [username]\n"; } my $x; sub genseed { my $psf; for (qw(-xlwwa -le)) { `ps $_ 2>/dev/null`; $psf = $_, last unless $?; } srand (time ^ $$ ^ unpack("%L*", `ps $psf | gzip -f`)); @range = (qw(. /), '0'..'9','a'..'z','A'..'Z'); $x = int scalar @range; } sub randchar { join '', map $range[rand $x], 1..shift||1; } sub salt { my $newstyle = $^O =~ /(?:$newstyle_salt)/; genseed() unless @range; return $newstyle ? join '', "_", randchar, "a..", randchar(4) : randchar(2); } sub getpass { my $prompt = shift || "Enter password:"; unless($Is_Win32) { open STDIN, "/dev/tty" or warn "couldn't open /dev/tty $!\n"; system "stty -echo;"; } my($c,$pwd); print STDERR $prompt; while (($c = getc(STDIN)) ne '' and $c ne "\n" and $c ne "\r") { $pwd .= $c; } system "stty echo" unless $Is_Win32; print STDERR "\n"; die "Can't use empty password!\n" unless length $pwd; return $pwd; } sub dbmc::update { die "Sorry, user `$key' doesn't exist!\n" unless $DB{$key}; dbmc->adduser; } sub dbmc::add { die "Can't use empty password!\n" unless $crypted_pwd; unless($is_update) { die "Sorry, user `$key' already exists!\n" if $DB{$key}; } $DB{$key} = $crypted_pwd; my $action = $is_update ? "updated" : "added"; print "User $key $action with password encrypted to $DB{$key}\n"; } sub dbmc::adduser { my $value = getpass "New password:"; die "They don't match, sorry.\n" unless getpass("Re-type new password:") eq $value; $crypted_pwd = crypt $value, caller->salt; dbmc->add; } sub dbmc::delete { die "Sorry, user `$key' doesn't exist!\n" unless $DB{$key}; delete $DB{$key}, print "`$key' deleted\n"; } sub dbmc::view { print $key ? "$key:$DB{$key}\n" : map { "$_:$DB{$_}\n" if $DB{$_} } keys %DB; } sub dbmc::check { die "Sorry, user `$key' doesn't exist!\n" unless $DB{$key}; print crypt(getpass(), $DB{$key}) eq $DB{$key} ? "password ok\n" : "password mismatch\n"; } sub dbmc::import { while(defined($_ = ) and chomp) { ($key,$crypted_pwd) = split /:/, $_, 2; dbmc->add; } }