2 * Copyright (C) 1998 Peter Zelezny.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18 * MS Proxy (ISA server) support is (c) 2006 Pavel Fedin <sonic_amiga@rambler.ru>
19 * based on Dante source code
20 * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
21 * Inferno Nettverk A/S, Norway. All rights reserved.
24 /*#define DEBUG_MSPROXY*/
47 send_msprequest(s
, state
, request
, end
)
49 struct msproxy_state_t
*state
;
50 struct msproxy_request_t
*request
;
56 request
->magic25
= htonl(MSPROXY_VERSION
);
57 request
->serverack
= state
->seq_recv
;
58 /* don't start incrementing sequence until we are acking packet #2. */
59 request
->sequence
= (unsigned char)(request
->serverack
>= 2 ? state
->seq_sent
+ 1 : 0);
61 memcpy(request
->RWSP
, "RWSP", sizeof(request
->RWSP
));
63 l
= end
- (char *)request
;
64 /* all requests must be atleast MSPROXY_MINLENGTH it seems. */
65 if (l
< MSPROXY_MINLENGTH
) {
66 bzero(end
, (size_t)(MSPROXY_MINLENGTH
- l
));
67 l
= MSPROXY_MINLENGTH
;
70 if ((w
= send(s
, request
, l
, 0)) != l
) {
72 printf ("send_msprequest(): send() failed (%d bytes sent instead of %d\n", w
, l
);
77 state
->seq_sent
= request
->sequence
;
83 recv_mspresponse(s
, state
, response
)
85 struct msproxy_state_t
*state
;
86 struct msproxy_response_t
*response
;
91 if ((r
= recv (s
, response
, sizeof (*response
), 0)) < MSPROXY_MINLENGTH
) {
93 printf ("recv_mspresponse(): expected to read atleast %d, read %d\n", MSPROXY_MINLENGTH
, r
);
97 if (state
->seq_recv
== 0)
98 break; /* not started incrementing yet. */
100 if (response
->sequence
== state
->seq_recv
)
101 printf ("seq_recv: %d, dup response, seqnumber: 0x%x\n", state
->seq_recv
, response
->sequence
);
103 } while (response
->sequence
== state
->seq_recv
);
105 state
->seq_recv
= response
->sequence
;
111 traverse_msproxy (int sok
, char *serverAddr
, int port
, struct msproxy_state_t
*state
, netstore
*ns_proxy
, int csok4
, int csok6
, int *csok
, char bound
)
113 struct msproxy_request_t req
;
114 struct msproxy_response_t res
;
116 char hostname
[NT_MAXNAMELEN
];
117 char ntdomain
[NT_MAXNAMELEN
];
124 if (!prefs
.proxy_auth
|| !prefs
.proxy_user
[0] || !prefs
.proxy_pass
[0] )
127 /* MS proxy protocol implementation currently doesn't support IPv6 */
128 destaddr
= net_getsockaddr_v4 (ns_proxy
);
136 printf ("Connecting to %s:%d via MS proxy\n", serverAddr
, port
);
139 gethostname (hostname
, NT_MAXNAMELEN
);
140 p
= strchr (hostname
, '.');
144 bzero (&req
, sizeof(req
));
145 req
.clientid
= htonl(0x0a000000); /* Initial client ID is always 0x0a */
146 req
.command
= htons(MSPROXY_HELLO
); /* HELLO command */
147 req
.packet
.hello
.magic5
= htons(0x4b00); /* Fill in magic values */
148 req
.packet
.hello
.magic10
= htons(0x1400);
149 req
.packet
.hello
.magic15
= htons(0x0400);
150 req
.packet
.hello
.magic20
= htons(0x5704);
151 req
.packet
.hello
.magic25
= htons(0x0004);
152 req
.packet
.hello
.magic30
= htons(0x0100);
153 req
.packet
.hello
.magic35
= htons(0x4a02);
154 req
.packet
.hello
.magic40
= htons(0x3000);
155 req
.packet
.hello
.magic45
= htons(0x4400);
156 req
.packet
.hello
.magic50
= htons(0x3900);
157 data
= req
.packet
.hello
.data
;
158 strcpy (data
, prefs
.proxy_user
); /* Append a username */
159 data
+= strlen (prefs
.proxy_user
)+2; /* +2 automatically creates second empty string */
160 strcpy (data
, MSPROXY_EXECUTABLE
); /* Append an application name */
161 data
+= strlen (MSPROXY_EXECUTABLE
)+1;
162 strcpy (data
, hostname
); /* Append a hostname */
163 data
+= strlen (hostname
)+1;
165 if (send_msprequest(sok
, state
, &req
, data
) == -1)
168 if (recv_mspresponse(sok
, state
, &res
) == -1)
171 if (strcmp(res
.RWSP
, "RWSP") != 0) {
173 printf ("Received mailformed packet (no RWSP signature)\n");
178 if (ntohs(res
.command
) >> 8 != 0x10) {
180 printf ("expected res.command = 10??, is %x", ntohs(res
.command
));
185 state
->clientid
= htonl(rand());
186 state
->serverid
= res
.serverid
;
189 printf ("clientid: 0x%x, serverid: 0x%0x\n", state
->clientid
, state
->serverid
);
190 printf ("packet #2\n");
193 /* almost identical. */
194 req
.clientid
= state
->clientid
;
195 req
.serverid
= state
->serverid
;
197 if (send_msprequest(sok
, state
, &req
, data
) == -1)
200 if (recv_mspresponse(sok
, state
, &res
) == -1)
203 if (res
.serverid
!= state
->serverid
) {
205 printf ("expected serverid = 0x%x, is 0x%x\n",state
->serverid
, res
.serverid
);
210 if (res
.sequence
!= 0x01) {
212 printf ("expected res.sequence = 0x01, is 0x%x\n", res
.sequence
);
217 if (ntohs(res
.command
) != MSPROXY_USERINFO_ACK
) {
219 printf ("expected res.command = 0x%x, is 0x%x\n", MSPROXY_USERINFO_ACK
, ntohs(res
.command
));
225 printf ("packet #3\n");
228 bzero(&req
, sizeof(req
));
229 req
.clientid
= state
->clientid
;
230 req
.serverid
= state
->serverid
;
231 req
.command
= htons(MSPROXY_AUTHENTICATE
);
232 memcpy(req
.packet
.auth
.NTLMSSP
, "NTLMSSP", sizeof("NTLMSSP"));
233 req
.packet
.auth
.bindaddr
= htonl(0x02000000);
234 req
.packet
.auth
.msgtype
= htonl(0x01000000);
235 /* NTLM flags: 0x80000000 Negotiate LAN Manager key
236 0x10000000 Negotiate sign
237 0x04000000 Request target
238 0x02000000 Negotiate OEM
239 0x00800000 Always sign
240 0x00020000 Negotiate NTLM
242 req
.packet
.auth
.flags
= htonl(0x06020000);
244 if (send_msprequest(sok
, state
, &req
, &req
.packet
.auth
.data
) == -1)
247 if (recv_mspresponse(sok
, state
, &res
) == -1)
250 if (res
.serverid
!= state
->serverid
) {
252 printf ("expected serverid = 0x%x, is 0x%x\n", state
->serverid
, res
.serverid
);
257 if (ntohs(res
.command
) != MSPROXY_AUTHENTICATE_ACK
) {
259 printf ("expected res.command = 0x%x, is 0x%x\n", MSPROXY_AUTHENTICATE_ACK
, ntohs(res
.command
));
264 flags
= res
.packet
.auth
.flags
& htonl(0x00020000); /* Remember if the server supports NTLM */
265 memcpy(challenge
, &res
.packet
.auth
.challenge
, sizeof(challenge
));
266 memcpy(ntdomain
, &res
.packet
.auth
.NTLMSSP
[res
.packet
.auth
.target
.offset
], res
.packet
.auth
.target
.len
);
267 ntdomain
[res
.packet
.auth
.target
.len
] = 0;
270 printf ("ntdomain: \"%s\"\n", ntdomain
);
271 printf ("packet #4\n");
274 bzero(&req
, sizeof(req
));
275 req
.clientid
= state
->clientid
;
276 req
.serverid
= state
->serverid
;
277 req
.command
= htons(MSPROXY_AUTHENTICATE_2
); /* Authentication response */
278 req
.packet
.auth2
.magic3
= htons(0x0200); /* Something */
279 memcpy(req
.packet
.auth2
.NTLMSSP
, "NTLMSSP", sizeof("NTLMSSP")); /* Start of NTLM message */
280 req
.packet
.auth2
.msgtype
= htonl(0x03000000); /* Message type 2 */
281 req
.packet
.auth2
.flags
= flags
| htonl(0x02000000); /* Choose authentication method */
282 data
= req
.packet
.auth2
.data
;
284 req
.packet
.auth2
.lm_resp
.len
= 0; /* We are here if NTLM is supported, */
285 req
.packet
.auth2
.lm_resp
.alloc
= 0; /* Do not fill in insecure LM response */
286 req
.packet
.auth2
.lm_resp
.offset
= data
- req
.packet
.auth2
.NTLMSSP
;
287 req
.packet
.auth2
.ntlm_resp
.len
= 24; /* Fill in NTLM response security buffer */
288 req
.packet
.auth2
.ntlm_resp
.alloc
= 24;
289 req
.packet
.auth2
.ntlm_resp
.offset
= data
- req
.packet
.auth2
.NTLMSSP
;
290 ntlm_smb_nt_encrypt(prefs
.proxy_pass
, challenge
, data
); /* Append an NTLM response */
293 req
.packet
.auth2
.lm_resp
.len
= 24; /* Fill in LM response security buffer */
294 req
.packet
.auth2
.lm_resp
.alloc
= 24;
295 req
.packet
.auth2
.lm_resp
.offset
= data
- req
.packet
.auth2
.NTLMSSP
;
296 ntlm_smb_encrypt(prefs
.proxy_pass
, challenge
, data
); /* Append an LM response */
298 req
.packet
.auth2
.ntlm_resp
.len
= 0; /* NTLM response is empty */
299 req
.packet
.auth2
.ntlm_resp
.alloc
= 0;
300 req
.packet
.auth2
.ntlm_resp
.offset
= data
- req
.packet
.auth2
.NTLMSSP
;
302 req
.packet
.auth2
.ntdomain_buf
.len
= strlen(ntdomain
); /* Domain name */
303 req
.packet
.auth2
.ntdomain_buf
.alloc
= req
.packet
.auth2
.ntdomain_buf
.len
;
304 req
.packet
.auth2
.ntdomain_buf
.offset
= data
- req
.packet
.auth2
.NTLMSSP
;
305 strcpy(data
, ntdomain
);
306 data
+= req
.packet
.auth2
.ntdomain_buf
.len
;
307 req
.packet
.auth2
.username_buf
.len
= strlen(prefs
.proxy_user
); /* Username */
308 req
.packet
.auth2
.username_buf
.alloc
= req
.packet
.auth2
.username_buf
.len
;
309 req
.packet
.auth2
.username_buf
.offset
= data
- req
.packet
.auth2
.NTLMSSP
;
310 strcpy(data
, prefs
.proxy_user
);
311 data
+= req
.packet
.auth2
.username_buf
.len
;
312 req
.packet
.auth2
.clienthost_buf
.len
= strlen(hostname
); /* Hostname */
313 req
.packet
.auth2
.clienthost_buf
.alloc
= req
.packet
.auth2
.clienthost_buf
.len
;
314 req
.packet
.auth2
.clienthost_buf
.offset
= data
- req
.packet
.auth2
.NTLMSSP
;
315 strcpy(data
, hostname
);
316 data
+= req
.packet
.auth2
.clienthost_buf
.len
;
317 req
.packet
.auth2
.sessionkey_buf
.len
= 0; /* Session key (we don't use it) */
318 req
.packet
.auth2
.sessionkey_buf
.alloc
= 0;
319 req
.packet
.auth2
.sessionkey_buf
.offset
= data
- req
.packet
.auth2
.NTLMSSP
;
321 if (send_msprequest(sok
, state
, &req
, data
) == -1)
324 if (recv_mspresponse(sok
, state
, &res
) == -1)
327 if (res
.serverid
!= state
->serverid
) {
329 printf ("expected res.serverid = 0x%x, is 0x%x\n", state
->serverid
, res
.serverid
);
334 if (res
.clientack
!= 0x01) {
336 printf ("expected res.clientack = 0x01, is 0x%x\n", res
.clientack
);
341 if (ntohs(res
.command
) >> 8 != 0x47) {
343 printf ("expected res.command = 47??, is 0x%x\n", ntohs(res
.command
));
348 if (ntohs(res
.command
) == MSPROXY_AUTHENTICATE_2_NAK
) {
350 printf ("Authentication failed\n");
356 printf ("packet #5\n");
359 bzero(&req
, sizeof(req
));
360 req
.clientid
= state
->clientid
;
361 req
.serverid
= state
->serverid
;
362 req
.command
= htons(MSPROXY_CONNECT
);
363 req
.packet
.connect
.magic2
= htons(0x0200);
364 req
.packet
.connect
.magic6
= htons(0x0200);
365 req
.packet
.connect
.destport
= htons(port
);
366 req
.packet
.connect
.destaddr
= destaddr
;
367 data
= req
.packet
.connect
.executable
;
368 strcpy(data
, MSPROXY_EXECUTABLE
);
369 data
+= strlen(MSPROXY_EXECUTABLE
) + 1;
372 * need to tell server what port we will connect from, so we bind our sockets.
374 ns_client
= net_store_new ();
376 net_store_fill_any (ns_client
);
377 net_bind(ns_client
, csok4
, csok6
);
379 perror ("bind() result");
382 clientport
= net_getsockport(csok4
, csok6
);
383 if (clientport
== -1) {
385 printf ("Unable to obtain source port\n");
389 req
.packet
.connect
.srcport
= clientport
;
391 if (send_msprequest(sok
, state
, &req
, data
) == -1)
394 if (recv_mspresponse(sok
, state
, &res
) == -1)
397 if (ntohs(res
.command
) != MSPROXY_CONNECT_ACK
) {
399 printf ("expected res.command = 0x%x, is 0x%x\n",MSPROXY_CONNECT_ACK
, ntohs(res
.command
));
404 net_store_fill_v4 (ns_client
, res
.packet
.connect
.clientaddr
, res
.packet
.connect
.clientport
);
407 printf ("Connecting...\n");
409 if (net_connect (ns_client
, csok4
, csok6
, csok
) != 0) {
411 printf ("Failed to connect to port %d\n", htons(res
.packet
.connect
.clientport
));
413 net_store_destroy (ns_client
);
416 net_store_destroy (ns_client
);
418 printf ("packet #6\n");
421 req
.clientid
= state
->clientid
;
422 req
.serverid
= state
->serverid
;
423 req
.command
= htons(MSPROXY_USERINFO_ACK
);
425 if (send_msprequest(sok
, state
, &req
, req
.packet
.connack
.data
) == -1)
432 msproxy_keepalive (void)
435 GSList
*list
= serv_list
;
436 struct msproxy_request_t req
;
437 struct msproxy_response_t res
;
442 if (serv
->connected
&& (serv
->proxy_sok
!= -1))
445 printf ("sending MS proxy keepalive packet\n");
448 bzero(&req
, sizeof(req
));
449 req
.clientid
= serv
->msp_state
.clientid
;
450 req
.serverid
= serv
->msp_state
.serverid
;
451 req
.command
= htons(MSPROXY_HELLO
);
453 if (send_msprequest(serv
->proxy_sok
, &serv
->msp_state
, &req
, req
.packet
.hello
.data
) == -1)
456 recv_mspresponse(serv
->proxy_sok
, &serv
->msp_state
, &res
);
459 if (ntohs(res
.command
) != MSPROXY_USERINFO_ACK
)
460 printf ("expected res.command = 0x%x, is 0x%x\n", MSPROXY_USERINFO_ACK
, ntohs(res
.command
));