1 /*
2  * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2019
3  *      Inferno Nettverk A/S, Norway.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. The above copyright notice, this list of conditions and the following
9  *    disclaimer must appear in all copies of the software, derivative works
10  *    or modified versions, and any portions thereof, aswell as in all
11  *    supporting documentation.
12  * 2. All advertising materials mentioning features or use of this software
13  *    must display the following acknowledgement:
14  *      This product includes software developed by
15  *      Inferno Nettverk A/S, Norway.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  * Inferno Nettverk A/S requests users of this software to return to
31  *
32  *  Software Distribution Coordinator  or  sdc@inet.no
33  *  Inferno Nettverk A/S
34  *  Oslo Research Park
35  *  Gaustadall�en 21
36  *  NO-0349 Oslo
37  *  Norway
38  *
39  * any improvements or extensions that they make and grant Inferno Nettverk A/S
40  * the rights to redistribute these changes.
41  *
42  */
43 
44  /*
45   * This code was contributed by
46   * Markus Moeller (markus_moeller at compuserve.com).
47   */
48 
49 #include "common.h"
50 
51 #if HAVE_GSSAPI
52 
53 static const char rcsid[] =
54    "$Id: method_gssapi.c,v 1.73.4.1.6.4 2020/11/11 17:02:28 karls Exp $";
55 
56 static negotiate_result_t
57 recv_gssapi_auth_ver(int s, request_t *request, negotiate_state_t *state);
58 
59 static negotiate_result_t
60 recv_gssapi_auth_type(int s, request_t *request, negotiate_state_t *state);
61 
62 static negotiate_result_t
63 recv_gssapi_auth_len(int s, request_t *request, negotiate_state_t *state);
64 
65 static negotiate_result_t
66 recv_gssapi_auth_token(int s, request_t *request, negotiate_state_t *state);
67 
68 static negotiate_result_t
69 recv_gssapi_enc_ver(int s, request_t *request, negotiate_state_t *state);
70 
71 static negotiate_result_t
72 recv_gssapi_enc_type(int s, request_t *request, negotiate_state_t *state);
73 
74 static negotiate_result_t
75 recv_gssapi_enc_len(int s, request_t *request, negotiate_state_t *state);
76 
77 static negotiate_result_t
78 recv_gssapi_enc_token(int s, request_t *request, negotiate_state_t *state);
79 
80 static negotiate_result_t
81 recv_gssapi_packet(int s, request_t *request, negotiate_state_t *state);
82 
83 static negotiate_result_t
84 recv_gssapi_packet_ver(int s, request_t *request, negotiate_state_t *state);
85 
86 static negotiate_result_t
87 recv_gssapi_packet_type(int s, request_t *request, negotiate_state_t *state);
88 
89 static negotiate_result_t
90 recv_gssapi_packet_len(int s, request_t *request, negotiate_state_t *state);
91 
92 static negotiate_result_t
93 recv_gssapi_packet_token(int s, request_t *request, negotiate_state_t *state);
94 
95 
96 negotiate_result_t
method_gssapi(s,request,state)97 method_gssapi(s, request, state)
98    int s;
99    request_t *request;
100    negotiate_state_t *state;
101 
102 {
103    const char *function = "method_gssapi()";
104 
105    slog(LOG_DEBUG, "%s", function);
106 
107    request->auth->mdata.gssapi.state.id = GSS_C_NO_CONTEXT;
108 
109    state->rcurrent = recv_gssapi_auth_ver;
110    return state->rcurrent(s, request, state);
111 }
112 
113 /*
114  *   RFC1961: client request
115  *
116  *   +------+------+------+.......................+
117  *   + ver  | mtyp | len  |       token           |
118  *   +------+------+------+.......................+
119  *   + 0x01 | 0x01 | 0x02 | up to 2^16 - 1 octets |
120  *   +------+------+------+.......................+
121  *
122  */
123 
124 static negotiate_result_t
recv_gssapi_auth_ver(s,request,state)125 recv_gssapi_auth_ver(s, request, state)
126    int s;
127    request_t *request;
128    negotiate_state_t *state;
129 {
130    const char *function = "recv_gssapi_auth_ver()";
131    unsigned char gssapi_auth_version;
132 
133    INIT(sizeof(gssapi_auth_version));
134    CHECK(&gssapi_auth_version, request->auth, NULL);
135 
136    switch (gssapi_auth_version) {
137       case SOCKS_GSSAPI_VERSION:
138          break;
139 
140       default:
141          snprintf(state->emsg, sizeof(state->emsg),
142                   "%s: unknown %s version on gssapi packet from client: %d",
143                   function,
144                   proxyprotocol2string(request->version),
145                   gssapi_auth_version);
146 
147          return NEGOTIATE_ERROR;
148    }
149 
150    state->rcurrent = recv_gssapi_auth_type;
151    return state->rcurrent(s, request, state);
152 }
153 
154 static negotiate_result_t
recv_gssapi_auth_type(s,request,state)155 recv_gssapi_auth_type(s, request, state)
156    int s;
157    request_t *request;
158    negotiate_state_t *state;
159 {
160    const char *function = "recv_gssapi_auth_type()";
161    unsigned char gssapi_auth_type;
162 
163    INIT(sizeof(gssapi_auth_type));
164    CHECK(&gssapi_auth_type, request->auth, NULL);
165 
166    switch (gssapi_auth_type) {
167       case SOCKS_GSSAPI_AUTHENTICATION:
168          break;
169 
170       case SOCKS_GSSAPI_ENCRYPTION:
171       case SOCKS_GSSAPI_PACKET:
172          snprintf(state->emsg, sizeof(state->emsg),
173          "%s: received out of sequence exchange from client.  "
174          "Got type %d, expected type %d",
175          function, gssapi_auth_type, SOCKS_GSSAPI_AUTHENTICATION);
176 
177          return NEGOTIATE_ERROR;
178 
179       default:
180          snprintf(state->emsg, sizeof(state->emsg),
181          "%s: unknown type on gssapi packet from client: %d",
182          function, gssapi_auth_type);
183 
184          return NEGOTIATE_ERROR;
185    }
186 
187    state->rcurrent = recv_gssapi_auth_len;
188    return state->rcurrent(s, request, state);
189 }
190 
191 static negotiate_result_t
recv_gssapi_auth_len(s,request,state)192 recv_gssapi_auth_len(s, request, state)
193    int s;
194    request_t *request;
195    negotiate_state_t *state;
196 {
197    INIT(sizeof(state->gssapitoken_len));
198    CHECK(&state->gssapitoken_len, request->auth, NULL);
199 
200    state->gssapitoken_len
201    = ntohs((short)state->gssapitoken_len);
202 
203    state->rcurrent = recv_gssapi_auth_token;
204    return state->rcurrent(s, request, state);
205 }
206 
207 static negotiate_result_t
recv_gssapi_auth_token(s,request,state)208 recv_gssapi_auth_token(s, request, state)
209    int s;
210    request_t *request;
211    negotiate_state_t *state;
212 {
213    const char *function = "recv_gssapi_auth_token()";
214    sendto_info_t sendtoflags;
215    gss_name_t            client_name   = GSS_C_NO_NAME;
216    gss_name_t            server_name   = GSS_C_NO_NAME;
217    gss_cred_id_t         server_creds  = GSS_C_NO_CREDENTIAL;
218    gss_buffer_desc       output_token  = GSS_C_EMPTY_BUFFER;
219    gss_buffer_desc       input_token;
220    OM_uint32             ret_flags, major_status, minor_status;
221    unsigned short        token_length;
222    ssize_t rc;
223    size_t buflen;
224    unsigned char buf[GSSAPI_HLEN + MAXGSSAPITOKENLEN];
225    char env[sizeof(request->auth->mdata.gssapi.keytab)], emsg[1024];
226 #if HAVE_PAC
227    krb5_context          k5_context = NULL;
228    krb5_error_code ret;
229    krb5_pac pac;
230 #if HAVE_HEIMDAL_KERBEROS
231    gss_buffer_desc       data_set = GSS_C_EMPTY_BUFFER;
232 #else
233    gss_buffer_desc       type_id  = GSS_C_EMPTY_BUFFER;
234 #endif /* HAVE_HEIMDAL_KERBEROS */
235 #endif /* HAVE_PAC */
236 
237    INIT(state->gssapitoken_len);
238 
239    input_token.length = state->gssapitoken_len;
240    input_token.value  = buf;
241    SASSERTX(input_token.length <= sizeof(buf));
242 
243    CHECK(input_token.value, request->auth, NULL);
244 
245    STRCPY_ASSERTLEN(env, request->auth->mdata.gssapi.keytab);
246    setenv("KRB5_KTNAME", env, 1);
247 
248 #if HAVE_HEIMDAL_KERBEROS
249    gsskrb5_register_acceptor_identity(request->auth->mdata.gssapi.keytab);
250 #endif /* HAVE_HEIMDAL_KERBEROS */
251 
252    slog(LOG_DEBUG,"%s: using gssapi service name %s",
253    function, request->auth->mdata.gssapi.servicename);
254 
255    if (strcasecmp(request->auth->mdata.gssapi.servicename, "GSS_C_NO_NAME")
256    != 0) {
257       gss_buffer_desc service;
258 
259       service.value  = request->auth->mdata.gssapi.servicename;
260       service.length = strlen(service.value);
261 
262       major_status
263       = gss_import_name(&minor_status,
264                         &service,
265                         strchr(request->auth->mdata.gssapi.servicename, '/')
266                         != NULL ?
267                                    (gss_OID)GSS_C_NULL_OID
268                                  : (gss_OID)gss_nt_service_name,
269                         &server_name);
270 
271       if (gss_err_isset(major_status, minor_status, emsg, sizeof(emsg))) {
272          snprintf(state->emsg, sizeof(state->emsg),
273          "%s: gss_import_name() %s", function, emsg);
274 
275          CLEAN_GSS_AUTH(client_name, server_name, server_creds);
276          return NEGOTIATE_ERROR;
277       }
278    }
279 
280    sockd_priv(SOCKD_PRIV_GSSAPI, PRIV_ON);
281    major_status = gss_acquire_cred(&minor_status,
282                                    server_name,
283                                    GSS_C_INDEFINITE,
284                                    GSS_C_NO_OID_SET,
285                                    GSS_C_ACCEPT,
286                                    &server_creds,
287                                    NULL,
288                                    NULL);
289    sockd_priv(SOCKD_PRIV_GSSAPI, PRIV_OFF);
290 
291    if (gss_err_isset(major_status, minor_status, emsg, sizeof(emsg))) {
292       snprintf(state->emsg, sizeof(state->emsg), "%s: gss_acquire_cred(): %s",
293                function, emsg);
294 
295       CLEAN_GSS_AUTH(client_name, server_name, server_creds);
296       return NEGOTIATE_ERROR;
297    }
298 
299    sockd_priv(SOCKD_PRIV_GSSAPI, PRIV_ON);
300    major_status
301    = gss_accept_sec_context(&minor_status,
302                             &request->auth->mdata.gssapi.state.id,
303                             server_creds,
304                             &input_token,
305                             GSS_C_NO_CHANNEL_BINDINGS,
306                             &client_name,
307                             NULL,
308                             &output_token,
309                             &ret_flags,
310                             NULL,
311                             NULL);
312    sockd_priv(SOCKD_PRIV_GSSAPI, PRIV_OFF);
313 
314    slog(LOG_DEBUG, "%s: length of output_token is %lu",
315         function, (unsigned long)output_token.length);
316 
317    if (gss_err_isset(major_status, minor_status, emsg, sizeof(emsg))) {
318       snprintf(state->emsg, sizeof(state->emsg),
319                "%s: gss_accept_sec_context() failed: %s", function, emsg);
320 
321       CLEAN_GSS_AUTH(client_name, server_name, server_creds);
322       return NEGOTIATE_ERROR;
323    }
324 
325    /*
326     * Don't need the input token anymore, so use the token buffer
327     * to hold the reply from now on.
328     */
329 
330    /*
331     * RFC1961: server reply
332     *
333     *   +------+------+------+.......................+
334     *   + ver  | mtyp | len  |       token           |
335     *   +------+------+------+.......................+
336     *   + 0x01 | 0x01 | 0x02 | up to 2^16 - 1 octets |
337     *   +------+------+------+.......................+
338     *
339     */
340 
341    SASSERTX(GSSAPI_HLEN + output_token.length <= sizeof(buf));
342 
343    buflen = 0;
344    buf[buflen++] = SOCKS_GSSAPI_VERSION;
345    buf[buflen++] = SOCKS_GSSAPI_AUTHENTICATION;
346 
347    token_length = htons(output_token.length);
348    memcpy(&buf[buflen], &token_length, sizeof(token_length));
349    buflen += sizeof(token_length);
350 
351    memcpy(&buf[buflen], output_token.value, output_token.length);
352    buflen += output_token.length;
353 
354    CLEAN_GSS_TOKEN(output_token);
355 
356    bzero(&sendtoflags, sizeof(sendtoflags));
357    sendtoflags.side = INTERNALIF;
358 
359    if ((rc = socks_sendton(s,
360                            buf,
361                            buflen,
362                            0,
363                            0,
364                            NULL,
365                            0,
366                            NULL,
367                            request->auth)) != (ssize_t)buflen)  {
368       snprintf(state->emsg, sizeof(state->emsg),
369               "socks_sendton() token: wrote %ld out of %lu byte%s: %s",
370                (long)rc,
371                (unsigned long)buflen,
372                buflen == 1 ? "" : "s",
373                strerror(errno));
374 
375       CLEAN_GSS_AUTH(client_name, server_name, server_creds);
376       return NEGOTIATE_ERROR;
377    }
378 
379    if (major_status == GSS_S_COMPLETE) {
380       /* Get username */
381       major_status = gss_display_name(&minor_status, client_name, &output_token,
382                                       NULL);
383 
384       if (gss_err_isset(major_status, minor_status, emsg, sizeof(emsg))) {
385          snprintf(state->emsg, sizeof(state->emsg),
386                   "%s: gss_display_name(): %s", function, emsg);
387 
388          CLEAN_GSS_AUTH(client_name, server_name, server_creds);
389          return NEGOTIATE_ERROR;
390       }
391 
392       memcpy(request->auth->mdata.gssapi.name, output_token.value,
393              output_token.length);
394       request->auth->mdata.gssapi.name[output_token.length] = NUL;
395 
396 #if HAVE_PAC
397       ret = krb5_init_context(&k5_context);
398       if (!krb5_err_isset(k5_context, emsg, sizeof(emsg), ret)) {
399 #define ADWIN2KPAC 128
400 #if HAVE_HEIMDAL_KERBEROS
401          major_status = gsskrb5_extract_authz_data_from_sec_context(&minor_status,
402                                                                     gss_context,
403                                                                     ADWIN2KPAC,
404                                                                     &data_set);
405          if (!gss_err_isset(major_status, minor_status, emsg, sizeof(emsg))) {
406             ret = krb5_pac_parse(k5_context, data_set.value, data_set.length, &pac);
407             gss_release_buffer(&minor_status, &data_set);
408             if (!check_k5_err(k5_context, "krb5_pac_parse", ret)) {
409                if (get_sids(request->auth->mdata.gssapi.sids, k5_context, pac, state)<0) {
410                   slog(LOG_INFO, "%s: error in getting sids", function);
411 	       }
412                krb5_pac_free(k5_context, pac);
413             }
414             krb5_free_context(k5context);
415          } else {
416 	    /* Not a major error - maybe not a MS AD setup */
417             snprintf(state->emsg, sizeof(state->emsg),
418                      "%s: gsskrb5_extract_authz_data_from_sec_context(): %s", function, emsg);
419             slog(LOG_INFO, "%s: gsskrb5_extract_authz_data_from_sec_context(): %s", function, emsg);
420          }
421 #else /* !HAVE_HEIMDAL_KERBEROS */
422          type_id.value = (void *)"mspac";
423          type_id.length = strlen((char *)type_id.value);
424 #define KRB5PACLOGONINFO 1
425          major_status = gss_map_name_to_any(&minor_status, client_name, KRB5PACLOGONINFO, &type_id, (gss_any_t *)&pac);
426          if (!gss_err_isset(major_status, minor_status, emsg, sizeof(emsg))){
427             if (get_sids(request->auth->mdata.gssapi.sids, k5_context, pac, state)<0){
428                slog(LOG_INFO, "%s: error in getting sids", function);
429 	    }
430          } else {
431 	    /* Not a major error - maybe not a MS AD setup */
432             snprintf(state->emsg, sizeof(state->emsg),
433                      "%s: gss_map_name_to_any(): %s", function, emsg);
434             slog(LOG_INFO, "%s: gss_map_name_to_any(): %s", function, emsg);
435          }
436          (void)gss_release_any_name_mapping(&minor_status, client_name, &type_id, (gss_any_t *)&pac);
437          krb5_free_context(k5_context);
438 #endif /* !HAVE_HEIMDAL_KERBEROS */
439    } else {
440       snprintf(state->emsg, sizeof(state->emsg),
441                "%s: krb5_init_context(): %s", function, emsg);
442       slog(LOG_INFO, "%s: krb5_init_context(): %s", function, emsg);
443    }
444 #endif /* HAVE_PAC */
445 
446       CLEAN_GSS_AUTH(client_name, server_name, server_creds);
447       CLEAN_GSS_TOKEN(output_token);
448 
449       state->rcurrent = recv_gssapi_enc_ver;
450       return state->rcurrent(s, request, state);
451    }
452    else if (major_status == GSS_S_CONTINUE_NEEDED) {
453       CLEAN_GSS_AUTH(client_name, server_name, server_creds);
454 
455       /* expect a new token, with the version, length, etc. header. */
456       state->rcurrent = recv_gssapi_auth_ver;
457 
458       /* presumably client is awaiting our response. */
459       return NEGOTIATE_CONTINUE;
460    }
461    else {
462       snprintf(state->emsg, sizeof(state->emsg),
463                "%s: unknown gss major_status %d", function, major_status);
464 
465       CLEAN_GSS_AUTH(client_name, server_name, server_creds);
466       return NEGOTIATE_ERROR;
467    }
468 
469    /* NOTREACHED */
470 }
471 
472 static negotiate_result_t
recv_gssapi_enc_ver(s,request,state)473 recv_gssapi_enc_ver(s, request, state)
474    int s;
475    request_t *request;
476    negotiate_state_t *state;
477 {
478    const char *function = "recv_gssapi_enc_ver()";
479    unsigned char gssapi_enc_version;
480 
481    INIT(sizeof(gssapi_enc_version));
482    CHECK(&gssapi_enc_version, request->auth, NULL);
483 
484    switch (gssapi_enc_version) {
485       case SOCKS_GSSAPI_VERSION:
486          break;
487 
488       default:
489          snprintf(state->emsg, sizeof(state->emsg),
490          "%s: unknown version on gssapi packet from client: %d",
491          function, gssapi_enc_version);
492 
493          return NEGOTIATE_ERROR;
494    }
495 
496    state->rcurrent = recv_gssapi_enc_type;
497    return state->rcurrent(s, request, state);
498 }
499 
500 /*
501  * RFC1961: client request
502  *
503  *   +------+------+------+.......................+
504  *   + ver  | mtyp | len  |       token           |
505  *   +------+------+------+.......................+
506  *   + 0x01 | 0x02 | 0x02 | up to 2^16 - 1 octets |
507  *   +------+------+------+.......................+
508  *
509  */
510 static negotiate_result_t
recv_gssapi_enc_type(s,request,state)511 recv_gssapi_enc_type(s, request, state)
512    int s;
513    request_t *request;
514    negotiate_state_t *state;
515 {
516    const char *function = "recv_gssapi_enc_type()";
517    unsigned char gssapi_enc_type;
518 
519    INIT(sizeof(gssapi_enc_type));
520    CHECK(&gssapi_enc_type, request->auth, NULL);
521 
522    switch (gssapi_enc_type) {
523       case SOCKS_GSSAPI_INTEGRITY:
524       case SOCKS_GSSAPI_CONFIDENTIALITY:
525          break;
526 
527       case SOCKS_GSSAPI_PERMESSAGE:
528          snprintf(state->emsg, sizeof(state->emsg),
529           "%s: unsupported per message encryption on gssapi packet from client",
530           function);
531 
532          return NEGOTIATE_ERROR;
533 
534       default:
535          snprintf(state->emsg, sizeof(state->emsg),
536          "%s: unknown type on gssapi packet from client: %d",
537          function, gssapi_enc_type);
538 
539          return NEGOTIATE_ERROR;
540    }
541 
542    state->rcurrent = recv_gssapi_enc_len;
543    return state->rcurrent(s, request, state);
544 }
545 
546 static negotiate_result_t
recv_gssapi_enc_len(s,request,state)547 recv_gssapi_enc_len(s, request, state)
548    int s;
549    request_t *request;
550    negotiate_state_t *state;
551 {
552 
553    INIT(sizeof(state->gssapitoken_len));
554    CHECK(&state->gssapitoken_len, request->auth, NULL);
555 
556    state->gssapitoken_len
557    = ntohs((short)state->gssapitoken_len);
558 
559    state->rcurrent = recv_gssapi_enc_token;
560    return state->rcurrent(s, request, state);
561 }
562 
563 static negotiate_result_t
recv_gssapi_enc_token(s,request,state)564 recv_gssapi_enc_token(s, request, state)
565    int s;
566    request_t *request;
567    negotiate_state_t *state;
568 {
569    const char *function = "recv_gssapi_enc_token()";
570    OM_uint32  minor_status, major_status;
571    gss_buffer_desc input_token, output_token = GSS_C_EMPTY_BUFFER;
572    unsigned short  unsigned_short;
573    ssize_t rc;
574    size_t buflen;
575    unsigned char buf[GSSAPI_HLEN + MAXGSSAPITOKENLEN], gss_enc, gss_server_enc;
576    int conf_state, do_rfc1961;
577    char emsg[1024];
578 
579    INIT(state->gssapitoken_len);
580 
581    input_token.length = state->gssapitoken_len;
582    input_token.value  = buf;
583 
584    CHECK(input_token.value, request->auth, NULL);
585 
586    if (state->gssapitoken_len == 1 /* clear text encryption selection packet */
587    &&  request->auth->mdata.gssapi.encryption.nec)
588       do_rfc1961 = 0; /*
589                        * It seems the NEC reference implementation does not do
590                        * this right.  Try to support it if configured as such.
591                        */
592    else
593       do_rfc1961 = 1;
594 
595    slog(LOG_DEBUG, "%s: rule assumes client uses %s exchange",
596         function, do_rfc1961? "rfc1961 encrypted" : "NEC-style unencrypted");
597 
598    if (do_rfc1961) {
599       major_status = gss_unwrap(&minor_status,
600                                 request->auth->mdata.gssapi.state.id,
601                                 &input_token,
602                                 &output_token,
603                                 0,
604                                 GSS_C_QOP_DEFAULT);
605 
606       if (gss_err_isset(major_status, minor_status, emsg, sizeof(emsg))) {
607          snprintf(state->emsg, sizeof(state->emsg), "%s: gss_unwrap(): %s",
608                   function, emsg);
609 
610          CLEAN_GSS_TOKEN(output_token);
611          return NEGOTIATE_ERROR;
612       }
613 
614       if (output_token.length != 1) {
615          snprintf(state->emsg, sizeof(state->emsg),
616                   "%s: gssapi encryption unwrapped length is wrong: expected 1 "
617                   "but is %lu.  If the client is a NEC-based client you can "
618                   "try enabling NEC (NOTE: unencrypted exchange) "
619                   "client-compatibility for this client-rule",
620                   function, (unsigned long)output_token.length);
621 
622          CLEAN_GSS_TOKEN(output_token);
623          return NEGOTIATE_ERROR;
624       }
625 
626       SASSERTX(output_token.length == sizeof(gss_enc));
627       memcpy(&gss_enc, output_token.value, output_token.length);
628       CLEAN_GSS_TOKEN(output_token);
629    }
630    else {
631       SASSERTX(input_token.length == sizeof(gss_enc));
632       memcpy(&gss_enc, input_token.value, input_token.length);
633    }
634 
635    if ((gss_enc == SOCKS_GSSAPI_CLEAR
636     && !request->auth->mdata.gssapi.encryption.clear)
637    ||  (gss_enc == SOCKS_GSSAPI_INTEGRITY
638     && !request->auth->mdata.gssapi.encryption.integrity)
639    ||  (gss_enc == SOCKS_GSSAPI_CONFIDENTIALITY
640     && !request->auth->mdata.gssapi.encryption.confidentiality)
641    ||  (gss_enc == SOCKS_GSSAPI_PERMESSAGE) ) {
642       /*
643        * enforce server encryption type, regardless of what client offers.
644        */
645 
646       snprintf(state->emsg, sizeof(state->emsg),
647       "the client requests different authentication from what we offer.  "
648       "Client requests %s (0x%x), but we offer: clear/%d, integrity/%d, "
649       "confidentiality/%d, per message/%d",
650       gssapiprotection2string(gss_enc),
651       gss_enc,
652       request->auth->mdata.gssapi.encryption.clear,
653       request->auth->mdata.gssapi.encryption.integrity,
654       request->auth->mdata.gssapi.encryption.confidentiality,
655       request->auth->mdata.gssapi.encryption.permessage);
656 
657       return NEGOTIATE_ERROR;
658    }
659 
660    gss_server_enc = gss_enc;
661 
662    slog(LOG_DEBUG, "%s: using %s protection (%d)",
663         function, gssapiprotection2string(gss_server_enc), gss_server_enc);
664 
665    if (do_rfc1961) {
666       input_token.length = 1;
667       input_token.value  = &gss_server_enc;
668 
669       major_status = gss_wrap(&minor_status,
670                               request->auth->mdata.gssapi.state.id,
671                               GSS_REQ_INT,
672                               GSS_C_QOP_DEFAULT,
673                               &input_token,
674                               &conf_state,
675                               &output_token);
676 
677       if (gss_err_isset(major_status, minor_status, emsg, sizeof(emsg))) {
678          snprintf(state->emsg, sizeof(state->emsg), "%s: gss_wrap(): %s",
679                   function, emsg);
680 
681          CLEAN_GSS_TOKEN(output_token);
682          return NEGOTIATE_ERROR;
683       }
684    }
685    else {
686       output_token.length  = 1;
687       output_token.value   = &gss_server_enc;
688    }
689 
690    request->auth->mdata.gssapi.state.protection = gss_server_enc;
691 
692    /*
693     * RFC1961: server reply
694     *
695     *   +------+------+------+.......................+
696     *   + ver  | mtyp | len  |       token           |
697     *   +------+------+------+.......................+
698     *   + 0x01 | 0x02 | 0x02 | up to 2^16 - 1 octets |
699     *   +------+------+------+.......................+
700     *
701     */
702 
703    SASSERTX(GSSAPI_HLEN + output_token.length <= sizeof(buf));
704 
705    buflen = 0;
706    buf[buflen++] = SOCKS_GSSAPI_VERSION;
707    buf[buflen++] = SOCKS_GSSAPI_ENCRYPTION;
708 
709    unsigned_short = htons(output_token.length);
710    memcpy(&buf[buflen], &unsigned_short, sizeof(unsigned_short));
711    buflen += sizeof(unsigned_short);
712 
713    memcpy(&buf[buflen], output_token.value, output_token.length);
714    buflen += (output_token.length);
715 
716    if ((rc = socks_sendton(s, buf, buflen, 0, 0, NULL, 0, NULL, request->auth))
717    != (ssize_t)buflen) {
718       snprintf(state->emsg, sizeof(state->emsg),
719                "socks_sendton() buf: wrote %ld out of %lu bytes: %s",
720                 (long)rc,
721                 (unsigned long)buflen,
722                 strerror(errno));
723 
724       if (do_rfc1961)
725          CLEAN_GSS_TOKEN(output_token);
726 
727       return NEGOTIATE_ERROR;
728    }
729 
730    if (do_rfc1961)
731       CLEAN_GSS_TOKEN(output_token);
732 
733    if (gss_server_enc)
734       state->rcurrent = recv_gssapi_packet;
735    else
736       /*
737        * Continue with clear text communication.
738        * Not RFC compliant but useful if authentication only is required.
739        */
740       state->rcurrent = recv_sockspacket;
741 
742    return NEGOTIATE_CONTINUE; /* presumably client is awaiting our response. */
743 }
744 
745 /*
746  * RFC1961: client request
747  *
748  *   +------+------+------+.......................+
749  *   + ver  | mtyp | len  |       token           |
750  *   +------+------+------+.......................+
751  *   + 0x01 | 0x03 | 0x02 | up to 2^16 - 1 octets |
752  *   +------+------+------+.......................+
753  *
754  */
755 static negotiate_result_t
recv_gssapi_packet(s,request,state)756 recv_gssapi_packet(s, request, state)
757    int s;
758    request_t *request;
759    negotiate_state_t *state;
760 
761 {
762 
763    state->rcurrent = recv_gssapi_packet_ver;
764    return state->rcurrent(s, request, state);
765 }
766 
767 static negotiate_result_t
recv_gssapi_packet_ver(s,request,state)768 recv_gssapi_packet_ver(s, request, state)
769    int s;
770    request_t *request;
771    negotiate_state_t *state;
772 {
773    const char *function = "recv_gssapi_packet_ver()";
774    unsigned char gssapi_packet_version;
775 
776    INIT(sizeof(gssapi_packet_version));
777    CHECK(&gssapi_packet_version, request->auth, NULL);
778 
779    switch (gssapi_packet_version) {
780       case SOCKS_GSSAPI_VERSION:
781          break;
782 
783       default:
784          snprintf(state->emsg, sizeof(state->emsg),
785          "%s: unknown version on gssapi packet from client: %d",
786          function, gssapi_packet_version);
787 
788          return NEGOTIATE_ERROR;
789    }
790 
791    state->rcurrent = recv_gssapi_packet_type;
792    return state->rcurrent(s, request, state);
793 }
794 
795 static negotiate_result_t
recv_gssapi_packet_type(s,request,state)796 recv_gssapi_packet_type(s, request, state)
797    int s;
798    request_t *request;
799    negotiate_state_t *state;
800 {
801    const char *function = "recv_gssapi_packet_type()";
802    unsigned char gssapi_enc_type;
803 
804    INIT(sizeof(gssapi_enc_type));
805    CHECK(&gssapi_enc_type, request->auth, NULL);
806 
807    switch (gssapi_enc_type) {
808       case SOCKS_GSSAPI_PACKET:
809          break;
810 
811       case SOCKS_GSSAPI_ENCRYPTION:
812       case SOCKS_GSSAPI_AUTHENTICATION:
813          snprintf(state->emsg, sizeof(state->emsg),
814          "%s: received out of sequence exchange from client, type: %d",
815          function, gssapi_enc_type);
816 
817          return NEGOTIATE_ERROR;
818 
819       default:
820          snprintf(state->emsg, sizeof(state->emsg),
821          "%s: unknown type on gssapi packet from client: %d",
822          function, gssapi_enc_type);
823 
824          return NEGOTIATE_ERROR;
825    }
826 
827    state->rcurrent = recv_gssapi_packet_len;
828    return state->rcurrent(s, request, state);
829 }
830 
831 static negotiate_result_t
recv_gssapi_packet_len(s,request,state)832 recv_gssapi_packet_len(s, request, state)
833    int s;
834    request_t *request;
835    negotiate_state_t *state;
836 {
837 
838    INIT(sizeof(state->gssapitoken_len));
839    CHECK(&state->gssapitoken_len, request->auth, NULL);
840 
841    state->gssapitoken_len
842    = ntohs((short)state->gssapitoken_len);
843 
844    state->rcurrent = recv_gssapi_packet_token;
845    return state->rcurrent(s, request, state);
846 }
847 
848 static negotiate_result_t
recv_gssapi_packet_token(s,request,state)849 recv_gssapi_packet_token(s, request, state)
850    int s;
851    request_t *request;
852    negotiate_state_t *state;
853 {
854    const char *function = "recv_gssapi_packet_token()";
855    OM_uint32        minor_status, major_status      = GSS_S_COMPLETE;
856    gss_buffer_desc                input_token       = GSS_C_EMPTY_BUFFER;
857    gss_buffer_desc                output_token      = GSS_C_EMPTY_BUFFER;
858    unsigned char                  *data;
859    unsigned char                  buf[GSSAPI_HLEN + MAXGSSAPITOKENLEN];
860    char                           emsg[1024];
861    int                            conf_state, offset;
862 
863    INIT(state->gssapitoken_len);
864 
865    input_token.length = state->gssapitoken_len;
866    input_token.value  = buf;
867 
868    CHECK(input_token.value, request->auth, NULL);
869 
870    conf_state = (request->auth->mdata.gssapi.state.protection
871    == GSSAPI_CONFIDENTIALITY) ? GSS_REQ_CONF : GSS_REQ_INT;
872 
873    major_status
874    = gss_unwrap(&minor_status,
875                 request->auth->mdata.gssapi.state.id,
876                 &input_token, &output_token, &conf_state, GSS_C_QOP_DEFAULT);
877 
878    if (gss_err_isset(major_status, minor_status, emsg, sizeof(emsg))) {
879       snprintf(state->emsg, sizeof(state->emsg),
880       "%s: gss_unwrap(): %s", function, emsg);
881 
882       return NEGOTIATE_ERROR;
883    }
884 
885    offset = 0;
886    data   = output_token.value;
887 
888    if (offset + sizeof(request->version) > output_token.length) {
889       snprintf(state->emsg, sizeof(state->emsg),
890       "%s: token has short length: %lu",
891       function, (unsigned long)output_token.length);
892 
893       CLEAN_GSS_TOKEN(output_token);
894       return NEGOTIATE_ERROR;
895    }
896 
897    memcpy(&request->version, &data[offset], sizeof(request->version));
898    if (request->version != PROXY_SOCKS_V5) {
899       snprintf(state->emsg, sizeof(state->emsg),
900       "%s: invalid socks version %d in request", function, request->version);
901 
902       CLEAN_GSS_TOKEN(output_token);
903       return NEGOTIATE_ERROR;
904    }
905    offset += sizeof(request->version);
906 
907    if (offset + sizeof(request->command) > output_token.length) {
908       snprintf(state->emsg, sizeof(state->emsg),
909       "%s: token has short length: %lu",
910       function, (unsigned long)output_token.length);
911 
912       CLEAN_GSS_TOKEN(output_token);
913       return NEGOTIATE_ERROR;
914    }
915    memcpy(&request->command, &data[offset], sizeof(request->command));
916    offset += sizeof(request->command);
917 
918    switch (request->command) {
919       case SOCKS_BIND:
920       case SOCKS_CONNECT:
921          request->protocol = SOCKS_TCP;
922          break;
923 
924        case SOCKS_UDPASSOCIATE:
925          request->protocol = SOCKS_UDP;
926          break;
927 
928        default:
929          snprintf(state->emsg, sizeof(state->emsg),
930          "%s: unknown command received from client: %d",
931          function, request->command);
932 
933          CLEAN_GSS_TOKEN(output_token);
934          return NEGOTIATE_ERROR;
935    }
936 
937    if (offset + sizeof(request->flag) > output_token.length) {
938       CLEAN_GSS_TOKEN(output_token);
939       return NEGOTIATE_ERROR;
940    }
941    memcpy(&request->flag, &data[offset], sizeof(request->flag));
942    offset += sizeof(request->flag);
943 
944    if (mem2sockshost(&request->host, &data[offset],
945    output_token.length - offset, request->version) == NULL) {
946       CLEAN_GSS_TOKEN(output_token);
947       return NEGOTIATE_ERROR;
948    }
949 
950    CLEAN_GSS_TOKEN(output_token);
951 
952    /* Negotiation finished => set connection state as protected */
953    if (request->auth->mdata.gssapi.state.protection)
954       request->auth->mdata.gssapi.state.wrap = 1;
955 
956    return NEGOTIATE_FINISHED;
957 }
958 
959 #endif /* HAVE_GSSAPI */
960