2 * Copyright (c) 1998-2002, 2005 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #include "ftpd_locl.h"
42 static enum protection_level command_prot
;
43 static enum protection_level data_prot
;
44 static size_t buffer_size
;
53 static struct buffer in_buffer
, out_buffer
;
57 enum protection_level level
;
60 { prot_clear
, "clear" },
61 { prot_safe
, "safe" },
62 { prot_confidential
, "confidential" },
63 { prot_private
, "private" }
67 level_to_name(enum protection_level level
)
70 for(i
= 0; i
< sizeof(level_names
) / sizeof(level_names
[0]); i
++)
71 if(level_names
[i
].level
== level
)
72 return level_names
[i
].name
;
76 #ifndef FTP_SERVER /* not used in server */
77 static enum protection_level
78 name_to_level(const char *name
)
81 for(i
= 0; i
< sizeof(level_names
) / sizeof(level_names
[0]); i
++)
82 if(!strncasecmp(level_names
[i
].name
, name
, strlen(name
)))
83 return level_names
[i
].level
;
90 static struct sec_server_mech
*mechs
[] = {
97 static struct sec_server_mech
*mech
;
101 static struct sec_client_mech
*mechs
[] = {
108 static struct sec_client_mech
*mech
;
112 static void *app_data
;
117 if(sec_complete
&& data_prot
) {
119 if(sec_read(fileno(F
), &c
, 1) <= 0)
127 block_read(int fd
, void *buf
, size_t len
)
129 unsigned char *p
= buf
;
132 b
= read(fd
, p
, len
);
140 return p
- (unsigned char*)buf
;
144 block_write(int fd
, void *buf
, size_t len
)
146 unsigned char *p
= buf
;
149 b
= write(fd
, p
, len
);
155 return p
- (unsigned char*)buf
;
159 sec_get_data(int fd
, struct buffer
*buf
, int level
)
165 b
= block_read(fd
, &len
, sizeof(len
));
171 tmp
= realloc(buf
->data
, len
);
175 b
= block_read(fd
, buf
->data
, len
);
180 buf
->size
= (*mech
->decode
)(app_data
, buf
->data
, len
, data_prot
);
186 buffer_read(struct buffer
*buf
, void *dataptr
, size_t len
)
188 len
= min(len
, buf
->size
- buf
->index
);
189 memcpy(dataptr
, (char*)buf
->data
+ buf
->index
, len
);
195 buffer_write(struct buffer
*buf
, void *dataptr
, size_t len
)
197 if(buf
->index
+ len
> buf
->size
) {
199 if(buf
->data
== NULL
)
202 tmp
= realloc(buf
->data
, buf
->index
+ len
);
206 buf
->size
= buf
->index
+ len
;
208 memcpy((char*)buf
->data
+ buf
->index
, dataptr
, len
);
214 sec_read(int fd
, void *dataptr
, int length
)
219 if(sec_complete
== 0 || data_prot
== 0)
220 return read(fd
, dataptr
, length
);
222 if(in_buffer
.eof_flag
){
223 in_buffer
.eof_flag
= 0;
227 len
= buffer_read(&in_buffer
, dataptr
, length
);
230 dataptr
= (char*)dataptr
+ len
;
235 ret
= sec_get_data(fd
, &in_buffer
, data_prot
);
238 if(ret
== 0 && in_buffer
.size
== 0) {
240 in_buffer
.eof_flag
= 1;
243 len
= buffer_read(&in_buffer
, dataptr
, length
);
246 dataptr
= (char*)dataptr
+ len
;
252 sec_send(int fd
, char *from
, int length
)
256 bytes
= (*mech
->encode
)(app_data
, from
, length
, data_prot
, &buf
);
257 bytes
= htonl(bytes
);
258 block_write(fd
, &bytes
, sizeof(bytes
));
259 block_write(fd
, buf
, ntohl(bytes
));
267 if(data_prot
!= prot_clear
) {
268 if(out_buffer
.index
> 0){
269 sec_write(fileno(F
), out_buffer
.data
, out_buffer
.index
);
270 out_buffer
.index
= 0;
272 sec_send(fileno(F
), NULL
, 0);
279 sec_write(int fd
, char *dataptr
, int length
)
281 int len
= buffer_size
;
284 if(data_prot
== prot_clear
)
285 return write(fd
, dataptr
, length
);
287 len
-= (*mech
->overhead
)(app_data
, data_prot
, len
);
291 sec_send(fd
, dataptr
, len
);
300 sec_vfprintf2(FILE *f
, const char *fmt
, va_list ap
)
304 if(data_prot
== prot_clear
)
305 return vfprintf(f
, fmt
, ap
);
308 len
= vasprintf(&buf
, fmt
, ap
);
311 ret
= buffer_write(&out_buffer
, buf
, len
);
318 sec_fprintf2(FILE *f
, const char *fmt
, ...)
323 ret
= sec_vfprintf2(f
, fmt
, ap
);
329 sec_putc(int c
, FILE *F
)
332 if(data_prot
== prot_clear
)
335 buffer_write(&out_buffer
, &ch
, 1);
336 if(c
== '\n' || out_buffer
.index
>= 1024 /* XXX */) {
337 sec_write(fileno(F
), out_buffer
.data
, out_buffer
.index
);
338 out_buffer
.index
= 0;
344 sec_read_msg(char *s
, int level
)
350 buf
= malloc(strlen(s
));
351 len
= rk_base64_decode(s
+ 4, buf
); /* XXX */
353 len
= (*mech
->decode
)(app_data
, buf
, len
, level
);
362 sscanf(buf
, "%d", &return_code
);
363 if(buf
[len
-1] == '\n')
371 sec_vfprintf(FILE *f
, const char *fmt
, va_list ap
)
377 return vfprintf(f
, fmt
, ap
);
379 if (vasprintf(&buf
, fmt
, ap
) == -1) {
380 printf("Failed to allocate command.\n");
383 len
= (*mech
->encode
)(app_data
, buf
, strlen(buf
), command_prot
, &enc
);
386 printf("Failed to encode command.\n");
389 if(rk_base64_encode(enc
, len
, &buf
) < 0){
391 printf("Out of memory base64-encoding.\n");
396 if(command_prot
== prot_safe
)
397 fprintf(f
, "631 %s\r\n", buf
);
398 else if(command_prot
== prot_private
)
399 fprintf(f
, "632 %s\r\n", buf
);
400 else if(command_prot
== prot_confidential
)
401 fprintf(f
, "633 %s\r\n", buf
);
403 if(command_prot
== prot_safe
)
404 fprintf(f
, "MIC %s", buf
);
405 else if(command_prot
== prot_private
)
406 fprintf(f
, "ENC %s", buf
);
407 else if(command_prot
== prot_confidential
)
408 fprintf(f
, "CONF %s", buf
);
415 sec_fprintf(FILE *f
, const char *fmt
, ...)
420 ret
= sec_vfprintf(f
, fmt
, ap
);
425 /* end common stuff */
432 auth(char *auth_name
)
437 for(i
= 0; (mech
= mechs
[i
]) != NULL
; i
++){
438 if(!strcasecmp(auth_name
, mech
->name
)){
439 tmp
= realloc(app_data
, mech
->size
);
441 reply(431, "Unable to accept %s at this time", mech
->name
);
446 if(mech
->init
&& (*mech
->init
)(app_data
) != 0) {
447 reply(431, "Unable to accept %s at this time", mech
->name
);
451 (*mech
->auth
)(app_data
);
455 reply(334, "Send authorization data.");
457 reply(234, "Authorization complete.");
463 reply(504, "%s is unknown to me", auth_name
);
467 adat(char *auth_data
)
469 if(mech
&& !sec_complete
) {
470 void *buf
= malloc(strlen(auth_data
));
472 len
= rk_base64_decode(auth_data
, buf
);
473 (*mech
->adat
)(app_data
, buf
, len
);
476 reply(503, "You must %sissue an AUTH first.", mech
? "re-" : "");
483 reply(503, "Incomplete security data exchange.");
485 new = (*mech
->pbsz
)(app_data
, size
);
486 if(buffer_size
!= new){
490 reply(200, "PBSZ=%lu", (unsigned long)new);
500 if(buffer_size
== 0){
501 reply(503, "No protection buffer size negotiated.");
505 if(!strcasecmp(pl
, "C"))
507 else if(!strcasecmp(pl
, "S"))
509 else if(!strcasecmp(pl
, "E"))
510 p
= prot_confidential
;
511 else if(!strcasecmp(pl
, "P"))
514 reply(504, "Unrecognized protection level.");
519 if((*mech
->check_prot
)(app_data
, p
)){
520 reply(536, "%s does not support %s protection.",
521 mech
->name
, level_to_name(p
));
523 data_prot
= (enum protection_level
)p
;
524 reply(200, "Data protection is %s.", level_to_name(p
));
527 reply(503, "Incomplete security data exchange.");
534 if(mech
->ccc
&& (*mech
->ccc
)(app_data
) == 0) {
535 command_prot
= data_prot
= prot_clear
;
538 reply(534, "You must be joking.");
540 reply(503, "Incomplete security data exchange.");
543 void mec(char *msg
, enum protection_level level
)
546 size_t len
, buf_size
;
548 reply(503, "Incomplete security data exchange.");
551 buf_size
= strlen(msg
) + 2;
552 buf
= malloc(buf_size
);
554 reply(501, "Failed to allocate %lu", (unsigned long)buf_size
);
557 len
= rk_base64_decode(msg
, buf
);
558 command_prot
= level
;
559 if(len
== (size_t)-1) {
561 reply(501, "Failed to base64-decode command");
564 len
= (*mech
->decode
)(app_data
, buf
, len
, level
);
565 if(len
== (size_t)-1) {
567 reply(535, "Failed to decode command");
570 ((char*)buf
)[len
] = '\0';
571 if(strstr((char*)buf
, "\r\n") == NULL
)
572 strlcat((char*)buf
, "\r\n", buf_size
);
573 new_ftp_command(buf
);
576 /* ------------------------------------------------------------ */
579 sec_userok(char *userstr
)
582 return (*mech
->userok
)(app_data
, userstr
);
587 sec_session(char *user
)
589 if(sec_complete
&& mech
->session
)
590 return (*mech
->session
)(app_data
, user
);
597 new_ftp_command(char *command
)
599 ftp_command
= command
;
603 delete_ftp_command(void)
612 return ftp_command
!= NULL
;
615 enum protection_level
616 get_command_prot(void)
621 #else /* FTP_SERVER */
627 printf("Using %s for authentication.\n", mech
->name
);
628 printf("Using %s command channel.\n", level_to_name(command_prot
));
629 printf("Using %s data channel.\n", level_to_name(data_prot
));
631 printf("Protection buffer size: %lu.\n",
632 (unsigned long)buffer_size
);
634 printf("Not using any security mechanism.\n");
639 sec_prot_internal(int level
)
643 unsigned int s
= 1048576;
645 int old_verbose
= verbose
;
649 printf("No security data exchange has taken place.\n");
654 ret
= command("PBSZ %u", s
);
656 printf("Failed to set protection buffer size.\n");
660 p
= strstr(reply_string
, "PBSZ=");
662 sscanf(p
, "PBSZ=%u", &s
);
666 verbose
= old_verbose
;
667 ret
= command("PROT %c", level
["CSEP"]); /* XXX :-) */
669 printf("Failed to set protection level.\n");
673 data_prot
= (enum protection_level
)level
;
677 enum protection_level
678 set_command_prot(enum protection_level level
)
681 enum protection_level old
= command_prot
;
682 if(level
!= command_prot
&& level
== prot_clear
) {
683 ret
= command("CCC");
684 if(ret
!= COMPLETE
) {
685 printf("Failed to clear command channel.\n");
689 command_prot
= level
;
694 sec_prot(int argc
, char **argv
)
706 printf("No security data exchange has taken place.\n");
710 level
= name_to_level(argv
[argc
- 1]);
715 if((*mech
->check_prot
)(app_data
, level
)) {
716 printf("%s does not implement %s protection.\n",
717 mech
->name
, level_to_name(level
));
722 if(argc
== 2 || strncasecmp(argv
[1], "data", strlen(argv
[1])) == 0) {
723 if(sec_prot_internal(level
) < 0){
727 } else if(strncasecmp(argv
[1], "command", strlen(argv
[1])) == 0) {
728 if(set_command_prot(level
) < 0) {
737 printf("usage: %s [command|data] [clear|safe|confidential|private]\n",
743 sec_prot_command(int argc
, char **argv
)
751 printf("No security data exchange has taken place.\n");
759 level
= name_to_level(argv
[1]);
763 if((*mech
->check_prot
)(app_data
, level
)) {
764 printf("%s does not implement %s protection.\n",
765 mech
->name
, level_to_name(level
));
769 if(set_command_prot(level
) < 0) {
777 printf("usage: %s [clear|safe|confidential|private]\n",
782 static enum protection_level request_data_prot
;
785 sec_set_protection_level(void)
787 if(sec_complete
&& data_prot
!= request_data_prot
)
788 sec_prot_internal(request_data_prot
);
793 sec_request_prot(char *level
)
795 int l
= name_to_level(level
);
798 request_data_prot
= (enum protection_level
)l
;
803 sec_login(char *host
)
806 struct sec_client_mech
**m
;
807 int old_verbose
= verbose
;
809 verbose
= -1; /* shut up all messages this will produce (they
810 are usually not very user friendly) */
812 for(m
= mechs
; *m
&& (*m
)->name
; m
++) {
815 tmp
= realloc(app_data
, (*m
)->size
);
817 warnx ("realloc %lu failed", (unsigned long)(*m
)->size
);
822 if((*m
)->init
&& (*(*m
)->init
)(app_data
) != 0) {
823 printf("Skipping %s...\n", (*m
)->name
);
826 printf("Trying %s...\n", (*m
)->name
);
827 ret
= command("AUTH %s", (*m
)->name
);
830 printf("%s is not supported by the server.\n", (*m
)->name
);
831 }else if(code
== 534){
832 printf("%s rejected as security mechanism.\n", (*m
)->name
);
833 }else if(ret
== ERROR
) {
834 printf("The server doesn't support the FTP "
835 "security extensions.\n");
836 verbose
= old_verbose
;
842 ret
= (*(*m
)->auth
)(app_data
, host
);
844 if(ret
== AUTH_CONTINUE
)
846 else if(ret
!= AUTH_OK
){
847 /* mechanism is supposed to output error string */
848 verbose
= old_verbose
;
854 command_prot
= prot_private
;
855 request_data_prot
= prot_private
;
857 command_prot
= prot_safe
;
862 verbose
= old_verbose
;
871 (*mech
->end
)(app_data
);
872 if (app_data
!= NULL
) {
873 memset(app_data
, 0, mech
->size
);
879 data_prot
= (enum protection_level
)0;
882 #endif /* FTP_SERVER */