External Authentication Problems

I've been wracking my brain on this for days and can't seem to figure out how to get external authentication to work. I've written scripts in every language, used every example, made all the necessary changes to the ejabberd.cfg but nothing works.

The particulars:

ejabberd.cfg
{auth_method, external}.
{extauth_program, "/etc/ejabberd/auth.php"}.

/etc/ejabberd/auth.php (one I borrowed and grossly simplified)

#!/usr/local/bin/php

<?php
error_reporting
(0);
$auth = new JabberAuth();
$auth->play(); // We simply start process !

class JabberAuth {
        var
$debug              = true;                                       /* Debug mode */
       
var $debugfile  = "/var/log/pipe-debug.log"/* Debug output */
       
var $logging    = false;                                      /* Do we log requests ? */
       
var $logfile    = "/var/log/pipe-log.log" ;   /* Log file ... */
        /*
         * For both debug and logging, ejabberd have to be able to write.
         */

       

var $jabber_user;   /* This is the jabber user passed to the script. filled by $this->command() */
       
var $jabber_pass;   /* This is the jabber user password passed to the script. filled by $this->command() */
       
var $jabber_server; /* This is the jabber server passed to the script. filled by $this->command(). Useful for VirtualHosts */
       
var $jid;           /* Simply the JID, if you need it, you have to fill. */
       
var $data;          /* This is what SM component send to us. */

       

var $dateformat = "M d H:i:s"; /* Check date() for string format. */
       
var $command; /* This is the command sent ... */
       
var $mysock/* MySQL connection ressource */
       
var $stdin;   /* stdin file pointer */
       
var $stdout/* stdout file pointer */

       

function JabberAuth()
        {
                @
define_syslog_variables();
                @
openlog("pipe-auth", LOG_NDELAY, LOG_SYSLOG);

                if(

$this->debug) {
                        @
error_reporting(E_ALL);
                        @
ini_set("log_errors", "1");
                        @
ini_set("error_log", $this->debugfile);
                }
               
$this->logg("Starting pipe-auth ..."); // We notice that it's starting ...
               
$this->openstd();
        }

        function

stop()
        {
               
$this->logg("Shutting down ..."); // Sorry, have to go ...
               
closelog();
               
$this->closestd(); // Simply close files
               
exit(0); // and exit cleanly
       
}

        function

openstd()
        {
               
$this->stdout = @fopen("php://stdout", "w"); // We open STDOUT so we can read
               
$this->stdin  = @fopen("php://stdin", "r"); // and STDIN so we can talk !
       
}

        function

readstdin()
        {
               
$l      = @fgets($this->stdin, 3); // We take the length of string
               
$length = @unpack("n", $l); // ejabberd give us something to play with ...
               
$len    = $length["1"]; // and we now know how long to read.
               
if($len > 0) { // if not, we'll fill logfile ... and disk full is just funny once
                       
$this->logg("Reading $len bytes ... "); // We notice ...
                       
$data   = @fgets($this->stdin, $len+1);
                       
// $data = iconv("UTF-8", "ISO-8859-15", $data); // To be tested, not sure if still needed.
                       
$this->data = $data; // We set what we got.
                       
$this->logg("IN: ".$data);
                }
        }

        function

closestd()
        {
                @
fclose($this->stdin); // We close everything ...
               
@fclose($this->stdout);
        }

        function

out($message)
        {
                @
fwrite($this->stdout, $message); // We reply ...
               
$dump = @unpack("nn", $message);
               
$dump = $dump["n"];
               
$this->logg("OUT: ". $dump);
        }

        function

play()
        {
                do {
                       
$this->readstdin(); // get data
                       
$length = strlen($this->data); // compute data length
                       
if($length > 0 ) { // for debug mainly ...
                               
$this->logg("GO: ".$this->data);
                               
$this->logg("data length is : ".$length);
                        }
                       
$ret = $this->command(); // play with data !
                       
$this->logg("RE: " . $ret); // this is what WE send.
                       
$this->out($ret); // send what we reply.
                       
$this->data = NULL; // more clean. ...
               
} while (true);
        }

