2 * Copyright (c) 1998-2002 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("$Id: security.c,v 1.19 2002/09/04 22:01:28 joda Exp $");
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;
84 return (enum protection_level)-1;
90 static struct sec_server_mech *mechs[] = {
100 static struct sec_server_mech *mech;
104 static struct sec_client_mech *mechs[] = {
114 static struct sec_client_mech *mech;
118 static void *app_data;
123 if(sec_complete && data_prot) {
125 if(sec_read(fileno(F), &c, 1) <= 0)
133 block_read(int fd, void *buf, size_t len)
135 unsigned char *p = buf;
138 b = read(fd, p, len);
146 return p - (unsigned char*)buf;
150 block_write(int fd, void *buf, size_t len)
152 unsigned char *p = buf;
155 b = write(fd, p, len);
161 return p - (unsigned char*)buf;
165 sec_get_data(int fd, struct buffer *buf, int level)
171 b = block_read(fd, &len, sizeof(len));
177 tmp = realloc(buf->data, len);
181 b = block_read(fd, buf->data, len);
186 buf->size = (*mech->decode)(app_data, buf->data, len, data_prot);
192 buffer_read(struct buffer *buf, void *data, size_t len)
194 len = min(len, buf->size - buf->index);
195 memcpy(data, (char*)buf->data + buf->index, len);
201 buffer_write(struct buffer *buf, void *data, size_t len)
203 if(buf->index + len > buf->size) {
205 if(buf->data == NULL)
208 tmp = realloc(buf->data, buf->index + len);
212 buf->size = buf->index + len;
214 memcpy((char*)buf->data + buf->index, data, len);
220 sec_read(int fd, void *data, int length)
225 if(sec_complete == 0 || data_prot == 0)
226 return read(fd, data, length);
228 if(in_buffer.eof_flag){
229 in_buffer.eof_flag = 0;
233 len = buffer_read(&in_buffer, data, length);
236 data = (char*)data + len;
241 ret = sec_get_data(fd, &in_buffer, data_prot);
244 if(ret == 0 && in_buffer.size == 0) {
246 in_buffer.eof_flag = 1;
249 len = buffer_read(&in_buffer, data, length);
252 data = (char*)data + len;
258 sec_send(int fd, char *from, int length)
262 bytes = (*mech->encode)(app_data, from, length, data_prot, &buf);
263 bytes = htonl(bytes);
264 block_write(fd, &bytes, sizeof(bytes));
265 block_write(fd, buf, ntohl(bytes));
273 if(data_prot != prot_clear) {
274 if(out_buffer.index > 0){
275 sec_write(fileno(F), out_buffer.data, out_buffer.index);
276 out_buffer.index = 0;
278 sec_send(fileno(F), NULL, 0);
285 sec_write(int fd, char *data, int length)
287 int len = buffer_size;
290 if(data_prot == prot_clear)
291 return write(fd, data, length);
293 len -= (*mech->overhead)(app_data, data_prot, len);
297 sec_send(fd, data, len);
306 sec_vfprintf2(FILE *f, const char *fmt, va_list ap)
310 if(data_prot == prot_clear)
311 return vfprintf(f, fmt, ap);
313 vasprintf(&buf, fmt, ap);
314 ret = buffer_write(&out_buffer, buf, strlen(buf));
321 sec_fprintf2(FILE *f, const char *fmt, ...)
326 ret = sec_vfprintf2(f, fmt, ap);
332 sec_putc(int c, FILE *F)
335 if(data_prot == prot_clear)
338 buffer_write(&out_buffer, &ch, 1);
339 if(c == '\n' || out_buffer.index >= 1024 /* XXX */) {
340 sec_write(fileno(F), out_buffer.data, out_buffer.index);
341 out_buffer.index = 0;
347 sec_read_msg(char *s, int level)
353 buf = malloc(strlen(s));
354 len = base64_decode(s + 4, buf); /* XXX */
356 len = (*mech->decode)(app_data, buf, len, level);
365 sscanf(buf, "%d", &code);
366 if(buf[len-1] == '\n')
374 sec_vfprintf(FILE *f, const char *fmt, va_list ap)
380 return vfprintf(f, fmt, ap);
382 vasprintf(&buf, fmt, ap);
383 len = (*mech->encode)(app_data, buf, strlen(buf), command_prot, &enc);
386 printf("Failed to encode command.\n");
389 if(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 */
430 auth(char *auth_name)
435 for(i = 0; (mech = mechs[i]) != NULL; i++){
436 if(!strcasecmp(auth_name, mech->name)){
437 tmp = realloc(app_data, mech->size);
439 reply(431, "Unable to accept %s at this time", mech->name);
444 if(mech->init && (*mech->init)(app_data) != 0) {
445 reply(431, "Unable to accept %s at this time", mech->name);
449 (*mech->auth)(app_data);
453 reply(334, "Send authorization data.");
455 reply(234, "Authorization complete.");
461 reply(504, "%s is unknown to me", auth_name);
465 adat(char *auth_data)
467 if(mech && !sec_complete) {
468 void *buf = malloc(strlen(auth_data));
470 len = base64_decode(auth_data, buf);
471 (*mech->adat)(app_data, buf, len);
474 reply(503, "You must %sissue an AUTH first.", mech ? "re-" : "");
481 reply(503, "Incomplete security data exchange.");
483 new = (*mech->pbsz)(app_data, size);
484 if(buffer_size != new){
488 reply(200, "PBSZ=%lu", (unsigned long)new);
498 if(buffer_size == 0){
499 reply(503, "No protection buffer size negotiated.");
503 if(!strcasecmp(pl, "C"))
505 else if(!strcasecmp(pl, "S"))
507 else if(!strcasecmp(pl, "E"))
508 p = prot_confidential;
509 else if(!strcasecmp(pl, "P"))
512 reply(504, "Unrecognized protection level.");
517 if((*mech->check_prot)(app_data, p)){
518 reply(536, "%s does not support %s protection.",
519 mech->name, level_to_name(p));
521 data_prot = (enum protection_level)p;
522 reply(200, "Data protection is %s.", level_to_name(p));
525 reply(503, "Incomplete security data exchange.");
532 if(mech->ccc && (*mech->ccc)(app_data) == 0)
533 command_prot = data_prot = prot_clear;
535 reply(534, "You must be joking.");
537 reply(503, "Incomplete security data exchange.");
540 void mec(char *msg, enum protection_level level)
545 reply(503, "Incomplete security data exchange.");
548 buf = malloc(strlen(msg) + 2); /* XXX go figure out where that 2
550 len = base64_decode(msg, buf);
551 command_prot = level;
552 if(len == (size_t)-1) {
553 reply(501, "Failed to base64-decode command");
556 len = (*mech->decode)(app_data, buf, len, level);
557 if(len == (size_t)-1) {
558 reply(535, "Failed to decode command");
561 ((char*)buf)[len] = '\0';
562 if(strstr((char*)buf, "\r\n") == NULL)
563 strcat((char*)buf, "\r\n");
564 new_ftp_command(buf);
567 /* ------------------------------------------------------------ */
570 sec_userok(char *user)
573 return (*mech->userok)(app_data, user);
580 new_ftp_command(char *command)
582 ftp_command = command;
586 delete_ftp_command(void)
595 return ftp_command != NULL;
598 enum protection_level
599 get_command_prot(void)
604 #else /* FTP_SERVER */
610 printf("Using %s for authentication.\n", mech->name);
611 printf("Using %s command channel.\n", level_to_name(command_prot));
612 printf("Using %s data channel.\n", level_to_name(data_prot));
614 printf("Protection buffer size: %lu.\n",
615 (unsigned long)buffer_size);
617 printf("Not using any security mechanism.\n");
622 sec_prot_internal(int level)
626 unsigned int s = 1048576;
628 int old_verbose = verbose;
632 printf("No security data exchange has taken place.\n");
637 ret = command("PBSZ %u", s);
639 printf("Failed to set protection buffer size.\n");
643 p = strstr(reply_string, "PBSZ=");
645 sscanf(p, "PBSZ=%u", &s);
649 verbose = old_verbose;
650 ret = command("PROT %c", level["CSEP"]); /* XXX :-) */
652 printf("Failed to set protection level.\n");
656 data_prot = (enum protection_level)level;
660 enum protection_level
661 set_command_prot(enum protection_level level)
663 enum protection_level old = command_prot;
664 command_prot = level;
669 sec_prot(int argc, char **argv)
673 if(argc < 2 || argc > 3)
676 printf("No security data exchange has taken place.\n");
680 level = name_to_level(argv[argc - 1]);
685 if((*mech->check_prot)(app_data, level)) {
686 printf("%s does not implement %s protection.\n",
687 mech->name, level_to_name(level));
692 if(argc == 2 || strncasecmp(argv[1], "data", strlen(argv[1])) == 0) {
693 if(sec_prot_internal(level) < 0){
697 } else if(strncasecmp(argv[1], "command", strlen(argv[1])) == 0)
698 set_command_prot(level);
704 printf("usage: %s [command|data] [clear|safe|confidential|private]\n",
709 static enum protection_level request_data_prot;
712 sec_set_protection_level(void)
714 if(sec_complete && data_prot != request_data_prot)
715 sec_prot_internal(request_data_prot);
720 sec_request_prot(char *level)
722 int l = name_to_level(level);
725 request_data_prot = (enum protection_level)l;
730 sec_login(char *host)
733 struct sec_client_mech **m;
734 int old_verbose = verbose;
736 verbose = -1; /* shut up all messages this will produce (they
737 are usually not very user friendly) */
739 for(m = mechs; *m && (*m)->name; m++) {
742 tmp = realloc(app_data, (*m)->size);
744 warnx ("realloc %u failed", (*m)->size);
749 if((*m)->init && (*(*m)->init)(app_data) != 0) {
750 printf("Skipping %s...\n", (*m)->name);
753 printf("Trying %s...\n", (*m)->name);
754 ret = command("AUTH %s", (*m)->name);
757 printf("%s is not supported by the server.\n", (*m)->name);
758 }else if(code == 534){
759 printf("%s rejected as security mechanism.\n", (*m)->name);
760 }else if(ret == ERROR) {
761 printf("The server doesn't support the FTP "
762 "security extensions.\n");
763 verbose = old_verbose;
769 ret = (*(*m)->auth)(app_data, host);
771 if(ret == AUTH_CONTINUE)
773 else if(ret != AUTH_OK){
774 /* mechanism is supposed to output error string */
775 verbose = old_verbose;
780 command_prot = prot_safe;
784 verbose = old_verbose;
793 (*mech->end)(app_data);
794 if (app_data != NULL) {
795 memset(app_data, 0, mech->size);
801 data_prot = (enum protection_level)0;
804 #endif /* FTP_SERVER */