/* * Copyright (c) 2015-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #include #include #include #include #define SECURITY_LAYER_NONE 1 namespace Swift { WindowsGSSAPIClientAuthenticator::WindowsGSSAPIClientAuthenticator(const std::string& hostname, const std::string& domainname, int port) : ClientAuthenticator("GSSAPI"), step_(BuildingSecurityContext), error_(false), haveCredentialsHandle_(false), haveContextHandle_(false), haveCompleteContext_(false) { WindowsServicePrincipalName servicePrincipalName(domainname); servicePrincipalName.setInstanceName(hostname); if ((port != -1) && (port != 5222)) { servicePrincipalName.setInstancePort(port); } servicePrincipalNameString_ = servicePrincipalName.toString(); errorCode_ = acquireCredentialsHandle(&credentialsHandle_); if (isError()) { return; } else { haveCredentialsHandle_ = true; } buildSecurityContext(boost::optional()); } WindowsGSSAPIClientAuthenticator::~WindowsGSSAPIClientAuthenticator() { if (haveContextHandle_) { deleteSecurityContext(&contextHandle_); } if (haveCredentialsHandle_) { freeCredentialsHandle(&credentialsHandle_); } } boost::optional WindowsGSSAPIClientAuthenticator::getResponse() const { SWIFT_LOG(debug) << "response_.size(): " << response_.size() << std::endl; return response_; } bool WindowsGSSAPIClientAuthenticator::setChallenge(const boost::optional& challengeData) { /* Following http://tools.ietf.org/html/rfc4752, https://msdn.microsoft.com/en-us/library/windows/desktop/aa380496%28v=vs.85%29.aspx */ if (step_ == BuildingSecurityContext) { buildSecurityContext(challengeData); } else if (step_ == SecurityLayerNegotiation) { if (!challengeData) { SWIFT_LOG(debug) << "Empty message received from the server" << std::endl; error_ = true; return false; } SafeByteArray challenge; errorCode_ = decryptMessage(&contextHandle_, challengeData.get(), challenge); if (isError()) { return false; } if (challenge.size() != 4) { SWIFT_LOG(debug) << "Token received from the server of incorrect length: " << challenge.size() << std::endl; error_ = true; return false; } unsigned char* challengePointer = vecptr(challenge); unsigned char serverSecurityLayer = challengePointer[0]; if (serverSecurityLayer == 0) { SWIFT_LOG(debug) << "Server supports unknown security layer, assuming no security layer" << std::endl; serverSecurityLayer = SECURITY_LAYER_NONE; } else if (serverSecurityLayer == SECURITY_LAYER_NONE) { SWIFT_LOG(debug) << "Server supports no security layer" << std::endl; } else { SWIFT_LOG(debug) << "Server supports security layer" << std::endl; } unsigned int serverMaximumBuffer = (challengePointer[1] << 16) | (challengePointer[2] << 8) | (challengePointer[3] << 0); if ((serverSecurityLayer == SECURITY_LAYER_NONE) && (serverMaximumBuffer != 0)) { SWIFT_LOG(debug) << "Server supports no security layer but has maximum buffer size" << serverMaximumBuffer << std::endl; error_ = true; return false; } SafeByteArray message(4); /* Commenting this out as streamSizes was not obtained before if (message.size() > streamSizes_.cbMaximumMessage) { error_ = true; return false; } */ unsigned char* messagePointer = vecptr(message); messagePointer[0] = SECURITY_LAYER_NONE; /* The next 3 bytes indicate the client's maximum size buffer which is set to 0 as we do not support a security layer */ messagePointer[1] = 0; messagePointer[2] = 0; messagePointer[3] = 0; /* The authorization identity is omitted as it is the same as the authentication identity */ errorCode_ = encryptMessage(&contextHandle_, sizes_, message, response_); if (isError()) { return false; } step_ = ServerAuthenticated; } if (isError()) { return false; } return true; } bool WindowsGSSAPIClientAuthenticator::isError() { if (error_) { return true; } if (!errorCode_) { return false; } return true; } void WindowsGSSAPIClientAuthenticator::buildSecurityContext(const boost::optional& inputToken) { ULONG contextSupported; /* An XMPP server may not support Kerberos encryption or SASL security layer so not requesting integrity or confidentiality */ errorCode_ = initializeSecurityContext(inputToken, servicePrincipalNameString_, &credentialsHandle_, haveContextHandle_, &contextHandle_, ISC_REQ_MUTUAL_AUTH, &contextSupported, &haveCompleteContext_, response_); if (isError()) { return; } haveContextHandle_ = true; if (!haveCompleteContext_) { return; } if (contextSupported & ISC_REQ_MUTUAL_AUTH == 0) { SWIFT_LOG(debug) << "Mutual authentication not supported" << std::endl; error_ = true; return; } errorCode_ = queryContextAttributes(&contextHandle_, SECPKG_ATTR_SIZES, &sizes_); if (isError()) { return; } /* Commenting this out as it gives the error code 0x80090302: The function requested is not supported errorCode_ = queryContextAttributes(&contextHandle_, SECPKG_ATTR_STREAM_SIZES, &streamSizes_); if (isError()) { return; }*/ SecPkgContext_Names names; errorCode_ = queryContextAttributes(&contextHandle_, SECPKG_ATTR_NAMES, &names); if (isError()) { return; } userName_ = names.sUserName; SWIFT_LOG(debug) << "User name: " << userName_ << std::endl; std::size_t position = userName_.find("\\"); clientName_ = userName_.substr(position + 1); SWIFT_LOG(debug) << "Client name: " << clientName_ << std::endl; serverName_ = userName_.substr(0, position); SWIFT_LOG(debug) << "Server name: " << serverName_ << std::endl; freeContextBuffer(names.sUserName); step_ = SecurityLayerNegotiation; } }