[Techtalk] Perl Sockets Communication
Kai MacTane
kmactane at GothPunk.com
Tue Nov 11 18:32:35 EST 2003
At 11/4/03 09:50 PM , januhe wrote:
>My name is Javier Nunez and I want to ask you a question. I was looking
>a script that you made to change passwords from a CGI script you opened
>a socket to a server running a daemon that change the password.
Was this the pwchanged script? Ah, I see from the link that it was. (Is.
Whatever.)
>Well I create two scripts that run on a UNIX environment and one is
>running as a daemon, the other is connecting every month to the server
>to request the password change. My problem is that I do not know how to
>handle the passwd command.
What sort of handling does it need?
>How do I redirect the output of the passwd command and how do I pass
>the command the string that I'm going to use as a password.
You could do this by opening a pipe to passwd, like so:
open PASSWD, "| passwd $username";
# Assume program is prompting for new password.
print PASSWD "$newpass\n";
# Now assume it's asking for confirmation, and not complaining
# about the password being weak.
print PASSWD "$newpass\n";
# Could try doing it a third time, just in case...
close PASSWD;
But, as you can see, that's kind of risky, given that it involves lots of
assuming. A better way would be to use the IPC::Open2 module (documented in
Chapter 7 of the Camel Book) to open the pipe bidirectionally, so that you
can read each line of output from passwd and then deliver the appropriate
input.
But the way I dealt with the situation in my finished script was to ignore
the passwd utility altogether, and just write directly into /etc/shadow. It
came out something like this (with tutorial comments added):
$shadow = '/etc/shadow';
$new_shadow = $shadow . '.pwchanged';
# Open /etc/shadow, and create a new /etc/shadow.pwchanged.
open SHADOW, "$shadow";
$ret = open NEW, ">$new_shadow";
unless ($ret) {
# Give some sort of error message; couldn't open new file
}
# Read through shadow line-by-line, copying each line into
# new shadow. On the one line we're interested in, make some
# substitutions.
while ($line = <SHADOW>) {
if ($line =~ /^$username:/) {
# You need to update the date-last-changed as well as
# the actual password.
$new_date = `date +%s`; # Seconds since epoch; GNU extension
$new_date = int($new_date / 86400); # convert to days
# Note that @line and $line are different variables!
@line = split(/:/, $line);
# Presume $hashed_pass has been set up before; it should
# be the crypted or MD5ed version of the new password.
$line[1] = $hashed_pass;
$line[2] = $new_date;
$line = join(':', @line);
}
print NEW "$line";
}
close SHADOW;
$ret = close NEW;
unless ($ret) {
# Give some sort of error message; couldn't close new file
}
unless (rename $new_shadow, $shadow) {
# Give error message that you couldn't mv temp file over /etc/shadow
}
unless (chmod 0400, $shadow) {
# Give yet another error message
}
This code was written without strict mode on, hence the lack of the word
"my" on any variable declaration. Were I writing this stuff now, I'd do it
with strict mode and taint checking on (and see a comment in that thread
you referenced, about the dangers of allowing unsanitized user input to be
used in a system command).
Heck, were I writing it now, I'd strongly consider using IPC:::Open2. But,
if you like, I can post the scripts I actually did write. They've been in
production use on the client's machine, and on my own server as well, for a
couple of years now.
Hope that helps; let me know if you need other information.
--Kai MacTane
----------------------------------------------------------------------
"In another life I see you, as an angel flying high,
And the hands of time will free you; you will cast your chains aside,
And the dawn will come and kiss away
Every tear that's ever fallen from your eyes...
--Concrete Blonde,
"Caroline"
More information about the Techtalk
mailing list