1*6236dae4SAndroid Build Coastguard Worker /* GSSAPI/krb5 support for FTP - loosely based on old krb4.c
2*6236dae4SAndroid Build Coastguard Worker *
3*6236dae4SAndroid Build Coastguard Worker * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
4*6236dae4SAndroid Build Coastguard Worker * (Royal Institute of Technology, Stockholm, Sweden).
5*6236dae4SAndroid Build Coastguard Worker * Copyright (C) Daniel Stenberg
6*6236dae4SAndroid Build Coastguard Worker * All rights reserved.
7*6236dae4SAndroid Build Coastguard Worker *
8*6236dae4SAndroid Build Coastguard Worker * SPDX-License-Identifier: BSD-3-Clause
9*6236dae4SAndroid Build Coastguard Worker *
10*6236dae4SAndroid Build Coastguard Worker * Redistribution and use in source and binary forms, with or without
11*6236dae4SAndroid Build Coastguard Worker * modification, are permitted provided that the following conditions
12*6236dae4SAndroid Build Coastguard Worker * are met:
13*6236dae4SAndroid Build Coastguard Worker *
14*6236dae4SAndroid Build Coastguard Worker * 1. Redistributions of source code must retain the above copyright
15*6236dae4SAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer.
16*6236dae4SAndroid Build Coastguard Worker *
17*6236dae4SAndroid Build Coastguard Worker * 2. Redistributions in binary form must reproduce the above copyright
18*6236dae4SAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer in the
19*6236dae4SAndroid Build Coastguard Worker * documentation and/or other materials provided with the distribution.
20*6236dae4SAndroid Build Coastguard Worker *
21*6236dae4SAndroid Build Coastguard Worker * 3. Neither the name of the Institute nor the names of its contributors
22*6236dae4SAndroid Build Coastguard Worker * may be used to endorse or promote products derived from this software
23*6236dae4SAndroid Build Coastguard Worker * without specific prior written permission.
24*6236dae4SAndroid Build Coastguard Worker *
25*6236dae4SAndroid Build Coastguard Worker * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
26*6236dae4SAndroid Build Coastguard Worker * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27*6236dae4SAndroid Build Coastguard Worker * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28*6236dae4SAndroid Build Coastguard Worker * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
29*6236dae4SAndroid Build Coastguard Worker * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30*6236dae4SAndroid Build Coastguard Worker * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31*6236dae4SAndroid Build Coastguard Worker * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32*6236dae4SAndroid Build Coastguard Worker * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33*6236dae4SAndroid Build Coastguard Worker * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34*6236dae4SAndroid Build Coastguard Worker * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35*6236dae4SAndroid Build Coastguard Worker * SUCH DAMAGE. */
36*6236dae4SAndroid Build Coastguard Worker
37*6236dae4SAndroid Build Coastguard Worker #include "curl_setup.h"
38*6236dae4SAndroid Build Coastguard Worker
39*6236dae4SAndroid Build Coastguard Worker #if defined(HAVE_GSSAPI) && !defined(CURL_DISABLE_FTP)
40*6236dae4SAndroid Build Coastguard Worker
41*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_NETDB_H
42*6236dae4SAndroid Build Coastguard Worker #include <netdb.h>
43*6236dae4SAndroid Build Coastguard Worker #endif
44*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_ARPA_INET_H
45*6236dae4SAndroid Build Coastguard Worker #include <arpa/inet.h>
46*6236dae4SAndroid Build Coastguard Worker #endif
47*6236dae4SAndroid Build Coastguard Worker
48*6236dae4SAndroid Build Coastguard Worker #include "urldata.h"
49*6236dae4SAndroid Build Coastguard Worker #include "cfilters.h"
50*6236dae4SAndroid Build Coastguard Worker #include "cf-socket.h"
51*6236dae4SAndroid Build Coastguard Worker #include "curl_base64.h"
52*6236dae4SAndroid Build Coastguard Worker #include "ftp.h"
53*6236dae4SAndroid Build Coastguard Worker #include "curl_gssapi.h"
54*6236dae4SAndroid Build Coastguard Worker #include "sendf.h"
55*6236dae4SAndroid Build Coastguard Worker #include "transfer.h"
56*6236dae4SAndroid Build Coastguard Worker #include "curl_krb5.h"
57*6236dae4SAndroid Build Coastguard Worker #include "warnless.h"
58*6236dae4SAndroid Build Coastguard Worker #include "strcase.h"
59*6236dae4SAndroid Build Coastguard Worker #include "strdup.h"
60*6236dae4SAndroid Build Coastguard Worker
61*6236dae4SAndroid Build Coastguard Worker /* The last 3 #include files should be in this order */
62*6236dae4SAndroid Build Coastguard Worker #include "curl_printf.h"
63*6236dae4SAndroid Build Coastguard Worker #include "curl_memory.h"
64*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h"
65*6236dae4SAndroid Build Coastguard Worker
ftpsend(struct Curl_easy * data,struct connectdata * conn,const char * cmd)66*6236dae4SAndroid Build Coastguard Worker static CURLcode ftpsend(struct Curl_easy *data, struct connectdata *conn,
67*6236dae4SAndroid Build Coastguard Worker const char *cmd)
68*6236dae4SAndroid Build Coastguard Worker {
69*6236dae4SAndroid Build Coastguard Worker size_t bytes_written;
70*6236dae4SAndroid Build Coastguard Worker #define SBUF_SIZE 1024
71*6236dae4SAndroid Build Coastguard Worker char s[SBUF_SIZE];
72*6236dae4SAndroid Build Coastguard Worker size_t write_len;
73*6236dae4SAndroid Build Coastguard Worker char *sptr = s;
74*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
75*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_GSSAPI
76*6236dae4SAndroid Build Coastguard Worker unsigned char data_sec = conn->data_prot;
77*6236dae4SAndroid Build Coastguard Worker #endif
78*6236dae4SAndroid Build Coastguard Worker
79*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(cmd);
80*6236dae4SAndroid Build Coastguard Worker
81*6236dae4SAndroid Build Coastguard Worker write_len = strlen(cmd);
82*6236dae4SAndroid Build Coastguard Worker if(!write_len || write_len > (sizeof(s) -3))
83*6236dae4SAndroid Build Coastguard Worker return CURLE_BAD_FUNCTION_ARGUMENT;
84*6236dae4SAndroid Build Coastguard Worker
85*6236dae4SAndroid Build Coastguard Worker memcpy(&s, cmd, write_len);
86*6236dae4SAndroid Build Coastguard Worker strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */
87*6236dae4SAndroid Build Coastguard Worker write_len += 2;
88*6236dae4SAndroid Build Coastguard Worker bytes_written = 0;
89*6236dae4SAndroid Build Coastguard Worker
90*6236dae4SAndroid Build Coastguard Worker for(;;) {
91*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_GSSAPI
92*6236dae4SAndroid Build Coastguard Worker conn->data_prot = PROT_CMD;
93*6236dae4SAndroid Build Coastguard Worker #endif
94*6236dae4SAndroid Build Coastguard Worker result = Curl_xfer_send(data, sptr, write_len, FALSE, &bytes_written);
95*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_GSSAPI
96*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
97*6236dae4SAndroid Build Coastguard Worker conn->data_prot = data_sec;
98*6236dae4SAndroid Build Coastguard Worker #endif
99*6236dae4SAndroid Build Coastguard Worker
100*6236dae4SAndroid Build Coastguard Worker if(result)
101*6236dae4SAndroid Build Coastguard Worker break;
102*6236dae4SAndroid Build Coastguard Worker
103*6236dae4SAndroid Build Coastguard Worker Curl_debug(data, CURLINFO_HEADER_OUT, sptr, bytes_written);
104*6236dae4SAndroid Build Coastguard Worker
105*6236dae4SAndroid Build Coastguard Worker if(bytes_written != write_len) {
106*6236dae4SAndroid Build Coastguard Worker write_len -= bytes_written;
107*6236dae4SAndroid Build Coastguard Worker sptr += bytes_written;
108*6236dae4SAndroid Build Coastguard Worker }
109*6236dae4SAndroid Build Coastguard Worker else
110*6236dae4SAndroid Build Coastguard Worker break;
111*6236dae4SAndroid Build Coastguard Worker }
112*6236dae4SAndroid Build Coastguard Worker
113*6236dae4SAndroid Build Coastguard Worker return result;
114*6236dae4SAndroid Build Coastguard Worker }
115*6236dae4SAndroid Build Coastguard Worker
116*6236dae4SAndroid Build Coastguard Worker static int
krb5_init(void * app_data)117*6236dae4SAndroid Build Coastguard Worker krb5_init(void *app_data)
118*6236dae4SAndroid Build Coastguard Worker {
119*6236dae4SAndroid Build Coastguard Worker gss_ctx_id_t *context = app_data;
120*6236dae4SAndroid Build Coastguard Worker /* Make sure our context is initialized for krb5_end. */
121*6236dae4SAndroid Build Coastguard Worker *context = GSS_C_NO_CONTEXT;
122*6236dae4SAndroid Build Coastguard Worker return 0;
123*6236dae4SAndroid Build Coastguard Worker }
124*6236dae4SAndroid Build Coastguard Worker
125*6236dae4SAndroid Build Coastguard Worker static int
krb5_check_prot(void * app_data,int level)126*6236dae4SAndroid Build Coastguard Worker krb5_check_prot(void *app_data, int level)
127*6236dae4SAndroid Build Coastguard Worker {
128*6236dae4SAndroid Build Coastguard Worker (void)app_data; /* unused */
129*6236dae4SAndroid Build Coastguard Worker if(level == PROT_CONFIDENTIAL)
130*6236dae4SAndroid Build Coastguard Worker return -1;
131*6236dae4SAndroid Build Coastguard Worker return 0;
132*6236dae4SAndroid Build Coastguard Worker }
133*6236dae4SAndroid Build Coastguard Worker
134*6236dae4SAndroid Build Coastguard Worker static int
krb5_decode(void * app_data,void * buf,int len,int level UNUSED_PARAM,struct connectdata * conn UNUSED_PARAM)135*6236dae4SAndroid Build Coastguard Worker krb5_decode(void *app_data, void *buf, int len,
136*6236dae4SAndroid Build Coastguard Worker int level UNUSED_PARAM,
137*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn UNUSED_PARAM)
138*6236dae4SAndroid Build Coastguard Worker {
139*6236dae4SAndroid Build Coastguard Worker gss_ctx_id_t *context = app_data;
140*6236dae4SAndroid Build Coastguard Worker OM_uint32 maj, min;
141*6236dae4SAndroid Build Coastguard Worker gss_buffer_desc enc, dec;
142*6236dae4SAndroid Build Coastguard Worker
143*6236dae4SAndroid Build Coastguard Worker (void)level;
144*6236dae4SAndroid Build Coastguard Worker (void)conn;
145*6236dae4SAndroid Build Coastguard Worker
146*6236dae4SAndroid Build Coastguard Worker enc.value = buf;
147*6236dae4SAndroid Build Coastguard Worker enc.length = len;
148*6236dae4SAndroid Build Coastguard Worker maj = gss_unwrap(&min, *context, &enc, &dec, NULL, NULL);
149*6236dae4SAndroid Build Coastguard Worker if(maj != GSS_S_COMPLETE)
150*6236dae4SAndroid Build Coastguard Worker return -1;
151*6236dae4SAndroid Build Coastguard Worker
152*6236dae4SAndroid Build Coastguard Worker memcpy(buf, dec.value, dec.length);
153*6236dae4SAndroid Build Coastguard Worker len = curlx_uztosi(dec.length);
154*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&min, &dec);
155*6236dae4SAndroid Build Coastguard Worker
156*6236dae4SAndroid Build Coastguard Worker return len;
157*6236dae4SAndroid Build Coastguard Worker }
158*6236dae4SAndroid Build Coastguard Worker
159*6236dae4SAndroid Build Coastguard Worker static int
krb5_encode(void * app_data,const void * from,int length,int level,void ** to)160*6236dae4SAndroid Build Coastguard Worker krb5_encode(void *app_data, const void *from, int length, int level, void **to)
161*6236dae4SAndroid Build Coastguard Worker {
162*6236dae4SAndroid Build Coastguard Worker gss_ctx_id_t *context = app_data;
163*6236dae4SAndroid Build Coastguard Worker gss_buffer_desc dec, enc;
164*6236dae4SAndroid Build Coastguard Worker OM_uint32 maj, min;
165*6236dae4SAndroid Build Coastguard Worker int state;
166*6236dae4SAndroid Build Coastguard Worker int len;
167*6236dae4SAndroid Build Coastguard Worker
168*6236dae4SAndroid Build Coastguard Worker /* NOTE that the cast is safe, neither of the krb5, gnu gss and heimdal
169*6236dae4SAndroid Build Coastguard Worker * libraries modify the input buffer in gss_wrap()
170*6236dae4SAndroid Build Coastguard Worker */
171*6236dae4SAndroid Build Coastguard Worker dec.value = (void *)from;
172*6236dae4SAndroid Build Coastguard Worker dec.length = (size_t)length;
173*6236dae4SAndroid Build Coastguard Worker maj = gss_wrap(&min, *context,
174*6236dae4SAndroid Build Coastguard Worker level == PROT_PRIVATE,
175*6236dae4SAndroid Build Coastguard Worker GSS_C_QOP_DEFAULT,
176*6236dae4SAndroid Build Coastguard Worker &dec, &state, &enc);
177*6236dae4SAndroid Build Coastguard Worker
178*6236dae4SAndroid Build Coastguard Worker if(maj != GSS_S_COMPLETE)
179*6236dae4SAndroid Build Coastguard Worker return -1;
180*6236dae4SAndroid Build Coastguard Worker
181*6236dae4SAndroid Build Coastguard Worker /* malloc a new buffer, in case gss_release_buffer does not work as
182*6236dae4SAndroid Build Coastguard Worker expected */
183*6236dae4SAndroid Build Coastguard Worker *to = malloc(enc.length);
184*6236dae4SAndroid Build Coastguard Worker if(!*to)
185*6236dae4SAndroid Build Coastguard Worker return -1;
186*6236dae4SAndroid Build Coastguard Worker memcpy(*to, enc.value, enc.length);
187*6236dae4SAndroid Build Coastguard Worker len = curlx_uztosi(enc.length);
188*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&min, &enc);
189*6236dae4SAndroid Build Coastguard Worker return len;
190*6236dae4SAndroid Build Coastguard Worker }
191*6236dae4SAndroid Build Coastguard Worker
192*6236dae4SAndroid Build Coastguard Worker static int
krb5_auth(void * app_data,struct Curl_easy * data,struct connectdata * conn)193*6236dae4SAndroid Build Coastguard Worker krb5_auth(void *app_data, struct Curl_easy *data, struct connectdata *conn)
194*6236dae4SAndroid Build Coastguard Worker {
195*6236dae4SAndroid Build Coastguard Worker int ret = AUTH_OK;
196*6236dae4SAndroid Build Coastguard Worker char *p;
197*6236dae4SAndroid Build Coastguard Worker const char *host = conn->host.name;
198*6236dae4SAndroid Build Coastguard Worker ssize_t nread;
199*6236dae4SAndroid Build Coastguard Worker curl_socklen_t l = sizeof(conn->local_addr);
200*6236dae4SAndroid Build Coastguard Worker CURLcode result;
201*6236dae4SAndroid Build Coastguard Worker const char *service = data->set.str[STRING_SERVICE_NAME] ?
202*6236dae4SAndroid Build Coastguard Worker data->set.str[STRING_SERVICE_NAME] :
203*6236dae4SAndroid Build Coastguard Worker "ftp";
204*6236dae4SAndroid Build Coastguard Worker const char *srv_host = "host";
205*6236dae4SAndroid Build Coastguard Worker gss_buffer_desc input_buffer, output_buffer, _gssresp, *gssresp;
206*6236dae4SAndroid Build Coastguard Worker OM_uint32 maj, min;
207*6236dae4SAndroid Build Coastguard Worker gss_name_t gssname;
208*6236dae4SAndroid Build Coastguard Worker gss_ctx_id_t *context = app_data;
209*6236dae4SAndroid Build Coastguard Worker struct gss_channel_bindings_struct chan;
210*6236dae4SAndroid Build Coastguard Worker size_t base64_sz = 0;
211*6236dae4SAndroid Build Coastguard Worker struct sockaddr_in *remote_addr =
212*6236dae4SAndroid Build Coastguard Worker (struct sockaddr_in *)(void *)&conn->remote_addr->curl_sa_addr;
213*6236dae4SAndroid Build Coastguard Worker char *stringp;
214*6236dae4SAndroid Build Coastguard Worker
215*6236dae4SAndroid Build Coastguard Worker if(getsockname(conn->sock[FIRSTSOCKET],
216*6236dae4SAndroid Build Coastguard Worker (struct sockaddr *)&conn->local_addr, &l) < 0)
217*6236dae4SAndroid Build Coastguard Worker perror("getsockname()");
218*6236dae4SAndroid Build Coastguard Worker
219*6236dae4SAndroid Build Coastguard Worker chan.initiator_addrtype = GSS_C_AF_INET;
220*6236dae4SAndroid Build Coastguard Worker chan.initiator_address.length = l - 4;
221*6236dae4SAndroid Build Coastguard Worker chan.initiator_address.value = &conn->local_addr.sin_addr.s_addr;
222*6236dae4SAndroid Build Coastguard Worker chan.acceptor_addrtype = GSS_C_AF_INET;
223*6236dae4SAndroid Build Coastguard Worker chan.acceptor_address.length = l - 4;
224*6236dae4SAndroid Build Coastguard Worker chan.acceptor_address.value = &remote_addr->sin_addr.s_addr;
225*6236dae4SAndroid Build Coastguard Worker chan.application_data.length = 0;
226*6236dae4SAndroid Build Coastguard Worker chan.application_data.value = NULL;
227*6236dae4SAndroid Build Coastguard Worker
228*6236dae4SAndroid Build Coastguard Worker /* this loop will execute twice (once for service, once for host) */
229*6236dae4SAndroid Build Coastguard Worker for(;;) {
230*6236dae4SAndroid Build Coastguard Worker /* this really should not be repeated here, but cannot help it */
231*6236dae4SAndroid Build Coastguard Worker if(service == srv_host) {
232*6236dae4SAndroid Build Coastguard Worker result = ftpsend(data, conn, "AUTH GSSAPI");
233*6236dae4SAndroid Build Coastguard Worker if(result)
234*6236dae4SAndroid Build Coastguard Worker return -2;
235*6236dae4SAndroid Build Coastguard Worker
236*6236dae4SAndroid Build Coastguard Worker if(Curl_GetFTPResponse(data, &nread, NULL))
237*6236dae4SAndroid Build Coastguard Worker return -1;
238*6236dae4SAndroid Build Coastguard Worker else {
239*6236dae4SAndroid Build Coastguard Worker struct pingpong *pp = &conn->proto.ftpc.pp;
240*6236dae4SAndroid Build Coastguard Worker char *line = Curl_dyn_ptr(&pp->recvbuf);
241*6236dae4SAndroid Build Coastguard Worker if(line[0] != '3')
242*6236dae4SAndroid Build Coastguard Worker return -1;
243*6236dae4SAndroid Build Coastguard Worker }
244*6236dae4SAndroid Build Coastguard Worker }
245*6236dae4SAndroid Build Coastguard Worker
246*6236dae4SAndroid Build Coastguard Worker stringp = aprintf("%s@%s", service, host);
247*6236dae4SAndroid Build Coastguard Worker if(!stringp)
248*6236dae4SAndroid Build Coastguard Worker return -2;
249*6236dae4SAndroid Build Coastguard Worker
250*6236dae4SAndroid Build Coastguard Worker input_buffer.value = stringp;
251*6236dae4SAndroid Build Coastguard Worker input_buffer.length = strlen(stringp);
252*6236dae4SAndroid Build Coastguard Worker maj = gss_import_name(&min, &input_buffer, GSS_C_NT_HOSTBASED_SERVICE,
253*6236dae4SAndroid Build Coastguard Worker &gssname);
254*6236dae4SAndroid Build Coastguard Worker free(stringp);
255*6236dae4SAndroid Build Coastguard Worker if(maj != GSS_S_COMPLETE) {
256*6236dae4SAndroid Build Coastguard Worker gss_release_name(&min, &gssname);
257*6236dae4SAndroid Build Coastguard Worker if(service == srv_host) {
258*6236dae4SAndroid Build Coastguard Worker failf(data, "Error importing service name %s@%s", service, host);
259*6236dae4SAndroid Build Coastguard Worker return AUTH_ERROR;
260*6236dae4SAndroid Build Coastguard Worker }
261*6236dae4SAndroid Build Coastguard Worker service = srv_host;
262*6236dae4SAndroid Build Coastguard Worker continue;
263*6236dae4SAndroid Build Coastguard Worker }
264*6236dae4SAndroid Build Coastguard Worker /* We pass NULL as |output_name_type| to avoid a leak. */
265*6236dae4SAndroid Build Coastguard Worker gss_display_name(&min, gssname, &output_buffer, NULL);
266*6236dae4SAndroid Build Coastguard Worker infof(data, "Trying against %s", (char *)output_buffer.value);
267*6236dae4SAndroid Build Coastguard Worker gssresp = GSS_C_NO_BUFFER;
268*6236dae4SAndroid Build Coastguard Worker *context = GSS_C_NO_CONTEXT;
269*6236dae4SAndroid Build Coastguard Worker
270*6236dae4SAndroid Build Coastguard Worker do {
271*6236dae4SAndroid Build Coastguard Worker /* Release the buffer at each iteration to avoid leaking: the first time
272*6236dae4SAndroid Build Coastguard Worker we are releasing the memory from gss_display_name. The last item is
273*6236dae4SAndroid Build Coastguard Worker taken care by a final gss_release_buffer. */
274*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&min, &output_buffer);
275*6236dae4SAndroid Build Coastguard Worker ret = AUTH_OK;
276*6236dae4SAndroid Build Coastguard Worker maj = Curl_gss_init_sec_context(data,
277*6236dae4SAndroid Build Coastguard Worker &min,
278*6236dae4SAndroid Build Coastguard Worker context,
279*6236dae4SAndroid Build Coastguard Worker gssname,
280*6236dae4SAndroid Build Coastguard Worker &Curl_krb5_mech_oid,
281*6236dae4SAndroid Build Coastguard Worker &chan,
282*6236dae4SAndroid Build Coastguard Worker gssresp,
283*6236dae4SAndroid Build Coastguard Worker &output_buffer,
284*6236dae4SAndroid Build Coastguard Worker TRUE,
285*6236dae4SAndroid Build Coastguard Worker NULL);
286*6236dae4SAndroid Build Coastguard Worker
287*6236dae4SAndroid Build Coastguard Worker if(gssresp) {
288*6236dae4SAndroid Build Coastguard Worker free(_gssresp.value);
289*6236dae4SAndroid Build Coastguard Worker gssresp = NULL;
290*6236dae4SAndroid Build Coastguard Worker }
291*6236dae4SAndroid Build Coastguard Worker
292*6236dae4SAndroid Build Coastguard Worker if(GSS_ERROR(maj)) {
293*6236dae4SAndroid Build Coastguard Worker infof(data, "Error creating security context");
294*6236dae4SAndroid Build Coastguard Worker ret = AUTH_ERROR;
295*6236dae4SAndroid Build Coastguard Worker break;
296*6236dae4SAndroid Build Coastguard Worker }
297*6236dae4SAndroid Build Coastguard Worker
298*6236dae4SAndroid Build Coastguard Worker if(output_buffer.length) {
299*6236dae4SAndroid Build Coastguard Worker char *cmd;
300*6236dae4SAndroid Build Coastguard Worker
301*6236dae4SAndroid Build Coastguard Worker result = Curl_base64_encode((char *)output_buffer.value,
302*6236dae4SAndroid Build Coastguard Worker output_buffer.length, &p, &base64_sz);
303*6236dae4SAndroid Build Coastguard Worker if(result) {
304*6236dae4SAndroid Build Coastguard Worker infof(data, "base64-encoding: %s", curl_easy_strerror(result));
305*6236dae4SAndroid Build Coastguard Worker ret = AUTH_ERROR;
306*6236dae4SAndroid Build Coastguard Worker break;
307*6236dae4SAndroid Build Coastguard Worker }
308*6236dae4SAndroid Build Coastguard Worker
309*6236dae4SAndroid Build Coastguard Worker cmd = aprintf("ADAT %s", p);
310*6236dae4SAndroid Build Coastguard Worker if(cmd)
311*6236dae4SAndroid Build Coastguard Worker result = ftpsend(data, conn, cmd);
312*6236dae4SAndroid Build Coastguard Worker else
313*6236dae4SAndroid Build Coastguard Worker result = CURLE_OUT_OF_MEMORY;
314*6236dae4SAndroid Build Coastguard Worker
315*6236dae4SAndroid Build Coastguard Worker free(p);
316*6236dae4SAndroid Build Coastguard Worker free(cmd);
317*6236dae4SAndroid Build Coastguard Worker
318*6236dae4SAndroid Build Coastguard Worker if(result) {
319*6236dae4SAndroid Build Coastguard Worker ret = -2;
320*6236dae4SAndroid Build Coastguard Worker break;
321*6236dae4SAndroid Build Coastguard Worker }
322*6236dae4SAndroid Build Coastguard Worker
323*6236dae4SAndroid Build Coastguard Worker if(Curl_GetFTPResponse(data, &nread, NULL)) {
324*6236dae4SAndroid Build Coastguard Worker ret = -1;
325*6236dae4SAndroid Build Coastguard Worker break;
326*6236dae4SAndroid Build Coastguard Worker }
327*6236dae4SAndroid Build Coastguard Worker else {
328*6236dae4SAndroid Build Coastguard Worker struct pingpong *pp = &conn->proto.ftpc.pp;
329*6236dae4SAndroid Build Coastguard Worker size_t len = Curl_dyn_len(&pp->recvbuf);
330*6236dae4SAndroid Build Coastguard Worker p = Curl_dyn_ptr(&pp->recvbuf);
331*6236dae4SAndroid Build Coastguard Worker if((len < 4) || (p[0] != '2' && p[0] != '3')) {
332*6236dae4SAndroid Build Coastguard Worker infof(data, "Server did not accept auth data");
333*6236dae4SAndroid Build Coastguard Worker ret = AUTH_ERROR;
334*6236dae4SAndroid Build Coastguard Worker break;
335*6236dae4SAndroid Build Coastguard Worker }
336*6236dae4SAndroid Build Coastguard Worker }
337*6236dae4SAndroid Build Coastguard Worker
338*6236dae4SAndroid Build Coastguard Worker _gssresp.value = NULL; /* make sure it is initialized */
339*6236dae4SAndroid Build Coastguard Worker _gssresp.length = 0;
340*6236dae4SAndroid Build Coastguard Worker p += 4; /* over '789 ' */
341*6236dae4SAndroid Build Coastguard Worker p = strstr(p, "ADAT=");
342*6236dae4SAndroid Build Coastguard Worker if(p) {
343*6236dae4SAndroid Build Coastguard Worker unsigned char *outptr;
344*6236dae4SAndroid Build Coastguard Worker size_t outlen;
345*6236dae4SAndroid Build Coastguard Worker result = Curl_base64_decode(p + 5, &outptr, &outlen);
346*6236dae4SAndroid Build Coastguard Worker if(result) {
347*6236dae4SAndroid Build Coastguard Worker failf(data, "base64-decoding: %s", curl_easy_strerror(result));
348*6236dae4SAndroid Build Coastguard Worker ret = AUTH_CONTINUE;
349*6236dae4SAndroid Build Coastguard Worker break;
350*6236dae4SAndroid Build Coastguard Worker }
351*6236dae4SAndroid Build Coastguard Worker _gssresp.value = outptr;
352*6236dae4SAndroid Build Coastguard Worker _gssresp.length = outlen;
353*6236dae4SAndroid Build Coastguard Worker }
354*6236dae4SAndroid Build Coastguard Worker
355*6236dae4SAndroid Build Coastguard Worker gssresp = &_gssresp;
356*6236dae4SAndroid Build Coastguard Worker }
357*6236dae4SAndroid Build Coastguard Worker } while(maj == GSS_S_CONTINUE_NEEDED);
358*6236dae4SAndroid Build Coastguard Worker
359*6236dae4SAndroid Build Coastguard Worker gss_release_name(&min, &gssname);
360*6236dae4SAndroid Build Coastguard Worker gss_release_buffer(&min, &output_buffer);
361*6236dae4SAndroid Build Coastguard Worker
362*6236dae4SAndroid Build Coastguard Worker if(gssresp)
363*6236dae4SAndroid Build Coastguard Worker free(_gssresp.value);
364*6236dae4SAndroid Build Coastguard Worker
365*6236dae4SAndroid Build Coastguard Worker if(ret == AUTH_OK || service == srv_host)
366*6236dae4SAndroid Build Coastguard Worker return ret;
367*6236dae4SAndroid Build Coastguard Worker
368*6236dae4SAndroid Build Coastguard Worker service = srv_host;
369*6236dae4SAndroid Build Coastguard Worker }
370*6236dae4SAndroid Build Coastguard Worker return ret;
371*6236dae4SAndroid Build Coastguard Worker }
372*6236dae4SAndroid Build Coastguard Worker
krb5_end(void * app_data)373*6236dae4SAndroid Build Coastguard Worker static void krb5_end(void *app_data)
374*6236dae4SAndroid Build Coastguard Worker {
375*6236dae4SAndroid Build Coastguard Worker OM_uint32 min;
376*6236dae4SAndroid Build Coastguard Worker gss_ctx_id_t *context = app_data;
377*6236dae4SAndroid Build Coastguard Worker if(*context != GSS_C_NO_CONTEXT) {
378*6236dae4SAndroid Build Coastguard Worker OM_uint32 maj = gss_delete_sec_context(&min, context, GSS_C_NO_BUFFER);
379*6236dae4SAndroid Build Coastguard Worker (void)maj;
380*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(maj == GSS_S_COMPLETE);
381*6236dae4SAndroid Build Coastguard Worker }
382*6236dae4SAndroid Build Coastguard Worker }
383*6236dae4SAndroid Build Coastguard Worker
384*6236dae4SAndroid Build Coastguard Worker static const struct Curl_sec_client_mech Curl_krb5_client_mech = {
385*6236dae4SAndroid Build Coastguard Worker "GSSAPI",
386*6236dae4SAndroid Build Coastguard Worker sizeof(gss_ctx_id_t),
387*6236dae4SAndroid Build Coastguard Worker krb5_init,
388*6236dae4SAndroid Build Coastguard Worker krb5_auth,
389*6236dae4SAndroid Build Coastguard Worker krb5_end,
390*6236dae4SAndroid Build Coastguard Worker krb5_check_prot,
391*6236dae4SAndroid Build Coastguard Worker
392*6236dae4SAndroid Build Coastguard Worker krb5_encode,
393*6236dae4SAndroid Build Coastguard Worker krb5_decode
394*6236dae4SAndroid Build Coastguard Worker };
395*6236dae4SAndroid Build Coastguard Worker
396*6236dae4SAndroid Build Coastguard Worker static const struct {
397*6236dae4SAndroid Build Coastguard Worker unsigned char level;
398*6236dae4SAndroid Build Coastguard Worker const char *name;
399*6236dae4SAndroid Build Coastguard Worker } level_names[] = {
400*6236dae4SAndroid Build Coastguard Worker { PROT_CLEAR, "clear" },
401*6236dae4SAndroid Build Coastguard Worker { PROT_SAFE, "safe" },
402*6236dae4SAndroid Build Coastguard Worker { PROT_CONFIDENTIAL, "confidential" },
403*6236dae4SAndroid Build Coastguard Worker { PROT_PRIVATE, "private" }
404*6236dae4SAndroid Build Coastguard Worker };
405*6236dae4SAndroid Build Coastguard Worker
name_to_level(const char * name)406*6236dae4SAndroid Build Coastguard Worker static unsigned char name_to_level(const char *name)
407*6236dae4SAndroid Build Coastguard Worker {
408*6236dae4SAndroid Build Coastguard Worker int i;
409*6236dae4SAndroid Build Coastguard Worker for(i = 0; i < (int)sizeof(level_names)/(int)sizeof(level_names[0]); i++)
410*6236dae4SAndroid Build Coastguard Worker if(curl_strequal(name, level_names[i].name))
411*6236dae4SAndroid Build Coastguard Worker return level_names[i].level;
412*6236dae4SAndroid Build Coastguard Worker return PROT_NONE;
413*6236dae4SAndroid Build Coastguard Worker }
414*6236dae4SAndroid Build Coastguard Worker
415*6236dae4SAndroid Build Coastguard Worker /* Convert a protocol |level| to its char representation.
416*6236dae4SAndroid Build Coastguard Worker We take an int to catch programming mistakes. */
level_to_char(int level)417*6236dae4SAndroid Build Coastguard Worker static char level_to_char(int level)
418*6236dae4SAndroid Build Coastguard Worker {
419*6236dae4SAndroid Build Coastguard Worker switch(level) {
420*6236dae4SAndroid Build Coastguard Worker case PROT_CLEAR:
421*6236dae4SAndroid Build Coastguard Worker return 'C';
422*6236dae4SAndroid Build Coastguard Worker case PROT_SAFE:
423*6236dae4SAndroid Build Coastguard Worker return 'S';
424*6236dae4SAndroid Build Coastguard Worker case PROT_CONFIDENTIAL:
425*6236dae4SAndroid Build Coastguard Worker return 'E';
426*6236dae4SAndroid Build Coastguard Worker case PROT_PRIVATE:
427*6236dae4SAndroid Build Coastguard Worker return 'P';
428*6236dae4SAndroid Build Coastguard Worker case PROT_CMD:
429*6236dae4SAndroid Build Coastguard Worker default:
430*6236dae4SAndroid Build Coastguard Worker /* Those 2 cases should not be reached! */
431*6236dae4SAndroid Build Coastguard Worker break;
432*6236dae4SAndroid Build Coastguard Worker }
433*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(0);
434*6236dae4SAndroid Build Coastguard Worker /* Default to the most secure alternative. */
435*6236dae4SAndroid Build Coastguard Worker return 'P';
436*6236dae4SAndroid Build Coastguard Worker }
437*6236dae4SAndroid Build Coastguard Worker
438*6236dae4SAndroid Build Coastguard Worker /* Send an FTP command defined by |message| and the optional arguments. The
439*6236dae4SAndroid Build Coastguard Worker function returns the ftp_code. If an error occurs, -1 is returned. */
440*6236dae4SAndroid Build Coastguard Worker static int ftp_send_command(struct Curl_easy *data, const char *message, ...)
441*6236dae4SAndroid Build Coastguard Worker CURL_PRINTF(2, 3);
442*6236dae4SAndroid Build Coastguard Worker
ftp_send_command(struct Curl_easy * data,const char * message,...)443*6236dae4SAndroid Build Coastguard Worker static int ftp_send_command(struct Curl_easy *data, const char *message, ...)
444*6236dae4SAndroid Build Coastguard Worker {
445*6236dae4SAndroid Build Coastguard Worker int ftp_code;
446*6236dae4SAndroid Build Coastguard Worker ssize_t nread = 0;
447*6236dae4SAndroid Build Coastguard Worker va_list args;
448*6236dae4SAndroid Build Coastguard Worker char print_buffer[50];
449*6236dae4SAndroid Build Coastguard Worker
450*6236dae4SAndroid Build Coastguard Worker va_start(args, message);
451*6236dae4SAndroid Build Coastguard Worker mvsnprintf(print_buffer, sizeof(print_buffer), message, args);
452*6236dae4SAndroid Build Coastguard Worker va_end(args);
453*6236dae4SAndroid Build Coastguard Worker
454*6236dae4SAndroid Build Coastguard Worker if(ftpsend(data, data->conn, print_buffer)) {
455*6236dae4SAndroid Build Coastguard Worker ftp_code = -1;
456*6236dae4SAndroid Build Coastguard Worker }
457*6236dae4SAndroid Build Coastguard Worker else {
458*6236dae4SAndroid Build Coastguard Worker if(Curl_GetFTPResponse(data, &nread, &ftp_code))
459*6236dae4SAndroid Build Coastguard Worker ftp_code = -1;
460*6236dae4SAndroid Build Coastguard Worker }
461*6236dae4SAndroid Build Coastguard Worker
462*6236dae4SAndroid Build Coastguard Worker (void)nread; /* Unused */
463*6236dae4SAndroid Build Coastguard Worker return ftp_code;
464*6236dae4SAndroid Build Coastguard Worker }
465*6236dae4SAndroid Build Coastguard Worker
466*6236dae4SAndroid Build Coastguard Worker /* Read |len| from the socket |fd| and store it in |to|. Return a CURLcode
467*6236dae4SAndroid Build Coastguard Worker saying whether an error occurred or CURLE_OK if |len| was read. */
468*6236dae4SAndroid Build Coastguard Worker static CURLcode
socket_read(struct Curl_easy * data,int sockindex,void * to,size_t len)469*6236dae4SAndroid Build Coastguard Worker socket_read(struct Curl_easy *data, int sockindex, void *to, size_t len)
470*6236dae4SAndroid Build Coastguard Worker {
471*6236dae4SAndroid Build Coastguard Worker char *to_p = to;
472*6236dae4SAndroid Build Coastguard Worker CURLcode result;
473*6236dae4SAndroid Build Coastguard Worker ssize_t nread = 0;
474*6236dae4SAndroid Build Coastguard Worker
475*6236dae4SAndroid Build Coastguard Worker while(len > 0) {
476*6236dae4SAndroid Build Coastguard Worker result = Curl_conn_recv(data, sockindex, to_p, len, &nread);
477*6236dae4SAndroid Build Coastguard Worker if(nread > 0) {
478*6236dae4SAndroid Build Coastguard Worker len -= nread;
479*6236dae4SAndroid Build Coastguard Worker to_p += nread;
480*6236dae4SAndroid Build Coastguard Worker }
481*6236dae4SAndroid Build Coastguard Worker else {
482*6236dae4SAndroid Build Coastguard Worker if(result == CURLE_AGAIN)
483*6236dae4SAndroid Build Coastguard Worker continue;
484*6236dae4SAndroid Build Coastguard Worker return result;
485*6236dae4SAndroid Build Coastguard Worker }
486*6236dae4SAndroid Build Coastguard Worker }
487*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
488*6236dae4SAndroid Build Coastguard Worker }
489*6236dae4SAndroid Build Coastguard Worker
490*6236dae4SAndroid Build Coastguard Worker
491*6236dae4SAndroid Build Coastguard Worker /* Write |len| bytes from the buffer |to| to the socket |fd|. Return a
492*6236dae4SAndroid Build Coastguard Worker CURLcode saying whether an error occurred or CURLE_OK if |len| was
493*6236dae4SAndroid Build Coastguard Worker written. */
494*6236dae4SAndroid Build Coastguard Worker static CURLcode
socket_write(struct Curl_easy * data,int sockindex,const void * to,size_t len)495*6236dae4SAndroid Build Coastguard Worker socket_write(struct Curl_easy *data, int sockindex, const void *to,
496*6236dae4SAndroid Build Coastguard Worker size_t len)
497*6236dae4SAndroid Build Coastguard Worker {
498*6236dae4SAndroid Build Coastguard Worker const char *to_p = to;
499*6236dae4SAndroid Build Coastguard Worker CURLcode result;
500*6236dae4SAndroid Build Coastguard Worker size_t written;
501*6236dae4SAndroid Build Coastguard Worker
502*6236dae4SAndroid Build Coastguard Worker while(len > 0) {
503*6236dae4SAndroid Build Coastguard Worker result = Curl_conn_send(data, sockindex, to_p, len, FALSE, &written);
504*6236dae4SAndroid Build Coastguard Worker if(!result && written > 0) {
505*6236dae4SAndroid Build Coastguard Worker len -= written;
506*6236dae4SAndroid Build Coastguard Worker to_p += written;
507*6236dae4SAndroid Build Coastguard Worker }
508*6236dae4SAndroid Build Coastguard Worker else {
509*6236dae4SAndroid Build Coastguard Worker if(result == CURLE_AGAIN)
510*6236dae4SAndroid Build Coastguard Worker continue;
511*6236dae4SAndroid Build Coastguard Worker return result;
512*6236dae4SAndroid Build Coastguard Worker }
513*6236dae4SAndroid Build Coastguard Worker }
514*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
515*6236dae4SAndroid Build Coastguard Worker }
516*6236dae4SAndroid Build Coastguard Worker
read_data(struct Curl_easy * data,int sockindex,struct krb5buffer * buf)517*6236dae4SAndroid Build Coastguard Worker static CURLcode read_data(struct Curl_easy *data, int sockindex,
518*6236dae4SAndroid Build Coastguard Worker struct krb5buffer *buf)
519*6236dae4SAndroid Build Coastguard Worker {
520*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn = data->conn;
521*6236dae4SAndroid Build Coastguard Worker int len;
522*6236dae4SAndroid Build Coastguard Worker CURLcode result;
523*6236dae4SAndroid Build Coastguard Worker int nread;
524*6236dae4SAndroid Build Coastguard Worker
525*6236dae4SAndroid Build Coastguard Worker result = socket_read(data, sockindex, &len, sizeof(len));
526*6236dae4SAndroid Build Coastguard Worker if(result)
527*6236dae4SAndroid Build Coastguard Worker return result;
528*6236dae4SAndroid Build Coastguard Worker
529*6236dae4SAndroid Build Coastguard Worker if(len) {
530*6236dae4SAndroid Build Coastguard Worker len = (int)ntohl((uint32_t)len);
531*6236dae4SAndroid Build Coastguard Worker if(len > CURL_MAX_INPUT_LENGTH)
532*6236dae4SAndroid Build Coastguard Worker return CURLE_TOO_LARGE;
533*6236dae4SAndroid Build Coastguard Worker
534*6236dae4SAndroid Build Coastguard Worker Curl_dyn_reset(&buf->buf);
535*6236dae4SAndroid Build Coastguard Worker }
536*6236dae4SAndroid Build Coastguard Worker else
537*6236dae4SAndroid Build Coastguard Worker return CURLE_RECV_ERROR;
538*6236dae4SAndroid Build Coastguard Worker
539*6236dae4SAndroid Build Coastguard Worker do {
540*6236dae4SAndroid Build Coastguard Worker char buffer[1024];
541*6236dae4SAndroid Build Coastguard Worker nread = CURLMIN(len, (int)sizeof(buffer));
542*6236dae4SAndroid Build Coastguard Worker result = socket_read(data, sockindex, buffer, (size_t)nread);
543*6236dae4SAndroid Build Coastguard Worker if(result)
544*6236dae4SAndroid Build Coastguard Worker return result;
545*6236dae4SAndroid Build Coastguard Worker result = Curl_dyn_addn(&buf->buf, buffer, nread);
546*6236dae4SAndroid Build Coastguard Worker if(result)
547*6236dae4SAndroid Build Coastguard Worker return result;
548*6236dae4SAndroid Build Coastguard Worker len -= nread;
549*6236dae4SAndroid Build Coastguard Worker } while(len);
550*6236dae4SAndroid Build Coastguard Worker /* this decodes the dynbuf *in place* */
551*6236dae4SAndroid Build Coastguard Worker nread = conn->mech->decode(conn->app_data,
552*6236dae4SAndroid Build Coastguard Worker Curl_dyn_ptr(&buf->buf),
553*6236dae4SAndroid Build Coastguard Worker len, conn->data_prot, conn);
554*6236dae4SAndroid Build Coastguard Worker if(nread < 0)
555*6236dae4SAndroid Build Coastguard Worker return CURLE_RECV_ERROR;
556*6236dae4SAndroid Build Coastguard Worker Curl_dyn_setlen(&buf->buf, nread);
557*6236dae4SAndroid Build Coastguard Worker buf->index = 0;
558*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
559*6236dae4SAndroid Build Coastguard Worker }
560*6236dae4SAndroid Build Coastguard Worker
561*6236dae4SAndroid Build Coastguard Worker static size_t
buffer_read(struct krb5buffer * buf,void * data,size_t len)562*6236dae4SAndroid Build Coastguard Worker buffer_read(struct krb5buffer *buf, void *data, size_t len)
563*6236dae4SAndroid Build Coastguard Worker {
564*6236dae4SAndroid Build Coastguard Worker size_t size = Curl_dyn_len(&buf->buf);
565*6236dae4SAndroid Build Coastguard Worker if(size - buf->index < len)
566*6236dae4SAndroid Build Coastguard Worker len = size - buf->index;
567*6236dae4SAndroid Build Coastguard Worker memcpy(data, Curl_dyn_ptr(&buf->buf) + buf->index, len);
568*6236dae4SAndroid Build Coastguard Worker buf->index += len;
569*6236dae4SAndroid Build Coastguard Worker return len;
570*6236dae4SAndroid Build Coastguard Worker }
571*6236dae4SAndroid Build Coastguard Worker
572*6236dae4SAndroid Build Coastguard Worker /* Matches Curl_recv signature */
sec_recv(struct Curl_easy * data,int sockindex,char * buffer,size_t len,CURLcode * err)573*6236dae4SAndroid Build Coastguard Worker static ssize_t sec_recv(struct Curl_easy *data, int sockindex,
574*6236dae4SAndroid Build Coastguard Worker char *buffer, size_t len, CURLcode *err)
575*6236dae4SAndroid Build Coastguard Worker {
576*6236dae4SAndroid Build Coastguard Worker size_t bytes_read;
577*6236dae4SAndroid Build Coastguard Worker size_t total_read = 0;
578*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn = data->conn;
579*6236dae4SAndroid Build Coastguard Worker
580*6236dae4SAndroid Build Coastguard Worker *err = CURLE_OK;
581*6236dae4SAndroid Build Coastguard Worker
582*6236dae4SAndroid Build Coastguard Worker /* Handle clear text response. */
583*6236dae4SAndroid Build Coastguard Worker if(conn->sec_complete == 0 || conn->data_prot == PROT_CLEAR) {
584*6236dae4SAndroid Build Coastguard Worker ssize_t nread;
585*6236dae4SAndroid Build Coastguard Worker *err = Curl_conn_recv(data, sockindex, buffer, len, &nread);
586*6236dae4SAndroid Build Coastguard Worker return nread;
587*6236dae4SAndroid Build Coastguard Worker }
588*6236dae4SAndroid Build Coastguard Worker
589*6236dae4SAndroid Build Coastguard Worker if(conn->in_buffer.eof_flag) {
590*6236dae4SAndroid Build Coastguard Worker conn->in_buffer.eof_flag = 0;
591*6236dae4SAndroid Build Coastguard Worker return 0;
592*6236dae4SAndroid Build Coastguard Worker }
593*6236dae4SAndroid Build Coastguard Worker
594*6236dae4SAndroid Build Coastguard Worker bytes_read = buffer_read(&conn->in_buffer, buffer, len);
595*6236dae4SAndroid Build Coastguard Worker len -= bytes_read;
596*6236dae4SAndroid Build Coastguard Worker total_read += bytes_read;
597*6236dae4SAndroid Build Coastguard Worker buffer += bytes_read;
598*6236dae4SAndroid Build Coastguard Worker
599*6236dae4SAndroid Build Coastguard Worker while(len > 0) {
600*6236dae4SAndroid Build Coastguard Worker if(read_data(data, sockindex, &conn->in_buffer))
601*6236dae4SAndroid Build Coastguard Worker return -1;
602*6236dae4SAndroid Build Coastguard Worker if(Curl_dyn_len(&conn->in_buffer.buf) == 0) {
603*6236dae4SAndroid Build Coastguard Worker if(bytes_read > 0)
604*6236dae4SAndroid Build Coastguard Worker conn->in_buffer.eof_flag = 1;
605*6236dae4SAndroid Build Coastguard Worker return bytes_read;
606*6236dae4SAndroid Build Coastguard Worker }
607*6236dae4SAndroid Build Coastguard Worker bytes_read = buffer_read(&conn->in_buffer, buffer, len);
608*6236dae4SAndroid Build Coastguard Worker len -= bytes_read;
609*6236dae4SAndroid Build Coastguard Worker total_read += bytes_read;
610*6236dae4SAndroid Build Coastguard Worker buffer += bytes_read;
611*6236dae4SAndroid Build Coastguard Worker }
612*6236dae4SAndroid Build Coastguard Worker return total_read;
613*6236dae4SAndroid Build Coastguard Worker }
614*6236dae4SAndroid Build Coastguard Worker
615*6236dae4SAndroid Build Coastguard Worker /* Send |length| bytes from |from| to the |fd| socket taking care of encoding
616*6236dae4SAndroid Build Coastguard Worker and negotiating with the server. |from| can be NULL. */
do_sec_send(struct Curl_easy * data,struct connectdata * conn,curl_socket_t fd,const char * from,int length)617*6236dae4SAndroid Build Coastguard Worker static void do_sec_send(struct Curl_easy *data, struct connectdata *conn,
618*6236dae4SAndroid Build Coastguard Worker curl_socket_t fd, const char *from, int length)
619*6236dae4SAndroid Build Coastguard Worker {
620*6236dae4SAndroid Build Coastguard Worker int bytes, htonl_bytes; /* 32-bit integers for htonl */
621*6236dae4SAndroid Build Coastguard Worker char *buffer = NULL;
622*6236dae4SAndroid Build Coastguard Worker char *cmd_buffer;
623*6236dae4SAndroid Build Coastguard Worker size_t cmd_size = 0;
624*6236dae4SAndroid Build Coastguard Worker CURLcode error;
625*6236dae4SAndroid Build Coastguard Worker enum protection_level prot_level = conn->data_prot;
626*6236dae4SAndroid Build Coastguard Worker bool iscmd = (prot_level == PROT_CMD);
627*6236dae4SAndroid Build Coastguard Worker
628*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(prot_level > PROT_NONE && prot_level < PROT_LAST);
629*6236dae4SAndroid Build Coastguard Worker
630*6236dae4SAndroid Build Coastguard Worker if(iscmd) {
631*6236dae4SAndroid Build Coastguard Worker if(!strncmp(from, "PASS ", 5) || !strncmp(from, "ACCT ", 5))
632*6236dae4SAndroid Build Coastguard Worker prot_level = PROT_PRIVATE;
633*6236dae4SAndroid Build Coastguard Worker else
634*6236dae4SAndroid Build Coastguard Worker prot_level = conn->command_prot;
635*6236dae4SAndroid Build Coastguard Worker }
636*6236dae4SAndroid Build Coastguard Worker bytes = conn->mech->encode(conn->app_data, from, length, (int)prot_level,
637*6236dae4SAndroid Build Coastguard Worker (void **)&buffer);
638*6236dae4SAndroid Build Coastguard Worker if(!buffer || bytes <= 0)
639*6236dae4SAndroid Build Coastguard Worker return; /* error */
640*6236dae4SAndroid Build Coastguard Worker
641*6236dae4SAndroid Build Coastguard Worker if(iscmd) {
642*6236dae4SAndroid Build Coastguard Worker error = Curl_base64_encode(buffer, curlx_sitouz(bytes),
643*6236dae4SAndroid Build Coastguard Worker &cmd_buffer, &cmd_size);
644*6236dae4SAndroid Build Coastguard Worker if(error) {
645*6236dae4SAndroid Build Coastguard Worker free(buffer);
646*6236dae4SAndroid Build Coastguard Worker return; /* error */
647*6236dae4SAndroid Build Coastguard Worker }
648*6236dae4SAndroid Build Coastguard Worker if(cmd_size > 0) {
649*6236dae4SAndroid Build Coastguard Worker static const char *enc = "ENC ";
650*6236dae4SAndroid Build Coastguard Worker static const char *mic = "MIC ";
651*6236dae4SAndroid Build Coastguard Worker if(prot_level == PROT_PRIVATE)
652*6236dae4SAndroid Build Coastguard Worker socket_write(data, fd, enc, 4);
653*6236dae4SAndroid Build Coastguard Worker else
654*6236dae4SAndroid Build Coastguard Worker socket_write(data, fd, mic, 4);
655*6236dae4SAndroid Build Coastguard Worker
656*6236dae4SAndroid Build Coastguard Worker socket_write(data, fd, cmd_buffer, cmd_size);
657*6236dae4SAndroid Build Coastguard Worker socket_write(data, fd, "\r\n", 2);
658*6236dae4SAndroid Build Coastguard Worker infof(data, "Send: %s%s", prot_level == PROT_PRIVATE ? enc : mic,
659*6236dae4SAndroid Build Coastguard Worker cmd_buffer);
660*6236dae4SAndroid Build Coastguard Worker free(cmd_buffer);
661*6236dae4SAndroid Build Coastguard Worker }
662*6236dae4SAndroid Build Coastguard Worker }
663*6236dae4SAndroid Build Coastguard Worker else {
664*6236dae4SAndroid Build Coastguard Worker htonl_bytes = (int)htonl((OM_uint32)bytes);
665*6236dae4SAndroid Build Coastguard Worker socket_write(data, fd, &htonl_bytes, sizeof(htonl_bytes));
666*6236dae4SAndroid Build Coastguard Worker socket_write(data, fd, buffer, curlx_sitouz(bytes));
667*6236dae4SAndroid Build Coastguard Worker }
668*6236dae4SAndroid Build Coastguard Worker free(buffer);
669*6236dae4SAndroid Build Coastguard Worker }
670*6236dae4SAndroid Build Coastguard Worker
sec_write(struct Curl_easy * data,struct connectdata * conn,curl_socket_t fd,const char * buffer,size_t length)671*6236dae4SAndroid Build Coastguard Worker static ssize_t sec_write(struct Curl_easy *data, struct connectdata *conn,
672*6236dae4SAndroid Build Coastguard Worker curl_socket_t fd, const char *buffer, size_t length)
673*6236dae4SAndroid Build Coastguard Worker {
674*6236dae4SAndroid Build Coastguard Worker ssize_t tx = 0, len = conn->buffer_size;
675*6236dae4SAndroid Build Coastguard Worker
676*6236dae4SAndroid Build Coastguard Worker if(len <= 0)
677*6236dae4SAndroid Build Coastguard Worker len = length;
678*6236dae4SAndroid Build Coastguard Worker while(length) {
679*6236dae4SAndroid Build Coastguard Worker if(length < (size_t)len)
680*6236dae4SAndroid Build Coastguard Worker len = length;
681*6236dae4SAndroid Build Coastguard Worker
682*6236dae4SAndroid Build Coastguard Worker do_sec_send(data, conn, fd, buffer, curlx_sztosi(len));
683*6236dae4SAndroid Build Coastguard Worker length -= len;
684*6236dae4SAndroid Build Coastguard Worker buffer += len;
685*6236dae4SAndroid Build Coastguard Worker tx += len;
686*6236dae4SAndroid Build Coastguard Worker }
687*6236dae4SAndroid Build Coastguard Worker return tx;
688*6236dae4SAndroid Build Coastguard Worker }
689*6236dae4SAndroid Build Coastguard Worker
690*6236dae4SAndroid Build Coastguard Worker /* Matches Curl_send signature */
sec_send(struct Curl_easy * data,int sockindex,const void * buffer,size_t len,bool eos,CURLcode * err)691*6236dae4SAndroid Build Coastguard Worker static ssize_t sec_send(struct Curl_easy *data, int sockindex,
692*6236dae4SAndroid Build Coastguard Worker const void *buffer, size_t len, bool eos,
693*6236dae4SAndroid Build Coastguard Worker CURLcode *err)
694*6236dae4SAndroid Build Coastguard Worker {
695*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn = data->conn;
696*6236dae4SAndroid Build Coastguard Worker curl_socket_t fd = conn->sock[sockindex];
697*6236dae4SAndroid Build Coastguard Worker (void)eos; /* unused */
698*6236dae4SAndroid Build Coastguard Worker *err = CURLE_OK;
699*6236dae4SAndroid Build Coastguard Worker return sec_write(data, conn, fd, buffer, len);
700*6236dae4SAndroid Build Coastguard Worker }
701*6236dae4SAndroid Build Coastguard Worker
Curl_sec_read_msg(struct Curl_easy * data,struct connectdata * conn,char * buffer,enum protection_level level)702*6236dae4SAndroid Build Coastguard Worker int Curl_sec_read_msg(struct Curl_easy *data, struct connectdata *conn,
703*6236dae4SAndroid Build Coastguard Worker char *buffer, enum protection_level level)
704*6236dae4SAndroid Build Coastguard Worker {
705*6236dae4SAndroid Build Coastguard Worker /* decoded_len should be size_t or ssize_t but conn->mech->decode returns an
706*6236dae4SAndroid Build Coastguard Worker int */
707*6236dae4SAndroid Build Coastguard Worker int decoded_len;
708*6236dae4SAndroid Build Coastguard Worker char *buf;
709*6236dae4SAndroid Build Coastguard Worker int ret_code = 0;
710*6236dae4SAndroid Build Coastguard Worker size_t decoded_sz = 0;
711*6236dae4SAndroid Build Coastguard Worker CURLcode error;
712*6236dae4SAndroid Build Coastguard Worker
713*6236dae4SAndroid Build Coastguard Worker (void) data;
714*6236dae4SAndroid Build Coastguard Worker
715*6236dae4SAndroid Build Coastguard Worker if(!conn->mech)
716*6236dae4SAndroid Build Coastguard Worker /* not initialized, return error */
717*6236dae4SAndroid Build Coastguard Worker return -1;
718*6236dae4SAndroid Build Coastguard Worker
719*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(level > PROT_NONE && level < PROT_LAST);
720*6236dae4SAndroid Build Coastguard Worker
721*6236dae4SAndroid Build Coastguard Worker error = Curl_base64_decode(buffer + 4, (unsigned char **)&buf, &decoded_sz);
722*6236dae4SAndroid Build Coastguard Worker if(error || decoded_sz == 0)
723*6236dae4SAndroid Build Coastguard Worker return -1;
724*6236dae4SAndroid Build Coastguard Worker
725*6236dae4SAndroid Build Coastguard Worker if(decoded_sz > (size_t)INT_MAX) {
726*6236dae4SAndroid Build Coastguard Worker free(buf);
727*6236dae4SAndroid Build Coastguard Worker return -1;
728*6236dae4SAndroid Build Coastguard Worker }
729*6236dae4SAndroid Build Coastguard Worker decoded_len = curlx_uztosi(decoded_sz);
730*6236dae4SAndroid Build Coastguard Worker
731*6236dae4SAndroid Build Coastguard Worker decoded_len = conn->mech->decode(conn->app_data, buf, decoded_len,
732*6236dae4SAndroid Build Coastguard Worker (int)level, conn);
733*6236dae4SAndroid Build Coastguard Worker if(decoded_len <= 0) {
734*6236dae4SAndroid Build Coastguard Worker free(buf);
735*6236dae4SAndroid Build Coastguard Worker return -1;
736*6236dae4SAndroid Build Coastguard Worker }
737*6236dae4SAndroid Build Coastguard Worker
738*6236dae4SAndroid Build Coastguard Worker {
739*6236dae4SAndroid Build Coastguard Worker buf[decoded_len] = '\n';
740*6236dae4SAndroid Build Coastguard Worker Curl_debug(data, CURLINFO_HEADER_IN, buf, decoded_len + 1);
741*6236dae4SAndroid Build Coastguard Worker }
742*6236dae4SAndroid Build Coastguard Worker
743*6236dae4SAndroid Build Coastguard Worker buf[decoded_len] = '\0';
744*6236dae4SAndroid Build Coastguard Worker if(decoded_len <= 3)
745*6236dae4SAndroid Build Coastguard Worker /* suspiciously short */
746*6236dae4SAndroid Build Coastguard Worker return 0;
747*6236dae4SAndroid Build Coastguard Worker
748*6236dae4SAndroid Build Coastguard Worker if(buf[3] != '-')
749*6236dae4SAndroid Build Coastguard Worker ret_code = atoi(buf);
750*6236dae4SAndroid Build Coastguard Worker
751*6236dae4SAndroid Build Coastguard Worker if(buf[decoded_len - 1] == '\n')
752*6236dae4SAndroid Build Coastguard Worker buf[decoded_len - 1] = '\0';
753*6236dae4SAndroid Build Coastguard Worker strcpy(buffer, buf);
754*6236dae4SAndroid Build Coastguard Worker free(buf);
755*6236dae4SAndroid Build Coastguard Worker return ret_code;
756*6236dae4SAndroid Build Coastguard Worker }
757*6236dae4SAndroid Build Coastguard Worker
sec_set_protection_level(struct Curl_easy * data)758*6236dae4SAndroid Build Coastguard Worker static int sec_set_protection_level(struct Curl_easy *data)
759*6236dae4SAndroid Build Coastguard Worker {
760*6236dae4SAndroid Build Coastguard Worker int code;
761*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn = data->conn;
762*6236dae4SAndroid Build Coastguard Worker unsigned char level = conn->request_data_prot;
763*6236dae4SAndroid Build Coastguard Worker
764*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(level > PROT_NONE && level < PROT_LAST);
765*6236dae4SAndroid Build Coastguard Worker
766*6236dae4SAndroid Build Coastguard Worker if(!conn->sec_complete) {
767*6236dae4SAndroid Build Coastguard Worker infof(data, "Trying to change the protection level after the"
768*6236dae4SAndroid Build Coastguard Worker " completion of the data exchange.");
769*6236dae4SAndroid Build Coastguard Worker return -1;
770*6236dae4SAndroid Build Coastguard Worker }
771*6236dae4SAndroid Build Coastguard Worker
772*6236dae4SAndroid Build Coastguard Worker /* Bail out if we try to set up the same level */
773*6236dae4SAndroid Build Coastguard Worker if(conn->data_prot == level)
774*6236dae4SAndroid Build Coastguard Worker return 0;
775*6236dae4SAndroid Build Coastguard Worker
776*6236dae4SAndroid Build Coastguard Worker if(level) {
777*6236dae4SAndroid Build Coastguard Worker char *pbsz;
778*6236dae4SAndroid Build Coastguard Worker unsigned int buffer_size = 1 << 20; /* 1048576 */
779*6236dae4SAndroid Build Coastguard Worker struct pingpong *pp = &conn->proto.ftpc.pp;
780*6236dae4SAndroid Build Coastguard Worker char *line;
781*6236dae4SAndroid Build Coastguard Worker
782*6236dae4SAndroid Build Coastguard Worker code = ftp_send_command(data, "PBSZ %u", buffer_size);
783*6236dae4SAndroid Build Coastguard Worker if(code < 0)
784*6236dae4SAndroid Build Coastguard Worker return -1;
785*6236dae4SAndroid Build Coastguard Worker
786*6236dae4SAndroid Build Coastguard Worker if(code/100 != 2) {
787*6236dae4SAndroid Build Coastguard Worker failf(data, "Failed to set the protection's buffer size.");
788*6236dae4SAndroid Build Coastguard Worker return -1;
789*6236dae4SAndroid Build Coastguard Worker }
790*6236dae4SAndroid Build Coastguard Worker conn->buffer_size = buffer_size;
791*6236dae4SAndroid Build Coastguard Worker
792*6236dae4SAndroid Build Coastguard Worker line = Curl_dyn_ptr(&pp->recvbuf);
793*6236dae4SAndroid Build Coastguard Worker pbsz = strstr(line, "PBSZ=");
794*6236dae4SAndroid Build Coastguard Worker if(pbsz) {
795*6236dae4SAndroid Build Coastguard Worker /* stick to default value if the check fails */
796*6236dae4SAndroid Build Coastguard Worker if(ISDIGIT(pbsz[5]))
797*6236dae4SAndroid Build Coastguard Worker buffer_size = (unsigned int)atoi(&pbsz[5]);
798*6236dae4SAndroid Build Coastguard Worker if(buffer_size < conn->buffer_size)
799*6236dae4SAndroid Build Coastguard Worker conn->buffer_size = buffer_size;
800*6236dae4SAndroid Build Coastguard Worker }
801*6236dae4SAndroid Build Coastguard Worker }
802*6236dae4SAndroid Build Coastguard Worker
803*6236dae4SAndroid Build Coastguard Worker /* Now try to negotiate the protection level. */
804*6236dae4SAndroid Build Coastguard Worker code = ftp_send_command(data, "PROT %c", level_to_char(level));
805*6236dae4SAndroid Build Coastguard Worker
806*6236dae4SAndroid Build Coastguard Worker if(code < 0)
807*6236dae4SAndroid Build Coastguard Worker return -1;
808*6236dae4SAndroid Build Coastguard Worker
809*6236dae4SAndroid Build Coastguard Worker if(code/100 != 2) {
810*6236dae4SAndroid Build Coastguard Worker failf(data, "Failed to set the protection level.");
811*6236dae4SAndroid Build Coastguard Worker return -1;
812*6236dae4SAndroid Build Coastguard Worker }
813*6236dae4SAndroid Build Coastguard Worker
814*6236dae4SAndroid Build Coastguard Worker conn->data_prot = level;
815*6236dae4SAndroid Build Coastguard Worker if(level == PROT_PRIVATE)
816*6236dae4SAndroid Build Coastguard Worker conn->command_prot = level;
817*6236dae4SAndroid Build Coastguard Worker
818*6236dae4SAndroid Build Coastguard Worker return 0;
819*6236dae4SAndroid Build Coastguard Worker }
820*6236dae4SAndroid Build Coastguard Worker
821*6236dae4SAndroid Build Coastguard Worker int
Curl_sec_request_prot(struct connectdata * conn,const char * level)822*6236dae4SAndroid Build Coastguard Worker Curl_sec_request_prot(struct connectdata *conn, const char *level)
823*6236dae4SAndroid Build Coastguard Worker {
824*6236dae4SAndroid Build Coastguard Worker unsigned char l = name_to_level(level);
825*6236dae4SAndroid Build Coastguard Worker if(l == PROT_NONE)
826*6236dae4SAndroid Build Coastguard Worker return -1;
827*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(l > PROT_NONE && l < PROT_LAST);
828*6236dae4SAndroid Build Coastguard Worker conn->request_data_prot = l;
829*6236dae4SAndroid Build Coastguard Worker return 0;
830*6236dae4SAndroid Build Coastguard Worker }
831*6236dae4SAndroid Build Coastguard Worker
choose_mech(struct Curl_easy * data,struct connectdata * conn)832*6236dae4SAndroid Build Coastguard Worker static CURLcode choose_mech(struct Curl_easy *data, struct connectdata *conn)
833*6236dae4SAndroid Build Coastguard Worker {
834*6236dae4SAndroid Build Coastguard Worker int ret;
835*6236dae4SAndroid Build Coastguard Worker void *tmp_allocation;
836*6236dae4SAndroid Build Coastguard Worker const struct Curl_sec_client_mech *mech = &Curl_krb5_client_mech;
837*6236dae4SAndroid Build Coastguard Worker
838*6236dae4SAndroid Build Coastguard Worker tmp_allocation = realloc(conn->app_data, mech->size);
839*6236dae4SAndroid Build Coastguard Worker if(!tmp_allocation) {
840*6236dae4SAndroid Build Coastguard Worker failf(data, "Failed realloc of size %zu", mech->size);
841*6236dae4SAndroid Build Coastguard Worker mech = NULL;
842*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
843*6236dae4SAndroid Build Coastguard Worker }
844*6236dae4SAndroid Build Coastguard Worker conn->app_data = tmp_allocation;
845*6236dae4SAndroid Build Coastguard Worker
846*6236dae4SAndroid Build Coastguard Worker if(mech->init) {
847*6236dae4SAndroid Build Coastguard Worker ret = mech->init(conn->app_data);
848*6236dae4SAndroid Build Coastguard Worker if(ret) {
849*6236dae4SAndroid Build Coastguard Worker infof(data, "Failed initialization for %s. Skipping it.",
850*6236dae4SAndroid Build Coastguard Worker mech->name);
851*6236dae4SAndroid Build Coastguard Worker return CURLE_FAILED_INIT;
852*6236dae4SAndroid Build Coastguard Worker }
853*6236dae4SAndroid Build Coastguard Worker Curl_dyn_init(&conn->in_buffer.buf, CURL_MAX_INPUT_LENGTH);
854*6236dae4SAndroid Build Coastguard Worker }
855*6236dae4SAndroid Build Coastguard Worker
856*6236dae4SAndroid Build Coastguard Worker infof(data, "Trying mechanism %s...", mech->name);
857*6236dae4SAndroid Build Coastguard Worker ret = ftp_send_command(data, "AUTH %s", mech->name);
858*6236dae4SAndroid Build Coastguard Worker if(ret < 0)
859*6236dae4SAndroid Build Coastguard Worker return CURLE_COULDNT_CONNECT;
860*6236dae4SAndroid Build Coastguard Worker
861*6236dae4SAndroid Build Coastguard Worker if(ret/100 != 3) {
862*6236dae4SAndroid Build Coastguard Worker switch(ret) {
863*6236dae4SAndroid Build Coastguard Worker case 504:
864*6236dae4SAndroid Build Coastguard Worker infof(data, "Mechanism %s is not supported by the server (server "
865*6236dae4SAndroid Build Coastguard Worker "returned ftp code: 504).", mech->name);
866*6236dae4SAndroid Build Coastguard Worker break;
867*6236dae4SAndroid Build Coastguard Worker case 534:
868*6236dae4SAndroid Build Coastguard Worker infof(data, "Mechanism %s was rejected by the server (server returned "
869*6236dae4SAndroid Build Coastguard Worker "ftp code: 534).", mech->name);
870*6236dae4SAndroid Build Coastguard Worker break;
871*6236dae4SAndroid Build Coastguard Worker default:
872*6236dae4SAndroid Build Coastguard Worker if(ret/100 == 5) {
873*6236dae4SAndroid Build Coastguard Worker infof(data, "server does not support the security extensions");
874*6236dae4SAndroid Build Coastguard Worker return CURLE_USE_SSL_FAILED;
875*6236dae4SAndroid Build Coastguard Worker }
876*6236dae4SAndroid Build Coastguard Worker break;
877*6236dae4SAndroid Build Coastguard Worker }
878*6236dae4SAndroid Build Coastguard Worker return CURLE_LOGIN_DENIED;
879*6236dae4SAndroid Build Coastguard Worker }
880*6236dae4SAndroid Build Coastguard Worker
881*6236dae4SAndroid Build Coastguard Worker /* Authenticate */
882*6236dae4SAndroid Build Coastguard Worker ret = mech->auth(conn->app_data, data, conn);
883*6236dae4SAndroid Build Coastguard Worker
884*6236dae4SAndroid Build Coastguard Worker if(ret != AUTH_CONTINUE) {
885*6236dae4SAndroid Build Coastguard Worker if(ret != AUTH_OK) {
886*6236dae4SAndroid Build Coastguard Worker /* Mechanism has dumped the error to stderr, do not error here. */
887*6236dae4SAndroid Build Coastguard Worker return CURLE_USE_SSL_FAILED;
888*6236dae4SAndroid Build Coastguard Worker }
889*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(ret == AUTH_OK);
890*6236dae4SAndroid Build Coastguard Worker
891*6236dae4SAndroid Build Coastguard Worker conn->mech = mech;
892*6236dae4SAndroid Build Coastguard Worker conn->sec_complete = 1;
893*6236dae4SAndroid Build Coastguard Worker conn->recv[FIRSTSOCKET] = sec_recv;
894*6236dae4SAndroid Build Coastguard Worker conn->send[FIRSTSOCKET] = sec_send;
895*6236dae4SAndroid Build Coastguard Worker conn->recv[SECONDARYSOCKET] = sec_recv;
896*6236dae4SAndroid Build Coastguard Worker conn->send[SECONDARYSOCKET] = sec_send;
897*6236dae4SAndroid Build Coastguard Worker conn->command_prot = PROT_SAFE;
898*6236dae4SAndroid Build Coastguard Worker /* Set the requested protection level */
899*6236dae4SAndroid Build Coastguard Worker /* BLOCKING */
900*6236dae4SAndroid Build Coastguard Worker (void)sec_set_protection_level(data);
901*6236dae4SAndroid Build Coastguard Worker }
902*6236dae4SAndroid Build Coastguard Worker
903*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
904*6236dae4SAndroid Build Coastguard Worker }
905*6236dae4SAndroid Build Coastguard Worker
906*6236dae4SAndroid Build Coastguard Worker CURLcode
Curl_sec_login(struct Curl_easy * data,struct connectdata * conn)907*6236dae4SAndroid Build Coastguard Worker Curl_sec_login(struct Curl_easy *data, struct connectdata *conn)
908*6236dae4SAndroid Build Coastguard Worker {
909*6236dae4SAndroid Build Coastguard Worker return choose_mech(data, conn);
910*6236dae4SAndroid Build Coastguard Worker }
911*6236dae4SAndroid Build Coastguard Worker
912*6236dae4SAndroid Build Coastguard Worker
913*6236dae4SAndroid Build Coastguard Worker void
Curl_sec_end(struct connectdata * conn)914*6236dae4SAndroid Build Coastguard Worker Curl_sec_end(struct connectdata *conn)
915*6236dae4SAndroid Build Coastguard Worker {
916*6236dae4SAndroid Build Coastguard Worker if(conn->mech && conn->mech->end)
917*6236dae4SAndroid Build Coastguard Worker conn->mech->end(conn->app_data);
918*6236dae4SAndroid Build Coastguard Worker Curl_safefree(conn->app_data);
919*6236dae4SAndroid Build Coastguard Worker Curl_dyn_free(&conn->in_buffer.buf);
920*6236dae4SAndroid Build Coastguard Worker conn->in_buffer.index = 0;
921*6236dae4SAndroid Build Coastguard Worker conn->in_buffer.eof_flag = 0;
922*6236dae4SAndroid Build Coastguard Worker conn->sec_complete = 0;
923*6236dae4SAndroid Build Coastguard Worker conn->data_prot = PROT_CLEAR;
924*6236dae4SAndroid Build Coastguard Worker conn->mech = NULL;
925*6236dae4SAndroid Build Coastguard Worker }
926*6236dae4SAndroid Build Coastguard Worker
927*6236dae4SAndroid Build Coastguard Worker #endif /* HAVE_GSSAPI && !CURL_DISABLE_FTP */
928