Reputation: 35
I have an XML file that has this structure:
<user-mapping>
<authorize username="user2" password="asdasdsss" >
<connection name="U2 - Windows 7 ">
<protocol>rdp</protocol>
<param name="hostname">192.168.203.2</param>
<param name="port">21122</param>
<param name="password">asdasdsss</param>
<param name="username">user</param>
</connection>
<connection name="U2 - Windows XP SP3 ">
<protocol>rdp</protocol>
<param name="hostname">192.168.203.2</param>
<param name="port">21120</param>
<param name="password">asdasdsss</param>
<param name="username">user</param>
</connection>
</authorize>
</user-mapping>
This file has around 20 users (authorize
elements) and each user has around 15 machine connections.
I have created a Perl program to change only the password field, but it is based on counting lines and characters until the field is found. If I add additional param
elements then the script has to be modified.
I want to have a dynamic way of doingit, so that Perl can select the correct user node and change the password field in all related machines. I tried many ways but I couldn't get it to work.
The password should be changed for the user and for all machines. They will all will be changed to the same password
My code which is used now:
open( FILL, "< /etc/user-mapping.xml" );
@strings = <FILL>;
$i = 0;
foreach $line (@strings) {
print $i;
print $line;
$i++;
}
print "Number: ";
print $set_id;
$set_id = $set_id - 2;
$set_id = $set_id * 102;
print "Line: ";
print $set_id;
substr( @strings[ 1 + $set_id ], 43, 9 ) = "$password";
substr( @strings[ 6 + $set_id ], 39, 9 ) = "$password";
substr( @strings[ 13 + $set_id ], 39, 9 ) = "$password";
foreach $line ( @strings ) {
print $i;
print $line;
$i++;
}
open( FH, "> /etc/user-mapping.xml" );
foreach $line (@strings) {
print( FH $line );
}
close(FH);
close(FILL);
Upvotes: 1
Views: 66
Reputation: 126722
I hope you understand that keeping passwords as plain text is a very bad idea?
You must use a proper XML parser, and I suggest that you use XML::Twig
as it is a little friendlier than some alternatives
Here's a program that does as you ask. It changes the password to abc123
throughout. As you can see, it's even rather shorter than your original program
It uses XPath expressions to find all the /user-mapping/authorize
elements in the document and changes their password attributes to the new password. Then it finds every connection/param
element within each authorize
element that has a name="password"
attribute, and changes the text value of those too
use strict;
use warnings 'all';
use XML::Twig;
use constant XML_FILE => 'user-mapping.xml';
use constant NEW_PASSWORD => 'abc123';
use constant USER_NAME => 'user2';
my $twig = XML::Twig->new;
$twig->parsefile(XML_FILE);
for my $auth ( $twig->findnodes('/user-mapping/authorize') ) {
next unless $auth->att('username') eq USER_NAME;
$auth->set_att(password => NEW_PASSWORD);
for my $pass ( $auth->findnodes('connection/param[@name="password"]') ) {
$pass->set_text(NEW_PASSWORD);
}
}
$twig->set_pretty_print('indented');
$twig->print;
<user-mapping>
<authorize password="abc123" username="user2">
<connection name="U2 - Windows 7 ">
<protocol>rdp</protocol>
<param name="hostname">192.168.203.2</param>
<param name="port">21122</param>
<param name="password">abc123</param>
<param name="username">user</param>
</connection>
<connection name="U2 - Windows XP SP3 ">
<protocol>rdp</protocol>
<param name="hostname">192.168.203.2</param>
<param name="port">21120</param>
<param name="password">abc123</param>
<param name="username">user</param>
</connection>
</authorize>
</user-mapping>
Upvotes: 3
Reputation: 295403
Use a real XML parser. For instance, with XMLStarlet, this would be as easy as:
xmlstarlet ed \
-u '//authorize/@password' -v "new-password" \
-u '//connection/param[@name="password"]' -v "new-password"
Upvotes: 1