155682Smarkm/* 2233294Sstas * Copyright (c) 1998-2002, 2005 Kungliga Tekniska H��gskolan 355682Smarkm * (Royal Institute of Technology, Stockholm, Sweden). 455682Smarkm * All rights reserved. 5233294Sstas * 655682Smarkm * Redistribution and use in source and binary forms, with or without 755682Smarkm * modification, are permitted provided that the following conditions 855682Smarkm * are met: 9233294Sstas * 1055682Smarkm * 1. Redistributions of source code must retain the above copyright 1155682Smarkm * notice, this list of conditions and the following disclaimer. 12233294Sstas * 1355682Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1455682Smarkm * notice, this list of conditions and the following disclaimer in the 1555682Smarkm * documentation and/or other materials provided with the distribution. 16233294Sstas * 1755682Smarkm * 3. Neither the name of the Institute nor the names of its contributors 1855682Smarkm * may be used to endorse or promote products derived from this software 1955682Smarkm * without specific prior written permission. 20233294Sstas * 2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2455682Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3155682Smarkm * SUCH DAMAGE. 3255682Smarkm */ 3355682Smarkm 3455682Smarkm#ifdef FTP_SERVER 3555682Smarkm#include "ftpd_locl.h" 3655682Smarkm#else 3755682Smarkm#include "ftp_locl.h" 3855682Smarkm#endif 3955682Smarkm 40233294SstasRCSID("$Id$"); 4155682Smarkm 4255682Smarkmstatic enum protection_level command_prot; 4355682Smarkmstatic enum protection_level data_prot; 4455682Smarkmstatic size_t buffer_size; 4555682Smarkm 4655682Smarkmstruct buffer { 4755682Smarkm void *data; 4855682Smarkm size_t size; 4955682Smarkm size_t index; 5055682Smarkm int eof_flag; 5155682Smarkm}; 5255682Smarkm 5355682Smarkmstatic struct buffer in_buffer, out_buffer; 5455682Smarkmint sec_complete; 5555682Smarkm 5655682Smarkmstatic struct { 5755682Smarkm enum protection_level level; 5855682Smarkm const char *name; 5955682Smarkm} level_names[] = { 6055682Smarkm { prot_clear, "clear" }, 6155682Smarkm { prot_safe, "safe" }, 6255682Smarkm { prot_confidential, "confidential" }, 6355682Smarkm { prot_private, "private" } 6455682Smarkm}; 6555682Smarkm 6655682Smarkmstatic const char * 6755682Smarkmlevel_to_name(enum protection_level level) 6855682Smarkm{ 6955682Smarkm int i; 7055682Smarkm for(i = 0; i < sizeof(level_names) / sizeof(level_names[0]); i++) 7155682Smarkm if(level_names[i].level == level) 7255682Smarkm return level_names[i].name; 7355682Smarkm return "unknown"; 7455682Smarkm} 7555682Smarkm 7655682Smarkm#ifndef FTP_SERVER /* not used in server */ 77233294Sstasstatic enum protection_level 7855682Smarkmname_to_level(const char *name) 7955682Smarkm{ 8055682Smarkm int i; 8155682Smarkm for(i = 0; i < sizeof(level_names) / sizeof(level_names[0]); i++) 8255682Smarkm if(!strncasecmp(level_names[i].name, name, strlen(name))) 8355682Smarkm return level_names[i].level; 84233294Sstas return prot_invalid; 8555682Smarkm} 8655682Smarkm#endif 8755682Smarkm 8855682Smarkm#ifdef FTP_SERVER 8955682Smarkm 9055682Smarkmstatic struct sec_server_mech *mechs[] = { 9155682Smarkm#ifdef KRB5 9255682Smarkm &gss_server_mech, 9355682Smarkm#endif 9455682Smarkm NULL 9555682Smarkm}; 9655682Smarkm 9755682Smarkmstatic struct sec_server_mech *mech; 9855682Smarkm 9955682Smarkm#else 10055682Smarkm 10155682Smarkmstatic struct sec_client_mech *mechs[] = { 10255682Smarkm#ifdef KRB5 10355682Smarkm &gss_client_mech, 10455682Smarkm#endif 10555682Smarkm NULL 10655682Smarkm}; 10755682Smarkm 10855682Smarkmstatic struct sec_client_mech *mech; 10955682Smarkm 11055682Smarkm#endif 11155682Smarkm 11255682Smarkmstatic void *app_data; 11355682Smarkm 11455682Smarkmint 11555682Smarkmsec_getc(FILE *F) 11655682Smarkm{ 11755682Smarkm if(sec_complete && data_prot) { 11855682Smarkm char c; 11955682Smarkm if(sec_read(fileno(F), &c, 1) <= 0) 12055682Smarkm return EOF; 12155682Smarkm return c; 12255682Smarkm } else 12355682Smarkm return getc(F); 12455682Smarkm} 12555682Smarkm 12655682Smarkmstatic int 12755682Smarkmblock_read(int fd, void *buf, size_t len) 12855682Smarkm{ 12955682Smarkm unsigned char *p = buf; 13055682Smarkm int b; 13155682Smarkm while(len) { 13255682Smarkm b = read(fd, p, len); 13355682Smarkm if (b == 0) 13455682Smarkm return 0; 13555682Smarkm else if (b < 0) 13655682Smarkm return -1; 13755682Smarkm len -= b; 13855682Smarkm p += b; 13955682Smarkm } 14055682Smarkm return p - (unsigned char*)buf; 14155682Smarkm} 14255682Smarkm 14355682Smarkmstatic int 14455682Smarkmblock_write(int fd, void *buf, size_t len) 14555682Smarkm{ 14655682Smarkm unsigned char *p = buf; 14755682Smarkm int b; 14855682Smarkm while(len) { 14955682Smarkm b = write(fd, p, len); 15055682Smarkm if(b < 0) 15155682Smarkm return -1; 15255682Smarkm len -= b; 15355682Smarkm p += b; 15455682Smarkm } 15555682Smarkm return p - (unsigned char*)buf; 15655682Smarkm} 15755682Smarkm 15855682Smarkmstatic int 15955682Smarkmsec_get_data(int fd, struct buffer *buf, int level) 16055682Smarkm{ 16155682Smarkm int len; 16255682Smarkm int b; 16378527Sassar void *tmp; 16455682Smarkm 16555682Smarkm b = block_read(fd, &len, sizeof(len)); 16655682Smarkm if (b == 0) 16755682Smarkm return 0; 16855682Smarkm else if (b < 0) 16955682Smarkm return -1; 17055682Smarkm len = ntohl(len); 17178527Sassar tmp = realloc(buf->data, len); 17278527Sassar if (tmp == NULL) 17378527Sassar return -1; 17478527Sassar buf->data = tmp; 17555682Smarkm b = block_read(fd, buf->data, len); 17655682Smarkm if (b == 0) 17755682Smarkm return 0; 17855682Smarkm else if (b < 0) 17955682Smarkm return -1; 18055682Smarkm buf->size = (*mech->decode)(app_data, buf->data, len, data_prot); 18155682Smarkm buf->index = 0; 18255682Smarkm return 0; 18355682Smarkm} 18455682Smarkm 18555682Smarkmstatic size_t 186178825Sdfrbuffer_read(struct buffer *buf, void *dataptr, size_t len) 18755682Smarkm{ 18855682Smarkm len = min(len, buf->size - buf->index); 189178825Sdfr memcpy(dataptr, (char*)buf->data + buf->index, len); 19055682Smarkm buf->index += len; 19155682Smarkm return len; 19255682Smarkm} 19355682Smarkm 19455682Smarkmstatic size_t 195178825Sdfrbuffer_write(struct buffer *buf, void *dataptr, size_t len) 19655682Smarkm{ 19755682Smarkm if(buf->index + len > buf->size) { 19855682Smarkm void *tmp; 19955682Smarkm if(buf->data == NULL) 20055682Smarkm tmp = malloc(1024); 20155682Smarkm else 20255682Smarkm tmp = realloc(buf->data, buf->index + len); 20355682Smarkm if(tmp == NULL) 20455682Smarkm return -1; 20555682Smarkm buf->data = tmp; 20655682Smarkm buf->size = buf->index + len; 20755682Smarkm } 208178825Sdfr memcpy((char*)buf->data + buf->index, dataptr, len); 20955682Smarkm buf->index += len; 21055682Smarkm return len; 21155682Smarkm} 21255682Smarkm 21355682Smarkmint 214178825Sdfrsec_read(int fd, void *dataptr, int length) 21555682Smarkm{ 21655682Smarkm size_t len; 21755682Smarkm int rx = 0; 21855682Smarkm 21955682Smarkm if(sec_complete == 0 || data_prot == 0) 220178825Sdfr return read(fd, dataptr, length); 22155682Smarkm 22255682Smarkm if(in_buffer.eof_flag){ 22355682Smarkm in_buffer.eof_flag = 0; 22455682Smarkm return 0; 22555682Smarkm } 226233294Sstas 227178825Sdfr len = buffer_read(&in_buffer, dataptr, length); 22855682Smarkm length -= len; 22955682Smarkm rx += len; 230178825Sdfr dataptr = (char*)dataptr + len; 231233294Sstas 23255682Smarkm while(length){ 23357416Smarkm int ret; 23457416Smarkm 23557416Smarkm ret = sec_get_data(fd, &in_buffer, data_prot); 23657416Smarkm if (ret < 0) 23755682Smarkm return -1; 23872445Sassar if(ret == 0 && in_buffer.size == 0) { 23955682Smarkm if(rx) 24055682Smarkm in_buffer.eof_flag = 1; 24155682Smarkm return rx; 24255682Smarkm } 243178825Sdfr len = buffer_read(&in_buffer, dataptr, length); 24455682Smarkm length -= len; 24555682Smarkm rx += len; 246178825Sdfr dataptr = (char*)dataptr + len; 24755682Smarkm } 24855682Smarkm return rx; 24955682Smarkm} 25055682Smarkm 25155682Smarkmstatic int 25255682Smarkmsec_send(int fd, char *from, int length) 25355682Smarkm{ 25455682Smarkm int bytes; 25555682Smarkm void *buf; 25655682Smarkm bytes = (*mech->encode)(app_data, from, length, data_prot, &buf); 25755682Smarkm bytes = htonl(bytes); 25855682Smarkm block_write(fd, &bytes, sizeof(bytes)); 25955682Smarkm block_write(fd, buf, ntohl(bytes)); 26055682Smarkm free(buf); 26155682Smarkm return length; 26255682Smarkm} 26355682Smarkm 26455682Smarkmint 26555682Smarkmsec_fflush(FILE *F) 26655682Smarkm{ 26755682Smarkm if(data_prot != prot_clear) { 26855682Smarkm if(out_buffer.index > 0){ 26955682Smarkm sec_write(fileno(F), out_buffer.data, out_buffer.index); 27055682Smarkm out_buffer.index = 0; 27155682Smarkm } 27255682Smarkm sec_send(fileno(F), NULL, 0); 27355682Smarkm } 27455682Smarkm fflush(F); 27555682Smarkm return 0; 27655682Smarkm} 27755682Smarkm 27855682Smarkmint 279178825Sdfrsec_write(int fd, char *dataptr, int length) 28055682Smarkm{ 28155682Smarkm int len = buffer_size; 28255682Smarkm int tx = 0; 283233294Sstas 28455682Smarkm if(data_prot == prot_clear) 285178825Sdfr return write(fd, dataptr, length); 28655682Smarkm 28755682Smarkm len -= (*mech->overhead)(app_data, data_prot, len); 28855682Smarkm while(length){ 28955682Smarkm if(length < len) 29055682Smarkm len = length; 291178825Sdfr sec_send(fd, dataptr, len); 29255682Smarkm length -= len; 293178825Sdfr dataptr += len; 29455682Smarkm tx += len; 29555682Smarkm } 29655682Smarkm return tx; 29755682Smarkm} 29855682Smarkm 29955682Smarkmint 30055682Smarkmsec_vfprintf2(FILE *f, const char *fmt, va_list ap) 30155682Smarkm{ 30255682Smarkm char *buf; 30355682Smarkm int ret; 30455682Smarkm if(data_prot == prot_clear) 30555682Smarkm return vfprintf(f, fmt, ap); 30655682Smarkm else { 307178825Sdfr int len; 308178825Sdfr len = vasprintf(&buf, fmt, ap); 309178825Sdfr if (len == -1) 310178825Sdfr return len; 311178825Sdfr ret = buffer_write(&out_buffer, buf, len); 31255682Smarkm free(buf); 31355682Smarkm return ret; 31455682Smarkm } 31555682Smarkm} 31655682Smarkm 31755682Smarkmint 31855682Smarkmsec_fprintf2(FILE *f, const char *fmt, ...) 31955682Smarkm{ 32055682Smarkm int ret; 32155682Smarkm va_list ap; 32255682Smarkm va_start(ap, fmt); 32355682Smarkm ret = sec_vfprintf2(f, fmt, ap); 32455682Smarkm va_end(ap); 32555682Smarkm return ret; 32655682Smarkm} 32755682Smarkm 32855682Smarkmint 32955682Smarkmsec_putc(int c, FILE *F) 33055682Smarkm{ 33155682Smarkm char ch = c; 33255682Smarkm if(data_prot == prot_clear) 33355682Smarkm return putc(c, F); 334233294Sstas 33555682Smarkm buffer_write(&out_buffer, &ch, 1); 33655682Smarkm if(c == '\n' || out_buffer.index >= 1024 /* XXX */) { 33755682Smarkm sec_write(fileno(F), out_buffer.data, out_buffer.index); 33855682Smarkm out_buffer.index = 0; 33955682Smarkm } 34055682Smarkm return c; 34155682Smarkm} 34255682Smarkm 34355682Smarkmint 34455682Smarkmsec_read_msg(char *s, int level) 34555682Smarkm{ 34655682Smarkm int len; 34755682Smarkm char *buf; 348178825Sdfr int return_code; 349233294Sstas 35055682Smarkm buf = malloc(strlen(s)); 35155682Smarkm len = base64_decode(s + 4, buf); /* XXX */ 352233294Sstas 35355682Smarkm len = (*mech->decode)(app_data, buf, len, level); 35455682Smarkm if(len < 0) 35555682Smarkm return -1; 356233294Sstas 35755682Smarkm buf[len] = '\0'; 35855682Smarkm 35955682Smarkm if(buf[3] == '-') 360178825Sdfr return_code = 0; 36155682Smarkm else 362178825Sdfr sscanf(buf, "%d", &return_code); 36355682Smarkm if(buf[len-1] == '\n') 36455682Smarkm buf[len-1] = '\0'; 36555682Smarkm strcpy(s, buf); 36655682Smarkm free(buf); 367178825Sdfr return return_code; 36855682Smarkm} 36955682Smarkm 37055682Smarkmint 37155682Smarkmsec_vfprintf(FILE *f, const char *fmt, va_list ap) 37255682Smarkm{ 37355682Smarkm char *buf; 37455682Smarkm void *enc; 37555682Smarkm int len; 37655682Smarkm if(!sec_complete) 37755682Smarkm return vfprintf(f, fmt, ap); 378233294Sstas 379178825Sdfr if (vasprintf(&buf, fmt, ap) == -1) { 380178825Sdfr printf("Failed to allocate command.\n"); 381178825Sdfr return -1; 382178825Sdfr } 38355682Smarkm len = (*mech->encode)(app_data, buf, strlen(buf), command_prot, &enc); 38455682Smarkm free(buf); 38555682Smarkm if(len < 0) { 38655682Smarkm printf("Failed to encode command.\n"); 38755682Smarkm return -1; 38855682Smarkm } 38955682Smarkm if(base64_encode(enc, len, &buf) < 0){ 390103423Snectar free(enc); 39155682Smarkm printf("Out of memory base64-encoding.\n"); 39255682Smarkm return -1; 39355682Smarkm } 394103423Snectar free(enc); 39555682Smarkm#ifdef FTP_SERVER 39655682Smarkm if(command_prot == prot_safe) 39755682Smarkm fprintf(f, "631 %s\r\n", buf); 39855682Smarkm else if(command_prot == prot_private) 39955682Smarkm fprintf(f, "632 %s\r\n", buf); 40055682Smarkm else if(command_prot == prot_confidential) 40155682Smarkm fprintf(f, "633 %s\r\n", buf); 40255682Smarkm#else 40355682Smarkm if(command_prot == prot_safe) 40455682Smarkm fprintf(f, "MIC %s", buf); 40555682Smarkm else if(command_prot == prot_private) 40655682Smarkm fprintf(f, "ENC %s", buf); 40755682Smarkm else if(command_prot == prot_confidential) 40855682Smarkm fprintf(f, "CONF %s", buf); 40955682Smarkm#endif 41055682Smarkm free(buf); 41155682Smarkm return 0; 41255682Smarkm} 41355682Smarkm 41455682Smarkmint 41555682Smarkmsec_fprintf(FILE *f, const char *fmt, ...) 41655682Smarkm{ 41755682Smarkm va_list ap; 41855682Smarkm int ret; 41955682Smarkm va_start(ap, fmt); 42055682Smarkm ret = sec_vfprintf(f, fmt, ap); 42155682Smarkm va_end(ap); 42255682Smarkm return ret; 42355682Smarkm} 42455682Smarkm 42555682Smarkm/* end common stuff */ 42655682Smarkm 42755682Smarkm#ifdef FTP_SERVER 42855682Smarkm 429178825Sdfrint ccc_passed; 430178825Sdfr 43155682Smarkmvoid 43255682Smarkmauth(char *auth_name) 43355682Smarkm{ 43455682Smarkm int i; 43578527Sassar void *tmp; 43678527Sassar 43755682Smarkm for(i = 0; (mech = mechs[i]) != NULL; i++){ 43855682Smarkm if(!strcasecmp(auth_name, mech->name)){ 43978527Sassar tmp = realloc(app_data, mech->size); 44078527Sassar if (tmp == NULL) { 44178527Sassar reply(431, "Unable to accept %s at this time", mech->name); 44278527Sassar return; 44378527Sassar } 44478527Sassar app_data = tmp; 44578527Sassar 44655682Smarkm if(mech->init && (*mech->init)(app_data) != 0) { 44755682Smarkm reply(431, "Unable to accept %s at this time", mech->name); 44855682Smarkm return; 44955682Smarkm } 45055682Smarkm if(mech->auth) { 45155682Smarkm (*mech->auth)(app_data); 45255682Smarkm return; 45355682Smarkm } 45455682Smarkm if(mech->adat) 45555682Smarkm reply(334, "Send authorization data."); 45655682Smarkm else 45755682Smarkm reply(234, "Authorization complete."); 45855682Smarkm return; 45955682Smarkm } 46055682Smarkm } 46155682Smarkm free (app_data); 46278527Sassar app_data = NULL; 46355682Smarkm reply(504, "%s is unknown to me", auth_name); 46455682Smarkm} 46555682Smarkm 46655682Smarkmvoid 46755682Smarkmadat(char *auth_data) 46855682Smarkm{ 46955682Smarkm if(mech && !sec_complete) { 47055682Smarkm void *buf = malloc(strlen(auth_data)); 47155682Smarkm size_t len; 47255682Smarkm len = base64_decode(auth_data, buf); 47355682Smarkm (*mech->adat)(app_data, buf, len); 47455682Smarkm free(buf); 47555682Smarkm } else 47655682Smarkm reply(503, "You must %sissue an AUTH first.", mech ? "re-" : ""); 47755682Smarkm} 47855682Smarkm 47955682Smarkmvoid pbsz(int size) 48055682Smarkm{ 48155682Smarkm size_t new = size; 48255682Smarkm if(!sec_complete) 48355682Smarkm reply(503, "Incomplete security data exchange."); 48455682Smarkm if(mech->pbsz) 48555682Smarkm new = (*mech->pbsz)(app_data, size); 48655682Smarkm if(buffer_size != new){ 48755682Smarkm buffer_size = size; 48855682Smarkm } 48955682Smarkm if(new != size) 49055682Smarkm reply(200, "PBSZ=%lu", (unsigned long)new); 49155682Smarkm else 49255682Smarkm reply(200, "OK"); 49355682Smarkm} 49455682Smarkm 49555682Smarkmvoid 49655682Smarkmprot(char *pl) 49755682Smarkm{ 49855682Smarkm int p = -1; 49955682Smarkm 50055682Smarkm if(buffer_size == 0){ 50155682Smarkm reply(503, "No protection buffer size negotiated."); 50255682Smarkm return; 50355682Smarkm } 50455682Smarkm 50555682Smarkm if(!strcasecmp(pl, "C")) 50655682Smarkm p = prot_clear; 50755682Smarkm else if(!strcasecmp(pl, "S")) 50855682Smarkm p = prot_safe; 50955682Smarkm else if(!strcasecmp(pl, "E")) 51055682Smarkm p = prot_confidential; 51155682Smarkm else if(!strcasecmp(pl, "P")) 51255682Smarkm p = prot_private; 51355682Smarkm else { 51455682Smarkm reply(504, "Unrecognized protection level."); 51555682Smarkm return; 51655682Smarkm } 517233294Sstas 51855682Smarkm if(sec_complete){ 51955682Smarkm if((*mech->check_prot)(app_data, p)){ 520233294Sstas reply(536, "%s does not support %s protection.", 52155682Smarkm mech->name, level_to_name(p)); 52255682Smarkm }else{ 52355682Smarkm data_prot = (enum protection_level)p; 52455682Smarkm reply(200, "Data protection is %s.", level_to_name(p)); 52555682Smarkm } 52655682Smarkm }else{ 52755682Smarkm reply(503, "Incomplete security data exchange."); 52855682Smarkm } 52955682Smarkm} 53055682Smarkm 53155682Smarkmvoid ccc(void) 53255682Smarkm{ 53355682Smarkm if(sec_complete){ 534178825Sdfr if(mech->ccc && (*mech->ccc)(app_data) == 0) { 53555682Smarkm command_prot = data_prot = prot_clear; 536178825Sdfr ccc_passed = 1; 537178825Sdfr } else 53855682Smarkm reply(534, "You must be joking."); 53955682Smarkm }else 54055682Smarkm reply(503, "Incomplete security data exchange."); 54155682Smarkm} 54255682Smarkm 54355682Smarkmvoid mec(char *msg, enum protection_level level) 54455682Smarkm{ 54555682Smarkm void *buf; 546178825Sdfr size_t len, buf_size; 54755682Smarkm if(!sec_complete) { 54855682Smarkm reply(503, "Incomplete security data exchange."); 54955682Smarkm return; 55055682Smarkm } 551178825Sdfr buf_size = strlen(msg) + 2; 552178825Sdfr buf = malloc(buf_size); 553233294Sstas if (buf == NULL) { 554233294Sstas reply(501, "Failed to allocate %lu", (unsigned long)buf_size); 555233294Sstas return; 556233294Sstas } 55755682Smarkm len = base64_decode(msg, buf); 55855682Smarkm command_prot = level; 55955682Smarkm if(len == (size_t)-1) { 560233294Sstas free(buf); 56155682Smarkm reply(501, "Failed to base64-decode command"); 56255682Smarkm return; 56355682Smarkm } 56455682Smarkm len = (*mech->decode)(app_data, buf, len, level); 56555682Smarkm if(len == (size_t)-1) { 566233294Sstas free(buf); 56755682Smarkm reply(535, "Failed to decode command"); 56855682Smarkm return; 56955682Smarkm } 57055682Smarkm ((char*)buf)[len] = '\0'; 57155682Smarkm if(strstr((char*)buf, "\r\n") == NULL) 572178825Sdfr strlcat((char*)buf, "\r\n", buf_size); 57355682Smarkm new_ftp_command(buf); 57455682Smarkm} 57555682Smarkm 57655682Smarkm/* ------------------------------------------------------------ */ 57755682Smarkm 57855682Smarkmint 579178825Sdfrsec_userok(char *userstr) 58055682Smarkm{ 58155682Smarkm if(sec_complete) 582178825Sdfr return (*mech->userok)(app_data, userstr); 58355682Smarkm return 0; 58455682Smarkm} 58555682Smarkm 586178825Sdfrint 587178825Sdfrsec_session(char *user) 588178825Sdfr{ 589178825Sdfr if(sec_complete && mech->session) 590178825Sdfr return (*mech->session)(app_data, user); 591178825Sdfr return 0; 592178825Sdfr} 593178825Sdfr 59455682Smarkmchar *ftp_command; 59555682Smarkm 59655682Smarkmvoid 59755682Smarkmnew_ftp_command(char *command) 59855682Smarkm{ 59955682Smarkm ftp_command = command; 60055682Smarkm} 60155682Smarkm 60255682Smarkmvoid 60355682Smarkmdelete_ftp_command(void) 60455682Smarkm{ 60555682Smarkm free(ftp_command); 60655682Smarkm ftp_command = NULL; 60755682Smarkm} 60855682Smarkm 60955682Smarkmint 61055682Smarkmsecure_command(void) 61155682Smarkm{ 61255682Smarkm return ftp_command != NULL; 61355682Smarkm} 61455682Smarkm 61555682Smarkmenum protection_level 61655682Smarkmget_command_prot(void) 61755682Smarkm{ 61855682Smarkm return command_prot; 61955682Smarkm} 62055682Smarkm 62155682Smarkm#else /* FTP_SERVER */ 62255682Smarkm 62355682Smarkmvoid 62455682Smarkmsec_status(void) 62555682Smarkm{ 62655682Smarkm if(sec_complete){ 62755682Smarkm printf("Using %s for authentication.\n", mech->name); 62855682Smarkm printf("Using %s command channel.\n", level_to_name(command_prot)); 62955682Smarkm printf("Using %s data channel.\n", level_to_name(data_prot)); 63055682Smarkm if(buffer_size > 0) 631233294Sstas printf("Protection buffer size: %lu.\n", 63255682Smarkm (unsigned long)buffer_size); 63355682Smarkm }else{ 63455682Smarkm printf("Not using any security mechanism.\n"); 63555682Smarkm } 63655682Smarkm} 63755682Smarkm 63855682Smarkmstatic int 63955682Smarkmsec_prot_internal(int level) 64055682Smarkm{ 64155682Smarkm int ret; 64255682Smarkm char *p; 64355682Smarkm unsigned int s = 1048576; 64455682Smarkm 64555682Smarkm int old_verbose = verbose; 64655682Smarkm verbose = 0; 64755682Smarkm 64855682Smarkm if(!sec_complete){ 64955682Smarkm printf("No security data exchange has taken place.\n"); 65055682Smarkm return -1; 65155682Smarkm } 65255682Smarkm 65355682Smarkm if(level){ 65455682Smarkm ret = command("PBSZ %u", s); 65555682Smarkm if(ret != COMPLETE){ 65655682Smarkm printf("Failed to set protection buffer size.\n"); 65755682Smarkm return -1; 65855682Smarkm } 65955682Smarkm buffer_size = s; 66055682Smarkm p = strstr(reply_string, "PBSZ="); 66155682Smarkm if(p) 66255682Smarkm sscanf(p, "PBSZ=%u", &s); 66355682Smarkm if(s < buffer_size) 66455682Smarkm buffer_size = s; 66555682Smarkm } 66655682Smarkm verbose = old_verbose; 66755682Smarkm ret = command("PROT %c", level["CSEP"]); /* XXX :-) */ 66855682Smarkm if(ret != COMPLETE){ 66955682Smarkm printf("Failed to set protection level.\n"); 67055682Smarkm return -1; 67155682Smarkm } 672233294Sstas 67355682Smarkm data_prot = (enum protection_level)level; 67455682Smarkm return 0; 67555682Smarkm} 67655682Smarkm 67755682Smarkmenum protection_level 67855682Smarkmset_command_prot(enum protection_level level) 67955682Smarkm{ 680178825Sdfr int ret; 68155682Smarkm enum protection_level old = command_prot; 682178825Sdfr if(level != command_prot && level == prot_clear) { 683178825Sdfr ret = command("CCC"); 684178825Sdfr if(ret != COMPLETE) { 685178825Sdfr printf("Failed to clear command channel.\n"); 686233294Sstas return prot_invalid; 687178825Sdfr } 688178825Sdfr } 68955682Smarkm command_prot = level; 69055682Smarkm return old; 69155682Smarkm} 69255682Smarkm 69355682Smarkmvoid 69455682Smarkmsec_prot(int argc, char **argv) 69555682Smarkm{ 69655682Smarkm int level = -1; 69755682Smarkm 698178825Sdfr if(argc > 3) 69955682Smarkm goto usage; 700178825Sdfr 701178825Sdfr if(argc == 1) { 702178825Sdfr sec_status(); 703178825Sdfr return; 704178825Sdfr } 70555682Smarkm if(!sec_complete) { 70655682Smarkm printf("No security data exchange has taken place.\n"); 70755682Smarkm code = -1; 70855682Smarkm return; 70955682Smarkm } 71055682Smarkm level = name_to_level(argv[argc - 1]); 711233294Sstas 71255682Smarkm if(level == -1) 71355682Smarkm goto usage; 714233294Sstas 71555682Smarkm if((*mech->check_prot)(app_data, level)) { 716233294Sstas printf("%s does not implement %s protection.\n", 71755682Smarkm mech->name, level_to_name(level)); 71855682Smarkm code = -1; 71955682Smarkm return; 72055682Smarkm } 721233294Sstas 72255682Smarkm if(argc == 2 || strncasecmp(argv[1], "data", strlen(argv[1])) == 0) { 72355682Smarkm if(sec_prot_internal(level) < 0){ 72455682Smarkm code = -1; 72555682Smarkm return; 72655682Smarkm } 727178825Sdfr } else if(strncasecmp(argv[1], "command", strlen(argv[1])) == 0) { 728178825Sdfr if(set_command_prot(level) < 0) { 729178825Sdfr code = -1; 730178825Sdfr return; 731178825Sdfr } 732178825Sdfr } else 73355682Smarkm goto usage; 73455682Smarkm code = 0; 73555682Smarkm return; 73655682Smarkm usage: 73755682Smarkm printf("usage: %s [command|data] [clear|safe|confidential|private]\n", 73855682Smarkm argv[0]); 73955682Smarkm code = -1; 74055682Smarkm} 74155682Smarkm 742178825Sdfrvoid 743178825Sdfrsec_prot_command(int argc, char **argv) 744178825Sdfr{ 745178825Sdfr int level; 746178825Sdfr 747178825Sdfr if(argc > 2) 748178825Sdfr goto usage; 749178825Sdfr 750178825Sdfr if(!sec_complete) { 751178825Sdfr printf("No security data exchange has taken place.\n"); 752178825Sdfr code = -1; 753178825Sdfr return; 754178825Sdfr } 755178825Sdfr 756178825Sdfr if(argc == 1) { 757178825Sdfr sec_status(); 758178825Sdfr } else { 759178825Sdfr level = name_to_level(argv[1]); 760178825Sdfr if(level == -1) 761178825Sdfr goto usage; 762233294Sstas 763178825Sdfr if((*mech->check_prot)(app_data, level)) { 764233294Sstas printf("%s does not implement %s protection.\n", 765178825Sdfr mech->name, level_to_name(level)); 766178825Sdfr code = -1; 767178825Sdfr return; 768178825Sdfr } 769178825Sdfr if(set_command_prot(level) < 0) { 770178825Sdfr code = -1; 771178825Sdfr return; 772178825Sdfr } 773178825Sdfr } 774178825Sdfr code = 0; 775178825Sdfr return; 776178825Sdfr usage: 777178825Sdfr printf("usage: %s [clear|safe|confidential|private]\n", 778178825Sdfr argv[0]); 779178825Sdfr code = -1; 780178825Sdfr} 781178825Sdfr 78255682Smarkmstatic enum protection_level request_data_prot; 78355682Smarkm 78455682Smarkmvoid 78555682Smarkmsec_set_protection_level(void) 78655682Smarkm{ 78755682Smarkm if(sec_complete && data_prot != request_data_prot) 78855682Smarkm sec_prot_internal(request_data_prot); 78955682Smarkm} 79055682Smarkm 79155682Smarkm 79255682Smarkmint 79355682Smarkmsec_request_prot(char *level) 79455682Smarkm{ 79555682Smarkm int l = name_to_level(level); 79655682Smarkm if(l == -1) 79755682Smarkm return -1; 79855682Smarkm request_data_prot = (enum protection_level)l; 79955682Smarkm return 0; 80055682Smarkm} 80155682Smarkm 80255682Smarkmint 80355682Smarkmsec_login(char *host) 80455682Smarkm{ 80555682Smarkm int ret; 80655682Smarkm struct sec_client_mech **m; 80755682Smarkm int old_verbose = verbose; 80855682Smarkm 80955682Smarkm verbose = -1; /* shut up all messages this will produce (they 81055682Smarkm are usually not very user friendly) */ 811233294Sstas 81255682Smarkm for(m = mechs; *m && (*m)->name; m++) { 81355682Smarkm void *tmp; 81455682Smarkm 81555682Smarkm tmp = realloc(app_data, (*m)->size); 81655682Smarkm if (tmp == NULL) { 817178825Sdfr warnx ("realloc %lu failed", (unsigned long)(*m)->size); 81855682Smarkm return -1; 81955682Smarkm } 82055682Smarkm app_data = tmp; 821233294Sstas 82255682Smarkm if((*m)->init && (*(*m)->init)(app_data) != 0) { 82355682Smarkm printf("Skipping %s...\n", (*m)->name); 82455682Smarkm continue; 82555682Smarkm } 82655682Smarkm printf("Trying %s...\n", (*m)->name); 82755682Smarkm ret = command("AUTH %s", (*m)->name); 82855682Smarkm if(ret != CONTINUE){ 82955682Smarkm if(code == 504){ 83055682Smarkm printf("%s is not supported by the server.\n", (*m)->name); 83155682Smarkm }else if(code == 534){ 83255682Smarkm printf("%s rejected as security mechanism.\n", (*m)->name); 83355682Smarkm }else if(ret == ERROR) { 83455682Smarkm printf("The server doesn't support the FTP " 83555682Smarkm "security extensions.\n"); 83655682Smarkm verbose = old_verbose; 83755682Smarkm return -1; 83855682Smarkm } 83955682Smarkm continue; 84055682Smarkm } 84155682Smarkm 84255682Smarkm ret = (*(*m)->auth)(app_data, host); 843233294Sstas 84455682Smarkm if(ret == AUTH_CONTINUE) 84555682Smarkm continue; 84655682Smarkm else if(ret != AUTH_OK){ 84755682Smarkm /* mechanism is supposed to output error string */ 84855682Smarkm verbose = old_verbose; 84955682Smarkm return -1; 85055682Smarkm } 85155682Smarkm mech = *m; 85255682Smarkm sec_complete = 1; 853178825Sdfr if(doencrypt) { 854178825Sdfr command_prot = prot_private; 855233294Sstas request_data_prot = prot_private; 856178825Sdfr } else { 857178825Sdfr command_prot = prot_safe; 858178825Sdfr } 85955682Smarkm break; 86055682Smarkm } 861233294Sstas 86255682Smarkm verbose = old_verbose; 86355682Smarkm return *m == NULL; 86455682Smarkm} 86555682Smarkm 86655682Smarkmvoid 86755682Smarkmsec_end(void) 86855682Smarkm{ 86955682Smarkm if (mech != NULL) { 87055682Smarkm if(mech->end) 87155682Smarkm (*mech->end)(app_data); 87278527Sassar if (app_data != NULL) { 87378527Sassar memset(app_data, 0, mech->size); 87478527Sassar free(app_data); 87578527Sassar app_data = NULL; 87678527Sassar } 87755682Smarkm } 87855682Smarkm sec_complete = 0; 87955682Smarkm data_prot = (enum protection_level)0; 88055682Smarkm} 88155682Smarkm 88255682Smarkm#endif /* FTP_SERVER */ 88355682Smarkm 884