Hi list,
I enhanced create-users.pl to write 'new' unique users directly to
Postgres or MySQL DBs if required.
As my knowledge in perl is limited someone will find some things are not
written in the most efficient way. Anyway, some people are using it and
so far it's working properly.
Uli
#!/usr/bin/perl
# Purpose: create lots of random users and passes
# for testing your radius server
# Read doc/README.testing for more information
# Postgres and MySQL support added 11/2003 Ulrich Walcher
# Used perl-modules: DBI, Crypt::PasswdMD5, DBD::Pg, DBD::mysql
use DBI;
use Crypt::PasswdMD5;
use strict;
######################
# Start editing here #
######################
# General
my $user_lenght = 8; # Length of the UserName
my $password_lenght = 8; # Lenght of the User-Password
my $user_attribute = "User-Password"; # use "User-Password" or "Crypt-Password"
# MySQL values
my $db_my_name = 'radius'; # Name of the MySQL database
my $db_my_host = 'localhost'; # IP address of the MySQL server
my $db_my_port = '3306'; # Connect port of the MySQL server
my $db_my_username = 'username'; # Username to connect to MySQL
my $db_my_password = 'password'; # Password to connect to MySQL
my $db_my_authcheck_table = 'radcheck'; # Name of the table the the CheckItems
# PostgreSQL values
my $db_pg_name = 'radius'; # Name of the PostgreSQL database
my $db_pg_host = 'localhost'; # IP address of the PostgreSQL server
my $db_pg_port = '5432'; # Connect port of the PostgreSQL server
my $db_pg_username = 'username'; # Username to connect to PostgreSQL
my $db_pg_password = 'password'; # Password to connect to PostgreSQL
my $db_pg_authcheck_table = 'radcheck'; # Name of the table the the CheckItems
#####################
# Stop editing here #
#####################
# database related variables
my $db_name = "";
my $db_host = "";
my $db_port = "";
my $db_username = "";
my $db_password = "";
my $db_authcheck_table = "";
my $dsn = "";
my $dbh = "";
my $sth = "";
my $rv = "";
my $i = 0;
my @row = "";
my %db_userlist = "";
# Program variables
my $numusers = 0;
my $num_exeption = 0;
my $num_db_exeption = 0;
my $num = 0;
my $username = "";
my %userlist = "";
my $char = "";
my $password = "";
my $crypt_pass = "";
my $encryption = "";
my $use_db = "";
# Output files
my $passfile = "./passwd";
my $shadfile = "./shadow";
my $radfile = "./radius.test";
my $nocrypt = "./passwd.nocrypt";
my $users = "./radius.users";
my $sql = "./users_nocrypt.sql";
my $sql_crypt = "./users_crypt.sql";
### PORGRAM START
# Check if we have two arguments on command line
if ( $#ARGV < 1 ) {
print "\n\tUsage: $0 <number of users> <clear|crypt|md5> [mysql|Pg]\n";
print "\t for example: $0 57 crypt Pg\n\n";
exit (1);
}
# Check if $ARGV[0] is really a number
if ( $ARGV[0] =~ /[^0-9]/ ) {
print "\n\nInvalid argument for <number of users>!\n\n";
exit (1);
} else {
$numusers = $ARGV[0];
}
# Check if a legal method for encryption is chosen
if ( ($ARGV[1] =~ /\bclear\b/) || ($ARGV[1] =~ /\bcrypt\b/) || ($ARGV[1] =~ /\bmd5\b/) ) {
$encryption = $ARGV[1];
} else {
print "\n\nInvalid argument for encryption method!\n\n";
exit (1);
}
# Check if a valid db type is present, if there is any at all
if ( $ARGV[2] ) {
if ( $ARGV[2] =~ /\bmysql\b/i ) {
use DBD::mysql;
$db_name = $db_my_name;
$db_host = $db_my_host;
$db_port = $db_my_port;
$db_username = $db_my_username;
$db_password = $db_my_password;
$db_authcheck_table = $db_my_authcheck_table;
$dsn = "DBI:mysql";
} else {
if ( $ARGV[2] =~ /\bPg\b/i ) {
use DBD::Pg;
$db_name = $db_pg_name;
$db_host = $db_pg_host;
$db_port = $db_pg_port;
$db_username = $db_pg_username;
$db_password = $db_pg_password;
$db_authcheck_table = $db_pg_authcheck_table;
$dsn = "DBI:Pg";
} else {
print "\n\nInvalid argument for database type!\n\n";
exit (1);
}
}
$use_db = 1;
}
# Open the file for writing
open(PASS, ">$passfile") || die "Can't open $passfile";
open(SHAD, ">$shadfile") || die "Can't open $shadfile";
open(RAD, ">$radfile") || die "Can't open $radfile";
open(NOCRYPT, ">$nocrypt") || die "Can't open $nocrypt";
open(USERS, ">$users") || die "Can't open $users";
open(SQL, ">$sql") || die "Can't open $sql";
open(SQL_CRYPT, ">$sql_crypt") || die "Can't open $sql_crypt";
for ($num=1; $num<=$numusers; $num++) {
# Break to stop the program from running infinite
if ( ($num_db_exeption > 10*$numusers) || ($num_exeption > 10*$numusers) ) {
print "\n\n\n\n\n\tW A R N I N G !!!!!\n\n";
print "\tIt seems the values set for your password lenght are too low!\n";
print "\tThis programs exits due to the fact that the number of discarded\n";
print "\tusernames is 10 times higher than the number of users you wanted to generate.\n\n";
print "\tDiscarded $num_exeption user(s) on program level.\n";
if ( $use_db ) {
print "\tDiscarded $num_db_exeption user(s) on database level.\n\n";
}
close(PASS);
close(SHAD);
close(RAD);
close(NOCRYPT);
close(USERS);
close(SQL);
close(SQL_CRYPT);
exit (1);
}
# generate username
$username = "";
for( $i = 0; $i < $user_lenght; $i++ ) {
do { ($char = chr(rand 254)) } until $char =~ /[AC-HK-NP-RTW-Za-fhikm-pr-tw-z2-4679]/;
$username .= $char;
}
# Make sure they're unique in this file
if( ($userlist{$username}) || (getpwnam($username)) ) {
$num--;
$num_exeption++;
next;
}
$userlist{$username} = 1;
# Check if the db should be used
if ( $use_db ) {
# Make sure they're unique in the database, too.
$dbh = DBI->connect("$dsn:dbname=$db_name;host=$db_host;port=$db_port", $db_username, $db_password,
{ RaiseError => 1, AutoCommit => 0 } )
or die "Couldn't connect to database: $dbh::errstr";
$sth = $dbh->prepare("SELECT UserName FROM $db_authcheck_table")
or die "Failed to prepare statement: $sth::errstr";
$sth->execute;
while(@row = $sth->fetchrow_array()) {
$db_userlist{$row[0]} = 1;
}
$sth->finish;
$dbh->disconnect();
if ($db_userlist{$username}) {
$num--;
$num_db_exeption++;;
next;
}
}
# generate password
$password = "";
for($i=0; $i<$password_lenght; $i++) {
do { ($char = chr(rand 254)) } until $char=~/[AC-HK-NP-RT-Za-fhikm-pr-tw-z2-4679]/;
$password .= $char;
}
# Encrypt the password
if ( $encryption =~ /\bclear\b/ ) {
$crypt_pass = $password;
} else {
if ($encryption =~ /\bcrypt\b/) {
$crypt_pass = crypt($password, $password);
} else {
$crypt_pass = unix_md5_crypt($password, $password);
}
}
# write the files
printf PASS "$username:$crypt_pass:1001:1001:Name:/dev/null:/dev/null\n";
printf SHAD "$username:$crypt_pass:1000:0:99999:7:::\n";
printf RAD "User-Name=$username, $user_attribute=$password,NAS-IP-Address=127.0.0.1,NAS-Port-Id=0\n";
printf NOCRYPT "$username:$password\n";
printf USERS "$username Auth-Type:=Local, User-Password==\"$password\"\n\tClass=\"0x$num\"\n";
# Only write to db if requested
if ( $use_db ) {
$dbh = DBI->connect("$dsn:dbname=$db_name;host=$db_host;port=$db_port", $db_username, $db_password,
{ RaiseError => 1, AutoCommit => 0 } )
or die "Couldn't connect to database $db_name for INSERT statement: $DBI::errstr";
$rv = $dbh->do("INSERT INTO $db_authcheck_table (UserName,Attribute,op,Value)
VALUES ('$username','$user_attribute','==','$crypt_pass')")
or die "Couldn't INSERT statement: $DBI::errstr";
$dbh->commit;
$dbh->disconnect();
}
}
# Close the files
close(PASS);
close(SHAD);
close(RAD);
close(NOCRYPT);
close(USERS);
close(SQL);
close(SQL_CRYPT);
# Write final statement
print "\nDiscarded $num_exeption user(s) on program level.\n";
if ( $use_db ) {
print "Discarded $num_db_exeption user(s) on database level.\n";
}
print "\n\n\tCreated $numusers random users and passwords.\n";
exit (0);