pidgin/pidgin

ff4278a29875
Merged in CMaiku/pidgin (pull request #199)

Split and internalize NTLM code

Approved-by: Gary Kramlich
Approved-by: Eion Robb
Approved-by: dx
--- a/ChangeLog.API Thu Jun 15 03:32:52 2017 +0000
+++ b/ChangeLog.API Thu Jun 15 03:52:01 2017 +0000
@@ -462,6 +462,7 @@
* purple_notify_searchresults_get_columns_count
* purple_notify_searchresults_get_rows_count
* purple_notify_searchresults_row_get
+ * purple_ntlm_*
* PurplePluginType
* PurplePluginPriority
* PurplePluginLoaderInfo
--- a/doc/reference/libpurple/libpurple-docs.xml Thu Jun 15 03:32:52 2017 +0000
+++ b/doc/reference/libpurple/libpurple-docs.xml Thu Jun 15 03:52:01 2017 +0000
@@ -59,7 +59,6 @@
<xi:include href="xml/nat-pmp.xml" />
<xi:include href="xml/network.xml" />
<xi:include href="xml/notify.xml" />
- <xi:include href="xml/ntlm.xml" />
<xi:include href="xml/plugins.xml" />
<xi:include href="xml/prefs.xml" />
<xi:include href="xml/pluginpref.xml" />
--- a/libpurple/Makefile.am Thu Jun 15 03:32:52 2017 +0000
+++ b/libpurple/Makefile.am Thu Jun 15 03:52:01 2017 +0000
@@ -78,7 +78,6 @@
mime.c \
nat-pmp.c \
network.c \
- ntlm.c \
notify.c \
plugins.c \
pluginpref.c \
@@ -163,7 +162,6 @@
nat-pmp.h \
network.h \
notify.h \
- ntlm.h \
plugins.h \
pluginpref.h \
pounce.h \
--- a/libpurple/Makefile.mingw Thu Jun 15 03:32:52 2017 +0000
+++ b/libpurple/Makefile.mingw Thu Jun 15 03:52:01 2017 +0000
@@ -102,7 +102,6 @@
nat-pmp.c \
network.c \
notify.c \
- ntlm.c \
plugins.c \
pluginpref.c \
pounce.c \
--- a/libpurple/http.c Thu Jun 15 03:32:52 2017 +0000
+++ b/libpurple/http.c Thu Jun 15 03:52:01 2017 +0000
@@ -26,7 +26,6 @@
#include "debug.h"
-#include "ntlm.h"
#include "proxy.h"
#include "purple-gio.h"
@@ -230,6 +229,25 @@
GString *pending;
};
+struct _ntlm_type1_message {
+ guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' */
+ guint32 type; /* 0x00000001 */
+ guint32 flags; /* 0x0000b203 */
+
+ guint16 dom_len1; /* domain string length */
+ guint16 dom_len2; /* domain string length */
+ guint32 dom_off; /* domain string offset */
+
+ guint16 host_len1; /* host string length */
+ guint16 host_len2; /* host string length */
+ guint32 host_off; /* host string offset (always 0x00000020) */
+
+#if 0
+ guint8 host[*]; /* host string (ASCII) */
+ guint8 dom[*]; /* domain string (ASCII) */
+#endif
+};
+
static time_t purple_http_rfc1123_to_time(const gchar *str);
static gboolean purple_http_request_is_method(PurpleHttpRequest *request,
@@ -461,6 +479,56 @@
g_free(gzs);
}
+/*** NTLM *********************************************************************/
+
+/**
+ * purple_ntlm_gen_type1:
+ * @hostname: Your hostname
+ * @domain: The domain to authenticate to
+ *
+ * Generates the base64 encoded type 1 message needed for NTLM authentication
+ *
+ * Returns: base64 encoded string to send to the server. This should
+ * be g_free'd by the caller.
+ */
+static gchar *
+purple_http_ntlm_gen_type1(const gchar *hostname, const gchar *domain)
+{
+ int hostnamelen,host_off;
+ int domainlen,dom_off;
+ unsigned char *msg;
+ struct _ntlm_type1_message *tmsg;
+ gchar *tmp;
+
+ hostnamelen = strlen(hostname);
+ domainlen = strlen(domain);
+ host_off = sizeof(struct _ntlm_type1_message);
+ dom_off = sizeof(struct _ntlm_type1_message) + hostnamelen;
+ msg = g_malloc0(sizeof(struct _ntlm_type1_message) + hostnamelen + domainlen);
+ tmsg = (struct _ntlm_type1_message*)(gpointer)msg;
+ tmsg->protocol[0] = 'N';
+ tmsg->protocol[1] = 'T';
+ tmsg->protocol[2] = 'L';
+ tmsg->protocol[3] = 'M';
+ tmsg->protocol[4] = 'S';
+ tmsg->protocol[5] = 'S';
+ tmsg->protocol[6] = 'P';
+ tmsg->protocol[7] = '\0';
+ tmsg->type = GUINT32_TO_LE(0x00000001);
+ tmsg->flags = GUINT32_TO_LE(0x0000b203);
+ tmsg->dom_len1 = tmsg->dom_len2 = GUINT16_TO_LE(domainlen);
+ tmsg->dom_off = GUINT32_TO_LE(dom_off);
+ tmsg->host_len1 = tmsg->host_len2 = GUINT16_TO_LE(hostnamelen);
+ tmsg->host_off = GUINT32_TO_LE(host_off);
+ memcpy(msg + host_off, hostname, hostnamelen);
+ memcpy(msg + dom_off, domain, domainlen);
+
+ tmp = g_base64_encode(msg, sizeof(struct _ntlm_type1_message) + hostnamelen + domainlen);
+ g_free(msg);
+
+ return tmp;
+}
+
/*** HTTP Sockets *************************************************************/
static gchar *
@@ -863,7 +931,8 @@
memset(tmp, 0, len);
g_free(tmp);
- ntlm_type1 = purple_ntlm_gen_type1(purple_get_host_name(), "");
+ ntlm_type1 = purple_http_ntlm_gen_type1(purple_get_host_name(),
+ "");
g_string_append_printf(h, "Proxy-Authorization: Basic %s\r\n",
proxy_auth);
--- a/libpurple/ntlm.c Thu Jun 15 03:32:52 2017 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,404 +0,0 @@
-/* purple
- *
- * Copyright (C) 2005 Thomas Butter <butter@uni-mannheim.de>
- *
- * hashing done according to description of NTLM on
- * http://www.innovation.ch/java/ntlm.html
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
- */
-
-#include "internal.h"
-
-#include "util.h"
-#include "ntlm.h"
-#include "debug.h"
-
-#include "ciphers/descipher.h"
-#include "ciphers/md4hash.h"
-
-#include <string.h>
-
-#define NTLM_NEGOTIATE_NTLM2_KEY 0x00080000
-
-struct type1_message {
- guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' */
- guint32 type; /* 0x00000001 */
- guint32 flags; /* 0x0000b203 */
-
- guint16 dom_len1; /* domain string length */
- guint16 dom_len2; /* domain string length */
- guint32 dom_off; /* domain string offset */
-
- guint16 host_len1; /* host string length */
- guint16 host_len2; /* host string length */
- guint32 host_off; /* host string offset (always 0x00000020) */
-
-#if 0
- guint8 host[*]; /* host string (ASCII) */
- guint8 dom[*]; /* domain string (ASCII) */
-#endif
-};
-
-struct type2_message {
- guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
- guint32 type; /* 0x00000002 */
-
- guint32 zero;
- guint16 msg_len1; /* target name length */
- guint16 msg_len2; /* target name length */
-
- guint32 flags; /* 0x00008201 */
-
- guint8 nonce[8]; /* nonce */
- guint8 context[8];
-};
-
-struct type3_message {
- guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
- guint32 type; /* 0x00000003 */
-
- guint16 lm_resp_len1; /* LanManager response length (always 0x18)*/
- guint16 lm_resp_len2; /* LanManager response length (always 0x18)*/
- guint32 lm_resp_off; /* LanManager response offset */
-
- guint16 nt_resp_len1; /* NT response length (always 0x18) */
- guint16 nt_resp_len2; /* NT response length (always 0x18) */
- guint32 nt_resp_off; /* NT response offset */
-
- guint16 dom_len1; /* domain string length */
- guint16 dom_len2; /* domain string length */
- guint32 dom_off; /* domain string offset (always 0x00000040) */
-
- guint16 user_len1; /* username string length */
- guint16 user_len2; /* username string length */
- guint32 user_off; /* username string offset */
-
- guint16 host_len1; /* host string length */
- guint16 host_len2; /* host string length */
- guint32 host_off; /* host string offset */
-
- guint16 sess_len1;
- guint16 sess_len2;
- guint32 sess_off; /* message length */
-
- guint32 flags; /* 0x00008201 */
- /* guint32 flags2; */ /* unknown, used in windows messenger */
- /* guint32 flags3; */
-
-#if 0
- guint8 dom[*]; /* domain string (unicode UTF-16LE) */
- guint8 user[*]; /* username string (unicode UTF-16LE) */
- guint8 host[*]; /* host string (unicode UTF-16LE) */
- guint8 lm_resp[*]; /* LanManager response */
- guint8 nt_resp[*]; /* NT response */
-#endif
-};
-
-gchar *
-purple_ntlm_gen_type1(const gchar *hostname, const gchar *domain)
-{
- int hostnamelen,host_off;
- int domainlen,dom_off;
- unsigned char *msg;
- struct type1_message *tmsg;
- gchar *tmp;
-
- hostnamelen = strlen(hostname);
- domainlen = strlen(domain);
- host_off = sizeof(struct type1_message);
- dom_off = sizeof(struct type1_message) + hostnamelen;
- msg = g_malloc0(sizeof(struct type1_message) + hostnamelen + domainlen);
- tmsg = (struct type1_message*)(gpointer)msg;
- tmsg->protocol[0] = 'N';
- tmsg->protocol[1] = 'T';
- tmsg->protocol[2] = 'L';
- tmsg->protocol[3] = 'M';
- tmsg->protocol[4] = 'S';
- tmsg->protocol[5] = 'S';
- tmsg->protocol[6] = 'P';
- tmsg->protocol[7] = '\0';
- tmsg->type = GUINT32_TO_LE(0x00000001);
- tmsg->flags = GUINT32_TO_LE(0x0000b203);
- tmsg->dom_len1 = tmsg->dom_len2 = GUINT16_TO_LE(domainlen);
- tmsg->dom_off = GUINT32_TO_LE(dom_off);
- tmsg->host_len1 = tmsg->host_len2 = GUINT16_TO_LE(hostnamelen);
- tmsg->host_off = GUINT32_TO_LE(host_off);
- memcpy(msg + host_off, hostname, hostnamelen);
- memcpy(msg + dom_off, domain, domainlen);
-
- tmp = g_base64_encode(msg, sizeof(struct type1_message) + hostnamelen + domainlen);
- g_free(msg);
-
- return tmp;
-}
-
-guint8 *
-purple_ntlm_parse_type2(const gchar *type2, guint32 *flags)
-{
- gsize retlen;
- guchar *buff;
- struct type2_message tmsg;
- static guint8 nonce[8];
-
- buff = g_base64_decode(type2, &retlen);
-
- if (buff != NULL && retlen >= (sizeof(struct type2_message) - 1)) {
- memcpy(&tmsg, buff, MIN(retlen, sizeof(tmsg)));
- memcpy(nonce, tmsg.nonce, 8);
- if (flags != NULL)
- *flags = GUINT16_FROM_LE(tmsg.flags);
- } else {
- purple_debug_error("ntlm", "Unable to parse type2 message - returning empty nonce.\n");
- memset(nonce, 0, 8);
- }
- g_free(buff);
-
- return nonce;
-}
-
-/*
- * Create a 64bit DES key by taking a 56bit key and adding
- * a parity bit after every 7th bit.
- */
-static void
-setup_des_key(const guint8 key_56[], guint8 *key)
-{
- key[0] = key_56[0];
- key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
- key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
- key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
- key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
- key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
- key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
- key[7] = (key_56[6] << 1) & 0xFF;
-}
-
-/*
- * helper function for purple cipher.c
- */
-static void
-des_ecb_encrypt(const guint8 *plaintext, guint8 *result, const guint8 *key)
-{
- PurpleCipher *cipher;
- gssize encsiz;
-
- cipher = purple_des_cipher_new();
- purple_cipher_set_key(cipher, key, 8);
- encsiz = purple_cipher_encrypt(cipher, plaintext, 8, result, 8);
- g_warn_if_fail(encsiz == 8);
- g_object_unref(cipher);
-}
-
-/*
- * takes a 21 byte array and treats it as 3 56-bit DES keys. The
- * 8 byte plaintext is encrypted with each key and the resulting 24
- * bytes are stored in the results array.
- */
-static void
-calc_resp(guint8 *keys, const guint8 *plaintext, unsigned char *results)
-{
- guint8 key[8];
- setup_des_key(keys, key);
- des_ecb_encrypt(plaintext, results, key);
-
- setup_des_key(keys + 7, key);
- des_ecb_encrypt(plaintext, results + 8, key);
-
- setup_des_key(keys + 14, key);
- des_ecb_encrypt(plaintext, results + 16, key);
-}
-
-/*
- * TODO: We think we should be using cryptographically secure random numbers
- * here. We think the rand() function is probably bad. We think
- * /dev/urandom is a step up, but using a random function from an SSL
- * library would probably be best. In Windows we could possibly also
- * use CryptGenRandom.
- */
-static void
-gensesskey(char *buffer)
-{
- int fd;
- int i;
- ssize_t red = 0;
-
- fd = open("/dev/urandom", O_RDONLY);
- if (fd >= 0) {
- red = read(fd, buffer, 16);
- if (red < 0) {
- purple_debug_warning("ntlm", "Error reading from /dev/urandom: %s."
- " Falling back to inferior method.\n", g_strerror(errno));
- red = 0;
- } else if (red < 16) {
- purple_debug_warning("ntlm", "Tried reading 16 bytes from "
- "/dev/urandom but only got %"
- G_GSSIZE_FORMAT ". Falling back to "
- "inferior method\n", (gssize)red);
- }
- close(fd);
- } else {
- purple_debug_warning("ntlm", "Error opening /dev/urandom: %s."
- " Falling back to inferior method.\n", g_strerror(errno));
- }
-
- for (i = red; i < 16; i++) {
- buffer[i] = (char)(g_random_int() & 0xff);
- }
-}
-
-gchar *
-purple_ntlm_gen_type3(const gchar *username, const gchar *passw, const gchar *hostname, const gchar *domain, const guint8 *nonce, guint32 *flags)
-{
- char lm_pw[14];
- unsigned char lm_hpw[21];
- char sesskey[16];
- guint8 key[8];
- int domainlen;
- int usernamelen;
- int hostnamelen;
- int msglen;
- struct type3_message *tmsg;
- int passwlen, lennt;
- unsigned char lm_resp[24], nt_resp[24];
- unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
- unsigned char nt_hpw[21];
- char nt_pw[128];
- PurpleHash *hash;
- char *tmp;
- int idx;
- gchar *ucs2le;
-
- domainlen = strlen(domain) * 2;
- usernamelen = strlen(username) * 2;
- hostnamelen = strlen(hostname) * 2;
- msglen = sizeof(struct type3_message) + domainlen +
- usernamelen + hostnamelen + 0x18 + 0x18 + ((flags) ? 0x10 : 0);
- tmsg = g_malloc0(msglen);
- passwlen = strlen(passw);
-
- /* type3 message initialization */
- tmsg->protocol[0] = 'N';
- tmsg->protocol[1] = 'T';
- tmsg->protocol[2] = 'L';
- tmsg->protocol[3] = 'M';
- tmsg->protocol[4] = 'S';
- tmsg->protocol[5] = 'S';
- tmsg->protocol[6] = 'P';
- tmsg->type = GUINT32_TO_LE(0x00000003);
- tmsg->lm_resp_len1 = tmsg->lm_resp_len2 = GUINT16_TO_LE(0x18);
- tmsg->lm_resp_off = GUINT32_TO_LE(sizeof(struct type3_message) + domainlen + usernamelen + hostnamelen);
- tmsg->nt_resp_len1 = tmsg->nt_resp_len2 = GUINT16_TO_LE(0x18);
- tmsg->nt_resp_off = GUINT32_TO_LE(sizeof(struct type3_message) + domainlen + usernamelen + hostnamelen + 0x18);
-
- tmsg->dom_len1 = tmsg->dom_len2 = GUINT16_TO_LE(domainlen);
- tmsg->dom_off = GUINT32_TO_LE(sizeof(struct type3_message));
-
- tmsg->user_len1 = tmsg->user_len2 = GUINT16_TO_LE(usernamelen);
- tmsg->user_off = GUINT32_TO_LE(sizeof(struct type3_message) + domainlen);
-
- tmsg->host_len1 = tmsg->host_len2 = GUINT16_TO_LE(hostnamelen);
- tmsg->host_off = GUINT32_TO_LE(sizeof(struct type3_message) + domainlen + usernamelen);
-
- if(flags) {
- tmsg->sess_off = GUINT32_TO_LE(sizeof(struct type3_message) + domainlen + usernamelen + hostnamelen + 0x18 + 0x18);
- tmsg->sess_len1 = tmsg->sess_len2 = GUINT16_TO_LE(0x0010);
- }
-
- tmsg->flags = GUINT32_TO_LE(0x00008201);
-
- tmp = (char *)tmsg + sizeof(struct type3_message);
-
- ucs2le = g_convert(domain, -1, "UTF-16LE", "UTF-8", NULL, NULL, NULL);
- if (ucs2le != NULL) {
- memcpy(tmp, ucs2le, domainlen);
- g_free(ucs2le);
- tmp += domainlen;
- } else {
- purple_debug_info("ntlm", "Unable to encode domain in UTF-16LE.\n");
- }
-
- ucs2le = g_convert(username, -1, "UTF-16LE", "UTF-8", NULL, NULL, NULL);
- if (ucs2le != NULL) {
- memcpy(tmp, ucs2le, usernamelen);
- g_free(ucs2le);
- tmp += usernamelen;
- } else {
- purple_debug_info("ntlm", "Unable to encode username in UTF-16LE.\n");
- }
-
- ucs2le = g_convert(hostname, -1, "UTF-16LE", "UTF-8", NULL, NULL, NULL);
- if (ucs2le != NULL) {
- memcpy(tmp, ucs2le, hostnamelen);
- g_free(ucs2le);
- tmp += hostnamelen;
- } else {
- purple_debug_info("ntlm", "Unable to encode hostname in UTF-16LE.\n");
- }
-
- /* LM */
- if (passwlen > 14)
- passwlen = 14;
-
- for (idx = 0; idx < passwlen; idx++)
- lm_pw[idx] = g_ascii_toupper(passw[idx]);
- for (; idx < 14; idx++)
- lm_pw[idx] = 0;
-
- setup_des_key((unsigned char*)lm_pw, key);
- des_ecb_encrypt(magic, lm_hpw, key);
-
- setup_des_key((unsigned char*)(lm_pw + 7), key);
- des_ecb_encrypt(magic, lm_hpw + 8, key);
-
- memset(lm_hpw + 16, 0, 5);
- calc_resp(lm_hpw, nonce, lm_resp);
- memcpy(tmp, lm_resp, 0x18);
- tmp += 0x18;
-
- /* NTLM */
- /* Convert the password to UTF-16LE */
- lennt = strlen(passw);
- for (idx = 0; idx < lennt; idx++)
- {
- nt_pw[2 * idx] = passw[idx];
- nt_pw[2 * idx + 1] = 0;
- }
-
- hash = purple_md4_hash_new();
- purple_hash_append(hash, (guint8 *)nt_pw, 2 * lennt);
- purple_hash_digest(hash, nt_hpw, sizeof(nt_hpw));
- g_object_unref(hash);
-
- memset(nt_hpw + 16, 0, 5);
- calc_resp(nt_hpw, nonce, nt_resp);
- memcpy(tmp, nt_resp, 0x18);
- tmp += 0x18;
-
- /* LCS Stuff */
- if (flags) {
- tmsg->flags = GUINT32_TO_LE(0x409082d4);
- gensesskey(sesskey);
- memcpy(tmp, sesskey, 0x10);
- }
-
- /*tmsg->flags2 = 0x0a280105;
- tmsg->flags3 = 0x0f000000;*/
-
- tmp = g_base64_encode((guchar *)tmsg, msglen);
- g_free(tmsg);
-
- return tmp;
-}
--- a/libpurple/ntlm.h Thu Jun 15 03:32:52 2017 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/* purple
- *
- * Copyright (C) 2005, Thomas Butter <butter@uni-mannheim.de>
- *
- * ntlm structs are taken from NTLM description on
- * http://www.innovation.ch/java/ntlm.html
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
- */
-
-#ifndef _PURPLE_NTLM_H
-#define _PURPLE_NTLM_H
-/**
- * SECTION:ntlm
- * @section_id: libpurple-ntlm
- * @short_description: <filename>ntlm.h</filename>
- * @title: NTLM Authentication
- */
-
-G_BEGIN_DECLS
-
-/**
- * purple_ntlm_gen_type1:
- * @hostname: Your hostname
- * @domain: The domain to authenticate to
- *
- * Generates the base64 encoded type 1 message needed for NTLM authentication
- *
- * Returns: base64 encoded string to send to the server. This should
- * be g_free'd by the caller.
- */
-gchar *purple_ntlm_gen_type1(const gchar *hostname, const gchar *domain);
-
-/**
- * purple_ntlm_parse_type2:
- * @type2: String containing the base64 encoded type2 message
- * @flags: If not %NULL, this will store the flags for the message
- *
- * Parses the ntlm type 2 message
- *
- * Returns: The nonce for use in message type3. This is a statically
- * allocated 8 byte binary string.
- */
-guint8 *purple_ntlm_parse_type2(const gchar *type2, guint32 *flags);
-
-/**
- * purple_ntlm_gen_type3:
- * @username: The username
- * @passw: The password
- * @hostname: The hostname
- * @domain: The domain to authenticate against
- * @nonce: The nonce returned by purple_ntlm_parse_type2
- * @flags: Pointer to the flags returned by purple_ntlm_parse_type2
- *
- * Generates a type3 message
- *
- * Returns: A base64 encoded type3 message. This should be g_free'd by
- * the caller.
- */
-gchar *purple_ntlm_gen_type3(const gchar *username, const gchar *passw, const gchar *hostname, const gchar *domain, const guint8 *nonce, guint32 *flags);
-
-G_END_DECLS
-
-#endif /* _PURPLE_NTLM_H */
--- a/libpurple/protocols/simple/Makefile.am Thu Jun 15 03:32:52 2017 +0000
+++ b/libpurple/protocols/simple/Makefile.am Thu Jun 15 03:52:01 2017 +0000
@@ -4,6 +4,8 @@
pkgdir = @PURPLE_PLUGINDIR@
SIMPLESOURCES = \
+ ntlm.c \
+ ntlm.h \
simple.c \
simple.h \
sipmsg.c \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/simple/ntlm.c Thu Jun 15 03:52:01 2017 +0000
@@ -0,0 +1,347 @@
+/* purple
+ *
+ * Copyright (C) 2005 Thomas Butter <butter@uni-mannheim.de>
+ *
+ * hashing done according to description of NTLM on
+ * http://www.innovation.ch/java/ntlm.html
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#include "internal.h"
+
+#include "util.h"
+#include "ntlm.h"
+#include "debug.h"
+
+#include "ciphers/descipher.h"
+#include "ciphers/md4hash.h"
+
+#include <string.h>
+
+#define NTLM_NEGOTIATE_NTLM2_KEY 0x00080000
+
+struct type2_message {
+ guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
+ guint32 type; /* 0x00000002 */
+
+ guint32 zero;
+ guint16 msg_len1; /* target name length */
+ guint16 msg_len2; /* target name length */
+
+ guint32 flags; /* 0x00008201 */
+
+ guint8 nonce[8]; /* nonce */
+ guint8 context[8];
+};
+
+struct type3_message {
+ guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
+ guint32 type; /* 0x00000003 */
+
+ guint16 lm_resp_len1; /* LanManager response length (always 0x18)*/
+ guint16 lm_resp_len2; /* LanManager response length (always 0x18)*/
+ guint32 lm_resp_off; /* LanManager response offset */
+
+ guint16 nt_resp_len1; /* NT response length (always 0x18) */
+ guint16 nt_resp_len2; /* NT response length (always 0x18) */
+ guint32 nt_resp_off; /* NT response offset */
+
+ guint16 dom_len1; /* domain string length */
+ guint16 dom_len2; /* domain string length */
+ guint32 dom_off; /* domain string offset (always 0x00000040) */
+
+ guint16 user_len1; /* username string length */
+ guint16 user_len2; /* username string length */
+ guint32 user_off; /* username string offset */
+
+ guint16 host_len1; /* host string length */
+ guint16 host_len2; /* host string length */
+ guint32 host_off; /* host string offset */
+
+ guint16 sess_len1;
+ guint16 sess_len2;
+ guint32 sess_off; /* message length */
+
+ guint32 flags; /* 0x00008201 */
+ /* guint32 flags2; */ /* unknown, used in windows messenger */
+ /* guint32 flags3; */
+
+#if 0
+ guint8 dom[*]; /* domain string (unicode UTF-16LE) */
+ guint8 user[*]; /* username string (unicode UTF-16LE) */
+ guint8 host[*]; /* host string (unicode UTF-16LE) */
+ guint8 lm_resp[*]; /* LanManager response */
+ guint8 nt_resp[*]; /* NT response */
+#endif
+};
+
+guint8 *
+purple_ntlm_parse_type2(const gchar *type2, guint32 *flags)
+{
+ gsize retlen;
+ guchar *buff;
+ struct type2_message tmsg;
+ static guint8 nonce[8];
+
+ buff = g_base64_decode(type2, &retlen);
+
+ if (buff != NULL && retlen >= (sizeof(struct type2_message) - 1)) {
+ memcpy(&tmsg, buff, MIN(retlen, sizeof(tmsg)));
+ memcpy(nonce, tmsg.nonce, 8);
+ if (flags != NULL)
+ *flags = GUINT16_FROM_LE(tmsg.flags);
+ } else {
+ purple_debug_error("ntlm", "Unable to parse type2 message - returning empty nonce.\n");
+ memset(nonce, 0, 8);
+ }
+ g_free(buff);
+
+ return nonce;
+}
+
+/*
+ * Create a 64bit DES key by taking a 56bit key and adding
+ * a parity bit after every 7th bit.
+ */
+static void
+setup_des_key(const guint8 key_56[], guint8 *key)
+{
+ key[0] = key_56[0];
+ key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
+ key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
+ key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
+ key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
+ key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
+ key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
+ key[7] = (key_56[6] << 1) & 0xFF;
+}
+
+/*
+ * helper function for purple cipher.c
+ */
+static void
+des_ecb_encrypt(const guint8 *plaintext, guint8 *result, const guint8 *key)
+{
+ PurpleCipher *cipher;
+ gssize encsiz;
+
+ cipher = purple_des_cipher_new();
+ purple_cipher_set_key(cipher, key, 8);
+ encsiz = purple_cipher_encrypt(cipher, plaintext, 8, result, 8);
+ g_warn_if_fail(encsiz == 8);
+ g_object_unref(cipher);
+}
+
+/*
+ * takes a 21 byte array and treats it as 3 56-bit DES keys. The
+ * 8 byte plaintext is encrypted with each key and the resulting 24
+ * bytes are stored in the results array.
+ */
+static void
+calc_resp(guint8 *keys, const guint8 *plaintext, unsigned char *results)
+{
+ guint8 key[8];
+ setup_des_key(keys, key);
+ des_ecb_encrypt(plaintext, results, key);
+
+ setup_des_key(keys + 7, key);
+ des_ecb_encrypt(plaintext, results + 8, key);
+
+ setup_des_key(keys + 14, key);
+ des_ecb_encrypt(plaintext, results + 16, key);
+}
+
+/*
+ * TODO: We think we should be using cryptographically secure random numbers
+ * here. We think the rand() function is probably bad. We think
+ * /dev/urandom is a step up, but using a random function from an SSL
+ * library would probably be best. In Windows we could possibly also
+ * use CryptGenRandom.
+ */
+static void
+gensesskey(char *buffer)
+{
+ int fd;
+ int i;
+ ssize_t red = 0;
+
+ fd = open("/dev/urandom", O_RDONLY);
+ if (fd >= 0) {
+ red = read(fd, buffer, 16);
+ if (red < 0) {
+ purple_debug_warning("ntlm", "Error reading from /dev/urandom: %s."
+ " Falling back to inferior method.\n", g_strerror(errno));
+ red = 0;
+ } else if (red < 16) {
+ purple_debug_warning("ntlm", "Tried reading 16 bytes from "
+ "/dev/urandom but only got %"
+ G_GSSIZE_FORMAT ". Falling back to "
+ "inferior method\n", (gssize)red);
+ }
+ close(fd);
+ } else {
+ purple_debug_warning("ntlm", "Error opening /dev/urandom: %s."
+ " Falling back to inferior method.\n", g_strerror(errno));
+ }
+
+ for (i = red; i < 16; i++) {
+ buffer[i] = (char)(g_random_int() & 0xff);
+ }
+}
+
+gchar *
+purple_ntlm_gen_type3(const gchar *username, const gchar *passw, const gchar *hostname, const gchar *domain, const guint8 *nonce, guint32 *flags)
+{
+ char lm_pw[14];
+ unsigned char lm_hpw[21];
+ char sesskey[16];
+ guint8 key[8];
+ int domainlen;
+ int usernamelen;
+ int hostnamelen;
+ int msglen;
+ struct type3_message *tmsg;
+ int passwlen, lennt;
+ unsigned char lm_resp[24], nt_resp[24];
+ unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
+ unsigned char nt_hpw[21];
+ char nt_pw[128];
+ PurpleHash *hash;
+ char *tmp;
+ int idx;
+ gchar *ucs2le;
+
+ domainlen = strlen(domain) * 2;
+ usernamelen = strlen(username) * 2;
+ hostnamelen = strlen(hostname) * 2;
+ msglen = sizeof(struct type3_message) + domainlen +
+ usernamelen + hostnamelen + 0x18 + 0x18 + ((flags) ? 0x10 : 0);
+ tmsg = g_malloc0(msglen);
+ passwlen = strlen(passw);
+
+ /* type3 message initialization */
+ tmsg->protocol[0] = 'N';
+ tmsg->protocol[1] = 'T';
+ tmsg->protocol[2] = 'L';
+ tmsg->protocol[3] = 'M';
+ tmsg->protocol[4] = 'S';
+ tmsg->protocol[5] = 'S';
+ tmsg->protocol[6] = 'P';
+ tmsg->type = GUINT32_TO_LE(0x00000003);
+ tmsg->lm_resp_len1 = tmsg->lm_resp_len2 = GUINT16_TO_LE(0x18);
+ tmsg->lm_resp_off = GUINT32_TO_LE(sizeof(struct type3_message) + domainlen + usernamelen + hostnamelen);
+ tmsg->nt_resp_len1 = tmsg->nt_resp_len2 = GUINT16_TO_LE(0x18);
+ tmsg->nt_resp_off = GUINT32_TO_LE(sizeof(struct type3_message) + domainlen + usernamelen + hostnamelen + 0x18);
+
+ tmsg->dom_len1 = tmsg->dom_len2 = GUINT16_TO_LE(domainlen);
+ tmsg->dom_off = GUINT32_TO_LE(sizeof(struct type3_message));
+
+ tmsg->user_len1 = tmsg->user_len2 = GUINT16_TO_LE(usernamelen);
+ tmsg->user_off = GUINT32_TO_LE(sizeof(struct type3_message) + domainlen);
+
+ tmsg->host_len1 = tmsg->host_len2 = GUINT16_TO_LE(hostnamelen);
+ tmsg->host_off = GUINT32_TO_LE(sizeof(struct type3_message) + domainlen + usernamelen);
+
+ if(flags) {
+ tmsg->sess_off = GUINT32_TO_LE(sizeof(struct type3_message) + domainlen + usernamelen + hostnamelen + 0x18 + 0x18);
+ tmsg->sess_len1 = tmsg->sess_len2 = GUINT16_TO_LE(0x0010);
+ }
+
+ tmsg->flags = GUINT32_TO_LE(0x00008201);
+
+ tmp = (char *)tmsg + sizeof(struct type3_message);
+
+ ucs2le = g_convert(domain, -1, "UTF-16LE", "UTF-8", NULL, NULL, NULL);
+ if (ucs2le != NULL) {
+ memcpy(tmp, ucs2le, domainlen);
+ g_free(ucs2le);
+ tmp += domainlen;
+ } else {
+ purple_debug_info("ntlm", "Unable to encode domain in UTF-16LE.\n");
+ }
+
+ ucs2le = g_convert(username, -1, "UTF-16LE", "UTF-8", NULL, NULL, NULL);
+ if (ucs2le != NULL) {
+ memcpy(tmp, ucs2le, usernamelen);
+ g_free(ucs2le);
+ tmp += usernamelen;
+ } else {
+ purple_debug_info("ntlm", "Unable to encode username in UTF-16LE.\n");
+ }
+
+ ucs2le = g_convert(hostname, -1, "UTF-16LE", "UTF-8", NULL, NULL, NULL);
+ if (ucs2le != NULL) {
+ memcpy(tmp, ucs2le, hostnamelen);
+ g_free(ucs2le);
+ tmp += hostnamelen;
+ } else {
+ purple_debug_info("ntlm", "Unable to encode hostname in UTF-16LE.\n");
+ }
+
+ /* LM */
+ if (passwlen > 14)
+ passwlen = 14;
+
+ for (idx = 0; idx < passwlen; idx++)
+ lm_pw[idx] = g_ascii_toupper(passw[idx]);
+ for (; idx < 14; idx++)
+ lm_pw[idx] = 0;
+
+ setup_des_key((unsigned char*)lm_pw, key);
+ des_ecb_encrypt(magic, lm_hpw, key);
+
+ setup_des_key((unsigned char*)(lm_pw + 7), key);
+ des_ecb_encrypt(magic, lm_hpw + 8, key);
+
+ memset(lm_hpw + 16, 0, 5);
+ calc_resp(lm_hpw, nonce, lm_resp);
+ memcpy(tmp, lm_resp, 0x18);
+ tmp += 0x18;
+
+ /* NTLM */
+ /* Convert the password to UTF-16LE */
+ lennt = strlen(passw);
+ for (idx = 0; idx < lennt; idx++)
+ {
+ nt_pw[2 * idx] = passw[idx];
+ nt_pw[2 * idx + 1] = 0;
+ }
+
+ hash = purple_md4_hash_new();
+ purple_hash_append(hash, (guint8 *)nt_pw, 2 * lennt);
+ purple_hash_digest(hash, nt_hpw, sizeof(nt_hpw));
+ g_object_unref(hash);
+
+ memset(nt_hpw + 16, 0, 5);
+ calc_resp(nt_hpw, nonce, nt_resp);
+ memcpy(tmp, nt_resp, 0x18);
+ tmp += 0x18;
+
+ /* LCS Stuff */
+ if (flags) {
+ tmsg->flags = GUINT32_TO_LE(0x409082d4);
+ gensesskey(sesskey);
+ memcpy(tmp, sesskey, 0x10);
+ }
+
+ /*tmsg->flags2 = 0x0a280105;
+ tmsg->flags3 = 0x0f000000;*/
+
+ tmp = g_base64_encode((guchar *)tmsg, msglen);
+ g_free(tmsg);
+
+ return tmp;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/simple/ntlm.h Thu Jun 15 03:52:01 2017 +0000
@@ -0,0 +1,58 @@
+/* purple
+ *
+ * Copyright (C) 2005, Thomas Butter <butter@uni-mannheim.de>
+ *
+ * ntlm structs are taken from NTLM description on
+ * http://www.innovation.ch/java/ntlm.html
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#ifndef _PURPLE_NTLM_H
+#define _PURPLE_NTLM_H
+
+G_BEGIN_DECLS
+
+/**
+ * purple_ntlm_parse_type2:
+ * @type2: String containing the base64 encoded type2 message
+ * @flags: If not %NULL, this will store the flags for the message
+ *
+ * Parses the ntlm type 2 message
+ *
+ * Returns: The nonce for use in message type3. This is a statically
+ * allocated 8 byte binary string.
+ */
+guint8 *purple_ntlm_parse_type2(const gchar *type2, guint32 *flags);
+
+/**
+ * purple_ntlm_gen_type3:
+ * @username: The username
+ * @passw: The password
+ * @hostname: The hostname
+ * @domain: The domain to authenticate against
+ * @nonce: The nonce returned by purple_ntlm_parse_type2
+ * @flags: Pointer to the flags returned by purple_ntlm_parse_type2
+ *
+ * Generates a type3 message
+ *
+ * Returns: A base64 encoded type3 message. This should be g_free'd by
+ * the caller.
+ */
+gchar *purple_ntlm_gen_type3(const gchar *username, const gchar *passw, const gchar *hostname, const gchar *domain, const guint8 *nonce, guint32 *flags);
+
+G_END_DECLS
+
+#endif /* _PURPLE_NTLM_H */
--- a/libpurple/proxy.c Thu Jun 15 03:32:52 2017 +0000
+++ b/libpurple/proxy.c Thu Jun 15 03:52:01 2017 +0000
@@ -30,7 +30,6 @@
#include "debug.h"
#include "http.h"
#include "notify.h"
-#include "ntlm.h"
#include "prefs.h"
#include "proxy.h"
#include "purple-gio.h"
--- a/libpurple/purple.h.in Thu Jun 15 03:32:52 2017 +0000
+++ b/libpurple/purple.h.in Thu Jun 15 03:52:01 2017 +0000
@@ -70,7 +70,6 @@
#include <nat-pmp.h>
#include <network.h>
#include <notify.h>
-#include <ntlm.h>
#include <plugins.h>
#include <pluginpref.h>
#include <pounce.h>