File IO on a remote Windows system - perl

Given a Perl script that can be running on unix or Windows, how can I best read/write to a file on a windows host? Is there anything similar to File::Remote?

I would try to mount the remote folder and then use the standard perl functions:
use constant W_REMOTE_FOLDER = '\\server\share';
use constant W_LOCAL_FOLDER = 'x:\share\';
use constant L_REMOTE_FOLDER = 'smb://server/share';
use constant L_LOCAL_FOLDER = '/mnt/share/';
my $localfolder = '';
if ($am_i_windows)
{
system('net use ...');
$localfolder = W_LOCAL_FOLDER;
}
if ($am_i_linux)
{
system('mount ...');
$localfolder = L_LOCAL_FOLDER;
}
die "What am I? if ($localfolder eq '');
open(HANDLE, "$localfolder/$filename");
# read/write (...)
close(HANDLE);

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.

How can I execute a series of commands using the Net::SSH::Any module?

I want to execute multiple commands in the same session after connecting to a server with Net::SSH::Any.
My sample code is as follows:
use strict;
use warnings;
use Net::SSH::Any;
my $host = "ip address";
my $user = "user";
my $passwd = "pass";
my $cmd1 = 'cd /usr/script';
my $ssh = Net::SSH::Any->new($host, user => $user, password => $passwd);
$ssh->system($cmd1);
my $pwd = $ssh->capture("pwd");
print $pwd;
I expected the following output:
/usr/script
but instead I am getting:
/home/user
How can I execute multiple commands in a single session?
You'll have to chain your commands in the remote shell like this:
my $cwd = $ssh->capture( q{cd /usr/script && pwd} );
You have to do it this way because even though both currently-supported backends to Net::SSH::Any provide other ways to do this (Net::OpenSSH has open2pty and Net::SSH2 has channels), the Net::SSH::Any API doesn't expose these.
For example, system invokes either Net::OpenSSH's system method or creates a Net::SSH2::Channel and invokes process('exec' => $cmd) (limited to one command per channel).

Access environment variable in perl written in double quotes via config file

I have an environment variable $ROOT. For eg. $ROOT = "/someroot" It is accessed in a Perl file via config file parameters.
Eg
In config file :
path = '$ROOT/abc/somepath'
In Perl file while using this variable when I write config->{$path} in back ticks config->{$path} value of $ROOT is accessible i.e /someroot/abc/somepath but when in double quotes "config->{$path}" the result is $ROOT/abc/somepath.
I need this to be written in double quotes for opening files : open (filehandle,"config->{$path}"); How can achieve the value of config->{$path} in double quotes.
P.S I have also used $ENV{'config->{$path}'};
Try
my path = $ENV{"ROOT"} . config->{$path};
open(filehandle, path);
But now you do not have to precede your configured path with $ROOT.
config file: path = '/abc/somepath'
Are you looking for this?
sub get_conf {
my ($config, $key) = #_;
my $val = $config{key};
return undef if !defined($val);
$val =~ s{\$ROOT\b}{$ENV{ROOT}}g;
return $val;
}
my $path = get_conf(config, 'path');
For a more general solution, try one of the String::Interpolate modules on CPAN. I favor String::Interpolate::RE (disclaimer: I wrote it):
use String::Interpolate::RE 'strinterp';
my $path = strinterp( $config{path}, {}, { useENV=> 1 } );

Use in-memory file as argument in SFTP

