1*6236dae4SAndroid Build Coastguard Worker /***************************************************************************
2*6236dae4SAndroid Build Coastguard Worker * _ _ ____ _
3*6236dae4SAndroid Build Coastguard Worker * Project ___| | | | _ \| |
4*6236dae4SAndroid Build Coastguard Worker * / __| | | | |_) | |
5*6236dae4SAndroid Build Coastguard Worker * | (__| |_| | _ <| |___
6*6236dae4SAndroid Build Coastguard Worker * \___|\___/|_| \_\_____|
7*6236dae4SAndroid Build Coastguard Worker *
8*6236dae4SAndroid Build Coastguard Worker * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9*6236dae4SAndroid Build Coastguard Worker * Copyright (C) Markus Moeller, <[email protected]>
10*6236dae4SAndroid Build Coastguard Worker *
11*6236dae4SAndroid Build Coastguard Worker * This software is licensed as described in the file COPYING, which
12*6236dae4SAndroid Build Coastguard Worker * you should have received as part of this distribution. The terms
13*6236dae4SAndroid Build Coastguard Worker * are also available at https://curl.se/docs/copyright.html.
14*6236dae4SAndroid Build Coastguard Worker *
15*6236dae4SAndroid Build Coastguard Worker * You may opt to use, copy, modify, merge, publish, distribute and/or sell
16*6236dae4SAndroid Build Coastguard Worker * copies of the Software, and permit persons to whom the Software is
17*6236dae4SAndroid Build Coastguard Worker * furnished to do so, under the terms of the COPYING file.
18*6236dae4SAndroid Build Coastguard Worker *
19*6236dae4SAndroid Build Coastguard Worker * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20*6236dae4SAndroid Build Coastguard Worker * KIND, either express or implied.
21*6236dae4SAndroid Build Coastguard Worker *
22*6236dae4SAndroid Build Coastguard Worker * SPDX-License-Identifier: curl
23*6236dae4SAndroid Build Coastguard Worker *
24*6236dae4SAndroid Build Coastguard Worker ***************************************************************************/
25*6236dae4SAndroid Build Coastguard Worker
26*6236dae4SAndroid Build Coastguard Worker #include "curl_setup.h"
27*6236dae4SAndroid Build Coastguard Worker
28*6236dae4SAndroid Build Coastguard Worker #if defined(HAVE_GSSAPI) && !defined(CURL_DISABLE_PROXY)
29*6236dae4SAndroid Build Coastguard Worker
30*6236dae4SAndroid Build Coastguard Worker #include "curl_gssapi.h"
31*6236dae4SAndroid Build Coastguard Worker #include "urldata.h"
32*6236dae4SAndroid Build Coastguard Worker #include "sendf.h"
33*6236dae4SAndroid Build Coastguard Worker #include "cfilters.h"
34*6236dae4SAndroid Build Coastguard Worker #include "connect.h"
35*6236dae4SAndroid Build Coastguard Worker #include "timeval.h"
36*6236dae4SAndroid Build Coastguard Worker #include "socks.h"
37*6236dae4SAndroid Build Coastguard Worker #include "warnless.h"
38*6236dae4SAndroid Build Coastguard Worker #include "strdup.h"
39*6236dae4SAndroid Build Coastguard Worker
40*6236dae4SAndroid Build Coastguard Worker /* The last 3 #include files should be in this order */
41*6236dae4SAndroid Build Coastguard Worker #include "curl_printf.h"
42*6236dae4SAndroid Build Coastguard Worker #include "curl_memory.h"
43*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h"
44*6236dae4SAndroid Build Coastguard Worker
45*6236dae4SAndroid Build Coastguard Worker #define MAX_GSS_LEN 1024
46*6236dae4SAndroid Build Coastguard Worker
47*6236dae4SAndroid Build Coastguard Worker static gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT;
48*6236dae4SAndroid Build Coastguard Worker
49*6236dae4SAndroid Build Coastguard Worker /*
50*6236dae4SAndroid Build Coastguard Worker * Helper GSS-API error functions.
51*6236dae4SAndroid Build Coastguard Worker */
check_gss_err(struct Curl_easy * data,OM_uint32 major_status,OM_uint32 minor_status,const char * function)52*6236dae4SAndroid Build Coastguard Worker static int check_gss_err(struct Curl_easy *data,
53*6236dae4SAndroid Build Coastguard Worker OM_uint32 major_status,
54*6236dae4SAndroid Build Coastguard Worker OM_uint32 minor_status,
55*6236dae4SAndroid Build Coastguard Worker const char *function)
56*6236dae4SAndroid Build Coastguard Worker {
57*6236dae4SAndroid Build Coastguard Worker if(GSS_ERROR(major_status)) {
58*6236dae4SAndroid Build Coastguard Worker OM_uint32 maj_stat, min_stat;
59*6236dae4SAndroid Build Coastguard Worker OM_uint32 msg_ctx = 0;
60*6236dae4SAndroid Build Coastguard Worker gss_buffer_desc status_string = GSS_C_EMPTY_BUFFER;
61*6236dae4SAndroid Build Coastguard Worker struct dynbuf dbuf;
62*6236dae4SAndroid Build Coastguard Worker
63*6236dae4SAndroid Build Coastguard Worker Curl_dyn_init(&dbuf, MAX_GSS_LEN);
64*6236dae4SAndroid Build Coastguard Worker msg_ctx = 0;
65*6236dae4SAndroid Build Coastguard Worker while(!msg_ctx) {
66*6236dae4SAndroid Build Coastguard Worker /* convert major status code (GSS-API error) to text */
67*6236dae4SAndroid Build Coastguard Worker maj_stat = gss_display_status(&min_stat, major_status,
68*6236dae4SAndroid Build Coastguard Worker GSS_C_GSS_CODE,
69*6236dae4SAndroid Build Coastguard Worker GSS_C_NULL_OID,
70*6236dae4SAndroid Build Coastguard Worker &msg_ctx, &status_string);
71*6236dae4SAndroid Build Coastguard Worker if(maj_stat == GSS_S_COMPLETE) {
72*6236dae4SAndroid Build Coastguard Worker if(Curl_dyn_addn(&dbuf, status_string.value,
73*6236dae4SAndroid Build Coastguard Worker status_string.length))
74*6236dae4SAndroid Build Coastguard Worker return 1; /* error */
75*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&min_stat, &status_string);
76*6236dae4SAndroid Build Coastguard Worker break;
77*6236dae4SAndroid Build Coastguard Worker }
78*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&min_stat, &status_string);
79*6236dae4SAndroid Build Coastguard Worker }
80*6236dae4SAndroid Build Coastguard Worker if(Curl_dyn_addn(&dbuf, ".\n", 2))
81*6236dae4SAndroid Build Coastguard Worker return 1; /* error */
82*6236dae4SAndroid Build Coastguard Worker msg_ctx = 0;
83*6236dae4SAndroid Build Coastguard Worker while(!msg_ctx) {
84*6236dae4SAndroid Build Coastguard Worker /* convert minor status code (underlying routine error) to text */
85*6236dae4SAndroid Build Coastguard Worker maj_stat = gss_display_status(&min_stat, minor_status,
86*6236dae4SAndroid Build Coastguard Worker GSS_C_MECH_CODE,
87*6236dae4SAndroid Build Coastguard Worker GSS_C_NULL_OID,
88*6236dae4SAndroid Build Coastguard Worker &msg_ctx, &status_string);
89*6236dae4SAndroid Build Coastguard Worker if(maj_stat == GSS_S_COMPLETE) {
90*6236dae4SAndroid Build Coastguard Worker if(Curl_dyn_addn(&dbuf, status_string.value,
91*6236dae4SAndroid Build Coastguard Worker status_string.length))
92*6236dae4SAndroid Build Coastguard Worker return 1; /* error */
93*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&min_stat, &status_string);
94*6236dae4SAndroid Build Coastguard Worker break;
95*6236dae4SAndroid Build Coastguard Worker }
96*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&min_stat, &status_string);
97*6236dae4SAndroid Build Coastguard Worker }
98*6236dae4SAndroid Build Coastguard Worker failf(data, "GSS-API error: %s failed: %s", function, Curl_dyn_ptr(&dbuf));
99*6236dae4SAndroid Build Coastguard Worker Curl_dyn_free(&dbuf);
100*6236dae4SAndroid Build Coastguard Worker return 1;
101*6236dae4SAndroid Build Coastguard Worker }
102*6236dae4SAndroid Build Coastguard Worker
103*6236dae4SAndroid Build Coastguard Worker return 0;
104*6236dae4SAndroid Build Coastguard Worker }
105*6236dae4SAndroid Build Coastguard Worker
Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter * cf,struct Curl_easy * data)106*6236dae4SAndroid Build Coastguard Worker CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
107*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data)
108*6236dae4SAndroid Build Coastguard Worker {
109*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn = cf->conn;
110*6236dae4SAndroid Build Coastguard Worker curl_socket_t sock = conn->sock[cf->sockindex];
111*6236dae4SAndroid Build Coastguard Worker CURLcode code;
112*6236dae4SAndroid Build Coastguard Worker ssize_t actualread;
113*6236dae4SAndroid Build Coastguard Worker ssize_t nwritten;
114*6236dae4SAndroid Build Coastguard Worker int result;
115*6236dae4SAndroid Build Coastguard Worker OM_uint32 gss_major_status, gss_minor_status, gss_status;
116*6236dae4SAndroid Build Coastguard Worker OM_uint32 gss_ret_flags;
117*6236dae4SAndroid Build Coastguard Worker int gss_conf_state, gss_enc;
118*6236dae4SAndroid Build Coastguard Worker gss_buffer_desc service = GSS_C_EMPTY_BUFFER;
119*6236dae4SAndroid Build Coastguard Worker gss_buffer_desc gss_send_token = GSS_C_EMPTY_BUFFER;
120*6236dae4SAndroid Build Coastguard Worker gss_buffer_desc gss_recv_token = GSS_C_EMPTY_BUFFER;
121*6236dae4SAndroid Build Coastguard Worker gss_buffer_desc gss_w_token = GSS_C_EMPTY_BUFFER;
122*6236dae4SAndroid Build Coastguard Worker gss_buffer_desc *gss_token = GSS_C_NO_BUFFER;
123*6236dae4SAndroid Build Coastguard Worker gss_name_t server = GSS_C_NO_NAME;
124*6236dae4SAndroid Build Coastguard Worker gss_name_t gss_client_name = GSS_C_NO_NAME;
125*6236dae4SAndroid Build Coastguard Worker unsigned short us_length;
126*6236dae4SAndroid Build Coastguard Worker char *user = NULL;
127*6236dae4SAndroid Build Coastguard Worker unsigned char socksreq[4]; /* room for GSS-API exchange header only */
128*6236dae4SAndroid Build Coastguard Worker const char *serviceptr = data->set.str[STRING_PROXY_SERVICE_NAME] ?
129*6236dae4SAndroid Build Coastguard Worker data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd";
130*6236dae4SAndroid Build Coastguard Worker const size_t serviceptr_length = strlen(serviceptr);
131*6236dae4SAndroid Build Coastguard Worker
132*6236dae4SAndroid Build Coastguard Worker /* GSS-API request looks like
133*6236dae4SAndroid Build Coastguard Worker * +----+------+-----+----------------+
134*6236dae4SAndroid Build Coastguard Worker * |VER | MTYP | LEN | TOKEN |
135*6236dae4SAndroid Build Coastguard Worker * +----+------+----------------------+
136*6236dae4SAndroid Build Coastguard Worker * | 1 | 1 | 2 | up to 2^16 - 1 |
137*6236dae4SAndroid Build Coastguard Worker * +----+------+-----+----------------+
138*6236dae4SAndroid Build Coastguard Worker */
139*6236dae4SAndroid Build Coastguard Worker
140*6236dae4SAndroid Build Coastguard Worker /* prepare service name */
141*6236dae4SAndroid Build Coastguard Worker if(strchr(serviceptr, '/')) {
142*6236dae4SAndroid Build Coastguard Worker service.length = serviceptr_length;
143*6236dae4SAndroid Build Coastguard Worker service.value = Curl_memdup(serviceptr, service.length);
144*6236dae4SAndroid Build Coastguard Worker if(!service.value)
145*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
146*6236dae4SAndroid Build Coastguard Worker
147*6236dae4SAndroid Build Coastguard Worker gss_major_status = gss_import_name(&gss_minor_status, &service,
148*6236dae4SAndroid Build Coastguard Worker (gss_OID) GSS_C_NULL_OID, &server);
149*6236dae4SAndroid Build Coastguard Worker }
150*6236dae4SAndroid Build Coastguard Worker else {
151*6236dae4SAndroid Build Coastguard Worker service.value = malloc(serviceptr_length +
152*6236dae4SAndroid Build Coastguard Worker strlen(conn->socks_proxy.host.name) + 2);
153*6236dae4SAndroid Build Coastguard Worker if(!service.value)
154*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
155*6236dae4SAndroid Build Coastguard Worker service.length = serviceptr_length +
156*6236dae4SAndroid Build Coastguard Worker strlen(conn->socks_proxy.host.name) + 1;
157*6236dae4SAndroid Build Coastguard Worker msnprintf(service.value, service.length + 1, "%s@%s",
158*6236dae4SAndroid Build Coastguard Worker serviceptr, conn->socks_proxy.host.name);
159*6236dae4SAndroid Build Coastguard Worker
160*6236dae4SAndroid Build Coastguard Worker gss_major_status = gss_import_name(&gss_minor_status, &service,
161*6236dae4SAndroid Build Coastguard Worker GSS_C_NT_HOSTBASED_SERVICE, &server);
162*6236dae4SAndroid Build Coastguard Worker }
163*6236dae4SAndroid Build Coastguard Worker
164*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&gss_status, &service); /* clear allocated memory */
165*6236dae4SAndroid Build Coastguard Worker
166*6236dae4SAndroid Build Coastguard Worker if(check_gss_err(data, gss_major_status,
167*6236dae4SAndroid Build Coastguard Worker gss_minor_status, "gss_import_name()")) {
168*6236dae4SAndroid Build Coastguard Worker failf(data, "Failed to create service name.");
169*6236dae4SAndroid Build Coastguard Worker gss_release_name(&gss_status, &server);
170*6236dae4SAndroid Build Coastguard Worker return CURLE_COULDNT_CONNECT;
171*6236dae4SAndroid Build Coastguard Worker }
172*6236dae4SAndroid Build Coastguard Worker
173*6236dae4SAndroid Build Coastguard Worker (void)curlx_nonblock(sock, FALSE);
174*6236dae4SAndroid Build Coastguard Worker
175*6236dae4SAndroid Build Coastguard Worker /* As long as we need to keep sending some context info, and there is no */
176*6236dae4SAndroid Build Coastguard Worker /* errors, keep sending it... */
177*6236dae4SAndroid Build Coastguard Worker for(;;) {
178*6236dae4SAndroid Build Coastguard Worker gss_major_status = Curl_gss_init_sec_context(data,
179*6236dae4SAndroid Build Coastguard Worker &gss_minor_status,
180*6236dae4SAndroid Build Coastguard Worker &gss_context,
181*6236dae4SAndroid Build Coastguard Worker server,
182*6236dae4SAndroid Build Coastguard Worker &Curl_krb5_mech_oid,
183*6236dae4SAndroid Build Coastguard Worker NULL,
184*6236dae4SAndroid Build Coastguard Worker gss_token,
185*6236dae4SAndroid Build Coastguard Worker &gss_send_token,
186*6236dae4SAndroid Build Coastguard Worker TRUE,
187*6236dae4SAndroid Build Coastguard Worker &gss_ret_flags);
188*6236dae4SAndroid Build Coastguard Worker
189*6236dae4SAndroid Build Coastguard Worker if(gss_token != GSS_C_NO_BUFFER)
190*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&gss_status, &gss_recv_token);
191*6236dae4SAndroid Build Coastguard Worker if(check_gss_err(data, gss_major_status,
192*6236dae4SAndroid Build Coastguard Worker gss_minor_status, "gss_init_sec_context")) {
193*6236dae4SAndroid Build Coastguard Worker gss_release_name(&gss_status, &server);
194*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&gss_status, &gss_recv_token);
195*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&gss_status, &gss_send_token);
196*6236dae4SAndroid Build Coastguard Worker gss_delete_sec_context(&gss_status, &gss_context, NULL);
197*6236dae4SAndroid Build Coastguard Worker failf(data, "Failed to initial GSS-API token.");
198*6236dae4SAndroid Build Coastguard Worker return CURLE_COULDNT_CONNECT;
199*6236dae4SAndroid Build Coastguard Worker }
200*6236dae4SAndroid Build Coastguard Worker
201*6236dae4SAndroid Build Coastguard Worker if(gss_send_token.length) {
202*6236dae4SAndroid Build Coastguard Worker socksreq[0] = 1; /* GSS-API subnegotiation version */
203*6236dae4SAndroid Build Coastguard Worker socksreq[1] = 1; /* authentication message type */
204*6236dae4SAndroid Build Coastguard Worker us_length = htons((unsigned short)gss_send_token.length);
205*6236dae4SAndroid Build Coastguard Worker memcpy(socksreq + 2, &us_length, sizeof(short));
206*6236dae4SAndroid Build Coastguard Worker
207*6236dae4SAndroid Build Coastguard Worker nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4,
208*6236dae4SAndroid Build Coastguard Worker FALSE, &code);
209*6236dae4SAndroid Build Coastguard Worker if(code || (4 != nwritten)) {
210*6236dae4SAndroid Build Coastguard Worker failf(data, "Failed to send GSS-API authentication request.");
211*6236dae4SAndroid Build Coastguard Worker gss_release_name(&gss_status, &server);
212*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&gss_status, &gss_recv_token);
213*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&gss_status, &gss_send_token);
214*6236dae4SAndroid Build Coastguard Worker gss_delete_sec_context(&gss_status, &gss_context, NULL);
215*6236dae4SAndroid Build Coastguard Worker return CURLE_COULDNT_CONNECT;
216*6236dae4SAndroid Build Coastguard Worker }
217*6236dae4SAndroid Build Coastguard Worker
218*6236dae4SAndroid Build Coastguard Worker nwritten = Curl_conn_cf_send(cf->next, data,
219*6236dae4SAndroid Build Coastguard Worker (char *)gss_send_token.value,
220*6236dae4SAndroid Build Coastguard Worker gss_send_token.length, FALSE, &code);
221*6236dae4SAndroid Build Coastguard Worker if(code || ((ssize_t)gss_send_token.length != nwritten)) {
222*6236dae4SAndroid Build Coastguard Worker failf(data, "Failed to send GSS-API authentication token.");
223*6236dae4SAndroid Build Coastguard Worker gss_release_name(&gss_status, &server);
224*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&gss_status, &gss_recv_token);
225*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&gss_status, &gss_send_token);
226*6236dae4SAndroid Build Coastguard Worker gss_delete_sec_context(&gss_status, &gss_context, NULL);
227*6236dae4SAndroid Build Coastguard Worker return CURLE_COULDNT_CONNECT;
228*6236dae4SAndroid Build Coastguard Worker }
229*6236dae4SAndroid Build Coastguard Worker
230*6236dae4SAndroid Build Coastguard Worker }
231*6236dae4SAndroid Build Coastguard Worker
232*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&gss_status, &gss_send_token);
233*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&gss_status, &gss_recv_token);
234*6236dae4SAndroid Build Coastguard Worker if(gss_major_status != GSS_S_CONTINUE_NEEDED)
235*6236dae4SAndroid Build Coastguard Worker break;
236*6236dae4SAndroid Build Coastguard Worker
237*6236dae4SAndroid Build Coastguard Worker /* analyse response */
238*6236dae4SAndroid Build Coastguard Worker
239*6236dae4SAndroid Build Coastguard Worker /* GSS-API response looks like
240*6236dae4SAndroid Build Coastguard Worker * +----+------+-----+----------------+
241*6236dae4SAndroid Build Coastguard Worker * |VER | MTYP | LEN | TOKEN |
242*6236dae4SAndroid Build Coastguard Worker * +----+------+----------------------+
243*6236dae4SAndroid Build Coastguard Worker * | 1 | 1 | 2 | up to 2^16 - 1 |
244*6236dae4SAndroid Build Coastguard Worker * +----+------+-----+----------------+
245*6236dae4SAndroid Build Coastguard Worker */
246*6236dae4SAndroid Build Coastguard Worker
247*6236dae4SAndroid Build Coastguard Worker result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread);
248*6236dae4SAndroid Build Coastguard Worker if(result || (actualread != 4)) {
249*6236dae4SAndroid Build Coastguard Worker failf(data, "Failed to receive GSS-API authentication response.");
250*6236dae4SAndroid Build Coastguard Worker gss_release_name(&gss_status, &server);
251*6236dae4SAndroid Build Coastguard Worker gss_delete_sec_context(&gss_status, &gss_context, NULL);
252*6236dae4SAndroid Build Coastguard Worker return CURLE_COULDNT_CONNECT;
253*6236dae4SAndroid Build Coastguard Worker }
254*6236dae4SAndroid Build Coastguard Worker
255*6236dae4SAndroid Build Coastguard Worker /* ignore the first (VER) byte */
256*6236dae4SAndroid Build Coastguard Worker if(socksreq[1] == 255) { /* status / message type */
257*6236dae4SAndroid Build Coastguard Worker failf(data, "User was rejected by the SOCKS5 server (%d %d).",
258*6236dae4SAndroid Build Coastguard Worker socksreq[0], socksreq[1]);
259*6236dae4SAndroid Build Coastguard Worker gss_release_name(&gss_status, &server);
260*6236dae4SAndroid Build Coastguard Worker gss_delete_sec_context(&gss_status, &gss_context, NULL);
261*6236dae4SAndroid Build Coastguard Worker return CURLE_COULDNT_CONNECT;
262*6236dae4SAndroid Build Coastguard Worker }
263*6236dae4SAndroid Build Coastguard Worker
264*6236dae4SAndroid Build Coastguard Worker if(socksreq[1] != 1) { /* status / message type */
265*6236dae4SAndroid Build Coastguard Worker failf(data, "Invalid GSS-API authentication response type (%d %d).",
266*6236dae4SAndroid Build Coastguard Worker socksreq[0], socksreq[1]);
267*6236dae4SAndroid Build Coastguard Worker gss_release_name(&gss_status, &server);
268*6236dae4SAndroid Build Coastguard Worker gss_delete_sec_context(&gss_status, &gss_context, NULL);
269*6236dae4SAndroid Build Coastguard Worker return CURLE_COULDNT_CONNECT;
270*6236dae4SAndroid Build Coastguard Worker }
271*6236dae4SAndroid Build Coastguard Worker
272*6236dae4SAndroid Build Coastguard Worker memcpy(&us_length, socksreq + 2, sizeof(short));
273*6236dae4SAndroid Build Coastguard Worker us_length = ntohs(us_length);
274*6236dae4SAndroid Build Coastguard Worker
275*6236dae4SAndroid Build Coastguard Worker gss_recv_token.length = us_length;
276*6236dae4SAndroid Build Coastguard Worker gss_recv_token.value = malloc(us_length);
277*6236dae4SAndroid Build Coastguard Worker if(!gss_recv_token.value) {
278*6236dae4SAndroid Build Coastguard Worker failf(data,
279*6236dae4SAndroid Build Coastguard Worker "Could not allocate memory for GSS-API authentication "
280*6236dae4SAndroid Build Coastguard Worker "response token.");
281*6236dae4SAndroid Build Coastguard Worker gss_release_name(&gss_status, &server);
282*6236dae4SAndroid Build Coastguard Worker gss_delete_sec_context(&gss_status, &gss_context, NULL);
283*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
284*6236dae4SAndroid Build Coastguard Worker }
285*6236dae4SAndroid Build Coastguard Worker
286*6236dae4SAndroid Build Coastguard Worker result = Curl_blockread_all(cf, data, (char *)gss_recv_token.value,
287*6236dae4SAndroid Build Coastguard Worker gss_recv_token.length, &actualread);
288*6236dae4SAndroid Build Coastguard Worker
289*6236dae4SAndroid Build Coastguard Worker if(result || (actualread != us_length)) {
290*6236dae4SAndroid Build Coastguard Worker failf(data, "Failed to receive GSS-API authentication token.");
291*6236dae4SAndroid Build Coastguard Worker gss_release_name(&gss_status, &server);
292*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&gss_status, &gss_recv_token);
293*6236dae4SAndroid Build Coastguard Worker gss_delete_sec_context(&gss_status, &gss_context, NULL);
294*6236dae4SAndroid Build Coastguard Worker return CURLE_COULDNT_CONNECT;
295*6236dae4SAndroid Build Coastguard Worker }
296*6236dae4SAndroid Build Coastguard Worker
297*6236dae4SAndroid Build Coastguard Worker gss_token = &gss_recv_token;
298*6236dae4SAndroid Build Coastguard Worker }
299*6236dae4SAndroid Build Coastguard Worker
300*6236dae4SAndroid Build Coastguard Worker gss_release_name(&gss_status, &server);
301*6236dae4SAndroid Build Coastguard Worker
302*6236dae4SAndroid Build Coastguard Worker /* Everything is good so far, user was authenticated! */
303*6236dae4SAndroid Build Coastguard Worker gss_major_status = gss_inquire_context(&gss_minor_status, gss_context,
304*6236dae4SAndroid Build Coastguard Worker &gss_client_name, NULL, NULL, NULL,
305*6236dae4SAndroid Build Coastguard Worker NULL, NULL, NULL);
306*6236dae4SAndroid Build Coastguard Worker if(check_gss_err(data, gss_major_status,
307*6236dae4SAndroid Build Coastguard Worker gss_minor_status, "gss_inquire_context")) {
308*6236dae4SAndroid Build Coastguard Worker gss_delete_sec_context(&gss_status, &gss_context, NULL);
309*6236dae4SAndroid Build Coastguard Worker gss_release_name(&gss_status, &gss_client_name);
310*6236dae4SAndroid Build Coastguard Worker failf(data, "Failed to determine username.");
311*6236dae4SAndroid Build Coastguard Worker return CURLE_COULDNT_CONNECT;
312*6236dae4SAndroid Build Coastguard Worker }
313*6236dae4SAndroid Build Coastguard Worker gss_major_status = gss_display_name(&gss_minor_status, gss_client_name,
314*6236dae4SAndroid Build Coastguard Worker &gss_send_token, NULL);
315*6236dae4SAndroid Build Coastguard Worker if(check_gss_err(data, gss_major_status,
316*6236dae4SAndroid Build Coastguard Worker gss_minor_status, "gss_display_name")) {
317*6236dae4SAndroid Build Coastguard Worker gss_delete_sec_context(&gss_status, &gss_context, NULL);
318*6236dae4SAndroid Build Coastguard Worker gss_release_name(&gss_status, &gss_client_name);
319*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&gss_status, &gss_send_token);
320*6236dae4SAndroid Build Coastguard Worker failf(data, "Failed to determine username.");
321*6236dae4SAndroid Build Coastguard Worker return CURLE_COULDNT_CONNECT;
322*6236dae4SAndroid Build Coastguard Worker }
323*6236dae4SAndroid Build Coastguard Worker user = malloc(gss_send_token.length + 1);
324*6236dae4SAndroid Build Coastguard Worker if(!user) {
325*6236dae4SAndroid Build Coastguard Worker gss_delete_sec_context(&gss_status, &gss_context, NULL);
326*6236dae4SAndroid Build Coastguard Worker gss_release_name(&gss_status, &gss_client_name);
327*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&gss_status, &gss_send_token);
328*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
329*6236dae4SAndroid Build Coastguard Worker }
330*6236dae4SAndroid Build Coastguard Worker
331*6236dae4SAndroid Build Coastguard Worker memcpy(user, gss_send_token.value, gss_send_token.length);
332*6236dae4SAndroid Build Coastguard Worker user[gss_send_token.length] = '\0';
333*6236dae4SAndroid Build Coastguard Worker gss_release_name(&gss_status, &gss_client_name);
334*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&gss_status, &gss_send_token);
335*6236dae4SAndroid Build Coastguard Worker infof(data, "SOCKS5 server authenticated user %s with GSS-API.",user);
336*6236dae4SAndroid Build Coastguard Worker free(user);
337*6236dae4SAndroid Build Coastguard Worker user = NULL;
338*6236dae4SAndroid Build Coastguard Worker
339*6236dae4SAndroid Build Coastguard Worker /* Do encryption */
340*6236dae4SAndroid Build Coastguard Worker socksreq[0] = 1; /* GSS-API subnegotiation version */
341*6236dae4SAndroid Build Coastguard Worker socksreq[1] = 2; /* encryption message type */
342*6236dae4SAndroid Build Coastguard Worker
343*6236dae4SAndroid Build Coastguard Worker gss_enc = 0; /* no data protection */
344*6236dae4SAndroid Build Coastguard Worker /* do confidentiality protection if supported */
345*6236dae4SAndroid Build Coastguard Worker if(gss_ret_flags & GSS_C_CONF_FLAG)
346*6236dae4SAndroid Build Coastguard Worker gss_enc = 2;
347*6236dae4SAndroid Build Coastguard Worker /* else do integrity protection */
348*6236dae4SAndroid Build Coastguard Worker else if(gss_ret_flags & GSS_C_INTEG_FLAG)
349*6236dae4SAndroid Build Coastguard Worker gss_enc = 1;
350*6236dae4SAndroid Build Coastguard Worker
351*6236dae4SAndroid Build Coastguard Worker infof(data, "SOCKS5 server supports GSS-API %s data protection.",
352*6236dae4SAndroid Build Coastguard Worker (gss_enc == 0) ? "no" :
353*6236dae4SAndroid Build Coastguard Worker ((gss_enc == 1) ? "integrity" : "confidentiality"));
354*6236dae4SAndroid Build Coastguard Worker /* force for the moment to no data protection */
355*6236dae4SAndroid Build Coastguard Worker gss_enc = 0;
356*6236dae4SAndroid Build Coastguard Worker /*
357*6236dae4SAndroid Build Coastguard Worker * Sending the encryption type in clear seems wrong. It should be
358*6236dae4SAndroid Build Coastguard Worker * protected with gss_seal()/gss_wrap(). See RFC1961 extract below
359*6236dae4SAndroid Build Coastguard Worker * The NEC reference implementations on which this is based is
360*6236dae4SAndroid Build Coastguard Worker * therefore at fault
361*6236dae4SAndroid Build Coastguard Worker *
362*6236dae4SAndroid Build Coastguard Worker * +------+------+------+.......................+
363*6236dae4SAndroid Build Coastguard Worker * + ver | mtyp | len | token |
364*6236dae4SAndroid Build Coastguard Worker * +------+------+------+.......................+
365*6236dae4SAndroid Build Coastguard Worker * + 0x01 | 0x02 | 0x02 | up to 2^16 - 1 octets |
366*6236dae4SAndroid Build Coastguard Worker * +------+------+------+.......................+
367*6236dae4SAndroid Build Coastguard Worker *
368*6236dae4SAndroid Build Coastguard Worker * Where:
369*6236dae4SAndroid Build Coastguard Worker *
370*6236dae4SAndroid Build Coastguard Worker * - "ver" is the protocol version number, here 1 to represent the
371*6236dae4SAndroid Build Coastguard Worker * first version of the SOCKS/GSS-API protocol
372*6236dae4SAndroid Build Coastguard Worker *
373*6236dae4SAndroid Build Coastguard Worker * - "mtyp" is the message type, here 2 to represent a protection
374*6236dae4SAndroid Build Coastguard Worker * -level negotiation message
375*6236dae4SAndroid Build Coastguard Worker *
376*6236dae4SAndroid Build Coastguard Worker * - "len" is the length of the "token" field in octets
377*6236dae4SAndroid Build Coastguard Worker *
378*6236dae4SAndroid Build Coastguard Worker * - "token" is the GSS-API encapsulated protection level
379*6236dae4SAndroid Build Coastguard Worker *
380*6236dae4SAndroid Build Coastguard Worker * The token is produced by encapsulating an octet containing the
381*6236dae4SAndroid Build Coastguard Worker * required protection level using gss_seal()/gss_wrap() with conf_req
382*6236dae4SAndroid Build Coastguard Worker * set to FALSE. The token is verified using gss_unseal()/
383*6236dae4SAndroid Build Coastguard Worker * gss_unwrap().
384*6236dae4SAndroid Build Coastguard Worker *
385*6236dae4SAndroid Build Coastguard Worker */
386*6236dae4SAndroid Build Coastguard Worker if(data->set.socks5_gssapi_nec) {
387*6236dae4SAndroid Build Coastguard Worker us_length = htons((short)1);
388*6236dae4SAndroid Build Coastguard Worker memcpy(socksreq + 2, &us_length, sizeof(short));
389*6236dae4SAndroid Build Coastguard Worker }
390*6236dae4SAndroid Build Coastguard Worker else {
391*6236dae4SAndroid Build Coastguard Worker gss_send_token.length = 1;
392*6236dae4SAndroid Build Coastguard Worker gss_send_token.value = Curl_memdup(&gss_enc, 1);
393*6236dae4SAndroid Build Coastguard Worker if(!gss_send_token.value) {
394*6236dae4SAndroid Build Coastguard Worker gss_delete_sec_context(&gss_status, &gss_context, NULL);
395*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
396*6236dae4SAndroid Build Coastguard Worker }
397*6236dae4SAndroid Build Coastguard Worker
398*6236dae4SAndroid Build Coastguard Worker gss_major_status = gss_wrap(&gss_minor_status, gss_context, 0,
399*6236dae4SAndroid Build Coastguard Worker GSS_C_QOP_DEFAULT, &gss_send_token,
400*6236dae4SAndroid Build Coastguard Worker &gss_conf_state, &gss_w_token);
401*6236dae4SAndroid Build Coastguard Worker
402*6236dae4SAndroid Build Coastguard Worker if(check_gss_err(data, gss_major_status, gss_minor_status, "gss_wrap")) {
403*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&gss_status, &gss_send_token);
404*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&gss_status, &gss_w_token);
405*6236dae4SAndroid Build Coastguard Worker gss_delete_sec_context(&gss_status, &gss_context, NULL);
406*6236dae4SAndroid Build Coastguard Worker failf(data, "Failed to wrap GSS-API encryption value into token.");
407*6236dae4SAndroid Build Coastguard Worker return CURLE_COULDNT_CONNECT;
408*6236dae4SAndroid Build Coastguard Worker }
409*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&gss_status, &gss_send_token);
410*6236dae4SAndroid Build Coastguard Worker
411*6236dae4SAndroid Build Coastguard Worker us_length = htons((unsigned short)gss_w_token.length);
412*6236dae4SAndroid Build Coastguard Worker memcpy(socksreq + 2, &us_length, sizeof(short));
413*6236dae4SAndroid Build Coastguard Worker }
414*6236dae4SAndroid Build Coastguard Worker
415*6236dae4SAndroid Build Coastguard Worker nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, FALSE,
416*6236dae4SAndroid Build Coastguard Worker &code);
417*6236dae4SAndroid Build Coastguard Worker if(code || (4 != nwritten)) {
418*6236dae4SAndroid Build Coastguard Worker failf(data, "Failed to send GSS-API encryption request.");
419*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&gss_status, &gss_w_token);
420*6236dae4SAndroid Build Coastguard Worker gss_delete_sec_context(&gss_status, &gss_context, NULL);
421*6236dae4SAndroid Build Coastguard Worker return CURLE_COULDNT_CONNECT;
422*6236dae4SAndroid Build Coastguard Worker }
423*6236dae4SAndroid Build Coastguard Worker
424*6236dae4SAndroid Build Coastguard Worker if(data->set.socks5_gssapi_nec) {
425*6236dae4SAndroid Build Coastguard Worker memcpy(socksreq, &gss_enc, 1);
426*6236dae4SAndroid Build Coastguard Worker nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 1, FALSE,
427*6236dae4SAndroid Build Coastguard Worker &code);
428*6236dae4SAndroid Build Coastguard Worker if(code || ( 1 != nwritten)) {
429*6236dae4SAndroid Build Coastguard Worker failf(data, "Failed to send GSS-API encryption type.");
430*6236dae4SAndroid Build Coastguard Worker gss_delete_sec_context(&gss_status, &gss_context, NULL);
431*6236dae4SAndroid Build Coastguard Worker return CURLE_COULDNT_CONNECT;
432*6236dae4SAndroid Build Coastguard Worker }
433*6236dae4SAndroid Build Coastguard Worker }
434*6236dae4SAndroid Build Coastguard Worker else {
435*6236dae4SAndroid Build Coastguard Worker nwritten = Curl_conn_cf_send(cf->next, data,
436*6236dae4SAndroid Build Coastguard Worker (char *)gss_w_token.value,
437*6236dae4SAndroid Build Coastguard Worker gss_w_token.length, FALSE, &code);
438*6236dae4SAndroid Build Coastguard Worker if(code || ((ssize_t)gss_w_token.length != nwritten)) {
439*6236dae4SAndroid Build Coastguard Worker failf(data, "Failed to send GSS-API encryption type.");
440*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&gss_status, &gss_w_token);
441*6236dae4SAndroid Build Coastguard Worker gss_delete_sec_context(&gss_status, &gss_context, NULL);
442*6236dae4SAndroid Build Coastguard Worker return CURLE_COULDNT_CONNECT;
443*6236dae4SAndroid Build Coastguard Worker }
444*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&gss_status, &gss_w_token);
445*6236dae4SAndroid Build Coastguard Worker }
446*6236dae4SAndroid Build Coastguard Worker
447*6236dae4SAndroid Build Coastguard Worker result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread);
448*6236dae4SAndroid Build Coastguard Worker if(result || (actualread != 4)) {
449*6236dae4SAndroid Build Coastguard Worker failf(data, "Failed to receive GSS-API encryption response.");
450*6236dae4SAndroid Build Coastguard Worker gss_delete_sec_context(&gss_status, &gss_context, NULL);
451*6236dae4SAndroid Build Coastguard Worker return CURLE_COULDNT_CONNECT;
452*6236dae4SAndroid Build Coastguard Worker }
453*6236dae4SAndroid Build Coastguard Worker
454*6236dae4SAndroid Build Coastguard Worker /* ignore the first (VER) byte */
455*6236dae4SAndroid Build Coastguard Worker if(socksreq[1] == 255) { /* status / message type */
456*6236dae4SAndroid Build Coastguard Worker failf(data, "User was rejected by the SOCKS5 server (%d %d).",
457*6236dae4SAndroid Build Coastguard Worker socksreq[0], socksreq[1]);
458*6236dae4SAndroid Build Coastguard Worker gss_delete_sec_context(&gss_status, &gss_context, NULL);
459*6236dae4SAndroid Build Coastguard Worker return CURLE_COULDNT_CONNECT;
460*6236dae4SAndroid Build Coastguard Worker }
461*6236dae4SAndroid Build Coastguard Worker
462*6236dae4SAndroid Build Coastguard Worker if(socksreq[1] != 2) { /* status / message type */
463*6236dae4SAndroid Build Coastguard Worker failf(data, "Invalid GSS-API encryption response type (%d %d).",
464*6236dae4SAndroid Build Coastguard Worker socksreq[0], socksreq[1]);
465*6236dae4SAndroid Build Coastguard Worker gss_delete_sec_context(&gss_status, &gss_context, NULL);
466*6236dae4SAndroid Build Coastguard Worker return CURLE_COULDNT_CONNECT;
467*6236dae4SAndroid Build Coastguard Worker }
468*6236dae4SAndroid Build Coastguard Worker
469*6236dae4SAndroid Build Coastguard Worker memcpy(&us_length, socksreq + 2, sizeof(short));
470*6236dae4SAndroid Build Coastguard Worker us_length = ntohs(us_length);
471*6236dae4SAndroid Build Coastguard Worker
472*6236dae4SAndroid Build Coastguard Worker gss_recv_token.length = us_length;
473*6236dae4SAndroid Build Coastguard Worker gss_recv_token.value = malloc(gss_recv_token.length);
474*6236dae4SAndroid Build Coastguard Worker if(!gss_recv_token.value) {
475*6236dae4SAndroid Build Coastguard Worker gss_delete_sec_context(&gss_status, &gss_context, NULL);
476*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
477*6236dae4SAndroid Build Coastguard Worker }
478*6236dae4SAndroid Build Coastguard Worker result = Curl_blockread_all(cf, data, (char *)gss_recv_token.value,
479*6236dae4SAndroid Build Coastguard Worker gss_recv_token.length, &actualread);
480*6236dae4SAndroid Build Coastguard Worker
481*6236dae4SAndroid Build Coastguard Worker if(result || (actualread != us_length)) {
482*6236dae4SAndroid Build Coastguard Worker failf(data, "Failed to receive GSS-API encryption type.");
483*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&gss_status, &gss_recv_token);
484*6236dae4SAndroid Build Coastguard Worker gss_delete_sec_context(&gss_status, &gss_context, NULL);
485*6236dae4SAndroid Build Coastguard Worker return CURLE_COULDNT_CONNECT;
486*6236dae4SAndroid Build Coastguard Worker }
487*6236dae4SAndroid Build Coastguard Worker
488*6236dae4SAndroid Build Coastguard Worker if(!data->set.socks5_gssapi_nec) {
489*6236dae4SAndroid Build Coastguard Worker gss_major_status = gss_unwrap(&gss_minor_status, gss_context,
490*6236dae4SAndroid Build Coastguard Worker &gss_recv_token, &gss_w_token,
491*6236dae4SAndroid Build Coastguard Worker 0, GSS_C_QOP_DEFAULT);
492*6236dae4SAndroid Build Coastguard Worker
493*6236dae4SAndroid Build Coastguard Worker if(check_gss_err(data, gss_major_status, gss_minor_status, "gss_unwrap")) {
494*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&gss_status, &gss_recv_token);
495*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&gss_status, &gss_w_token);
496*6236dae4SAndroid Build Coastguard Worker gss_delete_sec_context(&gss_status, &gss_context, NULL);
497*6236dae4SAndroid Build Coastguard Worker failf(data, "Failed to unwrap GSS-API encryption value into token.");
498*6236dae4SAndroid Build Coastguard Worker return CURLE_COULDNT_CONNECT;
499*6236dae4SAndroid Build Coastguard Worker }
500*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&gss_status, &gss_recv_token);
501*6236dae4SAndroid Build Coastguard Worker
502*6236dae4SAndroid Build Coastguard Worker if(gss_w_token.length != 1) {
503*6236dae4SAndroid Build Coastguard Worker failf(data, "Invalid GSS-API encryption response length (%zu).",
504*6236dae4SAndroid Build Coastguard Worker gss_w_token.length);
505*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&gss_status, &gss_w_token);
506*6236dae4SAndroid Build Coastguard Worker gss_delete_sec_context(&gss_status, &gss_context, NULL);
507*6236dae4SAndroid Build Coastguard Worker return CURLE_COULDNT_CONNECT;
508*6236dae4SAndroid Build Coastguard Worker }
509*6236dae4SAndroid Build Coastguard Worker
510*6236dae4SAndroid Build Coastguard Worker memcpy(socksreq, gss_w_token.value, gss_w_token.length);
511*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&gss_status, &gss_w_token);
512*6236dae4SAndroid Build Coastguard Worker }
513*6236dae4SAndroid Build Coastguard Worker else {
514*6236dae4SAndroid Build Coastguard Worker if(gss_recv_token.length != 1) {
515*6236dae4SAndroid Build Coastguard Worker failf(data, "Invalid GSS-API encryption response length (%zu).",
516*6236dae4SAndroid Build Coastguard Worker gss_recv_token.length);
517*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&gss_status, &gss_recv_token);
518*6236dae4SAndroid Build Coastguard Worker gss_delete_sec_context(&gss_status, &gss_context, NULL);
519*6236dae4SAndroid Build Coastguard Worker return CURLE_COULDNT_CONNECT;
520*6236dae4SAndroid Build Coastguard Worker }
521*6236dae4SAndroid Build Coastguard Worker
522*6236dae4SAndroid Build Coastguard Worker memcpy(socksreq, gss_recv_token.value, gss_recv_token.length);
523*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&gss_status, &gss_recv_token);
524*6236dae4SAndroid Build Coastguard Worker }
525*6236dae4SAndroid Build Coastguard Worker
526*6236dae4SAndroid Build Coastguard Worker (void)curlx_nonblock(sock, TRUE);
527*6236dae4SAndroid Build Coastguard Worker
528*6236dae4SAndroid Build Coastguard Worker infof(data, "SOCKS5 access with%s protection granted.",
529*6236dae4SAndroid Build Coastguard Worker (socksreq[0] == 0) ? "out GSS-API data":
530*6236dae4SAndroid Build Coastguard Worker ((socksreq[0] == 1) ? " GSS-API integrity" :
531*6236dae4SAndroid Build Coastguard Worker " GSS-API confidentiality"));
532*6236dae4SAndroid Build Coastguard Worker
533*6236dae4SAndroid Build Coastguard Worker conn->socks5_gssapi_enctype = socksreq[0];
534*6236dae4SAndroid Build Coastguard Worker if(socksreq[0] == 0)
535*6236dae4SAndroid Build Coastguard Worker gss_delete_sec_context(&gss_status, &gss_context, NULL);
536*6236dae4SAndroid Build Coastguard Worker
537*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
538*6236dae4SAndroid Build Coastguard Worker }
539*6236dae4SAndroid Build Coastguard Worker
540*6236dae4SAndroid Build Coastguard Worker #endif /* HAVE_GSSAPI && !CURL_DISABLE_PROXY */
541