summary refs log tree commit diff stats
path: root/src/common/identd.c
blob: 5cfc536fd91839c6d64eebe53422ba85e1d96037 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
/* simple identd server for HexChat under Win32 */

#include "inet.h"
#include "hexchat.h"
#include "hexchatc.h"
#include "text.h"

static int identd_is_running = FALSE;
#ifdef USE_IPV6
static int identd_ipv6_is_running = FALSE;
#endif

static int
identd (char *username)
{
	int sok, read_sok, len;
	char *p;
	char buf[256];
	char outbuf[256];
	struct sockaddr_in addr;

	sok = socket (AF_INET, SOCK_STREAM, 0);
	if (sok == INVALID_SOCKET)
	{
		free (username);
		return 0;
	}

	len = 1;
	setsockopt (sok, SOL_SOCKET, SO_REUSEADDR, (char *) &len, sizeof (len));

	memset (&addr, 0, sizeof (addr));
	addr.sin_family = AF_INET;
	addr.sin_port = htons (113);

	if (bind (sok, (struct sockaddr *) &addr, sizeof (addr)) == SOCKET_ERROR)
	{
		closesocket (sok);
		free (username);
		return 0;
	}

	if (listen (sok, 1) == SOCKET_ERROR)
	{
		closesocket (sok);
		free (username);
		return 0;
	}

	len = sizeof (addr);
	read_sok = accept (sok, (struct sockaddr *) &addr, &len);
	closesocket (sok);
	if (read_sok == INVALID_SOCKET)
	{
		free (username);
		return 0;
	}

	identd_is_running = FALSE;

#if 0	/* causes random crashes, probably due to CreateThread */
	EMIT_SIGNAL (XP_TE_IDENTD, current_sess, inet_ntoa (addr.sin_addr), username, NULL, NULL, 0);
#endif
	snprintf (outbuf, sizeof (outbuf), "*\tServicing ident request from %s as %s\n", inet_ntoa (addr.sin_addr), username);
	PrintText (current_sess, outbuf);

	recv (read_sok, buf, sizeof (buf) - 1, 0);
	buf[sizeof (buf) - 1] = 0;	  /* ensure null termination */

	p = strchr (buf, ',');
	if (p)
	{
		snprintf (outbuf, sizeof (outbuf) - 1, "%d, %d : USERID : UNIX : %s\r\n",
					 atoi (buf), atoi (p + 1), username);
		outbuf[sizeof (outbuf) - 1] = 0;	/* ensure null termination */
		send (read_sok, outbuf, strlen (outbuf), 0);
	}

	sleep (1);
	closesocket (read_sok);
	free (username);

	return 0;
}

#ifdef USE_IPV6
#define IPV6BUFLEN 60
static int
identd_ipv6 (char *username)
{
	int sok, read_sok, len;
	char *p;
	char buf[256];
	char outbuf[256];	
	LPSTR ipv6buf = (LPSTR) malloc (IPV6BUFLEN);
	struct sockaddr_in6 addr;

	sok = socket (AF_INET6, SOCK_STREAM, 0);

	if (sok == INVALID_SOCKET)
	{
		free (username);
		free (ipv6buf);
		return 0;
	}

	len = 1;
	setsockopt (sok, SOL_SOCKET, SO_REUSEADDR, (char *) &len, sizeof (len));

	memset (&addr, 0, sizeof (addr));
	addr.sin6_family = AF_INET6;
	addr.sin6_port = htons (113);

	if (bind (sok, (struct sockaddr *) &addr, sizeof (addr)) == SOCKET_ERROR)
	{
		closesocket (sok);
		free (username);
		free (ipv6buf);
		return 0;
	}

	if (listen (sok, 1) == SOCKET_ERROR)
	{
		closesocket (sok);
		free (username);
		free (ipv6buf);
		return 0;
	}

	len = sizeof (addr);
	read_sok = accept (sok, (struct sockaddr *) &addr, &len);
	closesocket (sok);

	if (read_sok == INVALID_SOCKET)
	{
		free (username);
		free (ipv6buf);
		return 0;
	}

	identd_ipv6_is_running = FALSE;

	if (WSAAddressToString ((struct sockaddr *) &addr, sizeof (addr), NULL, ipv6buf, (LPDWORD) IPV6BUFLEN) == SOCKET_ERROR)
	{
		snprintf (ipv6buf, sizeof (ipv6buf) - 1, "[SOCKET ERROR: 0x%X]", WSAGetLastError ());
	}

#if 0	/* causes random crashes, probably due to CreateThread */
	EMIT_SIGNAL (XP_TE_IDENTD, current_sess, ipv6buf, username, NULL, NULL, 0);
#endif
	snprintf (outbuf, sizeof (outbuf), "*\tServicing ident request from %s as %s\n", ipv6buf, username);
	PrintText (current_sess, outbuf);

	recv (read_sok, buf, sizeof (buf) - 1, 0);
	buf[sizeof (buf) - 1] = 0;	  /* ensure null termination */

	p = strchr (buf, ',');

	if (p)
	{
		snprintf (outbuf, sizeof (outbuf) - 1, "%d, %d : USERID : UNIX : %s\r\n", atoi (buf), atoi (p + 1), username);
		outbuf[sizeof (outbuf) - 1] = 0;	/* ensure null termination */
		send (read_sok, outbuf, strlen (outbuf), 0);
	}

	sleep (1);
	closesocket (read_sok);
	free (username);
	free (ipv6buf);

	return 0;
}
#endif

void
identd_start (char *username)
{
	DWORD tid;

#ifdef USE_IPV6
	DWORD tidv6;
	if (identd_ipv6_is_running == FALSE)
	{
		identd_ipv6_is_running = TRUE;
		CloseHandle (CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) identd_ipv6,
						 strdup (username), 0, &tidv6));
	}
#endif

	if (identd_is_running == FALSE)
	{
		identd_is_running = TRUE;
		CloseHandle (CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) identd,
						 strdup (username), 0, &tid));
	}
}
ponse, 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.hex_net_proxy_auth || !prefs.hex_net_proxy_user[0] || !prefs.hex_net_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.hex_net_proxy_user); /* Append a username */ data += strlen (prefs.hex_net_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.hex_net_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.hex_net_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.hex_net_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.hex_net_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