mirror of
https://github.com/ZoiteChat/zoitechat.git
synced 2026-03-12 08:40:19 +00:00
add xchat r1489
This commit is contained in:
467
src/common/msproxy.c
Normal file
467
src/common/msproxy.c
Normal file
@@ -0,0 +1,467 @@
|
||||
/* X-Chat
|
||||
* Copyright (C) 1998 Peter Zelezny.
|
||||
*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
* MS Proxy (ISA server) support is (c) 2006 Pavel Fedin <sonic_amiga@rambler.ru>
|
||||
* based on Dante source code
|
||||
* Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
|
||||
* Inferno Nettverk A/S, Norway. All rights reserved.
|
||||
*/
|
||||
|
||||
/*#define DEBUG_MSPROXY*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define WANTSOCKET
|
||||
#define WANTARPA
|
||||
#include "inet.h"
|
||||
|
||||
#include "xchat.h"
|
||||
#include "network.h"
|
||||
#include "xchatc.h"
|
||||
#include "server.h"
|
||||
#include "msproxy.h"
|
||||
|
||||
|
||||
#ifdef USE_MSPROXY
|
||||
#include <ntlm.h>
|
||||
|
||||
static int
|
||||
send_msprequest(s, state, request, end)
|
||||
int s;
|
||||
struct msproxy_state_t *state;
|
||||
struct msproxy_request_t *request;
|
||||
char *end;
|
||||
{
|
||||
ssize_t w;
|
||||
size_t l;
|
||||
|
||||
request->magic25 = htonl(MSPROXY_VERSION);
|
||||
request->serverack = state->seq_recv;
|
||||
/* don't start incrementing sequence until we are acking packet #2. */
|
||||
request->sequence = (unsigned char)(request->serverack >= 2 ? state->seq_sent + 1 : 0);
|
||||
|
||||
memcpy(request->RWSP, "RWSP", sizeof(request->RWSP));
|
||||
|
||||
l = end - (char *)request;
|
||||
/* all requests must be atleast MSPROXY_MINLENGTH it seems. */
|
||||
if (l < MSPROXY_MINLENGTH) {
|
||||
bzero(end, (size_t)(MSPROXY_MINLENGTH - l));
|
||||
l = MSPROXY_MINLENGTH;
|
||||
}
|
||||
|
||||
if ((w = send(s, request, l, 0)) != l) {
|
||||
#ifdef DEBUG_MSPROXY
|
||||
printf ("send_msprequest(): send() failed (%d bytes sent instead of %d\n", w, l);
|
||||
perror ("Error is");
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
state->seq_sent = request->sequence;
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
static int
|
||||
recv_mspresponse(s, state, response)
|
||||
int s;
|
||||
struct msproxy_state_t *state;
|
||||
struct msproxy_response_t *response;
|
||||
{
|
||||
ssize_t r;
|
||||
|
||||
do {
|
||||
if ((r = recv (s, response, sizeof (*response), 0)) < MSPROXY_MINLENGTH) {
|
||||
#ifdef DEBUG_MSPROXY
|
||||
printf ("recv_mspresponse(): expected to read atleast %d, read %d\n", MSPROXY_MINLENGTH, r);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
if (state->seq_recv == 0)
|
||||
break; /* not started incrementing yet. */
|
||||
#ifdef DEBUG_MSPROXY
|
||||
if (response->sequence == state->seq_recv)
|
||||
printf ("seq_recv: %d, dup response, seqnumber: 0x%x\n", state->seq_recv, response->sequence);
|
||||
#endif
|
||||
} while (response->sequence == state->seq_recv);
|
||||
|
||||
state->seq_recv = response->sequence;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
traverse_msproxy (int sok, char *serverAddr, int port, struct msproxy_state_t *state, netstore *ns_proxy, int csok4, int csok6, int *csok, char bound)
|
||||
{
|
||||
struct msproxy_request_t req;
|
||||
struct msproxy_response_t res;
|
||||
char *data, *p;
|
||||
char hostname[NT_MAXNAMELEN];
|
||||
char ntdomain[NT_MAXNAMELEN];
|
||||
char challenge[8];
|
||||
netstore *ns_client;
|
||||
int clientport;
|
||||
guint32 destaddr;
|
||||
guint32 flags;
|
||||
|
||||
if (!prefs.proxy_auth || !prefs.proxy_user[0] || !prefs.proxy_pass[0] )
|
||||
return 1;
|
||||
|
||||
/* MS proxy protocol implementation currently doesn't support IPv6 */
|
||||
destaddr = net_getsockaddr_v4 (ns_proxy);
|
||||
if (!destaddr)
|
||||
return 1;
|
||||
|
||||
state->seq_recv = 0;
|
||||
state->seq_sent = 0;
|
||||
|
||||
#ifdef DEBUG_MSPROXY
|
||||
printf ("Connecting to %s:%d via MS proxy\n", serverAddr, port);
|
||||
#endif
|
||||
|
||||
gethostname (hostname, NT_MAXNAMELEN);
|
||||
p = strchr (hostname, '.');
|
||||
if (p)
|
||||
*p = '\0';
|
||||
|
||||
bzero (&req, sizeof(req));
|
||||
req.clientid = htonl(0x0a000000); /* Initial client ID is always 0x0a */
|
||||
req.command = htons(MSPROXY_HELLO); /* HELLO command */
|
||||
req.packet.hello.magic5 = htons(0x4b00); /* Fill in magic values */
|
||||
req.packet.hello.magic10 = htons(0x1400);
|
||||
req.packet.hello.magic15 = htons(0x0400);
|
||||
req.packet.hello.magic20 = htons(0x5704);
|
||||
req.packet.hello.magic25 = htons(0x0004);
|
||||
req.packet.hello.magic30 = htons(0x0100);
|
||||
req.packet.hello.magic35 = htons(0x4a02);
|
||||
req.packet.hello.magic40 = htons(0x3000);
|
||||
req.packet.hello.magic45 = htons(0x4400);
|
||||
req.packet.hello.magic50 = htons(0x3900);
|
||||
data = req.packet.hello.data;
|
||||
strcpy (data, prefs.proxy_user); /* Append a username */
|
||||
data += strlen (prefs.proxy_user)+2; /* +2 automatically creates second empty string */
|
||||
strcpy (data, MSPROXY_EXECUTABLE); /* Append an application name */
|
||||
data += strlen (MSPROXY_EXECUTABLE)+1;
|
||||
strcpy (data, hostname); /* Append a hostname */
|
||||
data += strlen (hostname)+1;
|
||||
|
||||
if (send_msprequest(sok, state, &req, data) == -1)
|
||||
return 1;
|
||||
|
||||
if (recv_mspresponse(sok, state, &res) == -1)
|
||||
return 1;
|
||||
|
||||
if (strcmp(res.RWSP, "RWSP") != 0) {
|
||||
#ifdef DEBUG_MSPROXY
|
||||
printf ("Received mailformed packet (no RWSP signature)\n");
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ntohs(res.command) >> 8 != 0x10) {
|
||||
#ifdef DEBUG_MSPROXY
|
||||
printf ("expected res.command = 10??, is %x", ntohs(res.command));
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
state->clientid = htonl(rand());
|
||||
state->serverid = res.serverid;
|
||||
|
||||
#ifdef DEBUG_MSPROXY
|
||||
printf ("clientid: 0x%x, serverid: 0x%0x\n", state->clientid, state->serverid);
|
||||
printf ("packet #2\n");
|
||||
#endif
|
||||
|
||||
/* almost identical. */
|
||||
req.clientid = state->clientid;
|
||||
req.serverid = state->serverid;
|
||||
|
||||
if (send_msprequest(sok, state, &req, data) == -1)
|
||||
return 1;
|
||||
|
||||
if (recv_mspresponse(sok, state, &res) == -1)
|
||||
return 1;
|
||||
|
||||
if (res.serverid != state->serverid) {
|
||||
#ifdef DEBUG_MSPROXY
|
||||
printf ("expected serverid = 0x%x, is 0x%x\n",state->serverid, res.serverid);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (res.sequence != 0x01) {
|
||||
#ifdef DEBUG_MSPROXY
|
||||
printf ("expected res.sequence = 0x01, is 0x%x\n", res.sequence);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ntohs(res.command) != MSPROXY_USERINFO_ACK) {
|
||||
#ifdef DEBUG_MSPROXY
|
||||
printf ("expected res.command = 0x%x, is 0x%x\n", MSPROXY_USERINFO_ACK, ntohs(res.command));
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MSPROXY
|
||||
printf ("packet #3\n");
|
||||
#endif
|
||||
|
||||
bzero(&req, sizeof(req));
|
||||
req.clientid = state->clientid;
|
||||
req.serverid = state->serverid;
|
||||
req.command = htons(MSPROXY_AUTHENTICATE);
|
||||
memcpy(req.packet.auth.NTLMSSP, "NTLMSSP", sizeof("NTLMSSP"));
|
||||
req.packet.auth.bindaddr = htonl(0x02000000);
|
||||
req.packet.auth.msgtype = htonl(0x01000000);
|
||||
/* NTLM flags: 0x80000000 Negotiate LAN Manager key
|
||||
0x10000000 Negotiate sign
|
||||
0x04000000 Request target
|
||||
0x02000000 Negotiate OEM
|
||||
0x00800000 Always sign
|
||||
0x00020000 Negotiate NTLM
|
||||
*/
|
||||
req.packet.auth.flags = htonl(0x06020000);
|
||||
|
||||
if (send_msprequest(sok, state, &req, &req.packet.auth.data) == -1)
|
||||
return 1;
|
||||
|
||||
if (recv_mspresponse(sok, state, &res) == -1)
|
||||
return 1;
|
||||
|
||||
if (res.serverid != state->serverid) {
|
||||
#ifdef DEBUG_MSPROXY
|
||||
printf ("expected serverid = 0x%x, is 0x%x\n", state->serverid, res.serverid);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ntohs(res.command) != MSPROXY_AUTHENTICATE_ACK) {
|
||||
#ifdef DEBUG_MSPROXY
|
||||
printf ("expected res.command = 0x%x, is 0x%x\n", MSPROXY_AUTHENTICATE_ACK, ntohs(res.command));
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
flags = res.packet.auth.flags & htonl(0x00020000); /* Remember if the server supports NTLM */
|
||||
memcpy(challenge, &res.packet.auth.challenge, sizeof(challenge));
|
||||
memcpy(ntdomain, &res.packet.auth.NTLMSSP[res.packet.auth.target.offset], res.packet.auth.target.len);
|
||||
ntdomain[res.packet.auth.target.len] = 0;
|
||||
|
||||
#ifdef DEBUG_MSPROXY
|
||||
printf ("ntdomain: \"%s\"\n", ntdomain);
|
||||
printf ("packet #4\n");
|
||||
#endif
|
||||
|
||||
bzero(&req, sizeof(req));
|
||||
req.clientid = state->clientid;
|
||||
req.serverid = state->serverid;
|
||||
req.command = htons(MSPROXY_AUTHENTICATE_2); /* Authentication response */
|
||||
req.packet.auth2.magic3 = htons(0x0200); /* Something */
|
||||
memcpy(req.packet.auth2.NTLMSSP, "NTLMSSP", sizeof("NTLMSSP")); /* Start of NTLM message */
|
||||
req.packet.auth2.msgtype = htonl(0x03000000); /* Message type 2 */
|
||||
req.packet.auth2.flags = flags | htonl(0x02000000); /* Choose authentication method */
|
||||
data = req.packet.auth2.data;
|
||||
if (flags) {
|
||||
req.packet.auth2.lm_resp.len = 0; /* We are here if NTLM is supported, */
|
||||
req.packet.auth2.lm_resp.alloc = 0; /* Do not fill in insecure LM response */
|
||||
req.packet.auth2.lm_resp.offset = data - req.packet.auth2.NTLMSSP;
|
||||
req.packet.auth2.ntlm_resp.len = 24; /* Fill in NTLM response security buffer */
|
||||
req.packet.auth2.ntlm_resp.alloc = 24;
|
||||
req.packet.auth2.ntlm_resp.offset = data - req.packet.auth2.NTLMSSP;
|
||||
ntlm_smb_nt_encrypt(prefs.proxy_pass, challenge, data); /* Append an NTLM response */
|
||||
data += 24;
|
||||
} else {
|
||||
req.packet.auth2.lm_resp.len = 24; /* Fill in LM response security buffer */
|
||||
req.packet.auth2.lm_resp.alloc = 24;
|
||||
req.packet.auth2.lm_resp.offset = data - req.packet.auth2.NTLMSSP;
|
||||
ntlm_smb_encrypt(prefs.proxy_pass, challenge, data); /* Append an LM response */
|
||||
data += 24;
|
||||
req.packet.auth2.ntlm_resp.len = 0; /* NTLM response is empty */
|
||||
req.packet.auth2.ntlm_resp.alloc = 0;
|
||||
req.packet.auth2.ntlm_resp.offset = data - req.packet.auth2.NTLMSSP;
|
||||
}
|
||||
req.packet.auth2.ntdomain_buf.len = strlen(ntdomain); /* Domain name */
|
||||
req.packet.auth2.ntdomain_buf.alloc = req.packet.auth2.ntdomain_buf.len;
|
||||
req.packet.auth2.ntdomain_buf.offset = data - req.packet.auth2.NTLMSSP;
|
||||
strcpy(data, ntdomain);
|
||||
data += req.packet.auth2.ntdomain_buf.len;
|
||||
req.packet.auth2.username_buf.len = strlen(prefs.proxy_user); /* Username */
|
||||
req.packet.auth2.username_buf.alloc = req.packet.auth2.username_buf.len;
|
||||
req.packet.auth2.username_buf.offset = data - req.packet.auth2.NTLMSSP;
|
||||
strcpy(data, prefs.proxy_user);
|
||||
data += req.packet.auth2.username_buf.len;
|
||||
req.packet.auth2.clienthost_buf.len = strlen(hostname); /* Hostname */
|
||||
req.packet.auth2.clienthost_buf.alloc = req.packet.auth2.clienthost_buf.len;
|
||||
req.packet.auth2.clienthost_buf.offset = data - req.packet.auth2.NTLMSSP;
|
||||
strcpy(data, hostname);
|
||||
data += req.packet.auth2.clienthost_buf.len;
|
||||
req.packet.auth2.sessionkey_buf.len = 0; /* Session key (we don't use it) */
|
||||
req.packet.auth2.sessionkey_buf.alloc = 0;
|
||||
req.packet.auth2.sessionkey_buf.offset = data - req.packet.auth2.NTLMSSP;
|
||||
|
||||
if (send_msprequest(sok, state, &req, data) == -1)
|
||||
return 1;
|
||||
|
||||
if (recv_mspresponse(sok, state, &res) == -1)
|
||||
return 1;
|
||||
|
||||
if (res.serverid != state->serverid) {
|
||||
#ifdef DEBUG_MSPROXY
|
||||
printf ("expected res.serverid = 0x%x, is 0x%x\n", state->serverid, res.serverid);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (res.clientack != 0x01) {
|
||||
#ifdef DEBUG_MSPROXY
|
||||
printf ("expected res.clientack = 0x01, is 0x%x\n", res.clientack);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ntohs(res.command) >> 8 != 0x47) {
|
||||
#ifdef DEBUG_MSPROXY
|
||||
printf ("expected res.command = 47??, is 0x%x\n", ntohs(res.command));
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ntohs(res.command) == MSPROXY_AUTHENTICATE_2_NAK) {
|
||||
#ifdef DEBUG_MSPROXY
|
||||
printf ("Authentication failed\n");
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MSPROXY
|
||||
printf ("packet #5\n");
|
||||
#endif
|
||||
|
||||
bzero(&req, sizeof(req));
|
||||
req.clientid = state->clientid;
|
||||
req.serverid = state->serverid;
|
||||
req.command = htons(MSPROXY_CONNECT);
|
||||
req.packet.connect.magic2 = htons(0x0200);
|
||||
req.packet.connect.magic6 = htons(0x0200);
|
||||
req.packet.connect.destport = htons(port);
|
||||
req.packet.connect.destaddr = destaddr;
|
||||
data = req.packet.connect.executable;
|
||||
strcpy(data, MSPROXY_EXECUTABLE);
|
||||
data += strlen(MSPROXY_EXECUTABLE) + 1;
|
||||
|
||||
/*
|
||||
* need to tell server what port we will connect from, so we bind our sockets.
|
||||
*/
|
||||
ns_client = net_store_new ();
|
||||
if (!bound) {
|
||||
net_store_fill_any (ns_client);
|
||||
net_bind(ns_client, csok4, csok6);
|
||||
#ifdef DEBUG_MSPROXY
|
||||
perror ("bind() result");
|
||||
#endif
|
||||
}
|
||||
clientport = net_getsockport(csok4, csok6);
|
||||
if (clientport == -1) {
|
||||
#ifdef DEBUG_MSPROXY
|
||||
printf ("Unable to obtain source port\n");
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
req.packet.connect.srcport = clientport;
|
||||
|
||||
if (send_msprequest(sok, state, &req, data) == -1)
|
||||
return 1;
|
||||
|
||||
if (recv_mspresponse(sok, state, &res) == -1)
|
||||
return 1;
|
||||
|
||||
if (ntohs(res.command) != MSPROXY_CONNECT_ACK) {
|
||||
#ifdef DEBUG_MSPROXY
|
||||
printf ("expected res.command = 0x%x, is 0x%x\n",MSPROXY_CONNECT_ACK, ntohs(res.command));
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
net_store_fill_v4 (ns_client, res.packet.connect.clientaddr, res.packet.connect.clientport);
|
||||
|
||||
#ifdef DEBUG_MSPROXY
|
||||
printf ("Connecting...\n");
|
||||
#endif
|
||||
if (net_connect (ns_client, csok4, csok6, csok) != 0) {
|
||||
#ifdef DEBUG_MSPROXY
|
||||
printf ("Failed to connect to port %d\n", htons(res.packet.connect.clientport));
|
||||
#endif
|
||||
net_store_destroy (ns_client);
|
||||
return 1;
|
||||
}
|
||||
net_store_destroy (ns_client);
|
||||
#ifdef DEBUG_MSPROXY
|
||||
printf ("packet #6\n");
|
||||
#endif
|
||||
|
||||
req.clientid = state->clientid;
|
||||
req.serverid = state->serverid;
|
||||
req.command = htons(MSPROXY_USERINFO_ACK);
|
||||
|
||||
if (send_msprequest(sok, state, &req, req.packet.connack.data) == -1)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
msproxy_keepalive (void)
|
||||
{
|
||||
server *serv;
|
||||
GSList *list = serv_list;
|
||||
struct msproxy_request_t req;
|
||||
struct msproxy_response_t res;
|
||||
|
||||
while (list)
|
||||
{
|
||||
serv = list->data;
|
||||
if (serv->connected && (serv->proxy_sok != -1))
|
||||
{
|
||||
#ifdef DEBUG_MSPROXY
|
||||
printf ("sending MS proxy keepalive packet\n");
|
||||
#endif
|
||||
|
||||
bzero(&req, sizeof(req));
|
||||
req.clientid = serv->msp_state.clientid;
|
||||
req.serverid = serv->msp_state.serverid;
|
||||
req.command = htons(MSPROXY_HELLO);
|
||||
|
||||
if (send_msprequest(serv->proxy_sok, &serv->msp_state, &req, req.packet.hello.data) == -1)
|
||||
continue;
|
||||
|
||||
recv_mspresponse(serv->proxy_sok, &serv->msp_state, &res);
|
||||
|
||||
#ifdef DEBUG_MSPROXY
|
||||
if (ntohs(res.command) != MSPROXY_USERINFO_ACK)
|
||||
printf ("expected res.command = 0x%x, is 0x%x\n", MSPROXY_USERINFO_ACK, ntohs(res.command));
|
||||
#endif
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user