1 /*
2 * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 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 #include "common.h"
46
47 static const char rcsid[] =
48 "$Id: sockd_protocol.c,v 1.214.4.1 2014/08/15 18:16:43 karls Exp $";
49
50 #if SOCKS_SERVER
51 static negotiate_result_t
52 recv_v4req(int s, request_t *request, negotiate_state_t *state);
53
54 static negotiate_result_t
55 recv_v5req(int s, request_t *request, negotiate_state_t *state);
56
57 static negotiate_result_t
58 recv_methods(int s, request_t *request, negotiate_state_t *state);
59
60 static negotiate_result_t
61 recv_ver(int s, request_t *request, negotiate_state_t *state);
62
63 static negotiate_result_t
64 recv_cmd(int s, request_t *request, negotiate_state_t *state);
65
66 static negotiate_result_t
67 recv_flag(int s, request_t *request, negotiate_state_t *state);
68
69 static negotiate_result_t
70 recv_sockshost(int s, request_t *request, negotiate_state_t *state);
71
72 static negotiate_result_t
73 recv_atyp(int s, request_t *request, negotiate_state_t *state);
74
75 static negotiate_result_t
76 recv_port(int s, request_t *request, negotiate_state_t *state);
77
78 static negotiate_result_t
79 recv_address(int s, request_t *request, negotiate_state_t *state);
80
81 static negotiate_result_t
82 recv_domain(int s, request_t *request, negotiate_state_t *state);
83
84 static negotiate_result_t
85 recv_username(int s, request_t *request,
86 negotiate_state_t *state);
87
88 static negotiate_result_t
89 methodnegotiate(int s, request_t *request,
90 negotiate_state_t *state);
91 #endif /* SOCKS_SERVER */
92
93 negotiate_result_t
recv_clientrequest(s,request,state)94 recv_clientrequest(s, request, state)
95 int s;
96 request_t *request;
97 negotiate_state_t *state;
98 {
99 const char *function = "recv_clientrequest()";
100 #if HAVE_NEGOTIATE_PHASE
101 negotiate_result_t rc;
102 #endif /* HAVE_NEGOTIATE_PHASE */
103
104 slog(LOG_DEBUG,
105 "%s: fd %d, client %s, state->complete: %d, read so far: %lu",
106 function,
107 s,
108 sockshost2string(&state->src, NULL, 0),
109 state->complete,
110 (unsigned long)state->reqread);
111
112 if (state->complete)
113 return NEGOTIATE_FINISHED;
114
115 #if HAVE_NEGOTIATE_PHASE
116
117 #if SOCKS_SERVER
118 CTASSERT(sizeof(state->mem) > (MAXMETHODS + MAXNAMELEN + MAXPWLEN));
119 #endif /* SOCKS_SERVER */
120
121 if (state->rcurrent != NULL) /* not first call on this client. */
122 rc = state->rcurrent(s, request, state);
123 else {
124 char src[MAXSOCKSHOSTSTRING], dst[sizeof(src)];
125
126 #if SOCKS_SERVER
127 INIT(sizeof(request->version));
128 CHECK(&request->version, request->auth, NULL);
129
130 switch (request->version) {
131 case PROXY_SOCKS_V4:
132 state->rcurrent = recv_v4req;
133 break;
134
135 case PROXY_SOCKS_V5:
136 state->rcurrent = recv_v5req;
137 break;
138
139 default:
140 snprintf(state->emsg, sizeof(state->emsg),
141 "unknown SOCKS version %d in client request",
142 request->version);
143 return NEGOTIATE_ERROR;
144 }
145
146 #elif COVENANT
147 state->rcurrent = recv_httprequest;
148 #else /* !COVENANT */
149 SASSERTX(0); /* should never have been called. */
150 #endif
151
152 slog(LOG_DEBUG, "%s: initiating negotiation with client at %s "
153 "which connected to us on %s",
154 function,
155 sockshost2string(&state->src, src, sizeof(src)),
156 sockshost2string(&state->dst, dst, sizeof(dst)));
157
158 rc = state->rcurrent(s, request, state);
159 }
160
161 state->complete = (rc == NEGOTIATE_FINISHED);
162 return rc;
163 #else /* !HAVE_NEGOTIATE_PHASE */
164
165 SASSERTX(state->complete);
166 return NEGOTIATE_FINISHED;
167 /* NOTREACHED */
168
169 #endif /* !HAVE_NEGOTIATE_PHASE */
170 }
171
172 #if HAVE_NEGOTIATE_PHASE
173 void
send_failure(s,response,failure)174 send_failure(s, response, failure)
175 const int s;
176 response_t *response;
177 const unsigned int failure;
178 {
179 const char *function = "send_failure()";
180
181 socks_set_responsevalue(response, sockscode(response->version, failure));
182 if (send_response(s, response) != 0)
183 slog(LOG_DEBUG, "%s: could not send failure to client: %s",
184 function, strerror(errno));
185
186 #if HAVE_GSSAPI
187 if (response->auth->method == AUTHMETHOD_GSSAPI
188 && response->auth->mdata.gssapi.state.id != GSS_C_NO_CONTEXT) {
189 OM_uint32 major_status, minor_status;
190 char buf[512];
191
192 if ((major_status
193 = gss_delete_sec_context(&minor_status,
194 &response->auth->mdata.gssapi.state.id,
195 GSS_C_NO_BUFFER)) != GSS_S_COMPLETE) {
196 if (!gss_err_isset(major_status, minor_status, buf, sizeof(buf)))
197 *buf = NUL;
198
199 swarn("%s: gss_delete_sec_context() failed%s%s",
200 function,
201 *buf == NUL ? "" : ": ",
202 *buf == NUL ? "" : buf);
203 }
204 }
205 #endif /* HAVE_GSSAPI */
206 }
207
208 int
send_response(s,response)209 send_response(s, response)
210 int s;
211 const response_t *response;
212 {
213 const char *function = "send_response()";
214 iobuffer_t *tmpiobuf;
215 sendto_info_t sendtoflags;
216 ssize_t sent;
217 size_t length;
218 #if SOCKS_SERVER
219 unsigned char responsemem[sizeof(*response)], *p = responsemem;
220 #else /* !SOCKS_SERVER */
221 char responsemem[1024], *p = responsemem;
222 #endif
223
224 switch (response->version) {
225 #if SOCKS_SERVER
226 case PROXY_SOCKS_V4REPLY_VERSION:
227 /*
228 * socks V4 reply packet:
229 *
230 * VN CD DSTPORT DSTIP
231 * 1 + 1 + 2 + 4
232 *
233 * Always 8 octets long.
234 */
235
236 memcpy(p, &response->version, sizeof(response->version));
237 p += sizeof(response->version);
238
239 /* CD (reply) */
240 memcpy(p, &response->reply.socks, sizeof(response->reply.socks));
241 p += sizeof(response->reply.socks);
242
243 p = sockshost2mem(&response->host, p, response->version);
244 length = p - responsemem;
245
246 break;
247
248 case PROXY_SOCKS_V5:
249 /*
250 * socks V5 reply:
251 *
252 * +----+-----+-------+------+----------+----------+
253 * |VER | REP | FLAG | ATYP | BND.ADDR | BND.PORT |
254 * +----+-----+-------+------+----------+----------+
255 * | 1 | 1 | 1 | 1 | Variable | 2 |
256 * +----+-----+-------+------+----------+----------+
257 * 1 1 1 1 2
258 *
259 * Which gives a fixed size of at least 6 octets.
260 * The first octet of DST.ADDR when it is SOCKS_ADDR_DOMAINNAME
261 * contains the length.
262 *
263 */
264
265 /* VER */
266 memcpy(p, &response->version, sizeof(response->version));
267 p += sizeof(response->version);
268
269 /* REP */
270 memcpy(p, &response->reply.socks, sizeof(response->reply.socks));
271 p += sizeof(response->reply.socks);
272
273 /* FLAG */
274 memcpy(p, &response->flag, sizeof(response->flag));
275 p += sizeof(response->flag);
276
277 p = sockshost2mem(&response->host, p, response->version);
278 break;
279
280 #elif COVENANT /* !SOCKS_SERVER */
281 case PROXY_HTTP_10:
282 case PROXY_HTTP_11: {
283 size_t l;
284
285 l = httpresponse2mem(s, response, responsemem, sizeof(responsemem));
286 p += l;
287
288 break;
289 }
290 #endif /* COVENANT */
291
292 default:
293 SERRX(response->version);
294 }
295
296 length = p - responsemem;
297
298 #if SOCKS_SERVER
299 slog(LOG_DEBUG, "%s: sending response: %s, authmethod %d",
300 function, socks_packet2string(response, 0), response->auth->method);
301
302 #else /* COVENANT */
303 slog(LOG_DEBUG, "%s: sending response:\n%s", function, responsemem);
304 #endif
305
306 /*
307 * If sending response from a process that normally does not send
308 * any response, and thus does not allocate a buffer for this fd.
309 */
310 if (socks_getbuffer(s) == NULL)
311 tmpiobuf = socks_allocbuffer(s, SOCK_STREAM);
312 else
313 tmpiobuf = NULL;
314
315 bzero(&sendtoflags, sizeof(sendtoflags));
316 sendtoflags.side = INTERNALIF;
317
318 sent = socks_sendton(s,
319 responsemem,
320 length,
321 1,
322 0,
323 NULL,
324 0,
325 &sendtoflags,
326 response->auth);
327
328 if (tmpiobuf != NULL)
329 socks_freebuffer(s);
330
331 if (sent != (ssize_t)length) {
332 slog(LOG_DEBUG, "%s: socks_sendton(): %ld/%lu: %s",
333 function, (long)sent, (long unsigned)length, strerror(errno));
334
335 return -1;
336 }
337
338 return 0;
339 }
340
341 int
send_connectresponse(s,error,io)342 send_connectresponse(s, error, io)
343 const int s;
344 const int error;
345 sockd_io_t *io;
346 {
347 response_t response;
348
349 create_response(
350 #if SOCKS_SERVER
351 sockaddr2sockshost(&io->dst.laddr, NULL),
352 #elif COVENANT
353 &io->dst.host,
354 #else /* !COVENANT */
355 #error "who are we?"
356 #endif
357
358 &io->src.auth,
359 io->state.proxyprotocol,
360 error == 0 ?
361 SOCKS_SUCCESS : (int)errno2reply(error,
362 io->state.proxyprotocol),
363 &response);
364
365 if (send_response(s, &response) != 0)
366 return -1;
367
368 return 0;
369 }
370
371 response_t *
create_response(host,auth,version,responsecode,response)372 create_response(host, auth, version, responsecode, response)
373 const sockshost_t *host;
374 authmethod_t *auth;
375 const int version;
376 const int responsecode;
377 response_t *response;
378 {
379
380 bzero(response, sizeof(*response));
381 response->auth = auth;
382
383 switch (version) {
384 #if SOCKS_SERVER
385 case PROXY_SOCKS_V4:
386 response->version = PROXY_SOCKS_V4REPLY_VERSION;
387 break;
388
389 case PROXY_SOCKS_V5:
390 #elif COVENANT /* !SOCKS_SERVER */
391 case PROXY_HTTP_10:
392 case PROXY_HTTP_11:
393 #endif /* COVENANT */
394 response->version = version;
395 break;
396
397 default:
398 SERRX(version);
399 }
400
401 if (host != NULL)
402 response->host = *host;
403 else
404 response->host.atype = SOCKS_ADDR_IPV4;
405 /* rest can be 0. */
406
407 socks_set_responsevalue(response,
408 sockscode(version, responsecode));
409
410 return response;
411 }
412
413
414 #if SOCKS_SERVER
415 negotiate_result_t
recv_sockspacket(s,request,state)416 recv_sockspacket(s, request, state)
417 int s;
418 request_t *request;
419 negotiate_state_t *state;
420 {
421
422 return recv_ver(s, request, state);
423 }
424
425 static negotiate_result_t
recv_v4req(s,request,state)426 recv_v4req (s, request, state)
427 int s;
428 request_t *request;
429 negotiate_state_t *state;
430 {
431
432 /*
433 * v4 request:
434 * VN CD DSTPORT DSTIP USERID NUL
435 * 1 + 1 + 2 + 4 + ? + 1
436 *
437 * so minimum length is 9.
438 */
439
440 /*
441 * No methods supported in v4.
442 */
443 request->auth->method = AUTHMETHOD_NONE;
444
445 /* CD */
446 state->rcurrent = recv_cmd;
447 return state->rcurrent(s, request, state);
448
449 }
450
451 static negotiate_result_t
recv_v5req(s,request,state)452 recv_v5req (s, request, state)
453 int s;
454 request_t *request;
455 negotiate_state_t *state;
456 {
457
458 /*
459 * method negotiation;
460 * client first sends method selection message:
461 *
462 * +----+----------+----------+
463 * |VER | NMETHODS | METHODS |
464 * +----+----------+----------+
465 * | 1 | 1 | 1 to 255 |
466 * +----+----------+----------+
467 */
468
469 /*
470 * then the request:
471 *
472 * +----+-----+-------+------+----------+----------+
473 * |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
474 * +----+-----+-------+------+----------+----------+
475 * | 1 | 1 | X'00' | 1 | Variable | 2 |
476 * +----+-----+-------+------+----------+----------+
477 *
478 * 1 1 1 1 ? 2
479 *
480 * Since the request can contain different address types
481 * we do not know how long the request is before we have
482 * read the address type (ATYP) field.
483 *
484 */
485
486 /* NMETHODS */
487 INIT(sizeof(char));
488 CHECK(&state->mem[start], request->auth, NULL);
489 /* LINTED conversion from 'int' may lose accuracy */
490 OCTETIFY(state->mem[start]);
491
492 state->rcurrent = recv_methods;
493 return state->rcurrent(s, request, state);
494 }
495
496 static negotiate_result_t
recv_methods(s,request,state)497 recv_methods(s, request, state)
498 int s;
499 request_t *request;
500 negotiate_state_t *state;
501
502 {
503 const char *function = "recv_methods()";
504 sendto_info_t sendtoflags;
505 const unsigned char methodc = state->mem[AUTH_NMETHODS];
506 unsigned char reply[ 1 /* VERSION */
507 + 1 /* METHOD */
508 ];
509 char buf[(AUTHMETHOD_MAX + 1) * (sizeof("0x00 (some methodname")
510 + sizeof(", ")) + 1];
511 size_t bufused;
512 int i;
513
514 INIT(methodc);
515 CHECK(&state->mem[start], request->auth, NULL);
516
517 *buf = NUL;
518 for (i = bufused = 0; i < methodc; ++i)
519 bufused += snprintf(&buf[bufused], sizeof(buf) - bufused, "0x%x (%s), ",
520 state->mem[start + i],
521 method2string(state->mem[start + i]));
522
523 if (bufused >= sizeof(buf) - 1)
524 swarnx("%s: suspiciously many (%u) methods offered by client %s",
525 function, methodc, sockshost2string(&state->src, NULL, 0));
526
527 if (bufused >= strlen(", ") && buf[bufused - strlen(", ")] == ',')
528 buf[bufused - strlen(", ")] = NUL;
529
530 slog(LOG_DEBUG, "%s: client %s offered %d authentication method%s: %s",
531 function,
532 sockshost2string(&state->src, NULL, 0),
533 methodc, methodc == 1 ? "" : "s",
534 buf);
535
536 switch (request->auth->method) {
537 case AUTHMETHOD_NOTSET:
538 slog(LOG_DEBUG,
539 "%s: socksmethod to use not set, selecting amongst the "
540 "following %lu method%s: %s",
541 function,
542 (unsigned long)state->crule->state.smethodc,
543 (unsigned long)state->crule->state.smethodc == 1 ? "" : "s",
544 methods2string(state->crule->state.smethodc,
545 state->crule->state.smethodv,
546 NULL,
547 0));
548
549 request->auth->method = selectmethod(state->crule->state.smethodv,
550 state->crule->state.smethodc,
551 &state->mem[start],
552 (size_t)methodc);
553 break;
554
555 default: {
556 /*
557 * Socks-methods that can be decided for use before we receive
558 * the actual request. Normally only gssapi, but if the
559 * rule has singleauth enabled and the client matches the
560 * criteria for it, the socks-method will also have been
561 * chosen already (should be NONE).
562 */
563 size_t i;
564
565 slog(LOG_DEBUG,
566 "%s: method %d already chosen for this rule, not selecting again",
567 function, request->auth->method);
568
569 for (i = 0; i < methodc; ++i)
570 if (state->mem[start + i] == request->auth->method)
571 break;
572
573 if (i >= methodc)
574 request->auth->method = AUTHMETHOD_NOACCEPT;
575
576 break;
577 }
578 }
579
580 /* send reply:
581 *
582 * +----+--------+
583 * |VER | METHOD |
584 * +----+--------+
585 * | 1 | 1 |
586 * +----+--------+
587 */
588
589 slog(LOG_DEBUG, "%s: sending authentication reply: VER: %d METHOD: %d (%s)",
590 function,
591 request->version,
592 request->auth->method,
593 method2string(request->auth->method));
594
595 reply[AUTH_VERSION] = request->version;
596 reply[AUTH_SELECTEDMETHOD] = (unsigned char)request->auth->method;
597
598 bzero(&sendtoflags, sizeof(sendtoflags));
599 sendtoflags.side = EXTERNALIF;
600
601 if (socks_sendton(s,
602 reply,
603 sizeof(reply),
604 sizeof(reply),
605 0,
606 NULL,
607 0,
608 &sendtoflags,
609 request->auth) != sizeof(reply))
610 return NEGOTIATE_ERROR;
611
612 if (request->auth->method == AUTHMETHOD_NOACCEPT) {
613 snprintf(state->emsg, sizeof(state->emsg),
614 "client offered no acceptable authentication method");
615
616 return NEGOTIATE_ERROR;
617 }
618
619 state->rcurrent = methodnegotiate;
620 return NEGOTIATE_CONTINUE; /* presumably client is awaiting our response. */
621 }
622
623 static negotiate_result_t
methodnegotiate(s,request,state)624 methodnegotiate(s, request, state)
625 int s;
626 request_t *request;
627 negotiate_state_t *state;
628 {
629
630 /* authentication method dependent negotiation */
631 switch (request->auth->method) {
632 case AUTHMETHOD_NONE:
633 state->rcurrent = recv_sockspacket;
634 break;
635
636 #if HAVE_GSSAPI
637 case AUTHMETHOD_GSSAPI:
638 state->rcurrent = method_gssapi;
639 break;
640 #endif /* HAVE_GSSAPI */
641
642 case AUTHMETHOD_UNAME:
643 state->rcurrent = method_uname;
644 break;
645
646 default:
647 SERRX(request->auth->method);
648 }
649
650 return state->rcurrent(s, request, state);
651 }
652
653 static negotiate_result_t
recv_ver(s,request,state)654 recv_ver(s, request, state)
655 int s;
656 request_t *request;
657 negotiate_state_t *state;
658 {
659
660 /* VER */
661 {
662 INIT(sizeof(request->version));
663 CHECK(&request->version, request->auth, NULL);
664
665 switch (request->version) {
666 case PROXY_SOCKS_V4:
667 case PROXY_SOCKS_V5:
668 break;
669
670 default:
671 slog(LOG_DEBUG, "unknown version %d in request", request->version);
672 return NEGOTIATE_ERROR;
673 }
674 }
675
676 state->rcurrent = recv_cmd;
677 return state->rcurrent(s, request, state);
678 }
679
680 static negotiate_result_t
recv_cmd(s,request,state)681 recv_cmd(s, request, state)
682 int s;
683 request_t *request;
684 negotiate_state_t *state;
685 {
686 const char *function = "recv_cmd()";
687
688 INIT(sizeof(request->command));
689 CHECK(&request->command, request->auth, NULL);
690
691 switch (request->command) {
692 case SOCKS_BIND:
693 case SOCKS_CONNECT:
694 request->protocol = SOCKS_TCP;
695 break;
696
697 case SOCKS_UDPASSOCIATE:
698 request->protocol = SOCKS_UDP;
699 break;
700
701 default:
702 snprintf(state->emsg, sizeof(state->emsg),
703 "unknown %s command: %d",
704 proxyprotocol2string(request->version),
705 request->command);
706
707 return NEGOTIATE_ERROR;
708 }
709
710 switch (request->version) {
711 case PROXY_SOCKS_V4:
712 state->rcurrent = recv_sockshost;
713 break;
714
715 case PROXY_SOCKS_V5:
716 state->rcurrent = recv_flag;
717 break;
718
719 default:
720 SERRX(request->version);
721 }
722
723 return state->rcurrent(s, request, state);
724 }
725
726 static negotiate_result_t
recv_flag(s,request,state)727 recv_flag(s, request, state)
728 int s;
729 request_t *request;
730 negotiate_state_t *state;
731 {
732
733 INIT(sizeof(request->flag));
734 CHECK(&request->flag, request->auth, recv_sockshost);
735
736 SERRX(0); /* NOTREACHED */
737 }
738
739 static negotiate_result_t
recv_sockshost(s,request,state)740 recv_sockshost(s, request, state)
741 int s;
742 request_t *request;
743 negotiate_state_t *state;
744 {
745 switch (request->version) {
746 case PROXY_SOCKS_V4:
747 state->rcurrent = recv_port;
748 break;
749
750 case PROXY_SOCKS_V5:
751 state->rcurrent = recv_atyp;
752 break;
753
754 default:
755 SERRX(request->version);
756 }
757
758 return state->rcurrent(s, request, state);
759 }
760
761 static negotiate_result_t
recv_atyp(s,request,state)762 recv_atyp(s, request, state)
763 int s;
764 request_t *request;
765 negotiate_state_t *state;
766 {
767
768 INIT(sizeof(request->host.atype));
769 CHECK(&request->host.atype, request->auth, recv_address);
770
771 SERRX(0); /* NOTREACHED */
772 }
773
774 static negotiate_result_t
recv_address(s,request,state)775 recv_address(s, request, state)
776 int s;
777 request_t *request;
778 negotiate_state_t *state;
779 {
780
781 switch (request->version) {
782 case PROXY_SOCKS_V4: {
783 INIT(sizeof(request->host.addr.ipv4));
784
785 /* only one supported in v4. */
786 request->host.atype = SOCKS_ADDR_IPV4;
787
788 CHECK(&request->host.addr.ipv4, request->auth, recv_username);
789 SERRX(0); /* NOTREACHED */
790 }
791
792 case PROXY_SOCKS_V5:
793 switch(request->host.atype) {
794 case SOCKS_ADDR_IPV4: {
795 INIT(sizeof(request->host.addr.ipv4));
796 CHECK(&request->host.addr.ipv4, request->auth, recv_port);
797 SERRX(0); /* NOTREACHED */
798 }
799
800 case SOCKS_ADDR_IPV6: {
801 INIT(sizeof(request->host.addr.ipv6.ip));
802 CHECK(&request->host.addr.ipv6.ip, request->auth, recv_port);
803 SERRX(0); /* NOTREACHED */
804 }
805
806 case SOCKS_ADDR_DOMAIN: {
807 INIT(sizeof(*request->host.addr.domain));
808 CHECK(request->host.addr.domain, request->auth, NULL);
809
810 /* LINTED conversion from 'int' may lose accuracy */
811 OCTETIFY(*request->host.addr.domain);
812
813 state->rcurrent = recv_domain;
814 return state->rcurrent(s, request, state);
815 }
816
817 default:
818 snprintf(state->emsg, sizeof(state->emsg),
819 "unknown %s command: %d",
820 proxyprotocol2string(request->version),
821 request->command);
822 return NEGOTIATE_ERROR;
823 }
824
825 default:
826 SERRX(request->version);
827 }
828
829 SERRX(0); /* NOTREACHED */
830 }
831
832 static negotiate_result_t
recv_domain(s,request,state)833 recv_domain(s, request, state)
834 int s;
835 request_t *request;
836 negotiate_state_t *state;
837 {
838 unsigned char alen;
839 /* first byte gives length. */
840 INIT((unsigned char)*request->host.addr.domain);
841 CHECK(request->host.addr.domain + 1, request->auth, NULL);
842
843 alen = *request->host.addr.domain;
844
845 /* convert to C string. */
846 memmove(request->host.addr.domain, request->host.addr.domain + 1,
847 (size_t)alen);
848 request->host.addr.domain[alen] = NUL;
849
850 state->rcurrent = recv_port;
851 return state->rcurrent(s, request, state);
852 }
853
854 static negotiate_result_t
recv_port(s,request,state)855 recv_port(s, request, state)
856 int s;
857 request_t *request;
858 negotiate_state_t *state;
859 {
860
861 INIT(sizeof(request->host.port));
862 CHECK(&request->host.port, request->auth, NULL);
863
864 switch (request->version) {
865 case PROXY_SOCKS_V4:
866 state->rcurrent = recv_address; /* in v4, address after port. */
867 return state->rcurrent(s, request, state);
868
869 case PROXY_SOCKS_V5:
870 return NEGOTIATE_FINISHED; /* all done. */
871
872 default:
873 SERRX(request->version);
874 }
875
876 SERRX(0); /* NOTREACHED */
877 }
878
879 static negotiate_result_t
recv_username(s,request,state)880 recv_username(s, request, state)
881 int s;
882 request_t *request;
883 negotiate_state_t *state;
884 {
885 const char *function = "recv_username()";
886 char *username = (char *)&state->mem[sizeof(request->version)
887 + sizeof(request->command)
888 + sizeof(request->host.port)
889 + sizeof(request->host.addr.ipv4)];
890 /* read until 0. */
891 do {
892 INIT(MIN(1, MEMLEFT()));
893
894 if (MEMLEFT() == 0) {
895 char visstring[MAXNAMELEN * 4 + 1];
896
897 /*
898 * Normally this would indicate an internal error and thus
899 * be caught in CHECK(), but for the v4 case it could be
900 * someone sending a really long username, which is strange
901 * enough to log a warning about, but not an internal error.
902 */
903
904 state->mem[state->reqread - 1] = NUL;
905
906 snprintf(state->emsg, sizeof(state->emsg),
907 "%s username received from client is too long. Max length "
908 "s %lu, length of received name is longer than %lu: "
909 "\"%s ...\"",
910 proxyprotocol2string(request->version),
911 (unsigned long)(MAXNAMELEN - 1),
912 (unsigned long)strlen(username),
913 str2vis(username,
914 strlen(username),
915 visstring,
916 sizeof(visstring)));
917
918 slog(LOG_NOTICE, "%s: strange data from client %s: %s",
919 function, sockshost2string(&state->src, NULL, 0), state->emsg);
920
921 return NEGOTIATE_ERROR;
922 }
923
924 CHECK(&state->mem[start], request->auth, NULL);
925
926 /*
927 * Since we don't know how long the username is, we can only read one
928 * byte at a time. We don't want CHECK() to set state->rcurrent to
929 * NULL after each successful read of that one byte, since
930 * recv_clientrequest() will then think we are starting from the
931 * beginning next time we call it.
932 */
933 state->rcurrent = recv_username;
934 } while (state->mem[state->reqread - 1] != 0);
935 state->mem[state->reqread - 1] = NUL; /* style. */
936
937 slog(LOG_DEBUG, "%s: got socks v4 username: \"%s\"", function, username);
938
939 state->rcurrent = NULL;
940 return NEGOTIATE_FINISHED; /* end of request. */
941 }
942 #endif /* SOCKS_SERVER */
943 #endif /* HAVE_NEGOTIATE_PHASE */
944