|
|
|
@ -155,6 +155,7 @@ public:
|
|
|
|
|
TQString out_mech;
|
|
|
|
|
TQByteArray out_buf;
|
|
|
|
|
bool capable;
|
|
|
|
|
bool allow_plain;
|
|
|
|
|
int err;
|
|
|
|
|
|
|
|
|
|
TQCA_SASLNeedParams need;
|
|
|
|
@ -207,12 +208,13 @@ public:
|
|
|
|
|
host = _host;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setSecurityProps(bool, bool, bool, bool, bool reqForward, bool reqCreds, bool reqMutual, int ssfMin, int, const TQString &, int)
|
|
|
|
|
void setSecurityProps(bool noPlain, bool, bool, bool, bool reqForward, bool reqCreds, bool reqMutual, int ssfMin, int, const TQString &, int)
|
|
|
|
|
{
|
|
|
|
|
if(reqForward || reqCreds || reqMutual || ssfMin > 0)
|
|
|
|
|
capable = false;
|
|
|
|
|
else
|
|
|
|
|
capable = true;
|
|
|
|
|
allow_plain = !noPlain;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int security() const
|
|
|
|
@ -228,8 +230,17 @@ public:
|
|
|
|
|
bool clientStart(const TQStringList &mechlist)
|
|
|
|
|
{
|
|
|
|
|
bool haveMech = false;
|
|
|
|
|
resetState();
|
|
|
|
|
step = 0;
|
|
|
|
|
|
|
|
|
|
for(TQStringList::ConstIterator it = mechlist.begin(); it != mechlist.end(); ++it) {
|
|
|
|
|
if((*it) == "PLAIN" && allow_plain) {
|
|
|
|
|
out_mech = "PLAIN";
|
|
|
|
|
haveMech = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if((*it) == "DIGEST-MD5") {
|
|
|
|
|
out_mech = "DIGEST-MD5";
|
|
|
|
|
haveMech = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
@ -238,9 +249,6 @@ public:
|
|
|
|
|
err = TQCA::SASL::NoMech;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
resetState();
|
|
|
|
|
step = 0;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -316,7 +324,7 @@ public:
|
|
|
|
|
|
|
|
|
|
const TQByteArray *clientInit() const
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
return out_mech == "PLAIN" ? &out_buf : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TQByteArray result() const
|
|
|
|
@ -326,85 +334,126 @@ public:
|
|
|
|
|
|
|
|
|
|
int clientTryAgain()
|
|
|
|
|
{
|
|
|
|
|
if(step == 0) {
|
|
|
|
|
out_mech = "DIGEST-MD5";
|
|
|
|
|
++step;
|
|
|
|
|
return Continue;
|
|
|
|
|
if( out_mech == "PLAIN" ) {
|
|
|
|
|
if(step == 0) {
|
|
|
|
|
// First, check if we have everything
|
|
|
|
|
if(need.user || need.pass) {
|
|
|
|
|
err = -1;
|
|
|
|
|
return Error;
|
|
|
|
|
}
|
|
|
|
|
if(!have.user) {
|
|
|
|
|
need.user = true;
|
|
|
|
|
}
|
|
|
|
|
if(!have.pass) {
|
|
|
|
|
need.pass = true;
|
|
|
|
|
}
|
|
|
|
|
if(need.user || need.pass) {
|
|
|
|
|
return NeedParams;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TQCString authz_ = authz.utf8();
|
|
|
|
|
TQCString user_ = user.utf8();
|
|
|
|
|
TQCString pass_ = pass.utf8();
|
|
|
|
|
int l = 0;
|
|
|
|
|
|
|
|
|
|
out_buf.resize(authz_.length() + 1 + user_.length() + 1 + pass_.length());
|
|
|
|
|
memcpy(&out_buf[l], authz_.data(), authz_.length());
|
|
|
|
|
l += authz_.length();
|
|
|
|
|
out_buf[l] = '\0';
|
|
|
|
|
l += 1;
|
|
|
|
|
memcpy(&out_buf[l], user_.data(), user_.length());
|
|
|
|
|
l += user_.length();
|
|
|
|
|
out_buf[l] = '\0';
|
|
|
|
|
l += 1;
|
|
|
|
|
|
|
|
|
|
memcpy(&out_buf[l], pass_.data(), pass_.length());
|
|
|
|
|
++step;
|
|
|
|
|
return Continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out_buf.resize(0);
|
|
|
|
|
return Success;
|
|
|
|
|
}
|
|
|
|
|
else if(step == 1) {
|
|
|
|
|
// if we still need params, then the app has failed us!
|
|
|
|
|
if(need.user || need.authzid || need.pass || need.realm) {
|
|
|
|
|
err = -1;
|
|
|
|
|
return Error;
|
|
|
|
|
|
|
|
|
|
if( out_mech == "DIGEST-MD5" ) {
|
|
|
|
|
if(step == 0) {
|
|
|
|
|
++step;
|
|
|
|
|
return Continue;
|
|
|
|
|
}
|
|
|
|
|
else if(step == 1) {
|
|
|
|
|
// if we still need params, then the app has failed us!
|
|
|
|
|
if(need.user || need.authzid || need.pass || need.realm) {
|
|
|
|
|
err = -1;
|
|
|
|
|
return Error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// see if some params are needed
|
|
|
|
|
if(!have.user)
|
|
|
|
|
need.user = true;
|
|
|
|
|
if(!have.authzid)
|
|
|
|
|
need.authzid = true;
|
|
|
|
|
if(!have.pass)
|
|
|
|
|
need.pass = true;
|
|
|
|
|
if(need.user || need.authzid || need.pass)
|
|
|
|
|
return NeedParams;
|
|
|
|
|
|
|
|
|
|
// get props
|
|
|
|
|
TQCString cs(in_buf.data(), in_buf.size()+1);
|
|
|
|
|
PropList in;
|
|
|
|
|
if(!in.fromString(cs)) {
|
|
|
|
|
err = TQCA::SASL::BadProto;
|
|
|
|
|
return Error;
|
|
|
|
|
// see if some params are needed
|
|
|
|
|
if(!have.user)
|
|
|
|
|
need.user = true;
|
|
|
|
|
if(!have.authzid)
|
|
|
|
|
need.authzid = true;
|
|
|
|
|
if(!have.pass)
|
|
|
|
|
need.pass = true;
|
|
|
|
|
if(need.user || need.authzid || need.pass)
|
|
|
|
|
return NeedParams;
|
|
|
|
|
|
|
|
|
|
// get props
|
|
|
|
|
TQCString cs(in_buf.data(), in_buf.size()+1);
|
|
|
|
|
PropList in;
|
|
|
|
|
if(!in.fromString(cs)) {
|
|
|
|
|
err = TQCA::SASL::BadProto;
|
|
|
|
|
return Error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// make a cnonce
|
|
|
|
|
TQByteArray a(32);
|
|
|
|
|
for(int n = 0; n < (int)a.size(); ++n)
|
|
|
|
|
a[n] = (char)(256.0*rand()/(RAND_MAX+1.0));
|
|
|
|
|
TQCString cnonce = Base64::arrayToString(a).latin1();
|
|
|
|
|
|
|
|
|
|
// make other variables
|
|
|
|
|
realm = host;
|
|
|
|
|
TQCString nonce = in.get("nonce");
|
|
|
|
|
TQCString nc = "00000001";
|
|
|
|
|
TQCString uri = service.utf8() + '/' + host.utf8();
|
|
|
|
|
TQCString qop = "auth";
|
|
|
|
|
|
|
|
|
|
// build 'response'
|
|
|
|
|
TQCString X = user.utf8() + ':' + realm.utf8() + ':' + pass.utf8();
|
|
|
|
|
TQByteArray Y = TQCA::MD5::hash(X);
|
|
|
|
|
TQCString tmp = TQCString(":") + nonce + ':' + cnonce + ':' + authz.utf8();
|
|
|
|
|
TQByteArray A1(Y.size() + tmp.length());
|
|
|
|
|
memcpy(A1.data(), Y.data(), Y.size());
|
|
|
|
|
memcpy(A1.data() + Y.size(), tmp.data(), tmp.length());
|
|
|
|
|
TQCString A2 = "AUTHENTICATE:" + uri;
|
|
|
|
|
TQCString HA1 = TQCA::MD5::hashToString(A1).latin1();
|
|
|
|
|
TQCString HA2 = TQCA::MD5::hashToString(A2).latin1();
|
|
|
|
|
TQCString KD = HA1 + ':' + nonce + ':' + nc + ':' + cnonce + ':' + qop + ':' + HA2;
|
|
|
|
|
TQCString Z = TQCA::MD5::hashToString(KD).latin1();
|
|
|
|
|
|
|
|
|
|
// build output
|
|
|
|
|
PropList out;
|
|
|
|
|
out.set("username", user.utf8());
|
|
|
|
|
out.set("realm", host.utf8());
|
|
|
|
|
out.set("nonce", nonce);
|
|
|
|
|
out.set("cnonce", cnonce);
|
|
|
|
|
out.set("nc", nc);
|
|
|
|
|
out.set("serv-type", service.utf8());
|
|
|
|
|
out.set("host", host.utf8());
|
|
|
|
|
out.set("digest-uri", uri);
|
|
|
|
|
out.set("qop", qop);
|
|
|
|
|
out.set("response", Z);
|
|
|
|
|
out.set("charset", "utf-8");
|
|
|
|
|
out.set("authzid", authz.utf8());
|
|
|
|
|
TQCString s = out.toString();
|
|
|
|
|
|
|
|
|
|
// done
|
|
|
|
|
out_buf.resize(s.length());
|
|
|
|
|
memcpy(out_buf.data(), s.data(), out_buf.size());
|
|
|
|
|
++step;
|
|
|
|
|
return Continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// make a cnonce
|
|
|
|
|
TQByteArray a(32);
|
|
|
|
|
for(int n = 0; n < (int)a.size(); ++n)
|
|
|
|
|
a[n] = (char)(256.0*rand()/(RAND_MAX+1.0));
|
|
|
|
|
TQCString cnonce = Base64::arrayToString(a).latin1();
|
|
|
|
|
|
|
|
|
|
// make other variables
|
|
|
|
|
realm = host;
|
|
|
|
|
TQCString nonce = in.get("nonce");
|
|
|
|
|
TQCString nc = "00000001";
|
|
|
|
|
TQCString uri = service.utf8() + '/' + host.utf8();
|
|
|
|
|
TQCString qop = "auth";
|
|
|
|
|
|
|
|
|
|
// build 'response'
|
|
|
|
|
TQCString X = user.utf8() + ':' + realm.utf8() + ':' + pass.utf8();
|
|
|
|
|
TQByteArray Y = TQCA::MD5::hash(X);
|
|
|
|
|
TQCString tmp = TQCString(":") + nonce + ':' + cnonce + ':' + authz.utf8();
|
|
|
|
|
TQByteArray A1(Y.size() + tmp.length());
|
|
|
|
|
memcpy(A1.data(), Y.data(), Y.size());
|
|
|
|
|
memcpy(A1.data() + Y.size(), tmp.data(), tmp.length());
|
|
|
|
|
TQCString A2 = "AUTHENTICATE:" + uri;
|
|
|
|
|
TQCString HA1 = TQCA::MD5::hashToString(A1).latin1();
|
|
|
|
|
TQCString HA2 = TQCA::MD5::hashToString(A2).latin1();
|
|
|
|
|
TQCString KD = HA1 + ':' + nonce + ':' + nc + ':' + cnonce + ':' + qop + ':' + HA2;
|
|
|
|
|
TQCString Z = TQCA::MD5::hashToString(KD).latin1();
|
|
|
|
|
|
|
|
|
|
// build output
|
|
|
|
|
PropList out;
|
|
|
|
|
out.set("username", user.utf8());
|
|
|
|
|
out.set("realm", host.utf8());
|
|
|
|
|
out.set("nonce", nonce);
|
|
|
|
|
out.set("cnonce", cnonce);
|
|
|
|
|
out.set("nc", nc);
|
|
|
|
|
out.set("serv-type", service.utf8());
|
|
|
|
|
out.set("host", host.utf8());
|
|
|
|
|
out.set("digest-uri", uri);
|
|
|
|
|
out.set("qop", qop);
|
|
|
|
|
out.set("response", Z);
|
|
|
|
|
out.set("charset", "utf-8");
|
|
|
|
|
out.set("authzid", authz.utf8());
|
|
|
|
|
TQCString s = out.toString();
|
|
|
|
|
|
|
|
|
|
// done
|
|
|
|
|
out_buf.resize(s.length());
|
|
|
|
|
memcpy(out_buf.data(), s.data(), out_buf.size());
|
|
|
|
|
++step;
|
|
|
|
|
return Continue;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
out_buf.resize(0);
|
|
|
|
|
return Success;
|
|
|
|
|
}
|
|
|
|
|