        function

command()
        {
               
$data = $this->splitcomm(); // This is an array, where each node is part of what SM sent to us :
                // 0 => the command,
                // and the others are arguments .. e.g. : user, server, password ...

               

if(strlen($data[0]) > 0 ) {
                       
$this->logg("Command was : ".$data[0]);
                }
                switch(
$data[0]) {
                        case
"isuser": // this is the "isuser" command, used to check for user existance
                                       
$this->jabber_user = $data[1];
                                       
$parms = $data[1];  // only for logging purpose
                                       
$return = $this->checkuser();
                                break;

                        case

"auth": // check login, password
                                       
$this->jabber_user = $data[1];
                                       
$this->jabber_pass = $data[3];
                                       
$parms = $data[1].":".$data[2].":".md5($data[3]); // only for logging purpose
                                       
$return = $this->checkpass();
                                break;

                        case

"setpass":
                                       
$return = false; // We do not want jabber to be able to change password
                               
break;

                        default:
                                       

$this->stop(); // if it's not something known, we have to leave.
                                        // never had a problem with this using ejabberd, but might lead to problem ?
                               
break;
                }

               

$return = ($return) ? 1 : 0;

                if(

strlen($data[0]) > 0 && strlen($parms) > 0) {
                       
$this->logg("Command : ".$data[0].":".$parms." ==> ".$return." ");
                }
                return @
pack("nn", 2, $return);
        }

        function

checkpass()
        {
                return
true;
        }

        function

checkuser()
        {
                return
true;
        }

        function

splitcomm() // simply split command and arugments into an array.
       
{
                return
explode(":", $this->data);
        }

        function

logg($message) // pretty simple, using syslog.
        // some says it doesn't work ? perhaps, but AFAIR, it was working.
       
{
                if(
$this->logging) {
                        @
syslog(LOG_INFO, $message);
                }
        }
}
?>

Finally... The errors.

At startup:

=ERROR REPORT==== 2010-10-21 05:08:25 ===
C(<0.304.0>:extauth:91) : normal

At login attempt:

=ERROR REPORT==== 2010-10-21 05:22:40 ===
** State machine <0.422.0> terminating
** Last event in was {xmlstreamelement,
{xmlelement,"auth",
[{"xmlns","urn:ietf:params:xml:ns:xmpp-sasl"},
{"mechanism","PLAIN"}],
[{xmlcdata,<<"AGNocmlzAHRlc3QxMjM0">>}]}}
** When State == wait_for_feature_request
** Data == {state,{socket_state,tls,
{tlssock,#Port<0.2848>,#Port<0.2850>},
<0.421.0>},
ejabberd_socket,#Ref<0.0.0.9868>,false,"143191734",
{sasl_state,"jabber","qa.imedge.com",[],
#Fun,
#Fun,
#Fun,undefined,
undefined},
c2s,c2s_shaper,false,true,false,true,
[verify_none,{certfile,"/etc/ejabberd/ejabberd.pem"}],
false,undefined,[],"qa.imedge.com",[],undefined,
{0,nil},
{0,nil},
{0,nil},
{0,nil},
undefined,undefined,undefined,false,
{userlist,none,[],false},
unknown,unknown,
{{172,18,2,100},20082},
"en"}
** Reason for termination =
** {badarg,[{extauth,call_port,2},
{ejabberd_auth_external,check_password,3},
{ejabberd_auth,check_password_loop,2},
{cyrsasl_plain,mech_step,2},
{cyrsasl,server_step,2},
{ejabberd_c2s,wait_for_feature_request,2},
{p1_fsm,handle_msg,10},
{proc_lib,init_p_do_apply,3}]}

At this point, I'm at my wit's end. NOTHING has worked, and the errors I'm getting in the log don't make any sense to me. Why is it that, at startup, I get an ERROR report loading the external auth piece that simply says "normal". That doesn't mean anything to me. If someone can help me, I'm all ears.

Thanks,
Chris

Disclaimer: I didn't read in

Disclaimer: I didn't read in detail your script.

This document says
https://git.process-one.net/ejabberd/mainline/blobs/raw/2.1.x/doc/dev.ht...
"That script is supposed to do theses actions, in an infinite loop: "

If I modify the example check_pass_null.pl
and break the infinite loop to not be infinite:

--- a/examples/extauth/check_pass_null.pl
+++ b/examples/extauth/check_pass_null.pl
@@ -4,7 +4,7 @@ use Unix::Syslog qw(:macros :subs);

 my $domain = $ARGV[0] || "example.com";

-while(1)
+while(0)
   {
    # my $rin = '',$rout;
    # vec($rin,fileno(STDIN),1) = 1;

then I get exactly the same error messages that you got.

Syndicate content