passing a shells output to a perl script log - perl

what this script does is pull down a list of usernames and passowrds and hashes it and then adds it to
a list. When there are non asci characters, the quotemeta escapes them, which allows to htpasswd command to
consume the vaule. When I run it it prints the results of /usr/local/apache2/bin/htpasswd to the terminal.
I want to pass all the results to a file
#!/usr/bin/perl
use strict;
use warnings;
use DBI;
use File::Copy;
unshift #INC,"/production/lib";
require "config.pl";
$configFile = "/production/cfg/syncUsers.cfg";
readConfig($configFile);
#doBackup($prefs{passwdFile});
generatePasswdFile("tmpusers");
getUsers($prefs{dbUser},$prefs{dbPass},$prefs{dbSid});
#copyPasswdFile($prefs{passwdFile});
# getUsers - grab user from the db and set them up
sub getUsers {
$dbUser = shift;
$dbPass = shift;
$dbSid = shift;
$dbh = DBI->connect("dbi:Oracle:$dbSid","$dbUser","$dbPass") or die( "Couldn't connect: $!" );
$sql = "SELECT user_name,passwd FROM login_tbl";
$sth = $dbh->prepare($sql);
$sth->execute();
while ( ( $user_name,$passwd ) = $sth->fetchrow_array ) {
$user_name = quotemeta($user_name);
$passwd = quotemeta($passwd);
#print "$user_name,$passwd\n";
updatePasswdFile($user_name,$passwd);
}
$dbh->disconnect();
}
# generatePasswdFile - generate a dummy file to start with
sub generatePasswdFile {
$file = shift;
$cmd = "$prefs{htpasswd} -bc /tmp/$file dummyuser dummyuser";
system($cmd);
}
# updatePasswdFile - update the passwdfile
sub updatePasswdFile {
$file = "/tmp/tmpusers";
$user = shift;
$pass = shift;
print "Adding user: $user\n";
$cmd = "$prefs{htpasswd} -b $file $user $pass";
system($cmd);
}
this is what it does its I print out to screen.
Adding user: dev_ops
Adding password for user dev_ops
Adding user: dev_shed
Adding password for user dev_shed
Adding user: robogrl
Adding password for user robogrl
Adding user: a_foo
Adding password for user a_foo
Adding user: atank
Adding password for user atank
Adding user: acar
Adding password for user acar
Adding user: acarlson
Adding password for user acarlson
Adding user: dnick
Adding password for user dnick
When I pass it to a file so I can check for errors only one half goes to a file
and the other half is output to the screen.
bash-3.00$ ./caspser.pl > /tmp/checkFORerrors2013Nov19
this output still goes to the screen -
Adding password for user dev_ops
Adding password for user dev_shed
Adding password for user robogrl
Adding password for user a_foo
Adding password for user atank
Adding password for user acar
Adding password for user acarlson
Adding password for user dnick
and this goes to the file
Adding user: dev_ops
Adding user: dev_shed
Adding user: robogrl
Adding user: a_foo
Adding user: atank
Adding user: acar
Adding user: acarlson
Adding user: dnick
how do i get everything to go to a file?
better yet - is there a way to just print errors?

The htpasswd command you use prints to STDERR (standard error). The redirect you have performed redirects STDOUT (standard out) into the file. To redirect both, you need to update your command:
bash-3.00$ ./caspser.pl > /tmp/checkFORerrors2013Nov19 2>&1
Basically, errors are printed to a different stream. Both streams are showing in the terminal without redirections, and the difference only becomes obvious when you start changing them.

Related

perl LDAP entry not recognised

