How do I reset my LDAP password from Perl? - perl

My company, like everyone else's, requires password resets from time to time. This is all good and well for security's sake, but I'd like to explore the challenge of resetting it through a script (notably because we can't use our previous 25 passwords; Perl is much quicker about cycling through a list two-dozen deep than my fingers are).
I'm trying to use Perl and Win32::OLE's LDAP connectors to reset my password. I've followed a couple of examples online, and have, briefly:
use strict;
use Win32::OLE;
my $dn = 'cn=name,dc=corp,dc=com';
my $ldap = Win32::OLE->GetObject('LDAP:');
my $ldap_user = $ldap->OpenDSObject('LDAP://' . $dn,'username','password',1);
$ldap_user->SetPassword('mySw337NewPassword');
And all I get for my troubles is:
Win32::OLE(0.1707) error 0x80070005: "Access is denied"
in METHOD/PROPERTYGET "SetPassword" at pw.change.pl line 8
Is this something that can be worked around? I've located the Net::LDAP::Extension::SetPassword module, but no dice there.
Thanks!
Update for Leon (Max, you're next):
You're correct, I should have specified better. I tried Win32::OLE, failed, then separately tried Net::LDAP::Extension::SetPassword and failed even harder.
As for my server: I'm not certain, I'm not the LDAP guy :) By running ->root_dse->get_value('supportedExtension') I can see that the setPassword OID is not set, so maybe it's just not meant to be.
Final props to barneyton!
Final solution:
use strict;
use Win32::OLE;
my $orig_password = 'password123Test';
my $target_password = 'password321Test';
my $dn = 'cn=myname,dc=corp,dc=com';
my $ldap = Win32::OLE->GetObject('LDAP:');
my $ldap_user = $ldap->OpenDSObject('LDAP://'.$dn,'myname',$orig_password,1);
my $tmp_password = '';
for ( my $i = 0; $i < 30; ++$i )
{
$tmp_password = 'password' . $i . 'ABC';
print 'Changing to ' . $tmp_password . "\n";
$ldap_user->ChangePassword($orig_password,$tmp_password);
$orig_password = $tmp_password;
sleep 1;
}
$ldap_user->ChangePassword($tmp_password,$target_password);

When you said you were trying to "reset" your password, I think you really meant change password rather than set password. There is a difference between the two. "SetPassword" requires god/admin privilege since you are setting a user's password to a new value regardless of whether the old password is known, while "ChangePassword" requires the user to actually know the old password. I'm assuming your account does not have admin privilege, else you would not have gotten 0x80070005: "Access is denied"
So instead of:
$ldap_user->SetPassword('mySw337NewPassword');
try this:
$ldap_user->ChangePassword('password', 'mySw337NewPassword');
By the way, I've never done this stuff in perl, so I'm just guessing. Hope this helps you out.

Net::LDAP::Extension::SetPassword doesn't have anything to do with any OLE LDAP object. Either you use Net::LDAP, or you use Win32::OLE->GetObject('LDAP:').
You didn't mention what server you're using. Setting passwords requires an extension to LDAP, so that is relevant.

Another thing to keep in mind is Active Directory does not let you set passwords unless you bind to port 636 using LDAPS.

You could try to write the value to userPassword which would be a password reset, and you might not have rights to do that.
Otherwise you could try in one operation (LDIF would show it as separated by a single dash on a line) remove the value of the old password and then add the value of the new password. That would be a password change event.

Related

Connectivity issue to Sybase DB from Perl script

I have to connect my Perl script to a newly constructed Sybase server version - 16.0.03.08.1019
Error - login Failed (due to encrypt password issue)
Previously the script was written in Perl:
$conn = Sybase::DBlib->new($user,$pass,$server,"$dbase Handle");
$conn->sql("use $dbase");
I searched online every where it is written put EncryptPassword=1.
I tried two ways shown below, but couldn't succeed.
$conn = Sybase::DBlib->new($user,$pass,$server,"$dbase Handle","EncryptPassword=1");
$conn = Sybase::DBlib->new("EncryptPassword=1",$user,$pass,$server,"$dbase Handle");
My question is, where to use EncryptPassword=1 in Perl script. Am I using it in correct place.
Wow! DBlib - that takes me back. When I last worked with DBlib (in about 1995), one of the tasks on my list was to replace all use of DBlib with CTlib - which was Sybase's new technology that was intended to replace DBlib. Soon after that, the system was rewritten again to use DBI and DBD::Sybase - which has been the recommended way to talk to Sybase databases from Perl programs for over twenty years. You'll note that the most recent release of sybperl (which is the CPAN distribution containing Sybase::DBlib and Sybase::CTlib) was over ten years ago. I'm pretty sure that Sybase themselves haven't supported DBlib since about the start of this millennium.
So, bearing in mind that you're using ancient technology that is largely dead and shouldn't be used, is there anything that can be done to help you without rewriting the whole system?
Perhaps.
Looking at the documentation for Sybase::DBlib, I see this example of how to write calls to new():
$dbh = new Sybase::DBlib [$user [, $pwd [, $server [, $appname [, {additional attributes}]]]]]
Ignore the fact that it's using the new Class syntax that any rational programmer would avoid - the Class->new() version is this:
$dbh = Sybase::DBlib->new([$user [, $pwd [, $server [, $appname [, {additional attributes}]]]]])
Note the "additional attributes" field at the end. I bet that's where your stuff needs to go. Note also, that it's { additional attributes } - so it looks like it expects a hash reference.
So it seems likely that the syntax you want is this:
$conn = Sybase::DBlib->new($user, $pass, $server, "$dbase Handle", {
EncryptPassword => 1,
});
Note that there are huge caveats in this. Not least, given that Sybase::DBlib has been unsupported for ten years, I wouldn't be at all surprised if it didn't support encrypted passwords at all.
But it might work. It's probably your best hope.
And please do whatever you can to update your codebase to use tools and libraries that haven't been unsupported for such a long time.

