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