We are writing a Perl code (to be run from Unix) which will reset the password of a Windows AD User. (We are not using powershell as we have been asked not to use Windows scripts).
With the following Perl code, we are able to connect to the AD User directory and query the correct user.
#!/usr/bin/perl -w
#########################
#This script resets the password in active user directory
#########################
use strict;
use warnings;
use DBI;
use Net::LDAP;
use Net::LDAPS;
use Authen::SASL qw(Perl);
use Net::LDAP::Control::Paged;
use Time::Local;
my $CERTDIR = "<cert path>";
my $AD_PASS = "$CERTDIR/.VDIAD_pass";
my $sAN = "vahmed";
### Generate Random Password ###
my $randompass = askPasswd();
my $uninewpass;
my $mail;
my $fullname;
my $name;
my $distName;
my $finalresult;
my #AD_passwords = get_domain_pass();
my $result = reset_AD_Password();
#Reset AD user password
sub reset_AD_Password {
my $ad = Net::LDAP->new($AD_passwords[0]);
my $msg = $ad->bind(dn => "cn=$AD_passwords[2],$AD_passwords[1]",
password => $AD_passwords[3],
version => 3);
if ($msg->code)
{
print "Error :" . $msg->error() . "\n";
exit 2;
}
my $acc_name = 'sAMAccountName';
my $acc_fullname = 'displayName';
my $acc_base = 'manager';
my $acc_distName = 'distinguishedName';
my $acc_mail = 'mail';
my $act = $ad->search(
base => "$AD_passwords[1]",
filter => "(&(objectCategory=person)(sAMAccountName=$sAN))",
attrs => [$acc_name, $acc_fullname, $acc_distName, $acc_mail]);
die 1 if ($act->count() !=1 );
my $samdn = $act->entry(0)->dn;
$fullname = $samdn->get_value($acc_fullname);
$mail = $samdn->get_value($acc_mail);
}
}
However we get an error on the line:
$fullname = $samdn->get_value($acc_fullname);
$mail = $samdn->get_value($acc_mail);
The error states "Can't locate object method "get_value" via package (distinguished Name) (perhaps you forgot to load (distinguished Name))"
However the code works correctly when we replace $samdn with the following code:
foreach my $entry ($act->entries){
$name = $entry->get_value($acc_name);
$fullname = $entry->get_value($acc_fullname);
$distName = $entry->get_value($acc_distName);
$mail = $entry->get_value($acc_mail);
}
It would appear that the code is unable to identify $samdn as a Net::LDAP::Entry record.
We have tried typecasting $samdn but got the same error.
Could someone help in resolving this issue as we would not prefer to use the for loop just in case more that one record is returned by the search? Thanks in advance.
You are not assigning a Net::LDAP::Entry to $samdn. You are assigning the dn of the first entry.
# VVVV
my $samdn = $act->entry(0)->dn;
Get rid of that ->dn and it should work, if $act->entry(0) returns a Net::LDAP::Entry.

Authen::PAM login doesn't work after Vintela flush

