1 /* This source code was modified by Martin Hedenfalk <mhe@stacken.kth.se> for
2 * use in Curl. His latest changes were done 2000-09-18.
4 * It has since been patched and modified a lot by Daniel Stenberg
5 * <daniel@haxx.se> to make it better applied to curl conditions, and to make
6 * it not use globals, pollute name space and more. This source code awaits a
7 * rewrite to work around the paragraph 2 in the BSD licenses as explained
10 * Copyright (c) 1998, 1999 Kungliga Tekniska Högskolan
11 * (Royal Institute of Technology, Stockholm, Sweden).
12 * All rights reserved.
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
18 * 1. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
25 * 3. Neither the name of the Institute nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43 #ifndef CURL_DISABLE_FTP
46 #define _MPRINTF_REPLACE /* we want curl-functions instead of native ones */
47 #include <curl/mprintf.h>
64 /* The last #include file should be: */
67 #define min(a, b) ((a) < (b) ? (a) : (b))
70 enum protection_level level
;
73 { prot_clear
, "clear" },
74 { prot_safe
, "safe" },
75 { prot_confidential
, "confidential" },
76 { prot_private
, "private" }
79 static enum protection_level
80 name_to_level(const char *name
)
83 for(i
= 0; i
< (int)sizeof(level_names
)/(int)sizeof(level_names
[0]); i
++)
84 if(curl_strnequal(level_names
[i
].name
, name
, strlen(name
)))
85 return level_names
[i
].level
;
86 return (enum protection_level
)-1;
89 static const struct Curl_sec_client_mech
* const mechs
[] = {
94 &Curl_krb4_client_mech
,
100 Curl_sec_getc(struct connectdata
*conn
, FILE *F
)
102 if(conn
->sec_complete
&& conn
->data_prot
) {
104 if(Curl_sec_read(conn
, fileno(F
), &c
, 1) <= 0)
113 block_read(int fd
, void *buf
, size_t len
)
115 unsigned char *p
= buf
;
118 b
= read(fd
, p
, len
);
126 return p
- (unsigned char*)buf
;
130 block_write(int fd
, void *buf
, size_t len
)
132 unsigned char *p
= buf
;
135 b
= write(fd
, p
, len
);
141 return p
- (unsigned char*)buf
;
145 sec_get_data(struct connectdata
*conn
,
146 int fd
, struct krb4buffer
*buf
)
151 b
= block_read(fd
, &len
, sizeof(len
));
157 buf
->data
= realloc(buf
->data
, len
);
158 b
= block_read(fd
, buf
->data
, len
);
163 buf
->size
= (conn
->mech
->decode
)(conn
->app_data
, buf
->data
, len
,
164 conn
->data_prot
, conn
);
170 buffer_read(struct krb4buffer
*buf
, void *data
, size_t len
)
172 len
= min(len
, buf
->size
- buf
->index
);
173 memcpy(data
, (char*)buf
->data
+ buf
->index
, len
);
179 buffer_write(struct krb4buffer
*buf
, void *data
, size_t len
)
181 if(buf
->index
+ len
> buf
->size
) {
183 if(buf
->data
== NULL
)
186 tmp
= realloc(buf
->data
, buf
->index
+ len
);
190 buf
->size
= buf
->index
+ len
;
192 memcpy((char*)buf
->data
+ buf
->index
, data
, len
);
198 Curl_sec_read(struct connectdata
*conn
, int fd
, void *buffer
, int length
)
203 if(conn
->sec_complete
== 0 || conn
->data_prot
== 0)
204 return read(fd
, buffer
, length
);
206 if(conn
->in_buffer
.eof_flag
){
207 conn
->in_buffer
.eof_flag
= 0;
211 len
= buffer_read(&conn
->in_buffer
, buffer
, length
);
214 buffer
= (char*)buffer
+ len
;
217 if(sec_get_data(conn
, fd
, &conn
->in_buffer
) < 0)
219 if(conn
->in_buffer
.size
== 0) {
221 conn
->in_buffer
.eof_flag
= 1;
224 len
= buffer_read(&conn
->in_buffer
, buffer
, length
);
227 buffer
= (char*)buffer
+ len
;
233 sec_send(struct connectdata
*conn
, int fd
, char *from
, int length
)
237 bytes
= (conn
->mech
->encode
)(conn
->app_data
, from
, length
, conn
->data_prot
,
239 bytes
= htonl(bytes
);
240 block_write(fd
, &bytes
, sizeof(bytes
));
241 block_write(fd
, buf
, ntohl(bytes
));
247 Curl_sec_fflush_fd(struct connectdata
*conn
, int fd
)
249 if(conn
->data_prot
!= prot_clear
) {
250 if(conn
->out_buffer
.index
> 0){
251 Curl_sec_write(conn
, fd
,
252 conn
->out_buffer
.data
, conn
->out_buffer
.index
);
253 conn
->out_buffer
.index
= 0;
255 sec_send(conn
, fd
, NULL
, 0);
261 Curl_sec_write(struct connectdata
*conn
, int fd
, char *buffer
, int length
)
263 int len
= conn
->buffer_size
;
266 if(conn
->data_prot
== prot_clear
)
267 return write(fd
, buffer
, length
);
269 len
-= (conn
->mech
->overhead
)(conn
->app_data
, conn
->data_prot
, len
);
273 sec_send(conn
, fd
, buffer
, len
);
282 Curl_sec_send(struct connectdata
*conn
, int num
, char *buffer
, int length
)
284 curl_socket_t fd
= conn
->sock
[num
];
285 return (ssize_t
)Curl_sec_write(conn
, fd
, buffer
, length
);
289 Curl_sec_putc(struct connectdata
*conn
, int c
, FILE *F
)
292 if(conn
->data_prot
== prot_clear
)
295 buffer_write(&conn
->out_buffer
, &ch
, 1);
296 if(c
== '\n' || conn
->out_buffer
.index
>= 1024 /* XXX */) {
297 Curl_sec_write(conn
, fileno(F
), conn
->out_buffer
.data
,
298 conn
->out_buffer
.index
);
299 conn
->out_buffer
.index
= 0;
305 Curl_sec_read_msg(struct connectdata
*conn
, char *s
, int level
)
311 len
= Curl_base64_decode(s
+ 4, &buf
); /* XXX */
313 len
= (conn
->mech
->decode
)(conn
->app_data
, buf
, len
, level
, conn
);
327 sscanf((char *)buf
, "%d", &code
);
328 if(buf
[len
-1] == '\n')
330 strcpy(s
, (char *)buf
);
335 enum protection_level
336 Curl_set_command_prot(struct connectdata
*conn
, enum protection_level level
)
338 enum protection_level old
= conn
->command_prot
;
339 conn
->command_prot
= level
;
344 sec_prot_internal(struct connectdata
*conn
, int level
)
347 unsigned int s
= 1048576;
350 if(!conn
->sec_complete
){
351 infof(conn
->data
, "No security data exchange has taken place.\n");
357 if(Curl_ftpsendf(conn
, "PBSZ %u", s
))
360 if(Curl_GetFTPResponse(&nread
, conn
, &code
))
364 failf(conn
->data
, "Failed to set protection buffer size.");
367 conn
->buffer_size
= s
;
369 p
= strstr(conn
->data
->state
.buffer
, "PBSZ=");
371 sscanf(p
, "PBSZ=%u", &s
);
372 if(s
< conn
->buffer_size
)
373 conn
->buffer_size
= s
;
376 if(Curl_ftpsendf(conn
, "PROT %c", level
["CSEP"]))
379 if(Curl_GetFTPResponse(&nread
, conn
, NULL
))
382 if(conn
->data
->state
.buffer
[0] != '2'){
383 failf(conn
->data
, "Failed to set protection level.");
387 conn
->data_prot
= (enum protection_level
)level
;
392 Curl_sec_set_protection_level(struct connectdata
*conn
)
394 if(conn
->sec_complete
&& conn
->data_prot
!= conn
->request_data_prot
)
395 sec_prot_internal(conn
, conn
->request_data_prot
);
400 Curl_sec_request_prot(struct connectdata
*conn
, const char *level
)
402 int l
= name_to_level(level
);
405 conn
->request_data_prot
= (enum protection_level
)l
;
410 Curl_sec_login(struct connectdata
*conn
)
413 const struct Curl_sec_client_mech
* const *m
;
415 struct SessionHandle
*data
=conn
->data
;
418 for(m
= mechs
; *m
&& (*m
)->name
; m
++) {
421 tmp
= realloc(conn
->app_data
, (*m
)->size
);
423 failf (data
, "realloc %u failed", (*m
)->size
);
426 conn
->app_data
= tmp
;
428 if((*m
)->init
&& (*(*m
)->init
)(conn
->app_data
) != 0) {
429 infof(data
, "Skipping %s...\n", (*m
)->name
);
432 infof(data
, "Trying %s...\n", (*m
)->name
);
434 if(Curl_ftpsendf(conn
, "AUTH %s", (*m
)->name
))
437 if(Curl_GetFTPResponse(&nread
, conn
, &ftpcode
))
440 if(conn
->data
->state
.buffer
[0] != '3'){
444 "%s is not supported by the server.\n", (*m
)->name
);
447 infof(data
, "%s rejected as security mechanism.\n", (*m
)->name
);
450 if(conn
->data
->state
.buffer
[0] == '5') {
451 infof(data
, "The server doesn't support the FTP "
452 "security extensions.\n");
460 ret
= (*(*m
)->auth
)(conn
->app_data
, conn
);
462 if(ret
== AUTH_CONTINUE
)
464 else if(ret
!= AUTH_OK
){
465 /* mechanism is supposed to output error string */
469 conn
->sec_complete
= 1;
470 conn
->command_prot
= prot_safe
;
478 Curl_sec_end(struct connectdata
*conn
)
480 if (conn
->mech
!= NULL
) {
482 (conn
->mech
->end
)(conn
->app_data
);
483 memset(conn
->app_data
, 0, conn
->mech
->size
);
484 free(conn
->app_data
);
485 conn
->app_data
= NULL
;
487 conn
->sec_complete
= 0;
488 conn
->data_prot
= (enum protection_level
)0;
492 #endif /* HAVE_KRB4 */
493 #endif /* CURL_DISABLE_FTP */