ldap password change with Expect Module - linux

I don't have a super skill in perl. But, I did this both scripts for changing LDAP password by the users.
The first script:
#!/usr/bin/perl -w
use strict;
use Expect;
my $user= getpwuid( $< );
print "Enter your old password :" ;
my $oldpassword = <STDIN>;
chomp($oldpassword);
print "Enter you new password :";
my $newpassword = <STDIN>;
chomp($newpassword);
print "Running ' passwd ${user}'\n";
my $exp = Expect->spawn("passwd") or die "Can t acces to passwd \n";
unless ($exp->expect(1, "Enter login\(LDAP\) password:")) {} ;
print $exp "${oldpassword}\r" ;
unless ($exp->expect(1, "New password:")) {} ;
print $exp "${newpassword}\r" ;
unless ($exp->expect(1, "Re-enter new password:")) {} ;
print $exp "${newpassword}\r" ;
$exp->soft_close();
The second script:
#!/usr/bin/perl -w
use strict;
use Expect;
my $user= getpwuid( $< );
print "Enter your old password :" ;
my $oldpassword = <STDIN>;
chomp($oldpassword);
print "Enter your new password :";
my $newpassword = <STDIN>;
chomp($newpassword);
print "Running ' passwd ${user}'\n";
my $spawn_ok;
my $exp = Expect->spawn("passwd") or die "Can t acces to passwd \n";
$exp->expect(1,
[qr 'Enter login\(LDAP\) password:' ,
sub {
$spawn_ok = 1;
my $fh = shift;
$fh->send("${oldpassword}\n");
print "sent '${oldpassword}'\n";
exp_continue;
}
],
[eof =>
sub {
if ($spawn_ok) {
die "ERROR: premature EOF in login.\n";
} else {
die "ERROR: could not spawn old password.\n";
}
}
],
['New password: ' ,
sub {
my $fh =shift ;
$fh->send("${newpassword}\n");
print "sent '${newpassword}'\n";
exp_continue;
}
],
['Re-enter new password:' ,
sub {
my $fh =shift ;
$fh->send("${newpassword}\n");
print "sent '${newpassword}'\n";
exp_continue;
}
]
);
I don't know what is the better between them. But they work.
Actually my script are working same if the old password is wrong. I would like a control of the old password before the script continue, or maybe the script restarts if the old password is wrong. I thought about a loop, I tried to put is the booth scripts without success.
Could I've some help ?

