Проверка подлинности NTLM завершается неудачно с ошибками INVALID TOKEN

Я пытаюсь реализовать проверку подлинности NTLM в C++ с помощью Windows API

InitializeSecurityContext
AcquireCredentialsHandle
AcceptSecurityContext

Я реализовал сервер и клиент, которые обмениваются токеном, сгенерированным с использованием этих функций. Все работает нормально, когда я запускаю сервер и клиент на одной машине,... НО, как только я запускаю приложения на 2 разных машинах в ОДНОМ ЖЕ домене, он больше не работает.

Чтобы быть точным вызов сервера AcceptSecurityContext не удается с ошибкой SEC_E_INVALID_TOKEN,

Вы знаете, что я делаю не так?

Часть этого кода взята с веб-сервера. Если я использую INTERNET EXPLORER в качестве клиента для подключения с удаленного компьютера, работает фин.

Есть ли что-то, что я должен проверить, например, безопасность брандмауэра или сети, которая препятствует нормальной работе NTLM на двух компьютерах?

я использую boost::asio обменять токены через сети

Ниже полный список.

После завершения сборки используйте командную строку 's', чтобы запустить сервер, и 'c', чтобы определить клиент

        #pragma warning( disable: 4996 )

        #include <boost/asio.hpp>
        #include <boost/assert.hpp>
        #include <thread>

        #include <Windows.h>

        #define SECURITY_WIN32
        #include <Security.h>
        #include <cassert>
        #include <iostream>

        #define TARGET_INIT_SECURITY_CONTEXT "TEST/192.168.10.92"

        #define BYTES_MAX_MESSAGE            12000
        #define ASIO_BUFFER_SIZE             1024

        #define CLIENT_SECURITY_CONTEXT         "NTLM"
        #define CLIENT_SECURITY_REQUIREMENTS    ISC_REQ_CONNECTION

        #define SERVER_SECURITY_CONTEXT         "NTLM"
        #define SERVER_SECURITY_REQUIREMENETS   ASC_REQ_CONNECTION


        void cs_base64_encode(const unsigned char *src, int src_len, char *dst);
        int cs_base64_decode(const unsigned char *s, int len, char *dst, int *dec_len);

        std::string base64_decode(std::string const& encoded_string);
        std::string base64_encode(char const* bytes_to_encode, unsigned int in_len);


        class NTLMServer
        {
        public:
            std::string first_call(std::string clientToken_string)
            {
                SECURITY_STATUS status = ::AcquireCredentialsHandle(NULL,
                    SERVER_SECURITY_CONTEXT,
                    SECPKG_CRED_INBOUND,            
                    NULL,
                    NULL,
                    NULL,
                    NULL,
                    &serverCredentials_,
                    NULL);

                BOOST_ASSERT_MSG(status == SEC_E_OK, "AcquireCredentialsHandle failed");        

                BYTE       *pOut = new BYTE[BYTES_MAX_MESSAGE];
                std::memset(pOut, 0, sizeof(BYTE) * BYTES_MAX_MESSAGE);

                SecBuffer serverOutBuffer_;
                SecBufferDesc serverToken_;

                serverOutBuffer_.BufferType = SECBUFFER_TOKEN;
                serverOutBuffer_.cbBuffer = BYTES_MAX_MESSAGE;
                serverOutBuffer_.pvBuffer = pOut;        

                serverToken_.cBuffers = 1;
                serverToken_.pBuffers = &serverOutBuffer_;
                serverToken_.ulVersion = SECBUFFER_VERSION;

                std::string out;        

                SecBufferDesc clientToken;
                SecBuffer clientOutBuffer;

                {
                    std::string strToken = base64_decode(clientToken_string);            

                    BYTE       *pOut = new BYTE[BYTES_MAX_MESSAGE];
                    std::memset(pOut, 0, sizeof(BYTE) * BYTES_MAX_MESSAGE);
                    strToken.copy(reinterpret_cast<char*>(pOut), strToken.size());

                    clientToken.cBuffers = 1;
                    clientToken.pBuffers = &clientOutBuffer;
                    clientToken.ulVersion = SECBUFFER_VERSION;

                    clientOutBuffer.BufferType = SECBUFFER_TOKEN;
                    clientOutBuffer.cbBuffer = strToken.size();
                    clientOutBuffer.pvBuffer = pOut;

                    ULONG ContextAttributes = 0;

                    SECURITY_STATUS  status = AcceptSecurityContext(
                        &serverCredentials_,
                        NULL,
                        &clientToken,
                        SERVER_SECURITY_REQUIREMENETS,
                        SECURITY_NATIVE_DREP,
                        &hContext_,
                        &serverToken_,
                        &ContextAttributes,
                        NULL);


                    BOOST_ASSERT_MSG(status == SEC_I_CONTINUE_NEEDED || status == SEC_E_OK, "AcceptSecurityContext failed");

                    int bufferSize = static_cast< int >(serverOutBuffer_.cbBuffer);
                    out = base64_encode(reinterpret_cast< const char *> (serverToken_.pBuffers->pvBuffer), bufferSize);
                }

                return out;
            }

            void second_call(const std::string& clientToken_string)
            {
                SecBufferDesc clientToken;
                SecBuffer clientOutBuffer;

                std::string strToken = base64_decode(clientToken_string);        

                BYTE       *pIn = new BYTE[BYTES_MAX_MESSAGE];
                std::memset(pIn, 0, sizeof(BYTE) * BYTES_MAX_MESSAGE);
                strToken.copy(reinterpret_cast<char*>(pIn), strToken.size());

                clientToken.cBuffers = 1;
                clientToken.pBuffers = &clientOutBuffer;
                clientToken.ulVersion = SECBUFFER_VERSION;

                clientOutBuffer.BufferType = SECBUFFER_TOKEN;
                clientOutBuffer.cbBuffer = strToken.size();
                clientOutBuffer.pvBuffer = pIn;

                BYTE       *pOut = new BYTE[BYTES_MAX_MESSAGE];
                std::memset(pOut, 0, sizeof(BYTE) * BYTES_MAX_MESSAGE);

                SecBuffer serverOutBuffer_;
                SecBufferDesc serverToken_;

                serverOutBuffer_.BufferType = SECBUFFER_TOKEN;
                serverOutBuffer_.cbBuffer = BYTES_MAX_MESSAGE;
                serverOutBuffer_.pvBuffer = pOut;         

                serverToken_.cBuffers = 1;
                serverToken_.pBuffers = &serverOutBuffer_;
                serverToken_.ulVersion = SECBUFFER_VERSION;

                ULONG ContextAttributes = 0;

                SECURITY_STATUS  status = AcceptSecurityContext(
                    &serverCredentials_,
                    &hContext_,
                    &clientToken,
                    SERVER_SECURITY_REQUIREMENETS,
                    SECURITY_NATIVE_DREP,
                    &hContext_,
                    &serverToken_,
                    &ContextAttributes,
                    NULL);

                BOOST_ASSERT_MSG(status != SEC_E_INVALID_TOKEN, "Invalid Token!?!?!?");
                BOOST_ASSERT_MSG(status == SEC_E_OK, "NOT OK?!?!?" );
            }

            CredHandle      serverCredentials_;
            CtxtHandle      hContext_;
        };

        class NTLMClient
        {
        public:
            std::string first_call()
            {
                ULONG ContextAttributes = 0;
                SECURITY_STATUS  status = AcquireCredentialsHandle(
                    NULL,
                    CLIENT_SECURITY_CONTEXT,
                    SECPKG_CRED_OUTBOUND,            
                    NULL,
                    NULL,
                    NULL,
                    NULL,
                    &hCred_,
                    NULL);



                BOOST_ASSERT_MSG(status == SEC_E_OK, "AcquireCredentialsHandle failed");

                SecBuffer   OutSecBuff;

                BYTE       *pIn = NULL;

                BYTE       *pOut = new BYTE[BYTES_MAX_MESSAGE];
                std::memset(pOut, 0, sizeof(BYTE) * BYTES_MAX_MESSAGE);

                BOOL       fDone = FALSE;
                BOOL       *pfDone = &fDone;

                DWORD       cbOut = BYTES_MAX_MESSAGE;
                DWORD      *pcbOut = &cbOut;

                OutDesc_.ulVersion = 0;
                OutDesc_.cBuffers = 1;
                OutDesc_.pBuffers = &OutSecBuff;

                OutSecBuff.cbBuffer = *pcbOut;
                OutSecBuff.BufferType = SECBUFFER_TOKEN;
                OutSecBuff.pvBuffer = pOut;

                status = InitializeSecurityContext(
                    &hCred_,
                    NULL,
                    TARGET_INIT_SECURITY_CONTEXT,
                    CLIENT_SECURITY_REQUIREMENTS,
                    0,
                    SECURITY_NATIVE_DREP,
                    NULL,
                    0,
                    &hContext_,
                    &OutDesc_,
                    &ContextAttributes,
                    NULL);



                BOOST_ASSERT_MSG(status == SEC_I_CONTINUE_NEEDED, "InitializeSecurityContext failed");

                *pcbOut = OutSecBuff.cbBuffer;
                *pfDone = !((SEC_I_CONTINUE_NEEDED == status) ||
                    (SEC_I_COMPLETE_AND_CONTINUE == status));



                std::string output;
                output.resize(cbOut * 2);

                cs_base64_encode(pOut, cbOut, &output[0]);
                output.erase(output.find_first_of('\0'));  // remove the string

                return output;
            }

            std::string second_call(const std::string& server_response)
            {        
                SecBuffer   OutSecBuff;

                BYTE       *pIn;
                BYTE       *pOut;

                DWORD       cbOut = 0;
                DWORD      *pcbOut = &cbOut;

                BOOL        done;
                DWORD       cbIn;

                pIn = new BYTE[BYTES_MAX_MESSAGE];
                std::memset(pIn, 0, sizeof(BYTE) * BYTES_MAX_MESSAGE);

                pOut = new BYTE[BYTES_MAX_MESSAGE];
                std::memset(pOut, 0, sizeof(BYTE) * BYTES_MAX_MESSAGE);

                int what_is_this = cs_base64_decode(reinterpret_cast<const unsigned char *>(server_response.c_str()),
                    server_response.size(),
                    reinterpret_cast<char *>(pIn),
                    NULL);

                cbIn = what_is_this;
                cbOut = BYTES_MAX_MESSAGE;

                SecBuffer   InSecBuff;

                OutDesc_.ulVersion = 0;
                OutDesc_.cBuffers = 1;
                OutDesc_.pBuffers = &OutSecBuff;

                OutSecBuff.cbBuffer = *pcbOut;
                OutSecBuff.BufferType = SECBUFFER_TOKEN;
                OutSecBuff.pvBuffer = pOut;

                ServerTokenDesc_.ulVersion = 0;
                ServerTokenDesc_.cBuffers = 1;
                ServerTokenDesc_.pBuffers = &InSecBuff;

                InSecBuff.cbBuffer = cbIn;
                InSecBuff.BufferType = SECBUFFER_TOKEN;
                InSecBuff.pvBuffer = pIn;


                ULONG ContextAttributes = 0;
                SECURITY_STATUS  status = InitializeSecurityContext(
                    &hCred_,
                    &hContext_,
                    TARGET_INIT_SECURITY_CONTEXT,
                    CLIENT_SECURITY_REQUIREMENTS,
                    0,
                    SECURITY_NATIVE_DREP,
                    &ServerTokenDesc_,
                    0,
                    &hContext_,
                    &OutDesc_,
                    &ContextAttributes,
                    NULL);

                *pcbOut = OutSecBuff.cbBuffer;
                done = !((SEC_I_CONTINUE_NEEDED == status) ||
                    (SEC_I_COMPLETE_AND_CONTINUE == status));        

                BOOST_ASSERT_MSG(status == SEC_E_OK, "InitializeSecurityContext failed");



                std::string output;
                output.resize(cbOut * 2);

                cs_base64_encode(pOut, cbOut, &output[0]);
                output.erase(output.find_first_of('\0'));  // remove the string


                return output;
            }

        private:
            CredHandle      hCred_;
            CtxtHandle      hContext_;
            SecBufferDesc   ServerTokenDesc_;
            SecBufferDesc   OutDesc_;
        };

        class TCPServer
        {
        public:
            void start()
            {
                // STAT LISTENING AND READ
                //
                using boost::asio::ip::tcp;
                tcp::acceptor a(io_context, tcp::endpoint(tcp::v4(), 32111));
                tcp::socket sock(io_context);
                a.accept(sock);        

                char data[ASIO_BUFFER_SIZE];
                std::memset(data, 0, ASIO_BUFFER_SIZE);
                size_t length;

                boost::system::error_code error;
                length = sock.read_some(boost::asio::buffer(data), error);

                if (error == boost::asio::error::eof)
                    return; // Connection closed cleanly by peer.

                std::string client_token(data, length);
                auto first_response = ntlm_server_.first_call(client_token);

                std::memset(data, 0, ASIO_BUFFER_SIZE);
                first_response.copy(data, first_response.size());
                boost::asio::write(sock, boost::asio::buffer(data, first_response.size()));

                std::memset(data, 0, ASIO_BUFFER_SIZE);
                length = sock.read_some(boost::asio::buffer(data), error);
                if (error == boost::asio::error::eof)
                    return; // Connection closed cleanly by peer.

                client_token.assign(data, length);
                ntlm_server_.second_call(client_token);
            }

        private:
            NTLMServer ntlm_server_;
            boost::asio::io_service io_context;
        };

        class TCPClient
        {
        public:
            void start()
            {   
                // Connect
                using boost::asio::ip::tcp;        
                tcp::resolver resolver(io_context);
                tcp::socket s(io_context);
                s.connect( boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string("192.168.10.92"), 32111));        

                // Generate client token
                const std::string msg = ntlm_client_.first_call();

                char request[ASIO_BUFFER_SIZE];
                std::memset(request, 0, ASIO_BUFFER_SIZE);
                msg.copy(request, ASIO_BUFFER_SIZE);
                size_t reply_length;

                boost::asio::write(s, boost::asio::buffer(request, msg.size())); 

                char reply[ASIO_BUFFER_SIZE];
                reply_length = boost::asio::read(s, boost::asio::buffer(reply, 256));
                std::string first_server_response(reply, reply_length);

                auto second_msg = ntlm_client_.second_call(first_server_response);
                std::memset(request, 0, ASIO_BUFFER_SIZE);
                second_msg.copy(request, second_msg.size());

                boost::asio::write(s, boost::asio::buffer(request, second_msg.size()));

                std::this_thread::sleep_for(std::chrono::seconds(3));
            }
        private:
            NTLMClient ntlm_client_;
            boost::asio::io_service io_context;    
        };

        int main(int argc, char** argv)
        {
            if (argv[1][0] == 's')
            {
                std::cout << "SERVER" << std::endl;
                TCPServer server;
                server.start();
            }

            if (argv[1][0] == 'c')
            {
                std::cout << "CLIENT" << std::endl;
                TCPClient client;
                client.start();
            }   

            return EXIT_SUCCESS;    
        }



        // UTILITY

        #define BASE64_ENCODE_BODY                                                \
          static const char *b64 =                                                \
              "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; \
          int i, j, a, b, c;                                                      \
                                                                                  \
          for (i = j = 0; i < src_len; i += 3) {                                  \
            a = src[i];                                                           \
            b = i + 1 >= src_len ? 0 : src[i + 1];                                \
            c = i + 2 >= src_len ? 0 : src[i + 2];                                \
                                                                                  \
            BASE64_OUT(b64[a >> 2]);                                              \
            BASE64_OUT(b64[((a & 3) << 4) | (b >> 4)]);                           \
            if (i + 1 < src_len) {                                                \
              BASE64_OUT(b64[(b & 15) << 2 | (c >> 6)]);                          \
                }                                                                     \
            if (i + 2 < src_len) {                                                \
              BASE64_OUT(b64[c & 63]);                                            \
                }                                                                     \
            }                                                                       \
                                                                                  \
                                                                                    while (j % 4 != 0) {                                                    \
            BASE64_OUT('=');                                                      \
                                                                                      }                                                                       \
          BASE64_FLUSH()

        #define BASE64_OUT(ch) \
          do {                 \
            dst[j++] = (ch);   \
            } while (0)

        #define BASE64_FLUSH() \
          do {                 \
            dst[j++] = '\0';   \
            } while (0)

        void cs_base64_encode(const unsigned char *src, int src_len, char *dst) {
            BASE64_ENCODE_BODY;
        }

        const std::string base64_chars =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz"
        "0123456789+/";

        bool is_base64(unsigned char c) {
            return (std::isalnum(c) || (c == '+') || (c == '/'));
        }

        std::string base64_decode(std::string const& encoded_string)
        {
            int in_len = encoded_string.size();
            int i = 0;
            int j = 0;
            int in_ = 0;
            unsigned char char_array_4[4], char_array_3[3];
            std::string ret;

            while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
                char_array_4[i++] = encoded_string[in_]; in_++;
                if (i == 4) {
                    for (i = 0; i < 4; i++)
                        char_array_4[i] = base64_chars.find(char_array_4[i]);

                    char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
                    char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
                    char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

                    for (i = 0; (i < 3); i++)
                        ret += char_array_3[i];
                    i = 0;
                }
            }

            if (i) {
                for (j = i; j < 4; j++)
                    char_array_4[j] = 0;

                for (j = 0; j < 4; j++)
                    char_array_4[j] = base64_chars.find(char_array_4[j]);

                char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
                char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
                char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

                for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
            }

            return ret;
        }

        std::string base64_encode(char const* bytes_to_encode, unsigned int in_len)
        {
            std::string ret;
            int i = 0;
            int j = 0;
            unsigned char char_array_3[3];
            unsigned char char_array_4[4];

            while (in_len--) {
                char_array_3[i++] = *(bytes_to_encode++);
                if (i == 3) {
                    char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
                    char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
                    char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
                    char_array_4[3] = char_array_3[2] & 0x3f;

                    for (i = 0; (i < 4); i++)
                        ret += base64_chars[char_array_4[i]];
                    i = 0;
                }
            }

            if (i)
            {
                for (j = i; j < 3; j++)
                    char_array_3[j] = '\0';

                char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
                char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
                char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
                char_array_4[3] = char_array_3[2] & 0x3f;

                for (j = 0; (j < i + 1); j++)
                    ret += base64_chars[char_array_4[j]];

                while ((i++ < 3))
                    ret += '=';

            }

            return ret;
        }


        static unsigned char from_b64(unsigned char ch) {

            static const unsigned char tab[128] = {
                255, 255, 255, 255,
                255, 255, 255, 255, /*  0 */
                255, 255, 255, 255,
                255, 255, 255, 255, /*  8 */
                255, 255, 255, 255,
                255, 255, 255, 255, /*  16 */
                255, 255, 255, 255,
                255, 255, 255, 255, /*  24 */
                255, 255, 255, 255,
                255, 255, 255, 255, /*  32 */
                255, 255, 255, 62,
                255, 255, 255, 63, /*  40 */
                52, 53, 54, 55,
                56, 57, 58, 59, /*  48 */
                60, 61, 255, 255,
                255, 200, 255, 255, /*  56   '=' is 200, on index 61 */
                255, 0, 1, 2,
                3, 4, 5, 6, /*  64 */
                7, 8, 9, 10,
                11, 12, 13, 14, /*  72 */
                15, 16, 17, 18,
                19, 20, 21, 22, /*  80 */
                23, 24, 25, 255,
                255, 255, 255, 255, /*  88 */
                255, 26, 27, 28,
                29, 30, 31, 32, /*  96 */
                33, 34, 35, 36,
                37, 38, 39, 40, /*  104 */
                41, 42, 43, 44,
                45, 46, 47, 48, /*  112 */
                49, 50, 51, 255,
                255, 255, 255, 255, /*  120 */
            };
            return tab[ch & 127];
        }


        int cs_base64_decode(const unsigned char *s, int len, char *dst, int *dec_len) {
            unsigned char a, b, c, d;
            int orig_len = len;
            char *orig_dst = dst;
            while (len >= 4 && (a = from_b64(s[0])) != 255 &&
                (b = from_b64(s[1])) != 255 && (c = from_b64(s[2])) != 255 &&
                (d = from_b64(s[3])) != 255) {
                s += 4;
                len -= 4;
                if (a == 200 || b == 200) break; /* '=' can't be there */
                *dst++ = a << 2 | b >> 4;
                if (c == 200) break;
                *dst++ = b << 4 | c >> 2;
                if (d == 200) break;
                *dst++ = c << 6 | d;
            }
            *dst = 0;
            if (dec_len != NULL) *dec_len = (dst - orig_dst);
            return orig_len - len;
        }

0 ответов

Другие вопросы по тегам