0

ejabberd 2.1.2 に問題があり、external_auth が応答を受信しませんでした。Google のさまざまな投稿とここの質問をすべて確認しましたが、まだ解決策が見つかりません。

/etc/ejabberd/ejabberd.cfg には、次のエントリがあります。

{auth_method, external}.
{extauth_program, "/tmp/auth.php"}.

上記の extauth_program は以下にあります。「ejabberd」ユーザーとして php ファイルを実行できます。ファイルの作成/ファイルのアクセス許可 (ログ ファイルも) は問題ありません。

#!/usr/bin/php

<?
$fh  = fopen("php://stdin", 'r');
$stdout = fopen('php://stdout', 'w');
$fs = fopen("/tmp/auth-log.txt." . getmypid(), 'a');

if(!$fh){
    die("Cannot open STDIN\n");
}

$users = array('user1'=>'password1', 'user2'=>'password2');

do{
    $lenBytes = fgets($fh, 3);
    $len = unpack('n', $lenBytes);
    $len = $len[1];
    if($len<1) continue;
    $msg = fgets($fh, $len+1);
    $toks=explode(':',$msg);
    fwrite($fs, $msg . "\n");

    $method = array_shift($toks);
    fwrite($fs, "$method\n");
    $result = false;

    switch($method){
        case 'auth':
            list($username, $server, $password) = $toks;
            $password = trim($password);
            fwrite($fs, "checking user: $username and password $password\n");

            if($users[$username] == $password){
                fwrite($fs, "password match\n");
                $result = true;
            }else{
                $result = false;
            }
            break;

        case 'isuser':
            list($username, $server) = $toks;
            if(isset($users[$username])){
                $result = true;
            }else{
                $result = false;
            }
            break;

        default:
            $result = false;
    }
        $message =  @pack("nn", 2, $result);
        fwrite($stdout, $message);
        $dump = @unpack("nn", $message);
        $dump = $dump["n"];
        fwrite($fs, $dump . "\n");
        flush();
} while(true);
?>

xjabberd を起動して「user1@example.com」とパスワード「password1」で接続しようとすると、信じられないほど長い時間がかかり、最終的に失敗します。ログ ファイルに、上記の PHP スクリプトから生成された次のエントリが表示されます。これらは、クライアントからサーバーへの接続が発生すると、ほぼ瞬時に発生します。

auth:user1:example.com:password1
auth
checking user: user1 and password password1
password match
2

/var/log/ejabberd/ejabberd.log には、次のエントリがあります。

=INFO REPORT==== 2011-02-20 01:15:26 ===
I(<0.557.0>:ejabberd_c2s:587) : ({socket_state,tls,{tlssock,#Port<0.2820>,#Port<0.2844>},<0.556.0>}) Failed authentication for user1@example.com

=ERROR REPORT==== 2011-02-20 01:15:36 ===
E(<0.365.0>:extauth:80) : extauth call '["auth","user1@example.com",
                                         "example.com","password1"]' didn't receive response

=INFO REPORT==== 2011-02-20 01:15:36 ===
I(<0.559.0>:ejabberd_c2s:587) : ({socket_state,tls,{tlssock,#Port<0.2846>,#Port<0.2848>},<0.558.0>}) Failed authentication for user1@example.com@example.com

=INFO REPORT==== 2011-02-20 01:15:37 ===
I(<0.553.0>:ejabberd_listener:232) : (#Port<0.2850>) Accepted connection {{10,1,1,3},55051} -> {{10,130,11,243},5222}

=ERROR REPORT==== 2011-02-20 01:15:50 ===
E(<0.365.0>:extauth:80) : extauth call '["auth","user1","example.com",
                                         "password1"]' didn't receive response

=INFO REPORT==== 2011-02-20 01:15:50 ===
I(<0.561.0>:ejabberd_c2s:587) : ({socket_state,tls,{tlssock,#Port<0.2850>,#Port<0.2852>},<0.560.0>}) Failed authentication for user1@example.com

=INFO REPORT==== 2011-02-20 01:15:51 ===
I(<0.553.0>:ejabberd_listener:232) : (#Port<0.2854>) Accepted connection {{10,1,1,3},55052} -> {{10,130,11,243},5222}

=ERROR REPORT==== 2011-02-20 01:16:03 ===
E(<0.365.0>:extauth:80) : extauth call '["auth","user1@example.com",
                                         "example.com","password1"]' didn't receive response

=INFO REPORT==== 2011-02-20 01:16:03 ===
I(<0.563.0>:ejabberd_c2s:587) : ({socket_state,tls,{tlssock,#Port<0.2854>,#Port<0.2856>},<0.562.0>}) Failed authentication for user1@example.com@example.com

これを解決するための助けをいただければ幸いです。前もって感謝します!

4

2 に答える 2

1

仕事の ejabberd 認証を取得するために 1 日を費やしました。
基本的に、標準入力からの読み取り中にプロセスをブロックすると問題が発生します。クライアントがタイムアウトのために切断されるまで、リクエスト文字列の最後でブロックされたままになります。
記述子からのシンボル読み取りによる非ブロックシンボルの解決策は次のとおりです。

function non_block_read($fd, &$data) {
    $read = array($fd);
    $write = array();
    $except = array();
    $result = stream_select($read, $write, $except, 0);
    if($result === false) {
                throw new Exception('stream_select failed');
        }
    if($result === 0) return false;
    $data.= stream_get_line($fd, 1);
    return true;
}

これは、生涯読み取りサイクルを作成するためのデーモン コードです。

$fh  = fopen("php://stdin", 'r');
$fhout  = fopen("php://stdout", 'w');
$pdo = new PDO('mysql:host='.$host.';dbname='.$db, $user,$pass);
if(!$fh){
    die("Cannot open STDIN\n");
}
$aStr='';
$collect=false;
do {
        if (!non_block_read($fh,$aStr)) {
                if (strlen($aStr) > 0) {
                       $toAuth = substr(trim($aStr),1);
                       checkAuth($toAuth,$pdo,$fhout);
                       $aStr='';
                }
                else sleep (1);
        }
}
while (true);

いくつかの説明: checkAuth - 'auth' および 'isuser' ハンドラーを実装する任意の関数。
sleep(1) - CPU 負荷を回避する簡単な方法。
最初の記号 - メッセージの先頭に追加するサービス記号で、クライアントごとに異なるため、切り取っただけです。
これが応答コードです。返信 - 真 | 偽の値。

$message =  @pack("nn", 2, $result);
fwrite($stdout, $message);
flush();

楽しみ。

于 2014-08-15T12:55:04.603 に答える
1

行の前:

$message =  @pack("nn", 2, $result);

書く:

$result = ($result) ? 1 : 0;
于 2012-03-23T19:56:31.150 に答える