Authen-SASL-XS
view release on metacpan or search on metacpan
char *pkg
SV *parent
char *service
char *host
char *iplocalport
char *ipremoteport
CODE:
{
Authen_SASL_XS sasl = NULL;
int rc;
if ((rc = init_sasl(parent,service,host,&sasl,SASL_IS_CLIENT)) != SASL_OK)
croak("Saslinit failed. (%x)\n",rc);
sasl_client_init(NULL);
_DEBUG("service: %s, host: %s, mech: %s",sasl->service,sasl->server,sasl->mech);
#ifdef SASL2
rc = sasl_client_new(sasl->service, sasl->server, iplocalport, ipremoteport, sasl->callbacks, 1, &sasl->conn);
#else
rc = sasl_client_new(sasl->service, sasl->server, sasl->callbacks, 1, &sasl->conn);
#endif
if (SetSaslError(sasl,rc,"client_new error.") == SASL_OK)
{
#ifdef SASL2
set_secprop(sasl);
#endif
}
RETVAL = sasl;
}
OUTPUT:
RETVAL
=pod
=item server_start ( CHALLENGE )
C<server_start> begins the authentication using the chosen mechanism.
If the mechanism is not supported by the installed Cyrus-SASL it fails.
Because for some mechanisms the client has to start the negotiation,
you can give the client challenge as a parameter.
=cut
char *
server_start(sasl,instring=NULL)
Authen_SASL_XS sasl;
const char *instring;
PREINIT:
int rc;
unsigned outlen;
STRLEN inlen;
#ifdef SASL2
const char *outstring = NULL;
#else
char *outstring = NULL;
const char *error =NULL;
#endif
PPCODE:
_DEBUG("serverstart mech: %s",sasl->mech);
if (sasl->error_code)
XSRETURN_UNDEF;
if (instring != NULL)
SvPV(ST(1),inlen);
else
inlen = 0;
_DEBUG("serverstart len: %d",inlen);
_DEBUG("Server step: %s %d", instring,inlen);
#ifdef SASL2
rc = sasl_server_start(sasl->conn,sasl->mech, instring, inlen, &outstring, &outlen);
#else
rc = sasl_server_start(sasl->conn,sasl->mech, instring, inlen, &outstring, &outlen, &error);
#endif
SetSaslError(sasl,rc,"server_start error."); // SASL_CONTINUE has to be set
_DEBUG("Server step out: %s %d",outstring, outlen);
if (rc != SASL_OK && rc != SASL_CONTINUE)
XSRETURN_UNDEF;
else // Everything works fine
XPUSHp(outstring, outlen);
=pod
=item client_start ( )
The initial step to be performed. Returns the initial value to pass to the server.
Client has to start the negotiation always.
=cut
char *
client_start(sasl)
Authen_SASL_XS sasl
PREINIT:
int rc;
unsigned outlen;
#ifdef SASL2
const char *outstring;
#else
char *outstring;
#endif
const char *mech;
PPCODE:
if (sasl->error_code != SASL_OK)
XSRETURN_UNDEF;
_DEBUG("mech: %s",sasl->mech);
#ifdef SASL2
rc = sasl_client_start(sasl->conn, sasl->mech, NULL, &outstring, &outlen, &mech);
#else
rc = sasl_client_start(sasl->conn, sasl->mech, NULL, NULL, &outstring, &outlen, &mech);
#endif
_DEBUG("client_start. error %x, len: %d",rc,outlen);
SetSaslError(sasl,rc,"client_start error. (Callbacks?)");
if (rc != SASL_OK && rc != SASL_CONTINUE)
XSRETURN_UNDEF;
else
XPUSHp(outstring, outlen);
=pod
=item server_step ( CHALLENGE )
C<server_step> performs the next step in the negotiation process. The
first parameter you give is the clients challenge/response.
=cut
char *
server_step(sasl, instring)
Authen_SASL_XS sasl
char *instring
PREINIT:
#ifdef SASL2
const char *outstring=NULL;
#else
char *outstring=NULL;
const char *error=NULL;
#endif
int rc;
unsigned int outlen=0;
STRLEN inlen;
PPCODE:
if (sasl->error_code != SASL_CONTINUE)
XSRETURN_UNDEF;
SvPV(ST(1),inlen);
_DEBUG("Server step: %s %d", instring,inlen);
#ifdef SASL2
rc = sasl_server_step(sasl->conn,instring,inlen,&outstring,&outlen);
#else
rc = sasl_server_step(sasl->conn,instring,inlen,&outstring,&outlen,NULL);
#endif
// Setting error, if any
SetSaslError(sasl,rc,"server_step error.");
// return undef if error, code() will give the truth
if (rc != SASL_OK && rc != SASL_CONTINUE)
XSRETURN_UNDEF;
else
XPUSHp(outstring, outlen);
=pod
=item client_step ( CHALLENGE )
=back
B<Remark>:
C<client_start>, C<client_step>, C<server_start> and C<server_step>
will return the respective sasl response or undef. The returned value
says nothing about the current negotiation status. It is absolutely possible
that one of these functions return undef and everything is fine for SASL,
there is only another step needed.
Therefore you have to check C<need_step> and C<code> during negotiation.
See example below.
=over 4
=item
=cut
char *
client_step(sasl, instring)
Authen_SASL_XS sasl
char *instring
PPCODE:
{
#ifdef SASL2
const char *outstring=NULL;
#else
char *outstring=NULL;
#endif
int rc;
unsigned int outlen=0;
STRLEN inlen;
if (sasl->error_code != SASL_CONTINUE)
XSRETURN_UNDEF;
SvPV(ST(1),inlen);
_DEBUG("client_step: inlen: %d",inlen);
rc = sasl_client_step(sasl->conn, instring, inlen, NULL, &outstring, &outlen);
SetSaslError(sasl,rc,"client_step.");
_DEBUG("client_step: error code: %x, len: %d",rc,outlen);
if (rc != SASL_OK && rc != SASL_CONTINUE)
XSRETURN_UNDEF;
else
XPUSHp(outstring, outlen);
}
=pod
=item listmech( START , SEPARATOR , END )
C<listmech> returns a string containing all mechanisms allowed for the user
set by C<user>. START is the token which will be put at the beginning of the
string, SEPARATOR is the token which will be used to separate the mechanisms
and END is the token which will be put at the end of returned string.
=cut
char *
listmech(sasl,start="",separator="|",end="")
Authen_SASL_XS sasl;
const char* start;
const char* separator;
const char* end;
PPCODE:
{
int rc;
#ifdef SASL2
const char *mechs;
#else
char *mechs;
#endif
int mechcount;
unsigned mechlen;
rc = sasl_listmech(sasl->conn,sasl->user,start,separator,end,&mechs,&mechlen,&mechcount);
if (rc == SASL_OK)
XPUSHp(mechs,mechlen);
else
{
SetSaslError(sasl,rc,"listmech error.");
XSRETURN_UNDEF;
}
}
#ifdef SASL2
=pod
=item setpass(user, newpassword, oldpassword, flags)
=item checkpass(user, password)
C<setpass> and C<checkpass> is only available when using Cyrus-SASL 2.x library.
C<setpass> sets a new password (depends on the mechanism if the setpass callback
is called). C<checkpass> checks a password for the user (calls the checkpass
callback).
For both function see the man pages of the Cyrus SASL for a detailed description.
Both functions return true on success, false otherwise.
=cut
int
setpass(sasl, user, pass, oldpass, flags=0)
Authen_SASL_XS sasl;
const char *user;
const char *pass;
const char *oldpass;
int flags;
PREINIT:
int rc;
PPCODE:
_DEBUG("setpass: %s,%s,%s,%d",user,pass,oldpass,flags);
rc = sasl_setpass (sasl->conn,user,
pass,strlen(pass),
oldpass,strlen(oldpass),
flags);
XPUSHi(rc);
int checkpass(sasl,user,pass)
Authen_SASL_XS sasl;
const char *user;
const char *pass;
PREINIT:
int rc;
PPCODE:
_DEBUG("checkpass: %s,%s",user,pass);
rc = sasl_checkpass (sasl->conn,
user, strlen(user),
pass, strlen(pass));
XPUSHi(rc);
=pod
=item global_listmech ( )
C<global_listmech> is only available when using Cyrus-SASL 2.x library.
It returns an array with all mechanisms loaded by the library.
=cut
void
global_listmech(sasl)
Authen_SASL_XS sasl
PREINIT:
int i;
const char **mechs;
PPCODE:
if (sasl->error_code)
XSRETURN_UNDEF;
mechs = sasl_global_listmech();
if (mechs)
for (i = 0; mechs[i]; i++)
XPUSHs(sv_2mortal(newSVpv(mechs[i],0)));
else
XSRETURN_UNDEF;
#endif
=pod
=item encode ( STRING )
=item decode ( STRING )
Cyrus-SASL developers suggest using the C<encode> and C<decode> functions
for every traffic which will run over the network after a successful authentication
C<encode> returns the encrypted string generated from STRING.
C<decode> returns the decrypted string generated from STRING.
It depends on the used mechanism how secure the encryption will be.
=cut
char *
encode(sasl, instring)
Authen_SASL_XS sasl
char *instring
PPCODE:
{
#ifdef SASL2
const char *outstring=NULL;
#else
char *outstring=NULL;
#endif
int rc;
unsigned int outlen=0;
STRLEN inlen;
if (sasl->error_code)
XSRETURN_UNDEF;
instring = SvPV(ST(1),inlen);
rc = sasl_encode(sasl->conn, instring, inlen, &outstring, &outlen);
if (SetSaslError(sasl,rc,"sasl_encode failed") != SASL_OK)
XSRETURN_UNDEF;
else
XPUSHp(outstring, outlen);
}
char *
decode(sasl, instring)
Authen_SASL_XS sasl
char *instring
PPCODE:
{
#ifdef SASL2
const char *outstring=NULL;
#else
char *outstring=NULL;
#endif
int rc;
unsigned int outlen=0;
STRLEN inlen;
if (sasl->error_code)
XSRETURN_UNDEF;
instring = SvPV(ST(1),inlen);
rc = sasl_decode(sasl->conn, instring, inlen, &outstring, &outlen);
if (SetSaslError(sasl,rc,"sasl_decode failed.") != SASL_OK)
XSRETURN_UNDEF;
else
XPUSHp(outstring, outlen);
}
int
callback(sasl, ...)
Authen_SASL_XS sasl
CODE:
/*
This function is unnecessary since there is no
chance for changing callbacks in sasl after (server|
client)_new function calls. But without calling one
of these functions (from perl) you do not have an
object of this class. So you cannot call ->callback.
At least I was not able to use this function to fill in
a callback with this function.
-Patrick
*/
croak("Deprecated. Don't use, it isn't working anymore.");
RETVAL = 0;
OUTPUT:
RETVAL
=pod
=item error ( )
C<error> returns an array with all known error messages.
Basicly the sasl_errstring function is called with the current error_code.
When using Cyrus-SASL 2.x library also the string returned by sasl_errdetail
is given back. Additionally the special Authen::SASL::XS advise is
returned if set.
After calling the C<error> function, the error code and the special advice
are thrown away.
=cut
char *
error(sasl)
Authen_SASL_XS sasl
PPCODE:
{
_DEBUG("Current Error %x",sasl->error_code);
XPUSHs(newSVpv((char *)sasl_errstring(sasl->error_code,NULL,NULL),0));
#ifdef SASL2
XPUSHs(newSVpv((char *)sasl_errdetail(sasl->conn),0));
#endif
if (sasl->additional_errormsg != NULL)
XPUSHs(newSVpv(sasl->additional_errormsg,0));
// only real error should be overwritten
if (sasl->error_code != SASL_OK && sasl->error_code != SASL_CONTINUE)
{
sasl->error_code = SASL_OK;
if (sasl->additional_errormsg != NULL)
free(sasl->additional_errormsg);
sasl->additional_errormsg = NULL;
}
__DEBUG("End of Error");
}
=pod
=item code ( )
C<code> returns the current Cyrus-SASL error code.
=cut
int
code(sasl)
Authen_SASL_XS sasl
CODE:
RETVAL=sasl->error_code;
OUTPUT:
RETVAL
=pod
=item mechanism ( )
C<mechanism> returns the current used authentication mechanism.
=cut
char *
mechanism(sasl)
Authen_SASL_XS sasl
CODE:
RETVAL = sasl->mech;
OUTPUT:
RETVAL
char *
host(sasl, ...)
Authen_SASL_XS sasl
CODE:
if (items > 1) {
if (sasl->server) free(sasl->server);
sasl->server = strdup(SvPV_nolen(ST(1)));
}
RETVAL = sasl->server;
OUTPUT:
RETVAL
char *
user(sasl, ...)
Authen_SASL_XS sasl
CODE:
if (items > 1) {
if (sasl->user) free(sasl->user);
sasl->user = strdup(SvPV_nolen(ST(1)));
}
RETVAL = sasl->user;
OUTPUT:
RETVAL
char *
service(sasl, ...)
Authen_SASL_XS sasl
CODE:
if (items > 1) {
if (sasl->service) free(sasl->service);
sasl->service = strdup(SvPV_nolen(ST(1)));
}
RETVAL = sasl->service;
OUTPUT:
RETVAL
=pod
=item need_step ( )
C<need_step> returns true if another step is need by the SASL library. Otherwise
false is returned. You can also use C<code == 1> but it looks smarter I think.
That's why we all using perl, eh?
=cut
int
need_step(sasl)
Authen_SASL_XS sasl;
CODE:
RETVAL = sasl->error_code == SASL_CONTINUE;
OUTPUT:
RETVAL
int
property(sasl, ...)
Authen_SASL_XS sasl
PPCODE:
{
#ifdef SASL2
const void *value=NULL;
#else
void *value=NULL;
#endif
char *name;
int rc, x, propnum=-1;
SV *prop;
RETVAL = SASL_OK;
if (!sasl->conn) {
#ifdef SASL2
SetSaslError(sasl,SASL_NOTINIT,"property failed, init missed.");
RETVAL = SASL_NOTINIT;
#else
SetSaslError(sasl,SASL_FAIL,"property failed, init missed.");
RETVAL = SASL_FAIL;
#endif
items = 0;
}
/* Querying the value of a property */
if (items == 2) {
name = SvPV_nolen(ST(1));
propnum = PropertyNumber(name);
rc = sasl_getprop(sasl->conn, propnum, &value);
if (value == NULL || rc != SASL_OK)
XSRETURN_UNDEF;
switch(propnum){
case SASL_USERNAME:
#ifdef SASL2
case SASL_DEFUSERREALM:
#else
case SASL_REALM:
#endif
XPUSHp( (char *)value, strlen((char *)value));
break;
case SASL_SSF:
case SASL_MAXOUTBUF:
XPUSHi((long int)value);
break;
#ifdef SASL2
case SASL_IPLOCALPORT:
case SASL_IPREMOTEPORT:
XPUSHp( (char *)value, strlen((char *)value));
break;
case SASL_IP_LOCAL:
propnum = SASL_IPLOCALPORT;
{
char *addr = inet_ntoa( (*(struct in_addr *)value));
XPUSHp( addr, strlen(addr));
}
break;
case SASL_IP_REMOTE:
propnum = SASL_IPREMOTEPORT;
{
char *addr = inet_ntoa( (*(struct in_addr *)value));
( run in 1.132 second using v1.01-cache-2.11-cpan-71847e10f99 )