Problems check username input against flat file for user creation

I am working on a user login and am having trouble with the user creation part. My problem is that I am trying to check the input username against a text file to see if that username already exists. I can't seem to get it to compare the input username to the array that I have brought in. I have tried two different ways of accomplishing this. One using an array and another using something I read online that I don't quite understand. Any help or explanation would be greatly appreciated.
Here is my attempt using an array to compare off of
http://codepad.org/G7xmsf3z
Here is my second attempt
http://codepad.org/SbeqmdbG
In your first attempt, try to put the if inside of the loop:
foreach my $pair(#incomingarray) {
(my $name,my $value) = split (/:/, $pair);
if ($name eq $username) {
print p("Username is already taken, try again");
close(YYY);
print end_html();
}
else {
open(YYY, ">>password.txt");
print YYY $username.":".$hashpass."\n";
print p("Your account has been created sucessfully");
close(YYY);
print end_html();
}
}
In you second attempt, I think you should try and change the line:
if (%users eq $username) {
with this one:
if (defined $users{$username}) {
As has been stated above regarding locking the flatfile from other processes there is the issue with scaling too. the more users you have the slower the lookup will be.
I started years ago with a flat file, believing I would never scale enough to require a real database and didn't want to learn how to use mySQL for example. Eventually after flatfile corruptions and long lookup times I had no choice but to move to a database.
Later you will find yourself wanting to store user preferences and such, it's easy to add a new field to a database. Flatfile will end up having the overhead of splitting each line into separate fields.
I'd suggest you do it properly with a database.
As in my comment, you should not be using a flatfile to hold your user info. You should use a proper database that will handle concurrent access for you rather than having to understand and code up how to deal with all of that yourself!
If you insist on using an array, you can search it with grep() if it is not "too large":
if (grep /^$username:/, #incomingarray) {
print "user name '$username' is already registered, try again\n";
}
else {
print "user name '$username' is not already registered\n";
}
I see some other problems in your code as well.
You should always prefer lexical (my) variables over package (our) variables.
Why do you think (erroneously) that $name and $username cannot be lexical variables?
You should always use the 3-arg form of open() and check its return value like in your 2nd code example. Your open() in the 1st code example is how it was done many many years ago.

How can I store more information in a session in Zend?

So I created a user system, and I want to grab the a few other fields from my database after authenticate()ing them. How can I do this?
If you want to store extra information in the identity beyond the typical, you can do something like this upon successful authentication.
This is in my login controller, processAction() upon successful authentication:
$identity = new stdClass;
$identity->username = strtolower( $auth->getIdentity() );
$identity->miscParam1 = 'Miscellaneous parameter1';
$identity->miscParam2 = 'Miscellaneous parameter2';
# ... etc ...
$storage = $auth->getStorage();
$storage->write($identity);
It's important to note that if you use this approach, then every time you want to get the username or the other parameters, you will need to retrieve it like so:
$identity = Zend_Auth::getInstance()->getStorage()->read();
echo $identity->username; # echo is just for example
echo $identity->miscParam1;
echo $identity->miscParam2;
Note that you would use getStorage()->read() instead of getIdentity() (which might also work but I am not sure).
Now, the only thing left to do is populate $identity->miscParam1 (etc) with information from your database using Zend_Db_Select. (Looking back at your question... I hope you weren't asking how to query. I probably didn't even answer your question.)

How can I map UIDs to user names using Perl library functions?

I'm looking for a way of mapping a uid (unique number representing a system user) to a user name using Perl.
Please don't suggest greping /etc/passwd :)
Edit
As a clarification, I wasn't looking for a solution that involved reading /etc/passwd explicitly. I realize that under the hood any solution would end up doing this, but I was searching for a library function to do it for me.
The standard function getpwuid, just like the same C function, gets user information based on its ID. No uses needed:
my ($name) = getpwuid(1000);
print $name,"\n";
Although it eventually reads /etc/passwd file, using standard interfaces is much more clear for other users to see, let alone it saves you some keystrokes.
Read /etc/passwd and hash the UID to login name.
Edit:
$uid = getpwnam($name);
$name = getpwuid($num);
$name = getpwent();
$gid = getgrnam($name);
$name = getgrgid($num);
$name = getgrent();
As you can see, regardless of which one you pick, the system call reads from /etc/passwd (see this for reference)
Actually I would suggest building a hash based on /etc/passwd :-) This should work well as the user ids are required to be unique.

How can I get the extension entered by user in a Perl AGI script?

I'm new to Asterisk AGI programming. Im trying to create a simple IVR, using asterisk-perl, where a user can enter any extension from 1 to 4. Here is my code so far:
use Asterisk::AGI;
$AGI = new Asterisk::AGI;
for($i = 0 ; $i < 2 ; $i++)
{
$AGI->exec('Playback','welcome');
$AGI->exec('WaitExten','5|m');
}
Now, I want to know the extension the user entered and take some action accordingly. How to get the extension entered by the user?
Thank You.
I believe you want to use get_data, allowing you to play a file and then wait a given time for a given number of digits e.g.:
$AGI->get_data('demo-welcome', 15000, 5);
See here
Well since the WaitExten command changes the user to a new extension, I suppose you can read the special variable ${EXTEN} after calling WaitExten. I'm not familiar with Asterisk::Perl though, I've only used FastAGI from Java, so I don't know the exact command, but there must be some command to read a variable's value.