######################################################################
    PasswordMonkey 0.07
######################################################################

NAME
    PasswordMonkey - Password prompt responder

SYNOPSIS
        use PasswordMonkey;
        use PasswordMonkey::Filler::Sudo;
        use PasswordMonkey::Filler::Adduser;

        my $sudo = PasswordMonkey::Filler::Sudo->new(
            password => "supersecrEt",
        );

        my $adduser = PasswordMonkey::Filler::Adduser->new(
            password => "logmein",
        );

        my $monkey = PasswordMonkey->new();

        $monkey->filler_add( $sudo );
        $monkey->filler_add( $adduser );

          # Spawn a script that asks for 
          #  - the sudo password and then
          #  - the new password for 'adduser' twice
        $monkey->spawn("sudo adduser testuser");

          # Password monkey goes to work
        $monkey->go();

        # ==== In action:
        # [sudo] password for mschilli: 
        # (waits two seconds)
        # ******** (types 'supersecrEt\n')
        # ...
        # Copying files from `/etc/skel' ...
        # Enter new UNIX password: 
        # ******** (types 'logmein')
        # Retype new UNIX password: 
        # ******** (types 'logmein')

DESCRIPTION
    PasswordMonkey is a plugin-driven approach to provide passwords to
    prompts, following strategies human users would employ as well. It comes
    with a set of Filler plugins who know how to deal with common
    applications expecting password input (sudo, ssh) and a set of Bouncer
    plugins who know how to employ different security strategies once a
    prompt has been detected. It can be easily extended to support
    additional applications.

    That being said, let me remind you that USING PLAINTEXT PASSWORDS IN
    AUTOMATED SYSTEMS IS ALMOST ALWAYS A BAD IDEA. Use ssh keys, custom sudo
    rules, PAM modules, or other techniques instead. This Expect-based
    module uses plain text passwords and it's useful in a context with
    legacy applications, because it provides a slightly better and safer
    mechanism than simpler Expect-based scripts, but it is still worse than
    using passwordless technologies. You've been warned.

Return Codes
    The $monkey->go() method call returns a true value upon success, so
    running

        if( ! $monkey->go() ) {
            print "Something went wrong!\n";
        }

    will catch any errors. Also,

        $monkey->is_success();

    will return true on success. Note that hitting a timeout or a bad exit
    status of the spawned process is considered an error. To check for these
    cases, use the following accessors:

        if( $monkey->exit_status() ) {
            print "The process exited with rc=", $monkey->exit_status(), "\n";
        }

        if( $monkey->timed_out() ) {
            print "The monkey timed out!\n";
        }

    To get the number of password fills the monkey performed, use

        my $nof_fills = $monkey->fills();

    Note that "exit_status()" returns the Perl-specific return code of
    "system()". If you need the shell-specific return code, you need to use
    "exit_status() >> 8" instead (check 'perldoc -f system' for details).

Fillers
  PasswordMonkey::Filler::Sudo
    Sudo passwords

    Running a command like

        $ sudo adduser testuser
        [sudo] password for mschilli: 
        ********

  PasswordMonkey::Filler::Passwd
    The passwd Program

        Copying files from `/etc/skel' ...
        Enter new UNIX password: 
        ********
        Retype new UNIX password: 
        ********

  PasswordMonkey::Filler::SSH
        $ ssh localhost
        testuser@localhost's password: 
        ********

Bouncer Plugins
    Bouncer plugins can configure a number of security checks to run after a
    prompt has been detected. These checks are also implemented as plugins,
    and are added to filler plugins via their "bouncer_add" method.

  Verifying inactivity after password prompts: Bouncer::Wait
    To make sure that we are actually dealing with a sudo password prompt in
    the form of

        # [sudo] password for joeuser:

    and not just a fly-by text string matching the prompt regular
    expression, we add a Wait Bouncer object to it, which blocks the Sudo
    plugin's response until two seconds have passed without any other
    output, making sure that the application is actually waiting for input:

        use PasswordMonkey;

        my $sudo = PasswordMonkey::Filler::Sudo->new(
            password => "supersecrEt",
        );

        my $wait_two_secs =
            PasswordMonkey::Bouncer::Wait->new( seconds => 2 );

        $sudo->bouncer_add( $wait_two_secs );

        $monkey->filler_add( $sudo );

        $monkey->spawn("sudo ls");

    This will spawn sudo, detect if it's asking for the user's password by
    matching its output against a regular expression, and, upon a match,
    waits two seconds and proceeds only if there's no further output
    activity until then.

  Typing on terminals with echo on: Bouncer::NoEcho
    PasswordMonkey starts typing innocuous characters after receiving a
    password prompt like "Password:" and checks if those characters appear
    on the screen:

        Password: abc

    If nothing is displayed, the prompt is okay and the user hits
    "Backspace" to delete the test characters, followed by the real password
    and the "Return" key. If, on the other hand, characters start to show up
    on screen, the password entering process is aborted immediately.

  Hitting enter to see prompt reappear: Bouncer::Retry
    To see if a password prompt is really genuine, PasswordMonkey hits enter
    and verifies the prompt reappears:

        Password:
        Password:

    before it starts typing the password.

  Filler API
    Writing new filler plugins is easy, see the sudo plugin as an example:

        package PasswordMonkey::Filler::Sudo;
        use strict;
        use warnings;
        use base qw(PasswordMonkey::Filler);
    
        sub prompt {
            return qr(^\[sudo\] password for [\w_]+:\s*$);
        }

    All that's required is that you let your plugin inherit from the
    PasswordMonkey::Filler base class and then override the "prompt" method
    to return a regular expression for the prompt upon which the plugin is
    supposed to send its password.

    "new( key =" value )>
        Most plugins accept a 'password' option, to set the password they'll
        transmit with once their internally configured prompt has been
        detected.

    "prompt()"
        Returns the regular expression that the plugin is waiting for to
        respond with the password.

  Bouncer API
    A Bouncer plugin defines a "check()" method which uses the a reference
    to the Expect object to run its prompt verification tests.

AUTHOR
    2011, Mike Schilli <cpan@perlmeister.com>

COPYRIGHT & LICENSE
    Copyright (c) 2011 Yahoo! Inc. All rights reserved. The copyrights to
    the contents of this file are licensed under the Perl Artistic License
    (ver. 15 Aug 1997).