6 * Copyright (C) 2005 Thomas Butter <butter@uni-mannheim.de>
7 * Modify 2007, Anibal Avelar <avelar@gmail.com>
8 * hashing done according to description of NTLM on
9 * http://www.innovation.ch/java/ntlm.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include "gaim-compat.h"
33 #include <sys/ioctl.h>
35 #include <arpa/inet.h>
37 #define NTLM_NEGOTIATE_NTLM2_KEY 0x00080000
39 struct type2_message
{
40 guint8 protocol
[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
41 guint8 type
; /* 0x02 */
43 short msg_len
; /* 0x28 */
45 guint32 flags
; /* 0x8201 */
47 guint8 nonce
[8]; /* nonce */
51 struct type3_message
{
52 guint8 protocol
[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
53 guint8 type
; /* 0x03 */
56 short lm_resp_len1
; /* LanManager response length (always 0x18)*/
57 short lm_resp_len2
; /* LanManager response length (always 0x18)*/
58 short lm_resp_off
; /* LanManager response offset */
61 short nt_resp_len1
; /* NT response length (always 0x18) */
62 short nt_resp_len2
; /* NT response length (always 0x18) */
63 short nt_resp_off
; /* NT response offset */
66 short dom_len1
; /* domain string length */
67 short dom_len2
; /* domain string length */
68 short dom_off
; /* domain string offset (always 0x40) */
71 short user_len1
; /* username string length */
72 short user_len2
; /* username string length */
73 short user_off
; /* username string offset */
76 short host_len1
; /* host string length */
77 short host_len2
; /* host string length */
78 short host_off
; /* host string offset */
83 short sess_off
; /* message length */
86 guint32 flags
; /* 0x8201 */
87 /* guint32 flags2; unknown, used in windows messenger
91 guint8 dom
[*]; /* domain string (unicode UTF-16LE) */
92 guint8 user
[*]; /* username string (unicode UTF-16LE) */
93 guint8 host
[*]; /* host string (unicode UTF-16LE) */
94 guint8 lm_resp
[*]; /* LanManager response */
95 guint8 nt_resp
[*]; /* NT response */
99 gchar
*gaim_ntlm_parse_type2_sipe(gchar
*type2
, guint32
*flags
) {
101 static gchar nonce
[8];
102 struct type2_message
*tmsg
= (struct type2_message
*)gaim_base64_decode((char*)type2
, &retlen
);
103 memcpy(nonce
, tmsg
->nonce
, 8);
104 if(flags
) *flags
= tmsg
->flags
;
109 static void setup_des_key(unsigned char key_56
[], char *key
)
112 key
[1] = ((key_56
[0] << 7) & 0xFF) | (key_56
[1] >> 1);
113 key
[2] = ((key_56
[1] << 6) & 0xFF) | (key_56
[2] >> 2);
114 key
[3] = ((key_56
[2] << 5) & 0xFF) | (key_56
[3] >> 3);
115 key
[4] = ((key_56
[3] << 4) & 0xFF) | (key_56
[4] >> 4);
116 key
[5] = ((key_56
[4] << 3) & 0xFF) | (key_56
[5] >> 5);
117 key
[6] = ((key_56
[5] << 2) & 0xFF) | (key_56
[6] >> 6);
118 key
[7] = (key_56
[6] << 1) & 0xFF;
122 * helper function for gaim cipher.c
124 static void des_ecb_encrypt(char *plaintext
, char *result
, char *key
) {
126 GaimCipherContext
*context
;
129 cipher
= gaim_ciphers_find_cipher("des");
130 context
= gaim_cipher_context_new(cipher
, NULL
);
131 gaim_cipher_context_set_key(context
, (guchar
*)key
);
132 gaim_cipher_context_encrypt(context
, (guchar
*)plaintext
, 8, (guchar
*)result
, &outlen
);
133 gaim_cipher_context_destroy(context
);
137 * takes a 21 byte array and treats it as 3 56-bit DES keys. The
138 * 8 byte plaintext is encrypted with each key and the resulting 24
139 * bytes are stored in the results array.
141 static void calc_resp(unsigned char *keys
, unsigned char *plaintext
, unsigned char *results
)
144 setup_des_key(keys
, (char*)key
);
145 des_ecb_encrypt((char*)plaintext
, (char*)results
, (char*)key
);
147 setup_des_key(keys
+7, (char*)key
);
148 des_ecb_encrypt((char*)plaintext
, (char*)(results
+8), (char*)key
);
150 setup_des_key(keys
+14, (char*)key
);
151 des_ecb_encrypt((char*)plaintext
, (char*)(results
+16), (char*)key
);
154 static void gensesskey(char *buffer
, char *oldkey
) {
157 for(i
=0; i
<16; i
++) {
158 buffer
[i
] = (char)(rand() & 0xff);
161 memcpy(buffer
, oldkey
, 16);
166 gaim_ntlm_gen_type3_sipe(const gchar
*username
, const gchar
*passw
, const gchar
*hostname
, const gchar
*domain
, const guint8
*nonce
, guint32
*flags
)
169 unsigned char lm_hpw
[21];
171 const guint8
*sessionnonce
= nonce
;
173 int msglen
= sizeof(struct type3_message
)+
174 strlen(domain
) + strlen(username
)+
175 strlen(hostname
) + 24 +24 + ((flags
) ? 16 : 0);
176 struct type3_message
*tmsg
= g_malloc0(msglen
);
177 int len
= strlen(passw
);
178 unsigned char lm_resp
[24], nt_resp
[24];
179 unsigned char magic
[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
180 unsigned char nt_hpw
[21];
184 GaimCipherContext
*context
;
188 /* type3 message initialization */
189 tmsg
->protocol
[0] = 'N';
190 tmsg
->protocol
[1] = 'T';
191 tmsg
->protocol
[2] = 'L';
192 tmsg
->protocol
[3] = 'M';
193 tmsg
->protocol
[4] = 'S';
194 tmsg
->protocol
[5] = 'S';
195 tmsg
->protocol
[6] = 'P';
197 tmsg
->lm_resp_len1
= tmsg
->lm_resp_len2
= 0x18;
198 tmsg
->lm_resp_off
= sizeof(struct type3_message
) + strlen(domain
) + strlen(username
) + strlen(hostname
);
199 tmsg
->nt_resp_len1
= tmsg
->nt_resp_len2
= 0x18;
200 tmsg
->nt_resp_off
= sizeof(struct type3_message
) + strlen(domain
) + strlen(username
) + strlen(hostname
) + 0x18;
202 tmsg
->dom_len1
= tmsg
->dom_len2
= strlen(domain
);
203 tmsg
->dom_off
= 0x40;
205 tmsg
->user_len1
= tmsg
->user_len2
= strlen(username
);
206 tmsg
->user_off
= sizeof(struct type3_message
) + strlen(domain
);
208 tmsg
->host_len1
= tmsg
->host_len2
= strlen(hostname
);
209 tmsg
->host_off
= sizeof(struct type3_message
) + strlen(domain
) + strlen(username
);
212 tmsg
->sess_off
= sizeof(struct type3_message
) + strlen(domain
) + strlen(username
) + strlen(hostname
) + 0x18 + 0x18;
213 tmsg
->sess_len1
= tmsg
->sess_len2
= 0x10;
216 tmsg
->flags
= 0x8200;
218 tmp
= ((char*) tmsg
) + sizeof(struct type3_message
);
220 tmp
+= strlen(domain
);
221 strcpy(tmp
, username
);
222 tmp
+= strlen(username
);
223 strcpy(tmp
, hostname
);
224 tmp
+= strlen(hostname
);
227 if (len
> 14) len
= 14;
229 for (idx
=0; idx
<len
; idx
++)
230 lm_pw
[idx
] = g_ascii_toupper(passw
[idx
]);
231 for (; idx
<14; idx
++)
234 setup_des_key((unsigned char*)lm_pw
, (char*)key
);
235 des_ecb_encrypt((char*)magic
, (char*)lm_hpw
, (char*)key
);
237 setup_des_key((unsigned char*)(lm_pw
+7), (char*)key
);
238 des_ecb_encrypt((char*)magic
, (char*)lm_hpw
+8, (char*)key
);
240 memset(lm_hpw
+16, 0, 5);
241 calc_resp(lm_hpw
, (guchar
*)sessionnonce
, lm_resp
);
244 lennt
= strlen(passw
);
245 for (idx
=0; idx
<lennt
; idx
++)
247 nt_pw
[2*idx
] = passw
[idx
];
251 cipher
= gaim_ciphers_find_cipher("md4");
252 context
= gaim_cipher_context_new(cipher
, NULL
);
253 gaim_cipher_context_append(context
, (guchar
*)nt_pw
, 2*lennt
);
254 gaim_cipher_context_digest(context
, 21, (guchar
*)nt_hpw
, NULL
);
255 gaim_cipher_context_destroy(context
);
257 memset(nt_hpw
+16, 0, 5);
260 calc_resp(nt_hpw
, (guchar
*)sessionnonce
, nt_resp
);
261 memcpy(tmp
, lm_resp
, 0x18);
263 memcpy(tmp
, nt_resp
, 0x18);
268 //tmsg->flags = 0x409082d4;
269 tmsg
->flags
= 0x55828040;
270 gensesskey(sesskey
, NULL
);
271 memcpy(tmp
, sesskey
, 0x10);
274 /*tmsg->flags2 = 0x0a280105;
275 tmsg->flags3 = 0x0f000000;*/
277 tmp
= gaim_base64_encode((guchar
*) tmsg
, msglen
);
283 sipe_network_get_local_system_ip(void)
289 struct sockaddr_in
*sinptr
;
290 guint32 lhost
= htonl(127 * 256 * 256 * 256 + 1);
291 long unsigned int add
;
297 source
= socket(PF_INET
,SOCK_DGRAM
, 0);
299 ifc
.ifc_len
= sizeof(buffer
);
300 ifc
.ifc_req
= (struct ifreq
*)buffer
;
301 ioctl(source
, SIOCGIFCONF
, &ifc
);
302 num_ifreq
= ifc
.ifc_len
/ sizeof(struct ifreq
);
303 for ( ifr
= ifc
.ifc_req
, i
= 0 ; i
< num_ifreq
; ifr
++, i
++ ) {
304 gaim_debug_warning("sip-ntlm", "%d:name->%s\n",i
,ifr
->ifr_name
);
305 if (!strncmp(ifr
->ifr_name
,"tun",3)) {
307 gaim_debug_warning("sip-ntlm", "There is a tunnel %d:name->%s\n",i
,ifr
->ifr_name
);
310 for ( ifr
= ifc
.ifc_req
, i
= 0 ; i
< num_ifreq
; ifr
++, i
++ ) {
311 if((ifr
->ifr_flags
& IFF_UP
) != 0 ||
312 (ifr
->ifr_flags
& IFF_LOOPBACK
) ||
313 (ifr
->ifr_flags
& (IFF_BROADCAST
| IFF_POINTOPOINT
)) == 0)
315 if(!strncmp(ifr
->ifr_name
,"eth",3) && vpnc
== 1)
317 if (ifr
->ifr_addr
.sa_family
== AF_INET
){
318 sinptr
= (struct sockaddr_in
*)&ifr
->ifr_addr
;
319 if (!strncmp(ifr
->ifr_name
,"tun",3) || !strncmp(ifr
->ifr_name
,"eth",3)){
320 add
= ntohl(sinptr
->sin_addr
.s_addr
);
321 g_snprintf(ip
, 16, "%lu.%lu.%lu.%lu",
326 gaim_debug_warning("sip-ntlm", "ip->%s\n",ip
);