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"
40 __RCSID("$Heimdal: security.c 21225 2007-06-20 10:16:02Z lha $"
43 static enum protection_level command_prot
;
44 static enum protection_level data_prot
;
45 static size_t buffer_size
;
54 static struct buffer in_buffer
, out_buffer
;
58 enum protection_level level
;
61 { prot_clear
, "clear" },
62 { prot_safe
, "safe" },
63 { prot_confidential
, "confidential" },
64 { prot_private
, "private" }
68 level_to_name(enum protection_level level
)
71 for(i
= 0; i
< sizeof(level_names
) / sizeof(level_names
[0]); i
++)
72 if(level_names
[i
].level
== level
)
73 return level_names
[i
].name
;
77 #ifndef FTP_SERVER /* not used in server */
78 static enum protection_level
79 name_to_level(const char *name
)
82 for(i
= 0; i
< sizeof(level_names
) / sizeof(level_names
[0]); i
++)
83 if(!strncasecmp(level_names
[i
].name
, name
, strlen(name
)))
84 return level_names
[i
].level
;
85 return (enum protection_level
)-1;
91 static struct sec_server_mech
*mechs
[] = {
101 static struct sec_server_mech
*mech
;
105 static struct sec_client_mech
*mechs
[] = {
115 static struct sec_client_mech
*mech
;
119 static void *app_data
;
124 if(sec_complete
&& data_prot
) {
126 if(sec_read(fileno(F
), &c
, 1) <= 0)
134 block_read(int fd
, void *buf
, size_t len
)
136 unsigned char *p
= buf
;
139 b
= read(fd
, p
, len
);
147 return p
- (unsigned char*)buf
;
151 block_write(int fd
, void *buf
, size_t len
)
153 unsigned char *p
= buf
;
156 b
= write(fd
, p
, len
);
162 return p
- (unsigned char*)buf
;
166 sec_get_data(int fd
, struct buffer
*buf
, int level
)
172 b
= block_read(fd
, &len
, sizeof(len
));
178 tmp
= realloc(buf
->data
, len
);
182 b
= block_read(fd
, buf
->data
, len
);
187 buf
->size
= (*mech
->decode
)(app_data
, buf
->data
, len
, data_prot
);
193 buffer_read(struct buffer
*buf
, void *dataptr
, size_t len
)
195 len
= min(len
, buf
->size
- buf
->index
);
196 memcpy(dataptr
, (char*)buf
->data
+ buf
->index
, len
);
202 buffer_write(struct buffer
*buf
, void *dataptr
, size_t len
)
204 if(buf
->index
+ len
> buf
->size
) {
206 if(buf
->data
== NULL
)
209 tmp
= realloc(buf
->data
, buf
->index
+ len
);
213 buf
->size
= buf
->index
+ len
;
215 memcpy((char*)buf
->data
+ buf
->index
, dataptr
, len
);
221 sec_read(int fd
, void *dataptr
, int length
)
226 if(sec_complete
== 0 || data_prot
== 0)
227 return read(fd
, dataptr
, length
);
229 if(in_buffer
.eof_flag
){
230 in_buffer
.eof_flag
= 0;
234 len
= buffer_read(&in_buffer
, dataptr
, length
);
237 dataptr
= (char*)dataptr
+ len
;
242 ret
= sec_get_data(fd
, &in_buffer
, data_prot
);
245 if(ret
== 0 && in_buffer
.size
== 0) {
247 in_buffer
.eof_flag
= 1;
250 len
= buffer_read(&in_buffer
, dataptr
, length
);
253 dataptr
= (char*)dataptr
+ len
;
259 sec_send(int fd
, char *from
, int length
)
263 bytes
= (*mech
->encode
)(app_data
, from
, length
, data_prot
, &buf
);
264 bytes
= htonl(bytes
);
265 block_write(fd
, &bytes
, sizeof(bytes
));
266 block_write(fd
, buf
, ntohl(bytes
));
274 if(data_prot
!= prot_clear
) {
275 if(out_buffer
.index
> 0){
276 sec_write(fileno(F
), out_buffer
.data
, out_buffer
.index
);
277 out_buffer
.index
= 0;
279 sec_send(fileno(F
), NULL
, 0);
286 sec_write(int fd
, char *dataptr
, int length
)
288 int len
= buffer_size
;
291 if(data_prot
== prot_clear
)
292 return write(fd
, dataptr
, length
);
294 len
-= (*mech
->overhead
)(app_data
, data_prot
, len
);
298 sec_send(fd
, dataptr
, len
);
307 sec_vfprintf2(FILE *f
, const char *fmt
, va_list ap
)
311 if(data_prot
== prot_clear
)
312 return vfprintf(f
, fmt
, ap
);
315 len
= vasprintf(&buf
, fmt
, ap
);
318 ret
= buffer_write(&out_buffer
, buf
, len
);
325 sec_fprintf2(FILE *f
, const char *fmt
, ...)
330 ret
= sec_vfprintf2(f
, fmt
, ap
);
336 sec_putc(int c
, FILE *F
)
339 if(data_prot
== prot_clear
)
342 buffer_write(&out_buffer
, &ch
, 1);
343 if(c
== '\n' || out_buffer
.index
>= 1024 /* XXX */) {
344 sec_write(fileno(F
), out_buffer
.data
, out_buffer
.index
);
345 out_buffer
.index
= 0;
351 sec_read_msg(char *s
, int level
)
357 buf
= malloc(strlen(s
));
358 len
= base64_decode(s
+ 4, buf
); /* XXX */
360 len
= (*mech
->decode
)(app_data
, buf
, len
, level
);
369 sscanf(buf
, "%d", &return_code
);
370 if(buf
[len
-1] == '\n')
378 sec_vfprintf(FILE *f
, const char *fmt
, va_list ap
)
384 return vfprintf(f
, fmt
, ap
);
386 if (vasprintf(&buf
, fmt
, ap
) == -1) {
387 printf("Failed to allocate command.\n");
390 len
= (*mech
->encode
)(app_data
, buf
, strlen(buf
), command_prot
, &enc
);
393 printf("Failed to encode command.\n");
396 if(base64_encode(enc
, len
, &buf
) < 0){
398 printf("Out of memory base64-encoding.\n");
403 if(command_prot
== prot_safe
)
404 fprintf(f
, "631 %s\r\n", buf
);
405 else if(command_prot
== prot_private
)
406 fprintf(f
, "632 %s\r\n", buf
);
407 else if(command_prot
== prot_confidential
)
408 fprintf(f
, "633 %s\r\n", buf
);
410 if(command_prot
== prot_safe
)
411 fprintf(f
, "MIC %s", buf
);
412 else if(command_prot
== prot_private
)
413 fprintf(f
, "ENC %s", buf
);
414 else if(command_prot
== prot_confidential
)
415 fprintf(f
, "CONF %s", buf
);
422 sec_fprintf(FILE *f
, const char *fmt
, ...)
427 ret
= sec_vfprintf(f
, fmt
, ap
);
432 /* end common stuff */
439 auth(char *auth_name
)
444 for(i
= 0; (mech
= mechs
[i
]) != NULL
; i
++){
445 if(!strcasecmp(auth_name
, mech
->name
)){
446 tmp
= realloc(app_data
, mech
->size
);
448 reply(431, "Unable to accept %s at this time", mech
->name
);
453 if(mech
->init
&& (*mech
->init
)(app_data
) != 0) {
454 reply(431, "Unable to accept %s at this time", mech
->name
);
458 (*mech
->auth
)(app_data
);
462 reply(334, "Send authorization data.");
464 reply(234, "Authorization complete.");
470 reply(504, "%s is unknown to me", auth_name
);
474 adat(char *auth_data
)
476 if(mech
&& !sec_complete
) {
477 void *buf
= malloc(strlen(auth_data
));
479 len
= base64_decode(auth_data
, buf
);
480 (*mech
->adat
)(app_data
, buf
, len
);
483 reply(503, "You must %sissue an AUTH first.", mech
? "re-" : "");
490 reply(503, "Incomplete security data exchange.");
492 new = (*mech
->pbsz
)(app_data
, size
);
493 if(buffer_size
!= new){
497 reply(200, "PBSZ=%lu", (unsigned long)new);
507 if(buffer_size
== 0){
508 reply(503, "No protection buffer size negotiated.");
512 if(!strcasecmp(pl
, "C"))
514 else if(!strcasecmp(pl
, "S"))
516 else if(!strcasecmp(pl
, "E"))
517 p
= prot_confidential
;
518 else if(!strcasecmp(pl
, "P"))
521 reply(504, "Unrecognized protection level.");
526 if((*mech
->check_prot
)(app_data
, p
)){
527 reply(536, "%s does not support %s protection.",
528 mech
->name
, level_to_name(p
));
530 data_prot
= (enum protection_level
)p
;
531 reply(200, "Data protection is %s.", level_to_name(p
));
534 reply(503, "Incomplete security data exchange.");
541 if(mech
->ccc
&& (*mech
->ccc
)(app_data
) == 0) {
542 command_prot
= data_prot
= prot_clear
;
545 reply(534, "You must be joking.");
547 reply(503, "Incomplete security data exchange.");
550 void mec(char *msg
, enum protection_level level
)
553 size_t len
, buf_size
;
555 reply(503, "Incomplete security data exchange.");
558 buf_size
= strlen(msg
) + 2;
559 buf
= malloc(buf_size
);
560 len
= base64_decode(msg
, buf
);
561 command_prot
= level
;
562 if(len
== (size_t)-1) {
563 reply(501, "Failed to base64-decode command");
566 len
= (*mech
->decode
)(app_data
, buf
, len
, level
);
567 if(len
== (size_t)-1) {
568 reply(535, "Failed to decode command");
571 ((char*)buf
)[len
] = '\0';
572 if(strstr((char*)buf
, "\r\n") == NULL
)
573 strlcat((char*)buf
, "\r\n", buf_size
);
574 new_ftp_command(buf
);
577 /* ------------------------------------------------------------ */
580 sec_userok(char *userstr
)
583 return (*mech
->userok
)(app_data
, userstr
);
588 sec_session(char *user
)
590 if(sec_complete
&& mech
->session
)
591 return (*mech
->session
)(app_data
, user
);
598 new_ftp_command(char *command
)
600 ftp_command
= command
;
604 delete_ftp_command(void)
613 return ftp_command
!= NULL
;
616 enum protection_level
617 get_command_prot(void)
622 #else /* FTP_SERVER */
628 printf("Using %s for authentication.\n", mech
->name
);
629 printf("Using %s command channel.\n", level_to_name(command_prot
));
630 printf("Using %s data channel.\n", level_to_name(data_prot
));
632 printf("Protection buffer size: %lu.\n",
633 (unsigned long)buffer_size
);
635 printf("Not using any security mechanism.\n");
640 sec_prot_internal(int level
)
644 unsigned int s
= 1048576;
646 int old_verbose
= verbose
;
650 printf("No security data exchange has taken place.\n");
655 ret
= command("PBSZ %u", s
);
657 printf("Failed to set protection buffer size.\n");
661 p
= strstr(reply_string
, "PBSZ=");
663 sscanf(p
, "PBSZ=%u", &s
);
667 verbose
= old_verbose
;
668 ret
= command("PROT %c", level
["CSEP"]); /* XXX :-) */
670 printf("Failed to set protection level.\n");
674 data_prot
= (enum protection_level
)level
;
678 enum protection_level
679 set_command_prot(enum protection_level level
)
682 enum protection_level old
= command_prot
;
683 if(level
!= command_prot
&& level
== prot_clear
) {
684 ret
= command("CCC");
685 if(ret
!= COMPLETE
) {
686 printf("Failed to clear command channel.\n");
690 command_prot
= level
;
695 sec_prot(int argc
, char **argv
)
707 printf("No security data exchange has taken place.\n");
711 level
= name_to_level(argv
[argc
- 1]);
716 if((*mech
->check_prot
)(app_data
, level
)) {
717 printf("%s does not implement %s protection.\n",
718 mech
->name
, level_to_name(level
));
723 if(argc
== 2 || strncasecmp(argv
[1], "data", strlen(argv
[1])) == 0) {
724 if(sec_prot_internal(level
) < 0){
728 } else if(strncasecmp(argv
[1], "command", strlen(argv
[1])) == 0) {
729 if(set_command_prot(level
) < 0) {
738 printf("usage: %s [command|data] [clear|safe|confidential|private]\n",
744 sec_prot_command(int argc
, char **argv
)
752 printf("No security data exchange has taken place.\n");
760 level
= name_to_level(argv
[1]);
764 if((*mech
->check_prot
)(app_data
, level
)) {
765 printf("%s does not implement %s protection.\n",
766 mech
->name
, level_to_name(level
));
770 if(set_command_prot(level
) < 0) {
778 printf("usage: %s [clear|safe|confidential|private]\n",
783 static enum protection_level request_data_prot
;
786 sec_set_protection_level(void)
788 if(sec_complete
&& data_prot
!= request_data_prot
)
789 sec_prot_internal(request_data_prot
);
794 sec_request_prot(char *level
)
796 int l
= name_to_level(level
);
799 request_data_prot
= (enum protection_level
)l
;
804 sec_login(char *host
)
807 struct sec_client_mech
**m
;
808 int old_verbose
= verbose
;
810 verbose
= -1; /* shut up all messages this will produce (they
811 are usually not very user friendly) */
813 for(m
= mechs
; *m
&& (*m
)->name
; m
++) {
816 tmp
= realloc(app_data
, (*m
)->size
);
818 warnx ("realloc %lu failed", (unsigned long)(*m
)->size
);
823 if((*m
)->init
&& (*(*m
)->init
)(app_data
) != 0) {
824 printf("Skipping %s...\n", (*m
)->name
);
827 printf("Trying %s...\n", (*m
)->name
);
828 ret
= command("AUTH %s", (*m
)->name
);
831 printf("%s is not supported by the server.\n", (*m
)->name
);
832 }else if(code
== 534){
833 printf("%s rejected as security mechanism.\n", (*m
)->name
);
834 }else if(ret
== ERROR
) {
835 printf("The server doesn't support the FTP "
836 "security extensions.\n");
837 verbose
= old_verbose
;
843 ret
= (*(*m
)->auth
)(app_data
, host
);
845 if(ret
== AUTH_CONTINUE
)
847 else if(ret
!= AUTH_OK
){
848 /* mechanism is supposed to output error string */
849 verbose
= old_verbose
;
855 command_prot
= prot_private
;
856 request_data_prot
= prot_private
;
858 command_prot
= prot_safe
;
863 verbose
= old_verbose
;
872 (*mech
->end
)(app_data
);
873 if (app_data
!= NULL
) {
874 memset(app_data
, 0, mech
->size
);
880 data_prot
= (enum protection_level
)0;
883 #endif /* FTP_SERVER */