68user's page 掲示板

Prev< No. 1335〜1340> Next  [最新発言に戻る] [過去ログ一覧]
No. 1335 # as 2000/11/08 (水) 16:35:03
No.1269で、超初心者さんがやってたのと同じように、CGIからexpectスクリプト
を呼び出して、他のマシンにtelnetしてパスワードを変更するシステムを作って
いるんですが、telnetで戻ってきた文字が一部うまくexpectに渡されないようで
途中で止まってしまい、上手くいきません。

そこで$|=1にして出力を見たら、以下のところで止まっている事が分かりました。

spawn telnet server
Trying xxx.xxx.xxx.xxx ...
Connected to server.xxx.xxx.
Escape character is '^]'.

”Escape character is '^]'.”の後に、CRLFが来るんですが、それから先が上手
くexpectに渡されていない(?)ようです。

HTTPdがCRLFだから止めてしまっているんでしょうか?
それってHTTPdの仕様なんでしょうか?
exec 'expect';の後のprint文はexpectのtimeout後に出力されます。

どこで止めてしまってしまっているかを調べる方法や解決方法など、アイディア
がありましたら教えてください。

No. 1336 # 68user 2000/11/08 (水) 22:25:40
僕は expect 使ったことありませんのでわかりませんが、せっかく
perl を使っているんですから、Net::Telnet モジュールでやって
みてはいかがでしょう。
    use Net::Telnet;
    $t = Net::Telnet->(Timeout=>10, Prompt => '/\w+?@\w+?: /');
    $t->open('hostname');
    $t->login('yourname', 'password');
    @lines = $t->cmd("/bin/ls -l");
    print @lines;
    $t->close();
言うまでもないかもしれませんが、Prompt のところは適切に
変更しないと動きません。詳しくは perldoc Net::Telnet をどうぞ。

No. 1337 # 68user 2000/11/08 (水) 23:17:49
うーん、むずかしい…。全然理解してないことがよくわかった。
すごく汚くて変な書き方ですがこんな感じ。

    use Net::Telnet;
    $username='yourname';
    $oldpasswd='secret1';
    $newpasswd='secret2';
    $t = new Net::Telnet (Timeout => 5, Prompt => '/\w*? /', Dump_Log => 'telnet-log');
    $t->open("localhost");
    $t->login($username, $oldpasswd);
    $t->prompt('/Old password:/');

    $t->cmd("/usr/bin/passwd");

    $t->print("$oldpasswd\n");
    ($prematch,$match) = $t->waitfor('/[a-zA-Z ]+:/');
    print "[$prematch] [$match]\n";

    $t->print("$newpasswd\n");
    ($prematch,$match) = $t->waitfor('/[a-zA-Z ]+:/');
    print "[$prematch] [$match]\n";

    $t->print("$newpasswd\n");
    ($prematch,$match) = $t->waitfor('/[a-zA-Z ]+:/');
    print "[$prematch] [$match]\n";
    $t->close();

適当に $match の結果に応じて、パスワードが違うやら、
新しいパスワードが短いやら出力すればいいのかな。
expect の方がすっきり書けるような気も。

No. 1338 # 68user 2000/11/08 (水) 23:42:20
やっぱ僕がやるとしたら pw コマンドの wrapper 作って、
それを root に suid するなぁ。passwd の挙動を
全て把握するのは厳しい。

No. 1339 # as 2000/11/09 (木) 16:08:59
結局、68userさんのおっしゃる通りpasswdの挙動を全て把握するのは
厳しいので、telnetされる側のServerにID,Passwordを変数として受け
取って、passwdファイルを直接編集するperlを置き、それをCGI(Perl)
からtelnetして、rootで実行させるようにしました。

結局何故expectで動作しないのかは不明なままですが、要求を満たす
物は出来ました。

アドバイスありがとうございました。

No. 1340 # rosegarden 2000/11/10 (金) 02:48:35
私の場合、次のような感じのスクリプトで動きます。
一応、ログインしてコマンド実行程度なら、大丈夫のようです。
環境は perl 5.00503 + Expect-1.08 + FreeBSD 4.2-BETA です。

#!/usr/bin/perl

use Expect;

my $user = 'rose';
my $password = 'password';
my $prompt = 'host\{rose\}\d+\s';

my @cmdlist = (
        'ls -alF',
        'ps -auxw',
        'exit',
        );

my $telnet = Expect->spawn("telnet localhost");

$telnet->expect(30,"login: ") || die "NO login prompt";
print $telnet "$user\r";

$telnet->expect(30,"assword:") || die "NO password prompt";
print $telnet "$password\r";

my $match = $telnet->expect( 30,
        "closed by foreign host",
        "-re", $prompt
        );

die "refused by server\n" if $match == 1;
die "NO shell prompt, ".$telnet->exp_error()."\n" unless $match;

foreach $cmd ( @cmdlist ) {
        print $telnet "$cmd\r";

        my $match = $telnet->expect(
                30,
                "closed by foreign host",
                "-re", $prompt
                );
        last if $match == 1;
        die "NO prompt after command\n" if $telnet->exp_error();
}

$telnet->hard_close();
exit;

Prev< No. 1335〜1340> Next  [最新発言に戻る] [過去ログ一覧]