1 /*
2 * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2004, 2005, 2008, 2009, 2010,
3 * 2011, 2012, 2013, 2014
4 * Inferno Nettverk A/S, Norway. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. The above copyright notice, this list of conditions and the following
10 * disclaimer must appear in all copies of the software, derivative works
11 * or modified versions, and any portions thereof, aswell as in all
12 * supporting documentation.
13 * 2. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by
16 * Inferno Nettverk A/S, Norway.
17 * 3. The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 * Inferno Nettverk A/S requests users of this software to return to
32 *
33 * Software Distribution Coordinator or sdc@inet.no
34 * Inferno Nettverk A/S
35 * Oslo Research Park
36 * Gaustadall�en 21
37 * NO-0349 Oslo
38 * Norway
39 *
40 * any improvements or extensions that they make and grant Inferno Nettverk A/S
41 * the rights to redistribute these changes.
42 *
43 */
44
45 /*
46 * The gssapi code was contributed by
47 * Markus Moeller (markus_moeller at compuserve.com).
48 */
49
50
51 #include "common.h"
52
53 #if SOCKS_CLIENT || SOCKS_SERVER /* XXX is this correct? */
54 #include "interposition.h"
55 #endif /* SOCKS_CLIENT || SOCKS_SERVER */
56
57 static const char rcsid[] =
58 "$Id: clientprotocol.c,v 1.225.4.4.6.1 2021/01/07 15:46:46 karls Exp $";
59
60 static int
61 recv_sockshost(int s, sockshost_t *host, int version, authmethod_t *auth,
62 char *emsg, const size_t emsglen);
63 /*
64 * Fills "host" based on data read from "s". "version" is the version
65 * the remote peer is expected to send data in.
66 *
67 * Returns:
68 * On success: 0
69 * On failure: -1
70 */
71
72 int
socks_sendrequest(s,request,emsg,emsglen)73 socks_sendrequest(s, request, emsg, emsglen)
74 int s;
75 const request_t *request;
76 char *emsg;
77 const size_t emsglen;
78 {
79 const char *function = "socks_sendrequest()";
80 ssize_t rc;
81 size_t len;
82 unsigned char requestmem[sizeof(*request)], *p = requestmem;
83
84 switch (request->version) {
85 case PROXY_SOCKS_V4:
86 /*
87 * VN CD DSTPORT DSTIP USERID 0
88 * 1 + 1 + 2 + 4 + ? + 1 = 9 + USERID
89 */
90
91 /* VN */
92 memcpy(p, &request->version, sizeof(request->version));
93 p += sizeof(request->version);
94
95 /* CD */
96 memcpy(p, &request->command, sizeof(request->command));
97 p += sizeof(request->command);
98
99 p = sockshost2mem(&request->host, p, request->version);
100
101 *p = NUL; /* not bothering to send any userid. Should we? */
102 ++p;
103 break;
104
105 case PROXY_SOCKS_V5:
106 /*
107 * rfc1928 request:
108 *
109 * +----+-----+-------+------+----------+----------+
110 * |VER | CMD | FLAG | ATYP | DST.ADDR | DST.PORT |
111 * +----+-----+-------+------+----------+----------+
112 * | 1 | 1 | 1 | 1 | Variable | 2 |
113 * +----+-----+-------+------+----------+----------+
114 * 1 1 1 1 > 0 2
115 *
116 * Which gives a fixed size of minimum 7 octets.
117 * The first octet of DST.ADDR when it is SOCKS_ADDR_DOMAINNAME
118 * contains the length of DST.ADDR.
119 */
120
121 /* VER */
122 memcpy(p, &request->version, sizeof(request->version));
123 p += sizeof(request->version);
124
125 /* CMD */
126 memcpy(p, &request->command, sizeof(request->command));
127 p += sizeof(request->command);
128
129 /* FLAG */
130 memcpy(p, &request->flag, sizeof(request->flag));
131 p += sizeof(request->flag);
132
133 p = sockshost2mem(&request->host, p, request->version);
134 break;
135
136 default:
137 SERRX(request->version);
138 }
139
140 slog(LOG_NEGOTIATE, "%s: sending request to server: %s",
141 function, socks_packet2string(request, 1));
142
143 /*
144 * Send the request to the server.
145 */
146 len = p - requestmem;
147 if ((rc = socks_sendton(s,
148 requestmem,
149 len,
150 len,
151 0,
152 NULL,
153 0,
154 NULL,
155 request->auth)) != (ssize_t)len) {
156 snprintf(emsg, emsglen,
157 "could not send request to proxy server. Sent %ld/%lu: %s",
158 (long)rc, (unsigned long)len, strerror(errno));
159 return -1;
160 }
161
162 return 0;
163 }
164
165 int
socks_recvresponse(s,response,version,emsg,emsglen)166 socks_recvresponse(s, response, version, emsg, emsglen)
167 int s;
168 response_t *response;
169 int version;
170 char *emsg;
171 const size_t emsglen;
172 {
173 const char *function = "socks_recvresponse()";
174 ssize_t rc;
175
176 /* get the version specific data that prefixes the sockshost. */
177 switch (version) {
178 case PROXY_SOCKS_V4: {
179 /*
180 * The socks V4 reply length is fixed:
181 * VN CD DSTPORT DSTIP
182 * 1 + 1 + 2 + 4
183 */
184 char responsemem[ sizeof(response->version)
185 + sizeof(response->reply.socks)
186 ];
187 char *p = responsemem;
188
189 if ((rc = socks_recvfromn(s,
190 responsemem,
191 sizeof(responsemem),
192 sizeof(responsemem),
193 0,
194 NULL,
195 NULL,
196 NULL,
197 response->auth))
198 != (ssize_t)sizeof(responsemem)) {
199 fmtresponseerror(rc, sizeof(responsemem), emsg, emsglen);
200 return -1;
201 }
202
203 /* VN */
204 memcpy(&response->version, p, sizeof(response->version));
205 p += sizeof(response->version);
206 if (response->version != PROXY_SOCKS_V4REPLY_VERSION) {
207 fmtversionerror(PROXY_SOCKS_V4REPLY_VERSION,
208 response->version,
209 emsg,
210 emsglen);
211 return -1;
212 }
213
214 /* CD */
215 memcpy(&response->reply.socks, p, sizeof(response->reply.socks));
216 p += sizeof(response->reply.socks);
217 break;
218 }
219
220 case PROXY_SOCKS_V5: {
221 /*
222 * rfc1928 reply:
223 *
224 * +----+-----+-------+------+----------+----------+
225 * |VER | REP | FLAG | ATYP | BND.ADDR | BND.PORT |
226 * +----+-----+-------+------+----------+----------+
227 * | 1 | 1 | 1 | 1 | > 0 | 2 |
228 * +----+-----+-------+------+----------+----------+
229 *
230 * Which gives a size of >= 7 octets.
231 *
232 */
233 char responsemem[sizeof(response->version)
234 + sizeof(response->reply.socks)
235 + sizeof(response->flag)
236 ];
237 char *p = responsemem;
238
239 if ((rc = socks_recvfromn(s,
240 responsemem,
241 sizeof(responsemem),
242 sizeof(responsemem),
243 0,
244 NULL,
245 NULL,
246 NULL,
247 response->auth))
248 != (ssize_t)sizeof(responsemem)) {
249 fmtresponseerror(rc, sizeof(responsemem), emsg, emsglen);
250 return -1;
251 }
252
253 /* VER */
254 memcpy(&response->version, p, sizeof(response->version));
255 p += sizeof(response->version);
256 if (version != response->version) {
257 fmtversionerror(version, response->version, emsg, emsglen);
258 return -1;
259 }
260
261 /* REP */
262 memcpy(&response->reply.socks, p, sizeof(response->reply.socks));
263 p += sizeof(response->reply.socks);
264
265 /* FLAG */
266 memcpy(&response->flag, p, sizeof(response->flag));
267 p += sizeof(response->flag);
268
269 break;
270 }
271
272 default:
273 SERRX(version);
274 }
275
276 if (recv_sockshost(s,
277 &response->host,
278 version,
279 response->auth,
280 emsg,
281 emsglen) != 0)
282 return -1;
283
284 slog(LOG_NEGOTIATE, "%s: received response from server: %s",
285 function, socks_packet2string(response, 0));
286
287 return 0;
288 }
289
290 int
socks_negotiate(s,control,packet,route,emsg,emsglen)291 socks_negotiate(s, control, packet, route, emsg, emsglen)
292 int s;
293 int control;
294 socks_t *packet;
295 route_t *route;
296 char *emsg;
297 const size_t emsglen;
298 {
299 const char *function = "socks_negotiate()";
300 char sbuf[512], cbuf[512];
301 int failed = 0;
302
303 slog(LOG_NEGOTIATE,
304 "%s: initiating %s negotiation with control-fd %d (%s), "
305 "data-fd %d (%s), req.host = %s",
306 function,
307 proxyprotocol2string(packet->req.version),
308 control,
309 control == -1 ? "N/A" : socket2string(control, cbuf, sizeof(cbuf)),
310 s,
311 s == control ? "same" : socket2string(s, sbuf, sizeof(sbuf)),
312 sockshost2string(&packet->req.host, NULL, 0));
313
314 /* avoid false Valgrind warning later due to uninitialized padding bits. */
315 bzero(&packet->res.host, sizeof(packet->res.host));
316
317 packet->res.auth = packet->req.auth;
318
319 switch (packet->req.version) {
320 case PROXY_SOCKS_V4:
321 if (packet->req.command == SOCKS_BIND) {
322 if (route != NULL && route->gw.state.extension.bind)
323 packet->req.host.addr.ipv4.s_addr = htonl(BINDEXTENSION_IPADDR);
324 #if SOCKS_CLIENT
325 else {
326 if (packet->req.version == PROXY_SOCKS_V4)
327 /*
328 * v4/v5 difference. We always set up for v5 by default,
329 * but if v4 is what proxyserver us, modify the request
330 * slightly for v4.
331 */
332 if (ntohs(sockscf.state.lastconnect.port) != 0)
333 packet->req.host.port = sockscf.state.lastconnect.port;
334 }
335 #endif /* SOCKS_CLIENT */
336 }
337
338 /* FALLTHROUGH */
339
340 case PROXY_SOCKS_V5: {
341 /*
342 * Whatever these file descriptor-indexes were used for before, we
343 * need to reset them now.
344 */
345 int rc;
346
347 #if SOCKS_CLIENT
348 int original_s; /* false gcc warning: may be used uninitialized */
349 int executingdnscode;
350
351 socks_rmaddr(s, 1);
352 socks_rmaddr(control, 1);
353
354 /*
355 * Some resolverlibrary have bugs whose side-effect leads to
356 * them either closing the socket they created and called us
357 * on (e.g., for connect(2)), or they (naturally) don't expect
358 * that when they call connect(2), connect(2) will end up
359 * calling them again. The later can happen when their connect(2)
360 * is caught by our Rconnect(), and our Rconnect() needs to
361 * call one of the dns-functions to reach the socks-server.
362 *
363 * We attempt to slightly increase the chances of this working
364 * by dup(2)'ing the socket they called us with so that after
365 * method_negotiate(), which may end up calling dns-functions,
366 * returns, we still have the original socket they called us
367 * with, even if the dns-calls made by method_negotiate() ended
368 * up closing and recreating it.
369 */
370
371 SASSERTX(sockscf.state.executingdnscode >= 0);
372 if (sockscf.state.executingdnscode
373 && s != control
374 /* workaround is only usable for udp. */
375 && packet->req.command == SOCKS_UDPASSOCIATE)
376 executingdnscode = 1;
377 else
378 executingdnscode = 0;
379
380 if (executingdnscode) {
381 slog(LOG_DEBUG,
382 "%s: preparing to call method_negotiate() from dns-code",
383 function);
384
385 if ((original_s = dup(s)) == -1)
386 swarn("%s: dup() failed on fd %d while executing dns-code",
387 function, s);
388 else {
389 int tmp_s = socketoptdup(s, -1);
390
391 if (tmp_s == -1)
392 swarn("%s: socketoptdup() failed on fd %d while executing "
393 "dns-code",
394 function, s);
395 else {
396 rc = dup2(tmp_s, s);
397 close(tmp_s);
398
399 if (rc == s) {
400 slog(LOG_DEBUG,
401 "%s: successfully prepared things. Data-fd %d is "
402 "now a dummy-fd, while original data-fd is saved as "
403 "fd %d",
404 function, s, original_s);
405 }
406 else
407 swarn("%s: dup2() failed on fd %d, fd %d while executing "
408 "dns-code",
409 function, tmp_s, s);
410 }
411 }
412 }
413 #endif /* SOCKS_CLIENT */
414
415 rc = negotiate_method(control, packet, route, emsg, emsglen);
416
417 #if SOCKS_CLIENT
418 if (executingdnscode && original_s != -1) {
419 const int errno_s = errno;
420
421 slog(LOG_DEBUG, "%s: restoring data fd %d from saved fd %d (%s)",
422 function, s, original_s, socket2string(original_s, NULL, 0));
423
424 if (dup2(original_s, s) != s)
425 swarn("%s: failed to restore data fd %d from saved fd %d",
426 function, s, original_s);
427
428 close(original_s);
429 errno = errno_s;
430 }
431 #endif /* SOCKS_CLIENT */
432
433 if (rc != 0) {
434 if (errno == 0) /* something wrong. If nothing else ... */
435 errno = ECONNREFUSED;
436
437 failed = 1;
438 break;
439 }
440
441 slog(LOG_DEBUG,
442 "%s: method negotiation successful. Server selected method "
443 "%d (%s)",
444 function,
445 packet->req.auth->method,
446 method2string(packet->req.auth->method));
447
448 if (socks_sendrequest(control, &packet->req, emsg, emsglen) != 0) {
449 failed = 1;
450 break;
451 }
452
453 if (socks_recvresponse(control,
454 &packet->res,
455 packet->req.version,
456 emsg,
457 emsglen) != 0) {
458 socks_blacklist(route, emsg);
459
460 if (errno == 0) /* something wrong. If nothing else ... */
461 errno = ECONNREFUSED;
462
463 failed = 1;
464 }
465
466 break;
467 }
468
469 case PROXY_HTTP_10:
470 case PROXY_HTTP_11:
471 if (httpproxy_negotiate(control, packet, emsg, emsglen) != 0) {
472 if (errno == 0)
473 errno = ECONNREFUSED; /* something wrong. If nothing else ... */
474
475 failed = 1;
476 }
477
478 break;
479
480 #if HAVE_LIBMINIUPNP
481 case PROXY_UPNP:
482 if (upnp_negotiate(s, packet, &route->gw, emsg, emsglen) != 0) {
483 if (errno == 0)
484 errno = ECONNREFUSED; /* something wrong. If nothing else ... */
485
486 failed = 1;
487 }
488
489 break;
490 #endif /* HAVE_LIBMINIUPNP */
491
492 default:
493 SERRX(packet->req.version);
494 }
495
496 if (!failed) {
497 if (serverreplyisok(packet->res.version,
498 packet->req.command,
499 socks_get_responsevalue(&packet->res),
500 route,
501 emsg,
502 emsglen)) {
503 if (errno != EINPROGRESS)
504 errno = 0; /* all should be ok. */
505 }
506 else {
507 SASSERTX(errno != 0);
508 failed = 1;
509 }
510 }
511
512 if (failed) {
513 #if HAVE_GSSAPI
514 if (packet->req.auth->method == AUTHMETHOD_GSSAPI
515 && packet->req.auth->mdata.gssapi.state.id != GSS_C_NO_CONTEXT) {
516 OM_uint32 major_status, minor_status;
517 char buf[512];
518
519 if ((major_status
520 = gss_delete_sec_context(&minor_status,
521 &packet->req.auth->mdata.gssapi.state.id,
522 GSS_C_NO_BUFFER)) != GSS_S_COMPLETE) {
523 if (!gss_err_isset(major_status, minor_status, buf, sizeof(buf)))
524 *buf = NUL;
525
526 swarnx("%s: gss_delete_sec_context() failed%s%s",
527 function,
528 *buf == NUL ? "" : ": ",
529 *buf == NUL ? "" : buf);
530 }
531 }
532 #endif /* HAVE_GSSAPI */
533
534 return -1;
535 }
536
537 return 0;
538
539 }
540
541 #if SOCKS_CLIENT
542 void
update_after_negotiate(packet,socksfd)543 update_after_negotiate(packet, socksfd)
544 const socks_t *packet;
545 socksfd_t *socksfd;
546 {
547
548 socksfd->state.auth = *packet->req.auth;
549 socksfd->state.command = packet->req.command;
550 socksfd->state.version = packet->req.version;
551 }
552
553 #endif /* SOCKS_CLIENT */
554
555 static int
recv_sockshost(s,host,version,auth,emsg,emsglen)556 recv_sockshost(s, host, version, auth, emsg, emsglen)
557 int s;
558 sockshost_t *host;
559 int version;
560 authmethod_t *auth;
561 char *emsg;
562 const size_t emsglen;
563 {
564 const char *function = "recv_sockshost()";
565 ssize_t rc;
566
567 switch (version) {
568 case PROXY_SOCKS_V4:
569 case PROXY_SOCKS_V4REPLY_VERSION: {
570 /*
571 * DSTPORT DSTIP
572 * 2 + 4
573 */
574 char hostmem[ sizeof(host->port)
575 + sizeof(host->addr.ipv4)
576 ];
577 char *p = hostmem;
578
579 if ((rc = socks_recvfromn(s,
580 hostmem,
581 sizeof(hostmem),
582 sizeof(hostmem),
583 0,
584 NULL,
585 NULL,
586 NULL,
587 auth)) != (ssize_t)sizeof(hostmem)) {
588 fmtresponseerror(rc, sizeof(hostmem), emsg, emsglen);
589 return -1;
590 }
591
592 host->atype = SOCKS_ADDR_IPV4;
593
594 /* BND.PORT */
595 memcpy(&host->port, p, sizeof(host->port));
596 p += sizeof(host->port);
597
598 /* BND.ADDR */
599 memcpy(&host->addr.ipv4, p, sizeof(host->addr.ipv4));
600 p += sizeof(host->addr.ipv4);
601
602 break;
603 }
604
605 case PROXY_SOCKS_V5:
606 /*
607 * +------+----------+----------+
608 * | ATYP | BND.ADDR | BND.PORT |
609 * +------+----------+----------+
610 * | 1 | > 0 | 2 |
611 * +------+----------+----------+
612 */
613
614 /* ATYP */
615 if ((rc = socks_recvfromn(s,
616 &host->atype, sizeof(host->atype),
617 sizeof(host->atype),
618 0,
619 NULL,
620 NULL,
621 NULL,
622 auth)) != (ssize_t)sizeof(host->atype)) {
623 fmtresponseerror(rc, sizeof(host->atype), emsg, emsglen);
624 return -1;
625 }
626
627 switch(host->atype) {
628 case SOCKS_ADDR_IPV4:
629 if ((rc = socks_recvfromn(s,
630 &host->addr.ipv4,
631 sizeof(host->addr.ipv4),
632 sizeof(host->addr.ipv4),
633 0,
634 NULL,
635 NULL,
636 NULL,
637 auth))
638 != (ssize_t)sizeof(host->addr.ipv4)) {
639 fmtresponseerror(rc, sizeof(host->addr.ipv4), emsg, emsglen);
640 return -1;
641 }
642 break;
643
644 case SOCKS_ADDR_IPV6:
645 if ((rc = socks_recvfromn(s,
646 &host->addr.ipv6.ip,
647 sizeof(host->addr.ipv6.ip),
648 sizeof(host->addr.ipv6.ip),
649 0,
650 NULL,
651 NULL,
652 NULL,
653 auth))
654 != (ssize_t)sizeof(host->addr.ipv6.ip)) {
655 fmtresponseerror(rc,
656 sizeof(host->addr.ipv6.ip),
657 emsg,
658 emsglen);
659
660 return -1;
661 }
662 break;
663
664 case SOCKS_ADDR_DOMAIN: {
665 unsigned char alen;
666
667 /* read length of domain name. */
668 if ((rc = socks_recvfromn(s,
669 &alen,
670 sizeof(alen),
671 sizeof(alen),
672 0,
673 NULL,
674 NULL,
675 NULL,
676 auth)) != (ssize_t)sizeof(alen)) {
677 fmtresponseerror(rc, sizeof(alen), emsg, emsglen);
678 return -1;
679 }
680
681 OCTETIFY(alen);
682
683 #if MAXHOSTNAMELEN < 0xff
684 SASSERTX(alen < sizeof(host->addr.domain));
685 #endif /* MAXHOSTNAMELEN < 0xff */
686
687 /* BND.ADDR, alen octets */
688 if ((rc = socks_recvfromn(s,
689 host->addr.domain,
690 (size_t)alen,
691 (size_t)alen,
692 0,
693 NULL,
694 NULL,
695 NULL,
696 auth)) != (ssize_t)alen) {
697 fmtresponseerror(rc, alen, emsg, emsglen);
698 return -1;
699 }
700 host->addr.domain[alen] = NUL;
701
702 break;
703 }
704
705 default:
706 swarnx("%s: unsupported address format %d in reply",
707 function, host->atype);
708 return -1;
709 }
710
711 /* BND.PORT */
712 if ((rc = socks_recvfromn(s,
713 &host->port,
714 sizeof(host->port),
715 sizeof(host->port),
716 0,
717 NULL,
718 NULL,
719 NULL,
720 auth)) != (ssize_t)sizeof(host->port)) {
721 fmtresponseerror(rc, sizeof(host->port), emsg, emsglen);
722 return -1;
723 }
724
725 break;
726 }
727
728 return 0;
729 }
730
731 int
serverreplyisok(version,command,reply,route,emsg,emsglen)732 serverreplyisok(version, command, reply, route, emsg, emsglen)
733 const unsigned int version;
734 const unsigned int command;
735 const unsigned int reply;
736 route_t *route;
737 char *emsg;
738 const size_t emsglen;
739 {
740 const char *function = "serverreplyisok()";
741
742 slog(LOG_NEGOTIATE, "%s: version %d, command %d, reply %d",
743 function, version, command, reply);
744
745 switch (version) {
746 case PROXY_SOCKS_V4REPLY_VERSION:
747 switch (reply) {
748 case SOCKSV4_SUCCESS:
749 socks_clearblacklist(route);
750 return 1;
751
752 case SOCKSV4_FAIL:
753 snprintf(emsg, emsglen, "generic proxy server failure");
754
755 socks_clearblacklist(route);
756 errno = ECONNREFUSED;
757 break;
758
759 case SOCKSV4_NO_IDENTD:
760 snprintf(emsg, emsglen,
761 "proxy server says it could not get a ident (rfc931) "
762 "response from host we are running on");
763
764 /* will probably fail next time too, so blacklist it. */
765 socks_blacklist(route, emsg);
766
767 errno = ECONNREFUSED;
768 break;
769
770 case SOCKSV4_BAD_ID:
771 snprintf(emsg, emsglen,
772 "proxy server claims username/ident mismatch from us");
773
774 socks_blacklist(route, emsg);
775 errno = ECONNREFUSED;
776 break;
777
778 default:
779 snprintf(emsg, emsglen,
780 "unknown v%d reply from proxy server. Replycode: %d",
781 version, reply);
782
783 socks_blacklist(route, emsg);
784 errno = ECONNREFUSED;
785 break;
786 }
787 break;
788
789 case PROXY_SOCKS_V5:
790 switch (reply) {
791 case SOCKS_SUCCESS:
792 socks_clearblacklist(route);
793 return 1;
794
795 case SOCKS_FAILURE:
796 snprintf(emsg, emsglen,
797 "generic failure at remote proxy server");
798
799 if (command == SOCKS_BIND) {
800 errno = EADDRINUSE;
801 socks_clearblacklist(route);
802 }
803 else
804 socks_blacklist(route, emsg);
805
806 errno = ECONNREFUSED;
807 break;
808
809 case SOCKS_NOTALLOWED:
810 snprintf(emsg, emsglen, "connection denied by proxy server");
811
812 socks_clearblacklist(route);
813 errno = ECONNREFUSED;
814 break;
815
816 case SOCKS_NETUNREACH:
817 snprintf(emsg, emsglen, "net unreachable by proxy server");
818
819 socks_clearblacklist(route);
820 errno = ENETUNREACH;
821 break;
822
823 case SOCKS_HOSTUNREACH:
824 snprintf(emsg, emsglen, "target unreachable by proxy server");
825
826 socks_clearblacklist(route);
827 errno = EHOSTUNREACH;
828 break;
829
830 case SOCKS_CONNREFUSED:
831 snprintf(emsg, emsglen,
832 "target refused connection by proxy server");
833
834 socks_clearblacklist(route);
835 errno = ECONNREFUSED;
836 break;
837
838 case SOCKS_TTLEXPIRED:
839 snprintf(emsg, emsglen,
840 "connection to target from proxy server timed out");
841
842 socks_clearblacklist(route);
843 errno = ETIMEDOUT;
844 break;
845
846 case SOCKS_CMD_UNSUPP:
847 snprintf(emsg, emsglen, "command not supported by proxy server");
848
849 swarnx("%s: %s", function, emsg);
850
851 socks_blacklist(route, emsg);
852 errno = ECONNREFUSED;
853 break;
854
855 case SOCKS_ADDR_UNSUPP:
856 snprintf(emsg, emsglen,
857 "address format in the request we sent is not "
858 "supported by the proxy server");
859
860 socks_blacklist(route, emsg);
861 errno = ECONNREFUSED;
862 break;
863
864 default:
865 snprintf(emsg, emsglen,
866 "unknown v%d reply from proxy server: %d",
867 version, reply);
868
869 socks_blacklist(route, emsg);
870 errno = ECONNREFUSED;
871 break;
872 }
873 break;
874
875 case PROXY_HTTP_10:
876 case PROXY_HTTP_11:
877 switch (reply) {
878 case HTTP_SUCCESS:
879 socks_clearblacklist(route);
880 return 1;
881
882 default:
883 snprintf(emsg, emsglen, "unknown proxy server failure");
884
885 socks_blacklist(route, emsg);
886 errno = ECONNREFUSED;
887 break;
888 }
889 break;
890
891 case PROXY_UPNP:
892 switch (reply) {
893 case UPNP_SUCCESS:
894 socks_clearblacklist(route);
895 return 1;
896
897 default:
898 socks_blacklist(route, "UPNP failure");
899 errno = ECONNREFUSED;
900 break;
901 }
902 break;
903
904
905 default:
906 snprintf(emsg, emsglen, "unknown proxy version %d", version);
907 break;
908 }
909
910 SASSERTX(*emsg != NUL);
911
912 slog(LOG_DEBUG, "%s", emsg);
913
914 return 0;
915 }
916
917 /* ARGSUSED */
918 int
clientmethod_uname(s,host,version,name,password,emsg,emsglen)919 clientmethod_uname(s, host, version, name, password, emsg, emsglen)
920 int s;
921 const sockshost_t *host;
922 int version;
923 unsigned char *name;
924 unsigned char *password;
925 char *emsg;
926 const size_t emsglen;
927 {
928 const char *function = "clientmethod_uname()";
929 static authmethod_uname_t uname; /* cached userinfo. */
930 static sockshost_t unamehost; /* host cache was gotten for. */
931 static int usecachedinfo; /* cached data is ok? */
932 ssize_t rc;
933 size_t len;
934 unsigned char *offset;
935 unsigned char request[ 1 /* version. */
936 + 1 /* username length. */
937 + MAXNAMELEN /* username. */
938 + 1 /* password length. */
939 + MAXPWLEN /* password. */
940 ];
941 unsigned char response[ 1 /* version. */
942 + 1 /* status. */
943 ];
944
945 switch (version) {
946 case PROXY_SOCKS_V5:
947 break;
948
949 default:
950 SERRX(version);
951 }
952
953 if (memcmp(&unamehost, host, sizeof(unamehost)) != 0)
954 usecachedinfo = 0; /* not same host as cache was gotten for. */
955
956 /* fill in request. */
957
958 offset = request;
959 *offset = (unsigned char)SOCKS_UNAMEVERSION;
960 ++offset;
961
962 if (!usecachedinfo) {
963 if (name == NULL
964 && (name = (unsigned char *)socks_getusername(host,
965 (char *)offset + 1,
966 MAXNAMELEN)) == NULL) {
967 snprintf(emsg, emsglen, "could not determine username of client");
968 return -1;
969 }
970
971 if (strlen((char *)name) > sizeof(uname.name) - 1) {
972 char visbuf[MAXNAMELEN];
973
974 swarnx("%s: username \"%s ...\" is too long. Max length is %lu. "
975 "Trying to continue anyway.",
976 function,
977 str2vis((char *)name,
978 strlen((char *)name),
979 visbuf,
980 sizeof(visbuf)),
981 (unsigned long)(sizeof(uname.name) - 1));
982
983 /* perhaps it will be truncated at proxy too. */
984 name[sizeof(uname.name) - 1] = NUL;
985 }
986
987 SASSERTX(strlen((char *)name) < sizeof(uname.name));
988 strcpy((char *)uname.name, (char *)name);
989 }
990
991 slog(LOG_DEBUG, "%s: usecachedinfo %d, name \"%s\"",
992 function, usecachedinfo, uname.name);
993
994 /* first byte gives length. */
995 *offset = (unsigned char)strlen((char *)uname.name);
996 OCTETIFY(*offset);
997 strcpy((char *)offset + 1, (char *)uname.name);
998 offset += *offset + 1;
999
1000 if (!usecachedinfo) {
1001 if (password == NULL
1002 && (password = (unsigned char *)socks_getpassword(host,
1003 (char *)name,
1004 (char *)offset + 1,
1005 MAXPWLEN)) == NULL) {
1006 slog(LOG_NEGOTIATE,
1007 "%s: could not determine password of client, using an empty one",
1008 function);
1009
1010 password = (unsigned char *)"";
1011 }
1012
1013 if (strlen((char *)password) > sizeof(uname.password) - 1) {
1014 swarnx("%s: password is too long. Max length is %lu. "
1015 "Trying to continue anyway.",
1016 function, (unsigned long)(sizeof(uname.password) - 1));
1017
1018 /* perhaps it will be truncated at proxy too. */
1019 password[sizeof(uname.password) - 1] = NUL;
1020 }
1021
1022 SASSERTX(strlen((char *)password) < sizeof(uname.password));
1023 strcpy((char *)uname.password, (char *)password);
1024 }
1025
1026 /* first byte gives length. */
1027 *offset = (unsigned char)strlen((char *)uname.password);
1028 OCTETIFY(*offset);
1029 strcpy((char *)offset + 1, (char *)uname.password);
1030 offset += *offset + 1;
1031
1032 slog(LOG_NEGOTIATE, "%s: offering username \"%s\", password %s to server",
1033 function, uname.name, (*uname.password == NUL) ? "\"\"" : "********");
1034
1035 len = offset - request;
1036 if ((rc = socks_sendton(s,
1037 request,
1038 len,
1039 len,
1040 0,
1041 NULL,
1042 0,
1043 NULL,
1044 NULL)) != (ssize_t)len) {
1045 snprintf(emsg, emsglen,
1046 "send of username/password to proxy server failed, "
1047 "sent %ld/%lu: %s",
1048 (long)rc, (unsigned long)(offset - request), strerror(errno));
1049 return -1;
1050 }
1051
1052 if ((rc = socks_recvfromn(s,
1053 response,
1054 sizeof(response),
1055 sizeof(response),
1056 0,
1057 NULL,
1058 NULL,
1059 NULL,
1060 NULL)) != sizeof(response)) {
1061 snprintfn(emsg, emsglen,
1062 "failed to receive proxy server response, received %ld/%lu: %s",
1063 (long)rc, (unsigned long)sizeof(response), strerror(errno));
1064 return -1;
1065 }
1066
1067 slog(LOG_NEGOTIATE, "%s: received server response: 0x%x, 0x%x",
1068 function, response[0], response[1]);
1069
1070 if (request[UNAME_VERSION] != response[UNAME_VERSION]) {
1071 snprintf(emsg, emsglen,
1072 "sent a v%d uname request to proxy server, "
1073 "but got back a v%d response",
1074 request[0], response[1]);
1075 return -1;
1076 }
1077
1078 if (response[UNAME_STATUS] == UNAME_STATUS_ISOK) { /* server accepted. */
1079 unamehost = *host;
1080 usecachedinfo = 1;
1081
1082 return 0;
1083 }
1084
1085 snprintf(emsg, emsglen, "proxy server rejected our username/password");
1086
1087 return -1;
1088 }
1089
1090 #if HAVE_GSSAPI
1091 /*
1092 * This code was contributed by
1093 * Markus Moeller (markus_moeller at compuserve.com).
1094 */
1095
1096 int
clientmethod_gssapi(s,protocol,gw,version,auth,emsg,emsglen)1097 clientmethod_gssapi(s, protocol, gw, version, auth, emsg, emsglen)
1098 int s;
1099 int protocol;
1100 const gateway_t *gw;
1101 int version;
1102 authmethod_t *auth;
1103 char *emsg;
1104 const size_t emsglen;
1105 {
1106 const char *function = "clientmethod_gssapi()";
1107 OM_uint32 ret_flags, major_status, minor_status;
1108 gss_name_t client_name = GSS_C_NO_NAME,
1109 server_name = GSS_C_NO_NAME;
1110 gss_cred_id_t server_creds = GSS_C_NO_CREDENTIAL;
1111 gss_buffer_desc service = GSS_C_EMPTY_BUFFER,
1112 input_token = GSS_C_EMPTY_BUFFER,
1113 output_token = GSS_C_EMPTY_BUFFER,
1114 *context_token = GSS_C_NO_BUFFER;
1115 #if SOCKS_CLIENT
1116 sigset_t oldset;
1117 #endif /* SOCKS_CLIENT */
1118 ssize_t rc;
1119 size_t len;
1120 unsigned short token_length;
1121 unsigned char request[GSSAPI_HLEN + MAXGSSAPITOKENLEN],
1122 response[GSSAPI_HLEN + MAXGSSAPITOKENLEN],
1123 gss_server_enc, gss_enc;
1124 char nameinfo[MAXNAMELEN + MAXNAMELEN], buf[sizeof(nameinfo)], tmpbuf[512];
1125 int conf_state;
1126 int have_slash;
1127
1128 #if SOCKSLIBRARY_DYNAMIC && SOCKS_CLIENT
1129 /*
1130 * Make sure the gssapi functions use the native connect(2)/bind(2)
1131 * and sendto(2)/recvfrom(2) system calls, even if the user has not
1132 * created a direct route for the related addresses.
1133 *
1134 * During the process of establishing a socks gssapi session with
1135 * server X, we will need to contact the kdc for a ticket to
1136 * use with server X, but if our only route to the kdc is via
1137 * server X, that doesn't work of course. The correct thing
1138 * is for the user to create a direct route to kdc, but helping
1139 * him this way will hopefully save a ton of grief.
1140 *
1141 * It will not work in the (hopefully very rare) case where the
1142 * user actually has set things up correctly, but the route to
1143 * the kdc is via another, non-gssapi, proxy though.
1144 *
1145 * Based on an idea by Markus Moeller for forcing connect(2) to
1146 * the Kerberos kdc to use the native connect(2), rather than most
1147 * likely create a routing loop when the user neglects to mark the
1148 * route to the kdc as "direct" in socks.conf.
1149 */
1150 socks_mark_io_as_native();
1151 #endif /* SOCKSLIBRARY_DYNAMIC && SOCKS_CLIENT */
1152
1153
1154 /*
1155 * Get the hostname of the gateway so we can convert it to a gss-name
1156 * and contact the kdc to get a ticket for using the socks-service at
1157 * hostname.
1158 */
1159
1160 SASSERTX(gw != NULL);
1161 switch (gw->addr.atype) {
1162 case SOCKS_ADDR_IPV4: {
1163 struct sockaddr_storage addr;
1164
1165 sockshost2sockaddr(&gw->addr, &addr);
1166
1167 SOCKS_SIGBLOCK_IF_CLIENT(SIGIO, &oldset);
1168 rc = getnameinfo(TOSA(&addr),
1169 salen(addr.ss_family),
1170 nameinfo,
1171 sizeof(nameinfo),
1172 NULL,
1173 0,
1174 NI_NAMEREQD);
1175 SOCKS_SIGUNBLOCK_IF_CLIENT(&oldset);
1176
1177 if (rc != 0) {
1178 char ntop[MAXSOCKADDRSTRING];
1179
1180 if (inet_ntop(addr.ss_family,
1181 GET_SOCKADDRADDR(&addr),
1182 ntop,
1183 sizeof(ntop)) == NULL) {
1184 snprintf(emsg, emsglen, "inet_ntop(3) failed on addr %s: %s",
1185 sockaddr2string2(&addr, 0, NULL, 0), strerror(errno));
1186 }
1187 else
1188 snprintf(emsg, emsglen, "getnameinfo(%s) failed: error %ld",
1189 ntop, (long)rc);
1190
1191 swarnx("%s: %s", emsg, function); /* likely generic config error. */
1192 goto error;
1193 }
1194 break;
1195 }
1196
1197 case SOCKS_ADDR_DOMAIN:
1198 STRCPY_ASSERTSIZE(nameinfo, gw->addr.addr.domain);
1199 break;
1200
1201 default:
1202 SERRX(gw->addr.atype);
1203 }
1204
1205 have_slash = (strchr(gw->state.gssapiservicename, '/') != NULL);
1206 if (have_slash)
1207 snprintf(buf, sizeof(buf), "%s", gw->state.gssapiservicename);
1208 else
1209 snprintf(buf, sizeof(buf), "%s@%s", gw->state.gssapiservicename, nameinfo);
1210 service.value = buf;
1211 service.length = strlen((char *)service.value);
1212
1213 SOCKS_SIGBLOCK_IF_CLIENT(SIGIO, &oldset);
1214 major_status = gss_import_name(&minor_status,
1215 &service,
1216 have_slash ? (gss_OID)GSS_C_NULL_OID
1217 : (gss_OID)gss_nt_service_name,
1218 &server_name);
1219 SOCKS_SIGUNBLOCK_IF_CLIENT(&oldset);
1220
1221 if (gss_err_isset(major_status, minor_status, tmpbuf, sizeof(tmpbuf))) {
1222 snprintf(emsg, emsglen, "gss_import_name() failed: %s", emsg);
1223
1224 SOCKS_SIGUNBLOCK_IF_CLIENT(&oldset);
1225 goto error;
1226 }
1227
1228 request[GSSAPI_VERSION] = SOCKS_GSSAPI_VERSION;
1229 auth->mdata.gssapi.state.id = GSS_C_NO_CONTEXT;
1230
1231 while (1) {
1232 SOCKS_SIGBLOCK_IF_CLIENT(SIGIO, &oldset);
1233 major_status = gss_init_sec_context(&minor_status,
1234 GSS_C_NO_CREDENTIAL,
1235 &auth->mdata.gssapi.state.id,
1236 server_name,
1237 GSS_C_NULL_OID,
1238 GSS_C_MUTUAL_FLAG
1239 | GSS_C_REPLAY_FLAG
1240 | (protocol == SOCKS_TCP ?
1241 GSS_C_SEQUENCE_FLAG : 0),
1242 /*
1243 * | GSS_C_DELEG_FLAG
1244 * RFC 1961 says GSS_C_DELEG_FLAG
1245 * should also be set, but I can't
1246 * see any reason why the client
1247 * should want to forward it's
1248 * tickets to a socks server ...
1249 *
1250 * Don't set unless until we find
1251 * a reason to do so.
1252 */
1253 0,
1254 GSS_C_NO_CHANNEL_BINDINGS,
1255 context_token,
1256 NULL,
1257 &output_token,
1258 &ret_flags,
1259 NULL);
1260 SOCKS_SIGUNBLOCK_IF_CLIENT(&oldset);
1261
1262 slog(LOG_DEBUG, "%s: length of output_token is %lu",
1263 function, (unsigned long)output_token.length);
1264
1265 switch (major_status) {
1266 case GSS_S_COMPLETE:
1267 slog(LOG_NEGOTIATE, "%s: gssapi negotiation completed", function);
1268 break;
1269
1270 case GSS_S_CONTINUE_NEEDED:
1271 slog(LOG_DEBUG, "%s: gssapi negotiation to be continued", function);
1272 break;
1273
1274 default:
1275 if (!gss_err_isset(major_status,
1276 minor_status,
1277 tmpbuf,
1278 sizeof(tmpbuf)))
1279 snprintf(tmpbuf, sizeof(tmpbuf), "unknown gss major_status %d",
1280 major_status);
1281
1282 snprintf(emsg, emsglen,
1283 "gss_init_sec_context() failed: %s", tmpbuf);
1284 goto error;
1285 }
1286
1287 if(output_token.length != 0) {
1288 request[GSSAPI_STATUS] = SOCKS_GSSAPI_AUTHENTICATION;
1289
1290 token_length = htons((unsigned short)output_token.length);
1291 memcpy(request + GSSAPI_TOKEN_LENGTH, &token_length, sizeof(short));
1292
1293 SASSERTX(output_token.length <= sizeof(request) - GSSAPI_HLEN);
1294 memcpy(request + GSSAPI_HLEN, output_token.value, output_token.length);
1295
1296 slog(LOG_DEBUG, "%s: sending token of length %lu to server",
1297 function, (unsigned long)output_token.length);
1298
1299 len = (size_t)(GSSAPI_HLEN + output_token.length);
1300 if ((rc = socks_sendton(s,
1301 request,
1302 len,
1303 len,
1304 0,
1305 NULL,
1306 0,
1307 NULL,
1308 NULL)) != (ssize_t)len) {
1309 snprintf(emsg, emsglen,
1310 "send of request to proxy server failed, sent %ld/%ld: %s",
1311 (long)rc,
1312 (long)(GSSAPI_HLEN + output_token.length),
1313 strerror(errno));
1314 goto error;
1315 }
1316
1317 CLEAN_GSS_TOKEN(output_token);
1318 }
1319
1320 if (major_status == GSS_S_COMPLETE)
1321 break;
1322
1323 if ((rc = socks_recvfromn(s,
1324 response,
1325 GSSAPI_HLEN,
1326 GSSAPI_HLEN,
1327 0,
1328 NULL,
1329 NULL,
1330 NULL,
1331 NULL)) != GSSAPI_HLEN) {
1332 snprintf(emsg, emsglen,
1333 "read of response from proxy server failed, read %ld/%ld: %s",
1334 (long)rc, (long)GSSAPI_HLEN, strerror(errno));
1335 goto error;
1336 }
1337
1338 slog(LOG_DEBUG, "%s: read %ld bytes of response data from server",
1339 function, (long)rc);
1340
1341 if(response[GSSAPI_VERSION] != SOCKS_GSSAPI_VERSION) {
1342 snprintf(emsg, emsglen,
1343 "invalid GSSAPI authentication response type (%d, %d) from "
1344 "proxy server",
1345 response[GSSAPI_VERSION], response[GSSAPI_STATUS]);
1346 goto error;
1347 }
1348
1349 if (response[GSSAPI_STATUS] == 0xff) {
1350 snprintf(emsg, emsglen, "user was rejected by proxy server (%d, %d).",
1351 response[GSSAPI_VERSION], response[GSSAPI_STATUS]);
1352 goto error;
1353 }
1354
1355 if(response[GSSAPI_STATUS] != SOCKS_GSSAPI_AUTHENTICATION) {
1356 snprintf(emsg, emsglen,
1357 "invalid GSSAPI authentication response type (%d, %d) from "
1358 "proxy server",
1359 response[GSSAPI_VERSION], response[GSSAPI_STATUS]);
1360 goto error;
1361 }
1362
1363 memcpy(&token_length, &response[GSSAPI_TOKEN_LENGTH], sizeof(short));
1364 token_length = ntohs(token_length);
1365
1366 input_token.value = response + GSSAPI_HLEN;
1367 if ((input_token.length = token_length) > sizeof(response) - GSSAPI_HLEN){
1368 snprintf(emsg, emsglen,
1369 "proxy server sent illegal token length of %u, max is %lu",
1370 token_length, (long unsigned)sizeof(response) - GSSAPI_HLEN);
1371 goto error;
1372 }
1373
1374 if ((rc = socks_recvfromn(s,
1375 input_token.value,
1376 input_token.length,
1377 input_token.length,
1378 0,
1379 NULL,
1380 NULL,
1381 NULL,
1382 NULL)) != (ssize_t)input_token.length) {
1383 snprintf(emsg, emsglen,
1384 "read of response from proxy server failed, read %ld/%ld: %s",
1385 (long)rc, (long)input_token.length, strerror(errno));
1386
1387 goto error;
1388 }
1389
1390 slog(LOG_DEBUG, "%s: read %lu byte token from server",
1391 function, (long)input_token.length);
1392
1393 context_token = &input_token;
1394 }
1395
1396 CLEAN_GSS_TOKEN(output_token);
1397 CLEAN_GSS_AUTH(client_name, server_name, server_creds);
1398
1399 request[GSSAPI_STATUS] = SOCKS_GSSAPI_ENCRYPTION;
1400
1401 /*
1402 * offer the best we are configured to support.
1403 * Later when we get the reply from the server, check that it is, if
1404 * not the one we offered, at least one we are configured to support
1405 * for this rule.
1406 */
1407 if (gw->state.gssapiencryption.confidentiality)
1408 gss_enc = SOCKS_GSSAPI_CONFIDENTIALITY;
1409 else if (gw->state.gssapiencryption.integrity)
1410 gss_enc = SOCKS_GSSAPI_INTEGRITY;
1411 else if (gw->state.gssapiencryption.clear)
1412 gss_enc = SOCKS_GSSAPI_CLEAR;
1413 else {
1414 swarnx("%s: no gssapi type to offer set", function);
1415 SERRX(0);
1416 }
1417
1418 slog(LOG_NEGOTIATE,
1419 "%s: running in %s %s GSSAPI mode. Offering server protection "
1420 "\"%s\" (%d)",
1421 function,
1422 gw->state.gssapiencryption.nec ? "nec" : "rfc1961",
1423 gw->state.gssapiencryption.nec ? "non-standard" : "standard",
1424 gssapiprotection2string(gss_enc), gss_enc);
1425
1426 if (gw->state.gssapiencryption.nec) {
1427 const size_t tosend = GSSAPI_HLEN + 1, toread = tosend;
1428
1429 token_length = htons(1);
1430 memcpy(&request[GSSAPI_TOKEN_LENGTH], &token_length, sizeof(short));
1431 memcpy(request + GSSAPI_HLEN, &gss_enc, 1);
1432
1433 if ((rc = socks_sendton(s,
1434 request,
1435 tosend,
1436 tosend,
1437 0,
1438 NULL,
1439 0,
1440 NULL,
1441 NULL)) != (ssize_t)tosend) {
1442 snprintf(emsg, emsglen,
1443 "send of request to proxy server failed, sent %ld/%ld: %s",
1444 (long)rc, (long)tosend, strerror(errno));
1445 goto error;
1446 }
1447
1448 if ((rc = socks_recvfromn(s,
1449 response,
1450 toread,
1451 toread,
1452 0,
1453 NULL,
1454 NULL,
1455 NULL,
1456 NULL)) != (ssize_t)toread) {
1457 snprintf(emsg, emsglen,
1458 "read of response from proxy server failed, read %ld/%ld: %s",
1459 (long)rc, (long)(GSSAPI_HLEN + 1), strerror(errno));
1460 goto error;
1461 }
1462
1463 if (response[GSSAPI_STATUS] != SOCKS_GSSAPI_ENCRYPTION) {
1464 snprintf(emsg, emsglen,
1465 "invalid GSSAPI encryption response type (%d, %d) "
1466 "from proxy server",
1467 response[GSSAPI_VERSION], response[GSSAPI_STATUS]);
1468 goto error;
1469 }
1470
1471 memcpy(&token_length, &response[GSSAPI_TOKEN_LENGTH], sizeof(short));
1472 token_length = ntohs(token_length);
1473
1474 if (token_length != 1) {
1475 snprintf(emsg, emsglen,
1476 "received invalid encryption token length from proxy server "
1477 "(%d, not 1) ",
1478 token_length);
1479 goto error;
1480 }
1481
1482 gss_server_enc = response[GSSAPI_TOKEN];
1483 }
1484 else {
1485 unsigned char p;
1486
1487 input_token.value = &p;
1488 input_token.length = 1;
1489
1490 memcpy(input_token.value, &gss_enc, input_token.length);
1491
1492 SOCKS_SIGBLOCK_IF_CLIENT(SIGIO, &oldset);
1493 major_status = gss_wrap(&minor_status,
1494 auth->mdata.gssapi.state.id,
1495 0,
1496 GSS_C_QOP_DEFAULT,
1497 &input_token,
1498 &conf_state,
1499 &output_token);
1500 SOCKS_SIGUNBLOCK_IF_CLIENT(&oldset);
1501
1502 if (gss_err_isset(major_status, minor_status, tmpbuf, sizeof(tmpbuf))) {
1503 snprintf(emsg, emsglen, "gss_wrap() failed: %s", tmpbuf);
1504 goto error;
1505 }
1506
1507 token_length = htons((short)output_token.length);
1508 memcpy(&request[GSSAPI_TOKEN_LENGTH], &token_length, sizeof(short));
1509
1510 if ((rc = socks_sendton(s,
1511 request,
1512 GSSAPI_TOKEN,
1513 GSSAPI_TOKEN,
1514 0,
1515 NULL,
1516 0,
1517 NULL,
1518 NULL)) != GSSAPI_TOKEN) {
1519 snprintf(emsg, emsglen,
1520 "send of request to proxy server failed, sent %ld/%ld: %s",
1521 (long)rc, (long)GSSAPI_TOKEN, strerror(errno));
1522 goto error;
1523 }
1524
1525 if ((rc = socks_sendton(s,
1526 output_token.value,
1527 output_token.length,
1528 output_token.length,
1529 0,
1530 NULL,
1531 0,
1532 NULL,
1533 NULL)) != (ssize_t)output_token.length) {
1534 snprintf(emsg, emsglen,
1535 "send of request to proxy server failed, sent %ld/%ld: %s",
1536 (long)rc, (long)output_token.length, strerror(errno));
1537 goto error;
1538 }
1539
1540 CLEAN_GSS_TOKEN(output_token);
1541
1542 if ((rc = socks_recvfromn(s,
1543 response,
1544 GSSAPI_HLEN,
1545 GSSAPI_HLEN,
1546 0,
1547 NULL,
1548 NULL,
1549 NULL,
1550 NULL)) != GSSAPI_HLEN) {
1551 snprintf(emsg, emsglen,
1552 "read of response from proxy server failed, read %ld/%d: %s",
1553 (long)rc, GSSAPI_HLEN, strerror(errno));
1554 goto error;
1555 }
1556
1557 if (response[GSSAPI_STATUS] != SOCKS_GSSAPI_ENCRYPTION) {
1558 snprintf(emsg, emsglen,
1559 "received invalid GSSAPI encryption response type from "
1560 "proxy server (version %d, status %d)",
1561 response[GSSAPI_VERSION], response[GSSAPI_STATUS]);
1562 goto error;
1563 }
1564
1565 memcpy(&token_length, response + GSSAPI_TOKEN_LENGTH, sizeof(short));
1566 input_token.length = ntohs(token_length);
1567
1568 if (input_token.length > sizeof(response) - GSSAPI_HLEN) {
1569 snprintf(emsg, emsglen,
1570 "proxy server replied with too big a token of length %u, "
1571 "but the max length is %lu",
1572 (unsigned)token_length,
1573 (unsigned long)sizeof(response) - GSSAPI_HLEN);
1574 goto error;
1575 }
1576
1577 input_token.value = response + GSSAPI_HLEN;
1578
1579 if ((rc = socks_recvfromn(s,
1580 input_token.value,
1581 input_token.length,
1582 input_token.length,
1583 0,
1584 NULL,
1585 NULL,
1586 NULL,
1587 NULL)) != (ssize_t)input_token.length) {
1588 snprintf(emsg, emsglen,
1589 "read of response from proxy server failed, read %ld/%ld: %s",
1590 (long)rc, (long)input_token.length, strerror(errno));
1591 goto error;
1592 }
1593
1594 major_status = gss_unwrap(&minor_status,
1595 auth->mdata.gssapi.state.id,
1596 &input_token,
1597 &output_token,
1598 0,
1599 GSS_C_QOP_DEFAULT);
1600
1601 if (gss_err_isset(major_status, minor_status, tmpbuf, sizeof(tmpbuf))) {
1602 snprintf(emsg, emsglen,
1603 "gss_unwrap() of token received from proxy server failed: %s",
1604 tmpbuf);
1605 goto error;
1606 }
1607
1608 if (output_token.length != 1) {
1609 snprintf(emsg, emsglen,
1610 "gssapi encryption output_token.length is not 1 as expected, "
1611 "but instead %lu",
1612 (unsigned long)output_token.length);
1613 goto error;
1614 }
1615
1616 gss_server_enc = *(unsigned char *)output_token.value;
1617
1618 CLEAN_GSS_TOKEN(output_token);
1619 }
1620
1621 switch (gss_server_enc) {
1622 case SOCKS_GSSAPI_CLEAR:
1623 if (gw->state.gssapiencryption.clear)
1624 gss_enc = SOCKS_GSSAPI_CLEAR;
1625 break;
1626
1627 case SOCKS_GSSAPI_INTEGRITY:
1628 if (gw->state.gssapiencryption.integrity)
1629 gss_enc = SOCKS_GSSAPI_INTEGRITY;
1630 break;
1631
1632 case SOCKS_GSSAPI_CONFIDENTIALITY:
1633 if (gw->state.gssapiencryption.confidentiality)
1634 gss_enc = SOCKS_GSSAPI_CONFIDENTIALITY;
1635 break;
1636
1637 default:
1638 snprintf(emsg, emsglen,
1639 "proxy server responded with different encryption than we "
1640 "are accepting for this proxy server. "
1641 "Our settings for this server are: "
1642 "clear/%s, integrity/%s, confidentiality/%s, per message/%s, "
1643 "but server instead offered us %s (%d)",
1644 gw->state.gssapiencryption.clear ? "yes" : "no",
1645 gw->state.gssapiencryption.integrity ? "yes" : "no",
1646 gw->state.gssapiencryption.confidentiality ? "yes" : "no",
1647 gw->state.gssapiencryption.permessage ? "yes" : "no",
1648 gssapiprotection2string(gss_server_enc), gss_server_enc);
1649 goto error;
1650 }
1651
1652 slog(LOG_NEGOTIATE, "%s: using gssapi %s protection (%d)",
1653 function, gssapiprotection2string(gss_enc), gss_enc);
1654
1655 auth->mdata.gssapi.state.protection = gss_enc;
1656 if (auth->mdata.gssapi.state.protection != SOCKS_GSSAPI_CLEAR)
1657 auth->mdata.gssapi.state.wrap = 1;
1658
1659 major_status
1660 = gss_wrap_size_limit(&minor_status,
1661 auth->mdata.gssapi.state.id,
1662 auth->mdata.gssapi.state.protection
1663 == GSSAPI_CONFIDENTIALITY ?
1664 GSS_REQ_CONF : GSS_REQ_INT,
1665 GSS_C_QOP_DEFAULT,
1666 MAXGSSAPITOKENLEN - GSSAPI_HLEN,
1667 &auth->mdata.gssapi.state.maxgssdata);
1668
1669 if (gss_err_isset(major_status, minor_status, tmpbuf, sizeof(tmpbuf))) {
1670 snprintf(emsg, emsglen, "gss_wrap_size_limit() failed: %s", tmpbuf);
1671 goto error;
1672 }
1673 else {
1674 slog(LOG_DEBUG, "%s: max length of gssdata before encoding: %lu",
1675 function, (unsigned long)auth->mdata.gssapi.state.maxgssdata);
1676
1677 if ((unsigned long)auth->mdata.gssapi.state.maxgssdata == 0) {
1678 snprintf(emsg, emsglen,
1679 "for a token of length %lu gss_wrap_size_limit() returned "
1680 "%lu, which does not make sense. "
1681 "Possibly the kerberos library in use does not fully support "
1682 "the configured gssapi encoding type?",
1683 (unsigned long)auth->mdata.gssapi.state.maxgssdata,
1684 (unsigned long)auth->mdata.gssapi.state.maxgssdata);
1685 goto error;
1686 }
1687 }
1688
1689 #if SOCKSLIBRARY_DYNAMIC && SOCKS_CLIENT
1690 socks_mark_io_as_normal();
1691 #endif /* SOCKSLIBRARY_DYNAMIC && SOCKS_CLIENT */
1692
1693 return 0;
1694
1695 error:
1696 if (auth->mdata.gssapi.state.id != GSS_C_NO_CONTEXT) {
1697 if ((major_status
1698 = gss_delete_sec_context(&minor_status,
1699 &auth->mdata.gssapi.state.id,
1700 GSS_C_NO_BUFFER)) != GSS_S_COMPLETE) {
1701 if (!gss_err_isset(major_status, minor_status, tmpbuf, sizeof(tmpbuf)))
1702 *tmpbuf = NUL;
1703
1704 swarnx("%s: gss_delete_sec_context() failed%s%s",
1705 function,
1706 *tmpbuf == NUL ? "" : ": ",
1707 *tmpbuf == NUL ? "" : tmpbuf);
1708 }
1709 }
1710
1711 CLEAN_GSS_TOKEN(output_token);
1712 CLEAN_GSS_AUTH(client_name, server_name, server_creds);
1713
1714 #if SOCKSLIBRARY_DYNAMIC && SOCKS_CLIENT
1715 socks_mark_io_as_normal();
1716 #endif /* SOCKSLIBRARY_DYNAMIC && SOCKS_CLIENT */
1717
1718 slog(LOG_NEGOTIATE, "%s: failed, error is: %s", function, emsg);
1719 return -1;
1720 }
1721 #endif /* HAVE_GSSAPI and Markus' contributed code. */
1722