I have a perl script that gets the username and password from an external process and then does user authentication using Vintela. Everything works perfectly until someone forces Vintela to flush it's cache. After the cache is flushed, the Authen::PAM module returns code 10, which means that it couldn't find the username.
If I run the "id $username" command in the shell and then run the script then everything returns to normal for that user. Or if the user SSH's into the system then Authen::PAM works perfectly.
On the production server user's don't SSH into the server and hence after Vintela flush, user's can't login anymore. I don't want to run the "id" command for every user before I authenticate them. Is there a way I can force the script or PAM module to look for user and then authenticate them ?
Script --
BEGIN {
unshift(#INC, "..", "/usr/local/staf/bin", "/usr/local/staf/lib", "C:/STAF/Bin");
}
use strict;
use PLSTAF;
require Authen::PAM;
my $GlobalUserName = <STDIN>;
my $GlobalPasswd = <STDIN>;
my $result = -1;
$GlobalPasswd = STAF::RemovePrivacyDelimiters($GlobalPasswd);
my $pamHandle = Authen::PAM->new("login", $GlobalUserName, \&conversionFunction);
$result = $pamHandle->pam_authenticate();
# force the destructor execution for PAM
$pamHandle = 0;
# When $result is 0 then user has been authenticated
if ($result == 0) {
print $result;
exit $result;
}
else {
exit $result;
}
sub conversionFunction {
my #response = ();
# PAM constants
my $pamEchoOn = Authen::PAM->PAM_PROMPT_ECHO_ON();
my $pamEchoOff = Authen::PAM->PAM_PROMPT_ECHO_OFF();
my $pamSuccess = Authen::PAM->PAM_SUCCESS();
while ( #_ ) {
my $code = shift;
my $msg = shift;
my $answer = "";
if ($code == $pamEchoOn) {
$answer = $GlobalUserName;
}
if ($code == $pamEchoOff) {
$answer = $GlobalPasswd;
}
# response is always in pairs, response code and the actual answer
push(#response, $pamSuccess, $answer);
}
push(#response, $pamSuccess);
return #response;
}

Mojolicious, redirects, session and trying to create an authentication system

I'm trying to get away from Basic Auth in my Mojolicious application. I am able to detect the absence of a session key and redirect to a login page. The login page then posts to my application and I authenticate to a back end process. That back end process is returning success and then my mojo app sets the session like thus:
$self->session( user => $name, groups => $groups );
in debugging this, $name and $group are both defined and valid. I then wish to redirect into the "protected" space of my app. The redirect lands in the right place but then fails to detect the $self->session('user') (is undef when debugging) I end up redirecting back to login repeatedly.
I'll include snippets of the setup below. What am I missing?
MyApp.pm
my $r = $self->routes;
$r->route('/verify')->via('post')->to('util-auth#verify')->name('verify');
$r->route('/login')->via('get')->to('util-auth#login')->name('login');
my $app = $r->under('/myapp')->to('util-auth#check');
$app->route('/foo')->via('get')->to('controller-api#foo')->name('foo');
MyApp::Util::Auth
sub verify {
my $self = shift;
my $name = $self->param('username');
my $pass = $self->param('password');
my $dest = "/myapp/foo"; # in the protected area
if ( $self->authenticate($name, $pass) ) {
my $groups = $self->get_groups($name);
$self->session(
user => $name,
groups => $groups,
);
}
else {
$self->flash( message => "invalid login..." );
}
$self->redirect_to($dest);
}
sub login {
my $self = shift;
$self->render(); # renders the login form
}
sub check {
my $self = shift;
my $user = $self->session('user');
return 1 if defined $user;
$self->redirect_to('/login');
return 0;
}
I was having a similar problem and I ended up putting these in stash. I think session is string based, mainly because a cookie is set with session info.
Why your verify function accept name, pass via #_ variable?
May be need to use $self->param('name') and $self->param('pass')?
See working example here:
https://gist.github.com/Logioniz/bdf6f22c00fc51798c43

Net::Telnet Error Handling

Im trying to print "Error IP USER PASS Failed!", on failure.
When i use my script
use Net::Telnet ();
my $t = new Net::Telnet Timeout => 30,
Prompt => '/[\$#%:><][\s\b]+$/';
$t->open($ARGV[0]);
my $user = $ARGV[1];
my $pass = $ARGV[2];
print "Logging In...\n";
print "Sending Username....\n";
$t->print($user);
$t->waitfor('/[:>%\$#]/');
print "Sending Password....\n";
$t->print($pass);
$t->waitfor('/[:>%\$#]/');
if ($t->errmsg){
print "errmsg: " . $t->errmsg . "\n";
} else {
print"success\n";
}
The issue:
I know the IP and username: admin and admin are working.
root#localhost:~/tel# perl t2.pl *.*.*.* admin admin
Logging In...
Sending Username....
Sending Password....
success
Now using a NON working user and pass i get the same "success"
root#localhost:~/tel# perl t2.pl 36.85.134.191 admin admi1
Logging In...
Sending Username....
Sending Password....
success
What am i doing wrong with the if statement, something is not working correctly.
You should probably enable debugging, but I guess that your expectation for the result of passwort matches not only the prompt (e.g. $ or #) but also the username prompt you get if the password was wrong (:).

Trouble using Telnet in perl?

I'm having some trouble send commands and receiving text/data from the telnet connection that I set up.
#!perl
#Telnet.pl
use Net::Telnet;
# Create a new instance of Net::Telnet,
my $telnetCon = new Net::Telnet (Timeout => 20,
Dump_Log => "dump.log",
Input_Log => "infile.log",
Output_log => "output.log",
Prompt => '/\$ $/') or die "Could not make connection.";
# Connect to the host of the users choice
$telnetCon->open('');
#get username and password from user
my $CXusername = '';
my $CXpassword = '';
my $task = '50104'; # Get this input from the search
# Recreate the login
# Wait for the login: message and then enter the username
$telnetCon->waitfor(match => '/login:/i');
# this method adds a \n to the end of the username, it mimics hitting the enter key after entering your username
$telnetCon->print($CXusername);
$telnetCon->waitfor(match => '/Password:/i');
# does the same as the previous command but for the password
$telnetCon->print($CXpassword);
#Wait for the login successful message
$telnetCon->waitfor(match => '/$/');
$telnetCon->cmd("viewtask 50104");
$telnetCon->cmd(" ");
$telnetCon->cmd(" ");
#output = $telnetCon->cmd("who");
print #output;
($output) = $telnetCon->waitfor(match => '/$/');
print "Output: ",$output;
if($searched =~ /MODIFIED files in Task $_[1] :(.*?)The/s){
# to Logout of the telnet connection
$telnetCon->print("exit");
#return the modified data
return $1;
}
Tell me if the question doesn't make sense, I'll try and reword it.
So this is the telnet view. I get stuck on the first image when i enter the $telnetCon->cmd("viewtask 50140"). I want to get to the second image and continue entering commands into my telnet session.
The Net::Telnet cmd method writes your command (with a \n appended) and waits for the prompt. this is incompatible with your program's waiting for input to complete output.
I think in your case you would want to use a combination of print and getlines and/or waitfor to get this to work