Did you know about Net::Ldap module?
http://search.cpan.org/~gbarr/perl-ldap/lib/Net/LDAP/FAQ.pod#Ho_do_I_reset_a_user%27s_password_...
Without error checking!
use Net::LDAP;
my $ldap = Net::LDAP->new('ldaps://server.domain') or die "$#";
my $mesg = $ldap->bind('cn=Joe User,dc=perl,dc=ldap,dc=org',
password => 'oldPW');
my $rootdse = $ldap->root_dse();
if ($rootdse->supported_extension('1.3.6.1.4.1.4203.1.11.1') {
require Net::LDAP::Extension::SetPassword;
$mesg = $ldap->set_password(user => 'cn=Joe User,dc=perl,dc=ldap,dc=org',
oldpasswd => 'oldPW',
newpasswd => 'newPW');
}
else {
$mesg = $ldap->modify('cn=Joe User,dc=perl,dc=ldap,dc=org',
changes => [
delete => [ userPassword => $oldPW ]
add => [ userPassword => $newPW ] ]);
}
$ldap->unbind();

Related

how to club the names with space in between in AWK [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 25 days ago.
Improve this question
i am trying to use a awk command to filter out data from the file and get it into a CSV file. I am trying to create the column headers but the data has space between them so the script is taking each character as separate name.
Script i am using
$ cat tst.sh
#!/usr/bin/env bash
cat file |
awk '
BEGIN {
OFS = ","
numTags = split("Machine Name Type Node Name Agent Name Operating System Agent Release Agent Build",tags)
for ( tagNr=1; tagNr<=numTags; tagNr++ ) {
tag = tags[tagNr]
printf "\"%s\"%s", tag, (tagNr<numTags ? OFS : ORS)
}
}
!NF || /^\/\*/ { next }
{ gsub(/^[[:space:]]+|[[:space:]]+$/,"") }
match($0,/[[:space:]]job_type:/) {
if ( jobNr++ ) {
prt()
delete tag2val
}
# save "insert_job" value
tag = substr($1,1,length($1)-1)
val = substr($0,length($1)+1,RSTART-(length($1)+2))
gsub(/^[[:space:]]+|[[:space:]]+$/,"",val)
tag2val[tag] = val
# update $0 to start with "job_type" to look like all other input
$0 = substr($0,RSTART+1)
}
{
tag = val = $0
sub(/:.*/,"",tag)
sub(/[^:]+:[[:space:]]*/,"",val)
tag2val[tag] = val
}
END { prt() }
function prt( tagNr,tag,val) {
for ( tagNr=1; tagNr<=numTags; tagNr++ ) {
tag = tags[tagNr]
val = tag2val[tag]
printf "\"%s\"%s", val, (tagNr<numTags ? OFS : ORS)
}
}
'
Contents of File:
$ cat file
Machine Name: machine1
Type: a
Node Name: machine1.test
Agent Name: WA_AGENT
Operating System: Windows Server 2012
Agent Release: 12.0
Agent Build: 6181, Service Pack 00, Maintenance Level 00
Machine Name: machine2
Type: a
Node Name: machine2.test
Agent Name: WA_AGENT
Operating System: Windows Server 2012 for amd64
Agent Release: 12.0
Agent Build: 6181, Service Pack 00, Maintenance Level 00
Output i am getting:
"Machine","Name","Type","Node","Name","Agent","Name","Operating","System","Agent","Release","Agent","Build"
"","","a","","","","","","","","","",""
Required output:
"Machine Name","Type","Node Name","Agent Name","Operating System","Agent Release","Agent Build"
"machine1"," a"," machine1.test"," AGENT"," Windows Server 2012"," 12.0"," 6181, Service Pack 00, Maintenance Level 00"
"machine2"," a"," machine2.test"," AGENT"," Windows Server 2012"," 12.0"," 6181, Service Pack 00, Maintenance Level 00"
Is there a way to get the output that i want.
Ignoring the leading blanks in some output fields as idk if/why you'd want those and you can tweak this to add them if you really do, here's how to modify the code in your question to do what you want:
$ cat tst.sh
#!/usr/bin/env bash
cat file |
awk '
BEGIN {
OFS = ","
numTags = split("Machine Name:Type:Node Name:Agent Name:Operating System:Agent Release:Agent Build",tags,":")
for ( tagNr=1; tagNr<=numTags; tagNr++ ) {
tag = tags[tagNr]
printf "\"%s\"%s", tag, (tagNr<numTags ? OFS : ORS)
}
}
!NF || /^\/\*/ { next }
{ gsub(/^[[:space:]]+|[[:space:]]+$/,"") }
/^Machine Name:/ {
if ( jobNr++ ) {
prt()
delete tag2val
}
}
{
tag = val = $0
sub(/[[:space:]]*:.*/,"",tag)
sub(/[^:]+:[[:space:]]*/,"",val)
tag2val[tag] = val
}
END { prt() }
function prt( tagNr,tag,val) {
for ( tagNr=1; tagNr<=numTags; tagNr++ ) {
tag = tags[tagNr]
val = tag2val[tag]
printf "\"%s\"%s", val, (tagNr<numTags ? OFS : ORS)
}
}
'
$ ./tst.sh file
"Machine Name","Type","Node Name","Agent Name","Operating System","Agent Release","Agent Build"
"machine1","a","machine1.test","WA_AGENT","Windows Server 2012","12.0","6181, Service Pack 00, Maintenance Level 00"
"machine2","a","machine2.test","WA_AGENT","Windows Server 2012 for amd64","12.0","6181, Service Pack 00, Maintenance Level 00"
In reality, if I were to do this from scratch for this specific problem, I wouldn't hard-code tags in the question, I'd just print all values every time a blank line was hit. For example:
$ cat tst.sh
#!/usr/bin/env bash
cat file |
awk '
BEGIN {
OFS = ","
}
{ gsub(/^[[:space:]]+|[[:space:]]+$/,"") }
!NF {
prt()
delete tag2val
numTags = 0
next
}
{
tag = val = $0
sub(/[[:space:]]*:.*/,"",tag)
sub(/[^:]+:[[:space:]]*/,"",val)
if ( !(tag in tag2val) ) {
tags[++numTags] = tag
}
tag2val[tag] = val
}
END { prt() }
function prt( tagNr,tag,val) {
if ( !doneHdr++ ) {
for ( tagNr=1; tagNr<=numTags; tagNr++ ) {
tag = tags[tagNr]
printf "\"%s\"%s", tag, (tagNr<numTags ? OFS : ORS)
}
}
for ( tagNr=1; tagNr<=numTags; tagNr++ ) {
tag = tags[tagNr]
val = tag2val[tag]
printf "\"%s\"%s", val, (tagNr<numTags ? OFS : ORS)
}
}
'
$ ./tst.sh file
"Machine Name","Type","Node Name","Agent Name","Operating System","Agent Release","Agent Build"
"machine1","a","machine1.test","WA_AGENT","Windows Server 2012","12.0","6181, Service Pack 00, Maintenance Level 00"
"machine2","a","machine2.test","WA_AGENT","Windows Server 2012 for amd64","12.0","6181, Service Pack 00, Maintenance Level 00"
One thing to note about any of the scripts I've provided for you - I do not use fields such as $1 and $2 to hold the tag or value because as soon as you do that you run into problems if your data can contain whatever you use as an FS.
For example, if you have data that looks like:
tag: value
then do not do anything like this in your code:
FS = ": *"
tag = $1
val = $2
as it'll fail when the value (or, far less likely, the tag) contains a string that matches the FS, such as : in this case, e.g. given this data:
foo: "the ratio was 2:1"
you'd end up with val set to "the ratio was 2. Instead do this:
tag = val = $0
sub(/[[:space:]]*:.*/,"",tag)
sub(/^:+:[[:space:]]*/,"",val)
so you end up with val set to "the ratio was 2:1".

simplest possible XML-RPC query example using powershell?

Looking to simplify or even "dumb down" this example:
$source = #'
namespace OpenSubtitlesAPI
{
using CookComputing.XmlRpc;
[XmlRpcUrl("http://api.opensubtitles.org/xml-rpc")]
public interface IOpenSubtitles : IXmlRpcProxy
{
[XmlRpcMethod("LogIn")]
XmlRpcStruct LogIn(string username, string password, string language, string useragent);
[XmlRpcMethod("LogOut")]
XmlRpcStruct LogOut(string token);
[XmlRpcMethod("SearchSubtitles")]
XmlRpcStruct SearchSubtitles(string token, XmlRpcStruct[] queries);
[XmlRpcMethod("SearchSubtitles")]
XmlRpcStruct SearchSubtitles(string token, XmlRpcStruct[] queries, int limit);
}
public class ProxyFactory
{
public static IOpenSubtitles CreateProxy()
{
return XmlRpcProxyGen.Create<IOpenSubtitles>();
}
}
}
'#
so that the simplest possible xml-rpc query is invoked. Using .NET Core on Linux.
also trying:
desired output:
$VAR1 = {
'description' => 'Mountain Dew',
'upc' => '012000000850',
'upce' => '01208500',
'issuerCountryCode' => 'us',
'noCacheAfterUTC' => bless( do{\(my $o = '2020-11-16T17:20:29')}, 'Frontier::RPC2::DateTime::ISO8601' ),
'pendingUpdates' => '0',
'issuerCountry' => 'United States',
'ean' => '0012000000850',
'size' => '12fl oz (355mL)',
'found' => bless( do{\(my $o = '1')}, 'Frontier::RPC2::Boolean' ),
'status' => 'success',
'message' => 'Database entry found',
'lastModifiedUTC' => bless( do{\(my $o = '2014-05-27T04:52:02')}, 'Frontier::RPC2::DateTime::ISO8601' )
};
Adapting from an example script in perl:
#!/usr/bin/perl
#
# Get an RPC key assigned on the "Account Info" page on https://www.upcdatabase.com/
# Then substitute your own RPC key for $key below.
#
# Usage examples:
# perl_example_new.pl test
# perl_example_new.pl help
# perl_example_new.pl lookup upc 012000000850
# perl_example_new.pl lookup ean 0012000000850
use Frontier::Client;
use Data::Dumper;
use strict;
my $server_name = 'www.upcdatabase.com';
my $key = '445d...aa3';
my $server = Frontier::Client->new( 'url' => 'https://' . $server_name . '/xmlrpc', debug => 0, );
my $method = shift;
my $result = $server->call($method, { rpc_key => $key, #ARGV } );
print Dumper($result);
__END__
adapting to powershell using the REPL console:
PS /home/nicholas/powershell>
PS /home/nicholas/powershell> Get-Help Send-XmlRpcRequest -Examples
NAME
Send-XmlRpcRequest
SYNOPSIS
Send a XML RPC Request
-------------------------- EXAMPLE 1 --------------------------
PS > Send-XmlRpcRequest -Url "example.com" -MethodName "updateName" -Params #('oldName', 'newName')
---------
Description
Calls a method "updateName("oldName", "newName")" on the server example.com
PS /home/nicholas/powershell>
PS /home/nicholas/powershell> Send-XmlRpcRequest -Url "www.upcdatabase.com" -MethodName "012000000850" -Params #('fjkdlsfjd')
Exception: /home/nicholas/.local/share/powershell/Modules/XmlRpc/1.0.1.1/XmlRpc.psm1:323
Line |
323 | $doc.LoadXml($response)
| ~~~~~~~~~~~~~~~~~~~~~~~
| Exception calling "LoadXml" with "1" argument(s): "Root element is missing."
PS /home/nicholas/powershell>
or using a script file.

Expect TCL - How to handle ssh remote host identification has changed on some devices?

I have tcl expect script to daily check some version on the network devices.
#!/usr/bin/expect --
set env(TERM) vt100
set timeout 5
set username [lindex $argv 0]
set password [lindex $argv 1]
set hostname [lindex $argv 2]
set success 1
#login script
log_user 1
spawn ssh $username#$hostname
expect {
"Connection refused" {
spawn telnet $hostname
expect {
"?sername:" {
if { $success == 0 } {
log_user 1
puts "error user or password incorrect"
exit 1;
} else {
incr success -1
send "$username\r"
}
exp_continue
}
"?assword:" {
send "$password\r"
exp_continue
}
timeout {
log_user 1
puts "error could not ssh or telnet devices"
exit 1;
exp_continue
}
"#" {
send "terminal length 0\r"
}
}
exp_continue
}
timeout {
spawn telnet $hostname
expect {
timeout {
log_user 1
puts "error could not ssh or telnet devices"
exit 1;
exp_continue
}
"?..." {
log_user 1
puts "error could not ssh or telnet devices"
exit 1;
exp_continue
}
"?sername:" {
if { $success == 0 } {
log_user 1
puts "error user or password incorrect"
exit 1;
} else {
incr success -1
send "$username\r"
}
exp_continue
}
"?assword:" {
send "$password\r"
exp_continue
}
"#" {
send "terminal length 0\r"
}
}
exp_continue
}
"continue connecting (yes/no)?" {
send "yes\r"
exp_continue
}
"?assword:" {
if { $success == 0 } {
log_user 1
puts "error user or password incorrect"
exit 1;
} else {
incr success -1
send "$password\r"
}
exp_continue
}
"$ " {
send "ssh keygen -R $hostname\r"
exp_continue
}
"#" {
send "terminal length 0\r"
}
}
#execute script
expect "#"
send "\r"
expect "#"
log_user 1
send "show version\r"
expect "#"
send "exit\r"
My expect script working like this,
ssh to the devices.
If ssh not working ("Connection refused" or "timeout") it will go to telnet condition
If ssh known_hosts key is not present on linux devices, it will send "yes"
If ssh key on the remote devices is changed, it will send "ssh-keygen -R $hostname"
and the problem is, my expect program from could not work if ssh key on remote devices is changed.
[linux]$ ./sshtelnet.tcl mine password 1.1.1.1
spawn ssh mine#1.1.1.1
###########################################################
# WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! #
###########################################################
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that the RSA host key has just been changed.
The fingerprint for the RSA key sent by the remote host is
83:24:a5:c4:2c:98:0d:0b:d6:ad:cb:74:12:7e:84:83.
Please contact your system administrator.
Add correct host key in /home/linux/.ssh/known_hosts to get rid of this message.
Offending key in /home/linux/.ssh/known_hosts:152
RSA host key for 1.1.1.1 has changed and you have requested strict checking.
Host key verification failed.
expect: spawn id exp4 not open
while executing
"expect "#""
(file "./sshtelnet.tcl" line 106)
When the remote host identification has changed, the ssh process terminates. Assuming you know that this is not because "someone is doing something nasty", you want to execute the "ssh-keygen -R $hostname" locally, not send it to the spawned ssh process. After cleaning up the offending key, you have to spawn the ssh command again.
The easiest way to be able to repeat the ssh command is to put things in procs:
proc connectssh {username password hostname} {
global spawn_id
set success 1
spawn ssh $username#$hostname
expect {
"Connection refused" {
connecttelnet $username $password $hostname
}
timeout {
connecttelnet $username $password $hostname
}
"continue connecting (yes/no)?" {
send "yes\r"
exp_continue
}
"?assword:" {
if {$success == 0} {
log_user 1
puts "error user or password incorrect"
exit 1;
} else {
incr success -1
send "$password\r"
}
exp_continue
}
"Host key verification failed" {
wait
exec ssh-keygen -R $hostname
connectssh $username $password $hostname
}
"#" {
send "terminal length 0\r"
}
}
}
proc conecttelnet {username password hostname} {
global spawn_id
spawn telnet $hostname
expect {
# ...
}
}
set env(TERM) vt100
set timeout 5
lassign $argv username password hostname
log_user 1
connectssh $username $password $hostname
# The rest of your script

How to create a timer with text mode control in the Tcl / Tk language

What I want is something similar to this bash shell script just below:
Shell Bash
#!/bin/bash
# shell timer
# Note: Do not measure time precisely because there is loss in calculations and other commands
# For a human being is something almost imperceptible, fortunately.
# ------------------------------------------------- -----------------------------
s=00
m=00
h=00
key=""
function _screen() {
clear
# Shows the elapsed time on the terminal screen and plays to the time.txt file always updating
printf "%02d:%02d:%02d" $h $m $s > ~/time.txt
echo ":: 'p' to pause, 'c' to continue and 's' to exit ::"
}
function _time() {
_screen
sleep 1
s=$((s+1))
[ $s -eq 60 ] && m=$((m+1)) && s=00
[ $m -eq 60 ] && h=$((h+1)) && m=00
}
function _pause() {
while :
do
_screen
sleep 1
read key
[ "$key" = "c" ] && clear && break
done
}
function _main() {
# Put the terminal in special character interpretation mode
stty -echo -icanon min 0
while :
do
[ "$key" = "s" ] && break
[ "$key" = "p" ] && _pause
_time
read key
done
# Restores the default mode
stty sane
exit 0
}
_main
Perhaps the most obvious is to convert it to Tcl/Tk. I even tried, but I still did not succeed. See:
Shell Tclsh
#!/usr/bin/env tclsh
# shell timer
# Note: Do not measure time precisely because there is loss in calculations and other commands
# For a human being is something almost imperceptible, fortunately.
# ------------------------------------------------- -----------------------------
set s 00
set m 00
set h 00
puts -nonewline ""
flush stdout
set key [gets stdin]
proc _screen{ } {
clear
set archive [open [pwd]/time.txt w]
# Shows the elapsed time on the terminal screen and plays to the time.txt file always updating
puts $archive "%02d:%02d:%02d" $h $m $s"
puts -nonewline ":: 'p' to pause, 'c' to continue and 's' to exit ::"
}
proc _time{ } {
_screen
after 1000
s=[expr s+1]
if { $s -eq 60 } { m=[expr m+1] } { s=00 }
if { $m -eq 60 } { h=[expr h+1] } { m=00 }
}
proc _pause{ } {
while { 1 }
{
_screen
after 1000
$argv key
if { "$key" = "c" } { break }
}
}
proc _main{ } {
# Put the terminal in special character interpretation mode
stty -echo -icanon min 0
while { 1 }
{
if { "$key" = "s" } { break }
if { "$key" = "p" } { _pause }
_time
$argv key
}
# Restores the default mode
stty sane
close $archive
exit 0
}
after 1000 _main
I'm still committed and working for this to work identically to the example quoted - bash script. But do not rule out improvements and suggestions that you can promote.
What I have in mind something like:
If someone here knows and wants to share the idea, feel free.
There are several issues with your Tcl code:
proc _pause{ } { -- Tcl is very whitespace sensitive, so you need to separate the procedure name from the argument list
s=[expr s+1] -- use set to set variables, and you need to use $s to get the variable value: set s [expr {$s+1}] or in this case use the incr command incr s
if { $s -eq 60 } and if { "$key" = "s" } -- see the expr man page for the correct operators.
You want {$s == 60} and {$key eq "s"}
stty -echo -icanon min 0 -- stty is an external command, so you need exec stty ...
Those are the main syntax problems. Your indentation style can be improved so you code can be readable and maintainable.
I thought this was an interesting challenge so I decided to implement it independently of your code. Let me know if you have any questions:
#!/usr/bin/env tclsh
set seconds 0
set running true
array set status {
false "(paused)"
true " "
}
#################################################################
proc main {} {
enableRaw
puts "'p' to pause; 'c' to continue; 'q' to quit"
every 1000 display_time
chan configure stdout -buffering none
chan configure stdin -blocking no -buffering none
chan event stdin readable handleStdin
vwait ::forever
disableRaw
puts ""
}
# ref https://wiki.tcl.tk/14693
proc enableRaw {{channel stdin}} {
exec /bin/stty raw -echo <#$channel
}
proc disableRaw {{channel stdin}} {
exec /bin/stty -raw echo <#$channel
}
proc every {ms code} {
after $ms [list every $ms $code]
uplevel #0 $code
}
proc display_time {{event ""}} {
global running seconds
puts -nonewline "\r [format_time] $::status($running) "
if {$running && $event eq ""} {incr seconds}
}
proc format_time {} {
return [clock format $::seconds -format "%H:%M:%S" -gmt true]
}
proc handleStdin {} {
set data [chan read stdin 1]
switch -- $data {
P - p {set ::running false; display_time}
C - c {set ::running true; display_time unpausing}
Q - q {set ::forever "now"}
}
}
#################################################################
main
Here's a slight modification of enableRaw and disableRaw that doesn't exec for stty:
package require term::ansi::ctrl::unix
proc enableRaw {} {
term::ansi::ctrl::unix::raw
}
proc diableRaw {} {
term::ansi::ctrl::unix::cooked
}

Bash script - "err: command not found"?

I am writing a bash script and I am using a for cycle to check my arguments.
for var in "$#"
do
test_arg "$var"
done
And this is my test_arg function
function test_arg {
[ -n "$1" ] || err "Empty argument"
[ -f "$1" ] || err "Argument '$1' is not a file"
[ -r "$1" ] || err "Data file '$1' is not readable"
[ -s "$1" ] || err "Data file '$1' is empty"
egrep -v '^-?([0-9]+|[0-9]*\.[0-9]+)$' "$1" && { echo "Bad data format in '$1'"; exit 1; }
}
However, when any of these conditions are not met, script only writes out "script.sh: line XX: err: command not found". I am not quite sure about the testing, I am a bash begginer.
Thank you very much for your answers
Your code depends on a function named err. Consider defining it like so:
err() { echo "$*" >&2; exit 1; }

Resources