security.c revision 233294
1/* 2 * Copyright (c) 1998-2002, 2005 Kungliga Tekniska H��gskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 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. 16 * 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. 20 * 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 31 * SUCH DAMAGE. 32 */ 33 34#ifdef FTP_SERVER 35#include "ftpd_locl.h" 36#else 37#include "ftp_locl.h" 38#endif 39 40RCSID("$Id$"); 41 42static enum protection_level command_prot; 43static enum protection_level data_prot; 44static size_t buffer_size; 45 46struct buffer { 47 void *data; 48 size_t size; 49 size_t index; 50 int eof_flag; 51}; 52 53static struct buffer in_buffer, out_buffer; 54int sec_complete; 55 56static struct { 57 enum protection_level level; 58 const char *name; 59} level_names[] = { 60 { prot_clear, "clear" }, 61 { prot_safe, "safe" }, 62 { prot_confidential, "confidential" }, 63 { prot_private, "private" } 64}; 65 66static const char * 67level_to_name(enum protection_level level) 68{ 69 int i; 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; 73 return "unknown"; 74} 75 76#ifndef FTP_SERVER /* not used in server */ 77static enum protection_level 78name_to_level(const char *name) 79{ 80 int i; 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 prot_invalid; 85} 86#endif 87 88#ifdef FTP_SERVER 89 90static struct sec_server_mech *mechs[] = { 91#ifdef KRB5 92 &gss_server_mech, 93#endif 94 NULL 95}; 96 97static struct sec_server_mech *mech; 98 99#else 100 101static struct sec_client_mech *mechs[] = { 102#ifdef KRB5 103 &gss_client_mech, 104#endif 105 NULL 106}; 107 108static struct sec_client_mech *mech; 109 110#endif 111 112static void *app_data; 113 114int 115sec_getc(FILE *F) 116{ 117 if(sec_complete && data_prot) { 118 char c; 119 if(sec_read(fileno(F), &c, 1) <= 0) 120 return EOF; 121 return c; 122 } else 123 return getc(F); 124} 125 126static int 127block_read(int fd, void *buf, size_t len) 128{ 129 unsigned char *p = buf; 130 int b; 131 while(len) { 132 b = read(fd, p, len); 133 if (b == 0) 134 return 0; 135 else if (b < 0) 136 return -1; 137 len -= b; 138 p += b; 139 } 140 return p - (unsigned char*)buf; 141} 142 143static int 144block_write(int fd, void *buf, size_t len) 145{ 146 unsigned char *p = buf; 147 int b; 148 while(len) { 149 b = write(fd, p, len); 150 if(b < 0) 151 return -1; 152 len -= b; 153 p += b; 154 } 155 return p - (unsigned char*)buf; 156} 157 158static int 159sec_get_data(int fd, struct buffer *buf, int level) 160{ 161 int len; 162 int b; 163 void *tmp; 164 165 b = block_read(fd, &len, sizeof(len)); 166 if (b == 0) 167 return 0; 168 else if (b < 0) 169 return -1; 170 len = ntohl(len); 171 tmp = realloc(buf->data, len); 172 if (tmp == NULL) 173 return -1; 174 buf->data = tmp; 175 b = block_read(fd, buf->data, len); 176 if (b == 0) 177 return 0; 178 else if (b < 0) 179 return -1; 180 buf->size = (*mech->decode)(app_data, buf->data, len, data_prot); 181 buf->index = 0; 182 return 0; 183} 184 185static size_t 186buffer_read(struct buffer *buf, void *dataptr, size_t len) 187{ 188 len = min(len, buf->size - buf->index); 189 memcpy(dataptr, (char*)buf->data + buf->index, len); 190 buf->index += len; 191 return len; 192} 193 194static size_t 195buffer_write(struct buffer *buf, void *dataptr, size_t len) 196{ 197 if(buf->index + len > buf->size) { 198 void *tmp; 199 if(buf->data == NULL) 200 tmp = malloc(1024); 201 else 202 tmp = realloc(buf->data, buf->index + len); 203 if(tmp == NULL) 204 return -1; 205 buf->data = tmp; 206 buf->size = buf->index + len; 207 } 208 memcpy((char*)buf->data + buf->index, dataptr, len); 209 buf->index += len; 210 return len; 211} 212 213int 214sec_read(int fd, void *dataptr, int length) 215{ 216 size_t len; 217 int rx = 0; 218 219 if(sec_complete == 0 || data_prot == 0) 220 return read(fd, dataptr, length); 221 222 if(in_buffer.eof_flag){ 223 in_buffer.eof_flag = 0; 224 return 0; 225 } 226 227 len = buffer_read(&in_buffer, dataptr, length); 228 length -= len; 229 rx += len; 230 dataptr = (char*)dataptr + len; 231 232 while(length){ 233 int ret; 234 235 ret = sec_get_data(fd, &in_buffer, data_prot); 236 if (ret < 0) 237 return -1; 238 if(ret == 0 && in_buffer.size == 0) { 239 if(rx) 240 in_buffer.eof_flag = 1; 241 return rx; 242 } 243 len = buffer_read(&in_buffer, dataptr, length); 244 length -= len; 245 rx += len; 246 dataptr = (char*)dataptr + len; 247 } 248 return rx; 249} 250 251static int 252sec_send(int fd, char *from, int length) 253{ 254 int bytes; 255 void *buf; 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)); 260 free(buf); 261 return length; 262} 263 264int 265sec_fflush(FILE *F) 266{ 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; 271 } 272 sec_send(fileno(F), NULL, 0); 273 } 274 fflush(F); 275 return 0; 276} 277 278int 279sec_write(int fd, char *dataptr, int length) 280{ 281 int len = buffer_size; 282 int tx = 0; 283 284 if(data_prot == prot_clear) 285 return write(fd, dataptr, length); 286 287 len -= (*mech->overhead)(app_data, data_prot, len); 288 while(length){ 289 if(length < len) 290 len = length; 291 sec_send(fd, dataptr, len); 292 length -= len; 293 dataptr += len; 294 tx += len; 295 } 296 return tx; 297} 298 299int 300sec_vfprintf2(FILE *f, const char *fmt, va_list ap) 301{ 302 char *buf; 303 int ret; 304 if(data_prot == prot_clear) 305 return vfprintf(f, fmt, ap); 306 else { 307 int len; 308 len = vasprintf(&buf, fmt, ap); 309 if (len == -1) 310 return len; 311 ret = buffer_write(&out_buffer, buf, len); 312 free(buf); 313 return ret; 314 } 315} 316 317int 318sec_fprintf2(FILE *f, const char *fmt, ...) 319{ 320 int ret; 321 va_list ap; 322 va_start(ap, fmt); 323 ret = sec_vfprintf2(f, fmt, ap); 324 va_end(ap); 325 return ret; 326} 327 328int 329sec_putc(int c, FILE *F) 330{ 331 char ch = c; 332 if(data_prot == prot_clear) 333 return putc(c, F); 334 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; 339 } 340 return c; 341} 342 343int 344sec_read_msg(char *s, int level) 345{ 346 int len; 347 char *buf; 348 int return_code; 349 350 buf = malloc(strlen(s)); 351 len = base64_decode(s + 4, buf); /* XXX */ 352 353 len = (*mech->decode)(app_data, buf, len, level); 354 if(len < 0) 355 return -1; 356 357 buf[len] = '\0'; 358 359 if(buf[3] == '-') 360 return_code = 0; 361 else 362 sscanf(buf, "%d", &return_code); 363 if(buf[len-1] == '\n') 364 buf[len-1] = '\0'; 365 strcpy(s, buf); 366 free(buf); 367 return return_code; 368} 369 370int 371sec_vfprintf(FILE *f, const char *fmt, va_list ap) 372{ 373 char *buf; 374 void *enc; 375 int len; 376 if(!sec_complete) 377 return vfprintf(f, fmt, ap); 378 379 if (vasprintf(&buf, fmt, ap) == -1) { 380 printf("Failed to allocate command.\n"); 381 return -1; 382 } 383 len = (*mech->encode)(app_data, buf, strlen(buf), command_prot, &enc); 384 free(buf); 385 if(len < 0) { 386 printf("Failed to encode command.\n"); 387 return -1; 388 } 389 if(base64_encode(enc, len, &buf) < 0){ 390 free(enc); 391 printf("Out of memory base64-encoding.\n"); 392 return -1; 393 } 394 free(enc); 395#ifdef FTP_SERVER 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); 402#else 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); 409#endif 410 free(buf); 411 return 0; 412} 413 414int 415sec_fprintf(FILE *f, const char *fmt, ...) 416{ 417 va_list ap; 418 int ret; 419 va_start(ap, fmt); 420 ret = sec_vfprintf(f, fmt, ap); 421 va_end(ap); 422 return ret; 423} 424 425/* end common stuff */ 426 427#ifdef FTP_SERVER 428 429int ccc_passed; 430 431void 432auth(char *auth_name) 433{ 434 int i; 435 void *tmp; 436 437 for(i = 0; (mech = mechs[i]) != NULL; i++){ 438 if(!strcasecmp(auth_name, mech->name)){ 439 tmp = realloc(app_data, mech->size); 440 if (tmp == NULL) { 441 reply(431, "Unable to accept %s at this time", mech->name); 442 return; 443 } 444 app_data = tmp; 445 446 if(mech->init && (*mech->init)(app_data) != 0) { 447 reply(431, "Unable to accept %s at this time", mech->name); 448 return; 449 } 450 if(mech->auth) { 451 (*mech->auth)(app_data); 452 return; 453 } 454 if(mech->adat) 455 reply(334, "Send authorization data."); 456 else 457 reply(234, "Authorization complete."); 458 return; 459 } 460 } 461 free (app_data); 462 app_data = NULL; 463 reply(504, "%s is unknown to me", auth_name); 464} 465 466void 467adat(char *auth_data) 468{ 469 if(mech && !sec_complete) { 470 void *buf = malloc(strlen(auth_data)); 471 size_t len; 472 len = base64_decode(auth_data, buf); 473 (*mech->adat)(app_data, buf, len); 474 free(buf); 475 } else 476 reply(503, "You must %sissue an AUTH first.", mech ? "re-" : ""); 477} 478 479void pbsz(int size) 480{ 481 size_t new = size; 482 if(!sec_complete) 483 reply(503, "Incomplete security data exchange."); 484 if(mech->pbsz) 485 new = (*mech->pbsz)(app_data, size); 486 if(buffer_size != new){ 487 buffer_size = size; 488 } 489 if(new != size) 490 reply(200, "PBSZ=%lu", (unsigned long)new); 491 else 492 reply(200, "OK"); 493} 494 495void 496prot(char *pl) 497{ 498 int p = -1; 499 500 if(buffer_size == 0){ 501 reply(503, "No protection buffer size negotiated."); 502 return; 503 } 504 505 if(!strcasecmp(pl, "C")) 506 p = prot_clear; 507 else if(!strcasecmp(pl, "S")) 508 p = prot_safe; 509 else if(!strcasecmp(pl, "E")) 510 p = prot_confidential; 511 else if(!strcasecmp(pl, "P")) 512 p = prot_private; 513 else { 514 reply(504, "Unrecognized protection level."); 515 return; 516 } 517 518 if(sec_complete){ 519 if((*mech->check_prot)(app_data, p)){ 520 reply(536, "%s does not support %s protection.", 521 mech->name, level_to_name(p)); 522 }else{ 523 data_prot = (enum protection_level)p; 524 reply(200, "Data protection is %s.", level_to_name(p)); 525 } 526 }else{ 527 reply(503, "Incomplete security data exchange."); 528 } 529} 530 531void ccc(void) 532{ 533 if(sec_complete){ 534 if(mech->ccc && (*mech->ccc)(app_data) == 0) { 535 command_prot = data_prot = prot_clear; 536 ccc_passed = 1; 537 } else 538 reply(534, "You must be joking."); 539 }else 540 reply(503, "Incomplete security data exchange."); 541} 542 543void mec(char *msg, enum protection_level level) 544{ 545 void *buf; 546 size_t len, buf_size; 547 if(!sec_complete) { 548 reply(503, "Incomplete security data exchange."); 549 return; 550 } 551 buf_size = strlen(msg) + 2; 552 buf = malloc(buf_size); 553 if (buf == NULL) { 554 reply(501, "Failed to allocate %lu", (unsigned long)buf_size); 555 return; 556 } 557 len = base64_decode(msg, buf); 558 command_prot = level; 559 if(len == (size_t)-1) { 560 free(buf); 561 reply(501, "Failed to base64-decode command"); 562 return; 563 } 564 len = (*mech->decode)(app_data, buf, len, level); 565 if(len == (size_t)-1) { 566 free(buf); 567 reply(535, "Failed to decode command"); 568 return; 569 } 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); 574} 575 576/* ------------------------------------------------------------ */ 577 578int 579sec_userok(char *userstr) 580{ 581 if(sec_complete) 582 return (*mech->userok)(app_data, userstr); 583 return 0; 584} 585 586int 587sec_session(char *user) 588{ 589 if(sec_complete && mech->session) 590 return (*mech->session)(app_data, user); 591 return 0; 592} 593 594char *ftp_command; 595 596void 597new_ftp_command(char *command) 598{ 599 ftp_command = command; 600} 601 602void 603delete_ftp_command(void) 604{ 605 free(ftp_command); 606 ftp_command = NULL; 607} 608 609int 610secure_command(void) 611{ 612 return ftp_command != NULL; 613} 614 615enum protection_level 616get_command_prot(void) 617{ 618 return command_prot; 619} 620 621#else /* FTP_SERVER */ 622 623void 624sec_status(void) 625{ 626 if(sec_complete){ 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)); 630 if(buffer_size > 0) 631 printf("Protection buffer size: %lu.\n", 632 (unsigned long)buffer_size); 633 }else{ 634 printf("Not using any security mechanism.\n"); 635 } 636} 637 638static int 639sec_prot_internal(int level) 640{ 641 int ret; 642 char *p; 643 unsigned int s = 1048576; 644 645 int old_verbose = verbose; 646 verbose = 0; 647 648 if(!sec_complete){ 649 printf("No security data exchange has taken place.\n"); 650 return -1; 651 } 652 653 if(level){ 654 ret = command("PBSZ %u", s); 655 if(ret != COMPLETE){ 656 printf("Failed to set protection buffer size.\n"); 657 return -1; 658 } 659 buffer_size = s; 660 p = strstr(reply_string, "PBSZ="); 661 if(p) 662 sscanf(p, "PBSZ=%u", &s); 663 if(s < buffer_size) 664 buffer_size = s; 665 } 666 verbose = old_verbose; 667 ret = command("PROT %c", level["CSEP"]); /* XXX :-) */ 668 if(ret != COMPLETE){ 669 printf("Failed to set protection level.\n"); 670 return -1; 671 } 672 673 data_prot = (enum protection_level)level; 674 return 0; 675} 676 677enum protection_level 678set_command_prot(enum protection_level level) 679{ 680 int ret; 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"); 686 return prot_invalid; 687 } 688 } 689 command_prot = level; 690 return old; 691} 692 693void 694sec_prot(int argc, char **argv) 695{ 696 int level = -1; 697 698 if(argc > 3) 699 goto usage; 700 701 if(argc == 1) { 702 sec_status(); 703 return; 704 } 705 if(!sec_complete) { 706 printf("No security data exchange has taken place.\n"); 707 code = -1; 708 return; 709 } 710 level = name_to_level(argv[argc - 1]); 711 712 if(level == -1) 713 goto usage; 714 715 if((*mech->check_prot)(app_data, level)) { 716 printf("%s does not implement %s protection.\n", 717 mech->name, level_to_name(level)); 718 code = -1; 719 return; 720 } 721 722 if(argc == 2 || strncasecmp(argv[1], "data", strlen(argv[1])) == 0) { 723 if(sec_prot_internal(level) < 0){ 724 code = -1; 725 return; 726 } 727 } else if(strncasecmp(argv[1], "command", strlen(argv[1])) == 0) { 728 if(set_command_prot(level) < 0) { 729 code = -1; 730 return; 731 } 732 } else 733 goto usage; 734 code = 0; 735 return; 736 usage: 737 printf("usage: %s [command|data] [clear|safe|confidential|private]\n", 738 argv[0]); 739 code = -1; 740} 741 742void 743sec_prot_command(int argc, char **argv) 744{ 745 int level; 746 747 if(argc > 2) 748 goto usage; 749 750 if(!sec_complete) { 751 printf("No security data exchange has taken place.\n"); 752 code = -1; 753 return; 754 } 755 756 if(argc == 1) { 757 sec_status(); 758 } else { 759 level = name_to_level(argv[1]); 760 if(level == -1) 761 goto usage; 762 763 if((*mech->check_prot)(app_data, level)) { 764 printf("%s does not implement %s protection.\n", 765 mech->name, level_to_name(level)); 766 code = -1; 767 return; 768 } 769 if(set_command_prot(level) < 0) { 770 code = -1; 771 return; 772 } 773 } 774 code = 0; 775 return; 776 usage: 777 printf("usage: %s [clear|safe|confidential|private]\n", 778 argv[0]); 779 code = -1; 780} 781 782static enum protection_level request_data_prot; 783 784void 785sec_set_protection_level(void) 786{ 787 if(sec_complete && data_prot != request_data_prot) 788 sec_prot_internal(request_data_prot); 789} 790 791 792int 793sec_request_prot(char *level) 794{ 795 int l = name_to_level(level); 796 if(l == -1) 797 return -1; 798 request_data_prot = (enum protection_level)l; 799 return 0; 800} 801 802int 803sec_login(char *host) 804{ 805 int ret; 806 struct sec_client_mech **m; 807 int old_verbose = verbose; 808 809 verbose = -1; /* shut up all messages this will produce (they 810 are usually not very user friendly) */ 811 812 for(m = mechs; *m && (*m)->name; m++) { 813 void *tmp; 814 815 tmp = realloc(app_data, (*m)->size); 816 if (tmp == NULL) { 817 warnx ("realloc %lu failed", (unsigned long)(*m)->size); 818 return -1; 819 } 820 app_data = tmp; 821 822 if((*m)->init && (*(*m)->init)(app_data) != 0) { 823 printf("Skipping %s...\n", (*m)->name); 824 continue; 825 } 826 printf("Trying %s...\n", (*m)->name); 827 ret = command("AUTH %s", (*m)->name); 828 if(ret != CONTINUE){ 829 if(code == 504){ 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; 837 return -1; 838 } 839 continue; 840 } 841 842 ret = (*(*m)->auth)(app_data, host); 843 844 if(ret == AUTH_CONTINUE) 845 continue; 846 else if(ret != AUTH_OK){ 847 /* mechanism is supposed to output error string */ 848 verbose = old_verbose; 849 return -1; 850 } 851 mech = *m; 852 sec_complete = 1; 853 if(doencrypt) { 854 command_prot = prot_private; 855 request_data_prot = prot_private; 856 } else { 857 command_prot = prot_safe; 858 } 859 break; 860 } 861 862 verbose = old_verbose; 863 return *m == NULL; 864} 865 866void 867sec_end(void) 868{ 869 if (mech != NULL) { 870 if(mech->end) 871 (*mech->end)(app_data); 872 if (app_data != NULL) { 873 memset(app_data, 0, mech->size); 874 free(app_data); 875 app_data = NULL; 876 } 877 } 878 sec_complete = 0; 879 data_prot = (enum protection_level)0; 880} 881 882#endif /* FTP_SERVER */ 883 884