I need to open an SFTP connection in Perl and I need to use a dsa key file but I can't actually store the file on the hard disk for security reasons. I am trying to use Net::SFTP.
my $sftp = Net::SFTP->new(
$host, user=>"$userid",
ssh_args => {
identity_files => [ $pathToInMemoryKeyFile ]
}
);
I think I know how to get a string represented as an in memory file handle but I don't know how to get the path of that file handle such that I can pass it in as one of the ssh_args. Does anybody have any suggestions?
Thanks!
I've looked through the various options of doing SFTP (Net::SFTP hasn't been updated since 2005, Net::SFTP::Foreign is more up to date) and they all do key authentication via a file.
Net::SFTP is backed by Net::SSH::Perl which is a pure Perl SSH implementation. You can do some patching to make it do what you want. I'm going to sketch it out for you.
Patch or put a wrapper around Net::SSH::Perl::Auth::PublicKey->authenticate to look for a new configuration key. Let's call it identity_keys.
sub authenticate {
my $auth = shift;
my $ssh = $auth->{ssh};
my $sent = 0;
if (my $agent = $auth->mgr->agent) {
do {
$sent = $auth->_auth_agent;
} until $sent || $agent->num_left <= 0;
}
return $sent if $sent;
##### This is the new bit which tries any keys passed in. ######
my $ik = $ssh->config->get('identity_keys') || [];
for my $key (#$ik) {
return 1 if $auth->_auth_key($key);
}
my $if = $ssh->config->get('identity_files') || [];
my $idx = $auth->{_identity_idx} || 0;
for my $f (#$if[$idx..$#$if]) {
$auth->{_identity_idx}++;
return 1 if $auth->_auth_identity($f);
}
}
auth_key would be a copy of _auth_identity but calling Net::SSH::Perl::Key->read_private_key which would be the guts of Net::SSH::Perl::Key->read_private_pem minus opening and reading the key from a file. read_private_pem would then be gutted to use read_private_key.
Alternatively, use an ssh-agent. It holds the decrypted private key in memory, so you can immediately wipe it from the disk.

What does this perl crash means?

Can someone tell me what this means?
if (not defined $config{'crontab'}) {
die "no crontab defined!";
}
I want to open a file crontab.txt but the perl script crashes at this line and I don't really know any perl.
EDIT 1
It goes like this:
sub main()
{
my %config = %{getCommandLineOptions()};
my $programdir = File::Spec->canonpath ( (fileparse ( Win32::GetFullPathName($PROGRAM_NAME) ))[1] );
my $logdir = File::Spec->catdir ($programdir, 'logs');
$logfile = File::Spec->catfile ($logdir, 'cronw.log');
configureLogger($logfile);
$log = get_logger("cronw::cronService-pl");
# if --exec option supplied, we are being invoked to execute a job
if ($config{exec}) {
execJob(decodeArgs($config{exec}), decodeArgs($config{args}));
return;
}
my $cronfile = $config{'crontab'};
$log->info('starting service');
$log->debug('programdir: '.$programdir);
$log->debug('logfile: '.$logfile);
if (not defined $config{'crontab'}) {
$log->error("no crontab defined!\n");
die "no crontab defined!";
# fixme: crontab detection?
}
$log->debug('crontab: '.$config{'crontab'});
And I'm trying to load this 'crontab.txt' file...
sub getCommandLineOptions()
{
my $clParser = new Getopt::Long::Parser config => ["gnu_getopt", "pass_through"];
my %config = ();
my #parameter = ( 'crontab|cronfile=s',
'exec=s',
'args=s',
'v|verbose'
);
$clParser->getoptions (\%config, #parameter);
if (scalar (#ARGV) != 0) { $config{'unknownParameter'} = $true; }
return \%config;
}
Probably I have to give the script an argument
Probably I have to give the script an argument
I would say so.
$ script --cronfile=somefile
That code looks to see whether there is a key 'crontab' in the hash %config. If not, then it calls die and terminates.
If that's not what you expect to happen, then somewhere else in your script there should be something that is setting $config{'crontab'}, but there is not currently enough information in your question to determine what that might be.
Probably the file path of crontab.txt is expected in %config hash, pointed by the 'crontab' key, but isn't there! If so, a DIRTY solution CAN BE:
$config{'crontab'}='FULLPATH/crontab.txt';
#if (not defined $config{'crontab'}) {
# die "no crontab defined!";
#}
but this may not work because there is something like $config{'prefix'} and what you will try to open is the path represented by the concatenation of both, or just because in $config{'crontab'} is expected any other value than full path!