1178825Sdfr/* 2233294Sstas * Copyright (c) 1998-2002, 2005 Kungliga Tekniska H��gskolan 3178825Sdfr * (Royal Institute of Technology, Stockholm, Sweden). 4178825Sdfr * All rights reserved. 5233294Sstas * 6178825Sdfr * Redistribution and use in source and binary forms, with or without 7178825Sdfr * modification, are permitted provided that the following conditions 8178825Sdfr * are met: 9233294Sstas * 10178825Sdfr * 1. Redistributions of source code must retain the above copyright 11178825Sdfr * notice, this list of conditions and the following disclaimer. 12233294Sstas * 13178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright 14178825Sdfr * notice, this list of conditions and the following disclaimer in the 15178825Sdfr * documentation and/or other materials provided with the distribution. 16233294Sstas * 17178825Sdfr * 3. Neither the name of the Institute nor the names of its contributors 18178825Sdfr * may be used to endorse or promote products derived from this software 19178825Sdfr * without specific prior written permission. 20233294Sstas * 21178825Sdfr * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24178825Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25178825Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26178825Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27178825Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28178825Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29178825Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30178825Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31178825Sdfr * SUCH DAMAGE. 32178825Sdfr */ 33178825Sdfr 34178825Sdfr#ifdef FTP_SERVER 35178825Sdfr#include "ftpd_locl.h" 36178825Sdfr#else 37178825Sdfr#include "ftp_locl.h" 38178825Sdfr#endif 39178825Sdfr 40233294SstasRCSID("$Id$"); 41178825Sdfr 42178825Sdfrstatic enum protection_level command_prot; 43178825Sdfrstatic enum protection_level data_prot; 44178825Sdfrstatic size_t buffer_size; 45178825Sdfr 46178825Sdfrstruct buffer { 47178825Sdfr void *data; 48178825Sdfr size_t size; 49178825Sdfr size_t index; 50178825Sdfr int eof_flag; 51178825Sdfr}; 52178825Sdfr 53178825Sdfrstatic struct buffer in_buffer, out_buffer; 54178825Sdfrint sec_complete; 55178825Sdfr 56178825Sdfrstatic struct { 57178825Sdfr enum protection_level level; 58178825Sdfr const char *name; 59178825Sdfr} level_names[] = { 60178825Sdfr { prot_clear, "clear" }, 61178825Sdfr { prot_safe, "safe" }, 62178825Sdfr { prot_confidential, "confidential" }, 63178825Sdfr { prot_private, "private" } 64178825Sdfr}; 65178825Sdfr 66178825Sdfrstatic const char * 67178825Sdfrlevel_to_name(enum protection_level level) 68178825Sdfr{ 69178825Sdfr int i; 70178825Sdfr for(i = 0; i < sizeof(level_names) / sizeof(level_names[0]); i++) 71178825Sdfr if(level_names[i].level == level) 72178825Sdfr return level_names[i].name; 73178825Sdfr return "unknown"; 74178825Sdfr} 75178825Sdfr 76178825Sdfr#ifndef FTP_SERVER /* not used in server */ 77233294Sstasstatic enum protection_level 78178825Sdfrname_to_level(const char *name) 79178825Sdfr{ 80178825Sdfr int i; 81178825Sdfr for(i = 0; i < sizeof(level_names) / sizeof(level_names[0]); i++) 82178825Sdfr if(!strncasecmp(level_names[i].name, name, strlen(name))) 83178825Sdfr return level_names[i].level; 84233294Sstas return prot_invalid; 85178825Sdfr} 86178825Sdfr#endif 87178825Sdfr 88178825Sdfr#ifdef FTP_SERVER 89178825Sdfr 90178825Sdfrstatic struct sec_server_mech *mechs[] = { 91178825Sdfr#ifdef KRB5 92178825Sdfr &gss_server_mech, 93178825Sdfr#endif 94178825Sdfr NULL 95178825Sdfr}; 96178825Sdfr 97178825Sdfrstatic struct sec_server_mech *mech; 98178825Sdfr 99178825Sdfr#else 100178825Sdfr 101178825Sdfrstatic struct sec_client_mech *mechs[] = { 102178825Sdfr#ifdef KRB5 103178825Sdfr &gss_client_mech, 104178825Sdfr#endif 105178825Sdfr NULL 106178825Sdfr}; 107178825Sdfr 108178825Sdfrstatic struct sec_client_mech *mech; 109178825Sdfr 110178825Sdfr#endif 111178825Sdfr 112178825Sdfrstatic void *app_data; 113178825Sdfr 114178825Sdfrint 115178825Sdfrsec_getc(FILE *F) 116178825Sdfr{ 117178825Sdfr if(sec_complete && data_prot) { 118178825Sdfr char c; 119178825Sdfr if(sec_read(fileno(F), &c, 1) <= 0) 120178825Sdfr return EOF; 121178825Sdfr return c; 122178825Sdfr } else 123178825Sdfr return getc(F); 124178825Sdfr} 125178825Sdfr 126178825Sdfrstatic int 127178825Sdfrblock_read(int fd, void *buf, size_t len) 128178825Sdfr{ 129178825Sdfr unsigned char *p = buf; 130178825Sdfr int b; 131178825Sdfr while(len) { 132178825Sdfr b = read(fd, p, len); 133178825Sdfr if (b == 0) 134178825Sdfr return 0; 135178825Sdfr else if (b < 0) 136178825Sdfr return -1; 137178825Sdfr len -= b; 138178825Sdfr p += b; 139178825Sdfr } 140178825Sdfr return p - (unsigned char*)buf; 141178825Sdfr} 142178825Sdfr 143178825Sdfrstatic int 144178825Sdfrblock_write(int fd, void *buf, size_t len) 145178825Sdfr{ 146178825Sdfr unsigned char *p = buf; 147178825Sdfr int b; 148178825Sdfr while(len) { 149178825Sdfr b = write(fd, p, len); 150178825Sdfr if(b < 0) 151178825Sdfr return -1; 152178825Sdfr len -= b; 153178825Sdfr p += b; 154178825Sdfr } 155178825Sdfr return p - (unsigned char*)buf; 156178825Sdfr} 157178825Sdfr 158178825Sdfrstatic int 159178825Sdfrsec_get_data(int fd, struct buffer *buf, int level) 160178825Sdfr{ 161178825Sdfr int len; 162178825Sdfr int b; 163178825Sdfr void *tmp; 164178825Sdfr 165178825Sdfr b = block_read(fd, &len, sizeof(len)); 166178825Sdfr if (b == 0) 167178825Sdfr return 0; 168178825Sdfr else if (b < 0) 169178825Sdfr return -1; 170178825Sdfr len = ntohl(len); 171178825Sdfr tmp = realloc(buf->data, len); 172178825Sdfr if (tmp == NULL) 173178825Sdfr return -1; 174178825Sdfr buf->data = tmp; 175178825Sdfr b = block_read(fd, buf->data, len); 176178825Sdfr if (b == 0) 177178825Sdfr return 0; 178178825Sdfr else if (b < 0) 179178825Sdfr return -1; 180178825Sdfr buf->size = (*mech->decode)(app_data, buf->data, len, data_prot); 181178825Sdfr buf->index = 0; 182178825Sdfr return 0; 183178825Sdfr} 184178825Sdfr 185178825Sdfrstatic size_t 186178825Sdfrbuffer_read(struct buffer *buf, void *dataptr, size_t len) 187178825Sdfr{ 188178825Sdfr len = min(len, buf->size - buf->index); 189178825Sdfr memcpy(dataptr, (char*)buf->data + buf->index, len); 190178825Sdfr buf->index += len; 191178825Sdfr return len; 192178825Sdfr} 193178825Sdfr 194178825Sdfrstatic size_t 195178825Sdfrbuffer_write(struct buffer *buf, void *dataptr, size_t len) 196178825Sdfr{ 197178825Sdfr if(buf->index + len > buf->size) { 198178825Sdfr void *tmp; 199178825Sdfr if(buf->data == NULL) 200178825Sdfr tmp = malloc(1024); 201178825Sdfr else 202178825Sdfr tmp = realloc(buf->data, buf->index + len); 203178825Sdfr if(tmp == NULL) 204178825Sdfr return -1; 205178825Sdfr buf->data = tmp; 206178825Sdfr buf->size = buf->index + len; 207178825Sdfr } 208178825Sdfr memcpy((char*)buf->data + buf->index, dataptr, len); 209178825Sdfr buf->index += len; 210178825Sdfr return len; 211178825Sdfr} 212178825Sdfr 213178825Sdfrint 214178825Sdfrsec_read(int fd, void *dataptr, int length) 215178825Sdfr{ 216178825Sdfr size_t len; 217178825Sdfr int rx = 0; 218178825Sdfr 219178825Sdfr if(sec_complete == 0 || data_prot == 0) 220178825Sdfr return read(fd, dataptr, length); 221178825Sdfr 222178825Sdfr if(in_buffer.eof_flag){ 223178825Sdfr in_buffer.eof_flag = 0; 224178825Sdfr return 0; 225178825Sdfr } 226233294Sstas 227178825Sdfr len = buffer_read(&in_buffer, dataptr, length); 228178825Sdfr length -= len; 229178825Sdfr rx += len; 230178825Sdfr dataptr = (char*)dataptr + len; 231233294Sstas 232178825Sdfr while(length){ 233178825Sdfr int ret; 234178825Sdfr 235178825Sdfr ret = sec_get_data(fd, &in_buffer, data_prot); 236178825Sdfr if (ret < 0) 237178825Sdfr return -1; 238178825Sdfr if(ret == 0 && in_buffer.size == 0) { 239178825Sdfr if(rx) 240178825Sdfr in_buffer.eof_flag = 1; 241178825Sdfr return rx; 242178825Sdfr } 243178825Sdfr len = buffer_read(&in_buffer, dataptr, length); 244178825Sdfr length -= len; 245178825Sdfr rx += len; 246178825Sdfr dataptr = (char*)dataptr + len; 247178825Sdfr } 248178825Sdfr return rx; 249178825Sdfr} 250178825Sdfr 251178825Sdfrstatic int 252178825Sdfrsec_send(int fd, char *from, int length) 253178825Sdfr{ 254178825Sdfr int bytes; 255178825Sdfr void *buf; 256178825Sdfr bytes = (*mech->encode)(app_data, from, length, data_prot, &buf); 257178825Sdfr bytes = htonl(bytes); 258178825Sdfr block_write(fd, &bytes, sizeof(bytes)); 259178825Sdfr block_write(fd, buf, ntohl(bytes)); 260178825Sdfr free(buf); 261178825Sdfr return length; 262178825Sdfr} 263178825Sdfr 264178825Sdfrint 265178825Sdfrsec_fflush(FILE *F) 266178825Sdfr{ 267178825Sdfr if(data_prot != prot_clear) { 268178825Sdfr if(out_buffer.index > 0){ 269178825Sdfr sec_write(fileno(F), out_buffer.data, out_buffer.index); 270178825Sdfr out_buffer.index = 0; 271178825Sdfr } 272178825Sdfr sec_send(fileno(F), NULL, 0); 273178825Sdfr } 274178825Sdfr fflush(F); 275178825Sdfr return 0; 276178825Sdfr} 277178825Sdfr 278178825Sdfrint 279178825Sdfrsec_write(int fd, char *dataptr, int length) 280178825Sdfr{ 281178825Sdfr int len = buffer_size; 282178825Sdfr int tx = 0; 283233294Sstas 284178825Sdfr if(data_prot == prot_clear) 285178825Sdfr return write(fd, dataptr, length); 286178825Sdfr 287178825Sdfr len -= (*mech->overhead)(app_data, data_prot, len); 288178825Sdfr while(length){ 289178825Sdfr if(length < len) 290178825Sdfr len = length; 291178825Sdfr sec_send(fd, dataptr, len); 292178825Sdfr length -= len; 293178825Sdfr dataptr += len; 294178825Sdfr tx += len; 295178825Sdfr } 296178825Sdfr return tx; 297178825Sdfr} 298178825Sdfr 299178825Sdfrint 300178825Sdfrsec_vfprintf2(FILE *f, const char *fmt, va_list ap) 301178825Sdfr{ 302178825Sdfr char *buf; 303178825Sdfr int ret; 304178825Sdfr if(data_prot == prot_clear) 305178825Sdfr return vfprintf(f, fmt, ap); 306178825Sdfr 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); 312178825Sdfr free(buf); 313178825Sdfr return ret; 314178825Sdfr } 315178825Sdfr} 316178825Sdfr 317178825Sdfrint 318178825Sdfrsec_fprintf2(FILE *f, const char *fmt, ...) 319178825Sdfr{ 320178825Sdfr int ret; 321178825Sdfr va_list ap; 322178825Sdfr va_start(ap, fmt); 323178825Sdfr ret = sec_vfprintf2(f, fmt, ap); 324178825Sdfr va_end(ap); 325178825Sdfr return ret; 326178825Sdfr} 327178825Sdfr 328178825Sdfrint 329178825Sdfrsec_putc(int c, FILE *F) 330178825Sdfr{ 331178825Sdfr char ch = c; 332178825Sdfr if(data_prot == prot_clear) 333178825Sdfr return putc(c, F); 334233294Sstas 335178825Sdfr buffer_write(&out_buffer, &ch, 1); 336178825Sdfr if(c == '\n' || out_buffer.index >= 1024 /* XXX */) { 337178825Sdfr sec_write(fileno(F), out_buffer.data, out_buffer.index); 338178825Sdfr out_buffer.index = 0; 339178825Sdfr } 340178825Sdfr return c; 341178825Sdfr} 342178825Sdfr 343178825Sdfrint 344178825Sdfrsec_read_msg(char *s, int level) 345178825Sdfr{ 346178825Sdfr int len; 347178825Sdfr char *buf; 348178825Sdfr int return_code; 349233294Sstas 350178825Sdfr buf = malloc(strlen(s)); 351178825Sdfr len = base64_decode(s + 4, buf); /* XXX */ 352233294Sstas 353178825Sdfr len = (*mech->decode)(app_data, buf, len, level); 354178825Sdfr if(len < 0) 355178825Sdfr return -1; 356233294Sstas 357178825Sdfr buf[len] = '\0'; 358178825Sdfr 359178825Sdfr if(buf[3] == '-') 360178825Sdfr return_code = 0; 361178825Sdfr else 362178825Sdfr sscanf(buf, "%d", &return_code); 363178825Sdfr if(buf[len-1] == '\n') 364178825Sdfr buf[len-1] = '\0'; 365178825Sdfr strcpy(s, buf); 366178825Sdfr free(buf); 367178825Sdfr return return_code; 368178825Sdfr} 369178825Sdfr 370178825Sdfrint 371178825Sdfrsec_vfprintf(FILE *f, const char *fmt, va_list ap) 372178825Sdfr{ 373178825Sdfr char *buf; 374178825Sdfr void *enc; 375178825Sdfr int len; 376178825Sdfr if(!sec_complete) 377178825Sdfr return vfprintf(f, fmt, ap); 378233294Sstas 379178825Sdfr if (vasprintf(&buf, fmt, ap) == -1) { 380178825Sdfr printf("Failed to allocate command.\n"); 381178825Sdfr return -1; 382178825Sdfr } 383178825Sdfr len = (*mech->encode)(app_data, buf, strlen(buf), command_prot, &enc); 384178825Sdfr free(buf); 385178825Sdfr if(len < 0) { 386178825Sdfr printf("Failed to encode command.\n"); 387178825Sdfr return -1; 388178825Sdfr } 389178825Sdfr if(base64_encode(enc, len, &buf) < 0){ 390178825Sdfr free(enc); 391178825Sdfr printf("Out of memory base64-encoding.\n"); 392178825Sdfr return -1; 393178825Sdfr } 394178825Sdfr free(enc); 395178825Sdfr#ifdef FTP_SERVER 396178825Sdfr if(command_prot == prot_safe) 397178825Sdfr fprintf(f, "631 %s\r\n", buf); 398178825Sdfr else if(command_prot == prot_private) 399178825Sdfr fprintf(f, "632 %s\r\n", buf); 400178825Sdfr else if(command_prot == prot_confidential) 401178825Sdfr fprintf(f, "633 %s\r\n", buf); 402178825Sdfr#else 403178825Sdfr if(command_prot == prot_safe) 404178825Sdfr fprintf(f, "MIC %s", buf); 405178825Sdfr else if(command_prot == prot_private) 406178825Sdfr fprintf(f, "ENC %s", buf); 407178825Sdfr else if(command_prot == prot_confidential) 408178825Sdfr fprintf(f, "CONF %s", buf); 409178825Sdfr#endif 410178825Sdfr free(buf); 411178825Sdfr return 0; 412178825Sdfr} 413178825Sdfr 414178825Sdfrint 415178825Sdfrsec_fprintf(FILE *f, const char *fmt, ...) 416178825Sdfr{ 417178825Sdfr va_list ap; 418178825Sdfr int ret; 419178825Sdfr va_start(ap, fmt); 420178825Sdfr ret = sec_vfprintf(f, fmt, ap); 421178825Sdfr va_end(ap); 422178825Sdfr return ret; 423178825Sdfr} 424178825Sdfr 425178825Sdfr/* end common stuff */ 426178825Sdfr 427178825Sdfr#ifdef FTP_SERVER 428178825Sdfr 429178825Sdfrint ccc_passed; 430178825Sdfr 431178825Sdfrvoid 432178825Sdfrauth(char *auth_name) 433178825Sdfr{ 434178825Sdfr int i; 435178825Sdfr void *tmp; 436178825Sdfr 437178825Sdfr for(i = 0; (mech = mechs[i]) != NULL; i++){ 438178825Sdfr if(!strcasecmp(auth_name, mech->name)){ 439178825Sdfr tmp = realloc(app_data, mech->size); 440178825Sdfr if (tmp == NULL) { 441178825Sdfr reply(431, "Unable to accept %s at this time", mech->name); 442178825Sdfr return; 443178825Sdfr } 444178825Sdfr app_data = tmp; 445178825Sdfr 446178825Sdfr if(mech->init && (*mech->init)(app_data) != 0) { 447178825Sdfr reply(431, "Unable to accept %s at this time", mech->name); 448178825Sdfr return; 449178825Sdfr } 450178825Sdfr if(mech->auth) { 451178825Sdfr (*mech->auth)(app_data); 452178825Sdfr return; 453178825Sdfr } 454178825Sdfr if(mech->adat) 455178825Sdfr reply(334, "Send authorization data."); 456178825Sdfr else 457178825Sdfr reply(234, "Authorization complete."); 458178825Sdfr return; 459178825Sdfr } 460178825Sdfr } 461178825Sdfr free (app_data); 462178825Sdfr app_data = NULL; 463178825Sdfr reply(504, "%s is unknown to me", auth_name); 464178825Sdfr} 465178825Sdfr 466178825Sdfrvoid 467178825Sdfradat(char *auth_data) 468178825Sdfr{ 469178825Sdfr if(mech && !sec_complete) { 470178825Sdfr void *buf = malloc(strlen(auth_data)); 471178825Sdfr size_t len; 472178825Sdfr len = base64_decode(auth_data, buf); 473178825Sdfr (*mech->adat)(app_data, buf, len); 474178825Sdfr free(buf); 475178825Sdfr } else 476178825Sdfr reply(503, "You must %sissue an AUTH first.", mech ? "re-" : ""); 477178825Sdfr} 478178825Sdfr 479178825Sdfrvoid pbsz(int size) 480178825Sdfr{ 481178825Sdfr size_t new = size; 482178825Sdfr if(!sec_complete) 483178825Sdfr reply(503, "Incomplete security data exchange."); 484178825Sdfr if(mech->pbsz) 485178825Sdfr new = (*mech->pbsz)(app_data, size); 486178825Sdfr if(buffer_size != new){ 487178825Sdfr buffer_size = size; 488178825Sdfr } 489178825Sdfr if(new != size) 490178825Sdfr reply(200, "PBSZ=%lu", (unsigned long)new); 491178825Sdfr else 492178825Sdfr reply(200, "OK"); 493178825Sdfr} 494178825Sdfr 495178825Sdfrvoid 496178825Sdfrprot(char *pl) 497178825Sdfr{ 498178825Sdfr int p = -1; 499178825Sdfr 500178825Sdfr if(buffer_size == 0){ 501178825Sdfr reply(503, "No protection buffer size negotiated."); 502178825Sdfr return; 503178825Sdfr } 504178825Sdfr 505178825Sdfr if(!strcasecmp(pl, "C")) 506178825Sdfr p = prot_clear; 507178825Sdfr else if(!strcasecmp(pl, "S")) 508178825Sdfr p = prot_safe; 509178825Sdfr else if(!strcasecmp(pl, "E")) 510178825Sdfr p = prot_confidential; 511178825Sdfr else if(!strcasecmp(pl, "P")) 512178825Sdfr p = prot_private; 513178825Sdfr else { 514178825Sdfr reply(504, "Unrecognized protection level."); 515178825Sdfr return; 516178825Sdfr } 517233294Sstas 518178825Sdfr if(sec_complete){ 519178825Sdfr if((*mech->check_prot)(app_data, p)){ 520233294Sstas reply(536, "%s does not support %s protection.", 521178825Sdfr mech->name, level_to_name(p)); 522178825Sdfr }else{ 523178825Sdfr data_prot = (enum protection_level)p; 524178825Sdfr reply(200, "Data protection is %s.", level_to_name(p)); 525178825Sdfr } 526178825Sdfr }else{ 527178825Sdfr reply(503, "Incomplete security data exchange."); 528178825Sdfr } 529178825Sdfr} 530178825Sdfr 531178825Sdfrvoid ccc(void) 532178825Sdfr{ 533178825Sdfr if(sec_complete){ 534178825Sdfr if(mech->ccc && (*mech->ccc)(app_data) == 0) { 535178825Sdfr command_prot = data_prot = prot_clear; 536178825Sdfr ccc_passed = 1; 537178825Sdfr } else 538178825Sdfr reply(534, "You must be joking."); 539178825Sdfr }else 540178825Sdfr reply(503, "Incomplete security data exchange."); 541178825Sdfr} 542178825Sdfr 543178825Sdfrvoid mec(char *msg, enum protection_level level) 544178825Sdfr{ 545178825Sdfr void *buf; 546178825Sdfr size_t len, buf_size; 547178825Sdfr if(!sec_complete) { 548178825Sdfr reply(503, "Incomplete security data exchange."); 549178825Sdfr return; 550178825Sdfr } 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 } 557178825Sdfr len = base64_decode(msg, buf); 558178825Sdfr command_prot = level; 559178825Sdfr if(len == (size_t)-1) { 560233294Sstas free(buf); 561178825Sdfr reply(501, "Failed to base64-decode command"); 562178825Sdfr return; 563178825Sdfr } 564178825Sdfr len = (*mech->decode)(app_data, buf, len, level); 565178825Sdfr if(len == (size_t)-1) { 566233294Sstas free(buf); 567178825Sdfr reply(535, "Failed to decode command"); 568178825Sdfr return; 569178825Sdfr } 570178825Sdfr ((char*)buf)[len] = '\0'; 571178825Sdfr if(strstr((char*)buf, "\r\n") == NULL) 572178825Sdfr strlcat((char*)buf, "\r\n", buf_size); 573178825Sdfr new_ftp_command(buf); 574178825Sdfr} 575178825Sdfr 576178825Sdfr/* ------------------------------------------------------------ */ 577178825Sdfr 578178825Sdfrint 579178825Sdfrsec_userok(char *userstr) 580178825Sdfr{ 581178825Sdfr if(sec_complete) 582178825Sdfr return (*mech->userok)(app_data, userstr); 583178825Sdfr return 0; 584178825Sdfr} 585178825Sdfr 586178825Sdfrint 587178825Sdfrsec_session(char *user) 588178825Sdfr{ 589178825Sdfr if(sec_complete && mech->session) 590178825Sdfr return (*mech->session)(app_data, user); 591178825Sdfr return 0; 592178825Sdfr} 593178825Sdfr 594178825Sdfrchar *ftp_command; 595178825Sdfr 596178825Sdfrvoid 597178825Sdfrnew_ftp_command(char *command) 598178825Sdfr{ 599178825Sdfr ftp_command = command; 600178825Sdfr} 601178825Sdfr 602178825Sdfrvoid 603178825Sdfrdelete_ftp_command(void) 604178825Sdfr{ 605178825Sdfr free(ftp_command); 606178825Sdfr ftp_command = NULL; 607178825Sdfr} 608178825Sdfr 609178825Sdfrint 610178825Sdfrsecure_command(void) 611178825Sdfr{ 612178825Sdfr return ftp_command != NULL; 613178825Sdfr} 614178825Sdfr 615178825Sdfrenum protection_level 616178825Sdfrget_command_prot(void) 617178825Sdfr{ 618178825Sdfr return command_prot; 619178825Sdfr} 620178825Sdfr 621178825Sdfr#else /* FTP_SERVER */ 622178825Sdfr 623178825Sdfrvoid 624178825Sdfrsec_status(void) 625178825Sdfr{ 626178825Sdfr if(sec_complete){ 627178825Sdfr printf("Using %s for authentication.\n", mech->name); 628178825Sdfr printf("Using %s command channel.\n", level_to_name(command_prot)); 629178825Sdfr printf("Using %s data channel.\n", level_to_name(data_prot)); 630178825Sdfr if(buffer_size > 0) 631233294Sstas printf("Protection buffer size: %lu.\n", 632178825Sdfr (unsigned long)buffer_size); 633178825Sdfr }else{ 634178825Sdfr printf("Not using any security mechanism.\n"); 635178825Sdfr } 636178825Sdfr} 637178825Sdfr 638178825Sdfrstatic int 639178825Sdfrsec_prot_internal(int level) 640178825Sdfr{ 641178825Sdfr int ret; 642178825Sdfr char *p; 643178825Sdfr unsigned int s = 1048576; 644178825Sdfr 645178825Sdfr int old_verbose = verbose; 646178825Sdfr verbose = 0; 647178825Sdfr 648178825Sdfr if(!sec_complete){ 649178825Sdfr printf("No security data exchange has taken place.\n"); 650178825Sdfr return -1; 651178825Sdfr } 652178825Sdfr 653178825Sdfr if(level){ 654178825Sdfr ret = command("PBSZ %u", s); 655178825Sdfr if(ret != COMPLETE){ 656178825Sdfr printf("Failed to set protection buffer size.\n"); 657178825Sdfr return -1; 658178825Sdfr } 659178825Sdfr buffer_size = s; 660178825Sdfr p = strstr(reply_string, "PBSZ="); 661178825Sdfr if(p) 662178825Sdfr sscanf(p, "PBSZ=%u", &s); 663178825Sdfr if(s < buffer_size) 664178825Sdfr buffer_size = s; 665178825Sdfr } 666178825Sdfr verbose = old_verbose; 667178825Sdfr ret = command("PROT %c", level["CSEP"]); /* XXX :-) */ 668178825Sdfr if(ret != COMPLETE){ 669178825Sdfr printf("Failed to set protection level.\n"); 670178825Sdfr return -1; 671178825Sdfr } 672233294Sstas 673178825Sdfr data_prot = (enum protection_level)level; 674178825Sdfr return 0; 675178825Sdfr} 676178825Sdfr 677178825Sdfrenum protection_level 678178825Sdfrset_command_prot(enum protection_level level) 679178825Sdfr{ 680178825Sdfr int ret; 681178825Sdfr 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 } 689178825Sdfr command_prot = level; 690178825Sdfr return old; 691178825Sdfr} 692178825Sdfr 693178825Sdfrvoid 694178825Sdfrsec_prot(int argc, char **argv) 695178825Sdfr{ 696178825Sdfr int level = -1; 697178825Sdfr 698178825Sdfr if(argc > 3) 699178825Sdfr goto usage; 700178825Sdfr 701178825Sdfr if(argc == 1) { 702178825Sdfr sec_status(); 703178825Sdfr return; 704178825Sdfr } 705178825Sdfr if(!sec_complete) { 706178825Sdfr printf("No security data exchange has taken place.\n"); 707178825Sdfr code = -1; 708178825Sdfr return; 709178825Sdfr } 710178825Sdfr level = name_to_level(argv[argc - 1]); 711233294Sstas 712178825Sdfr if(level == -1) 713178825Sdfr goto usage; 714233294Sstas 715178825Sdfr if((*mech->check_prot)(app_data, level)) { 716233294Sstas printf("%s does not implement %s protection.\n", 717178825Sdfr mech->name, level_to_name(level)); 718178825Sdfr code = -1; 719178825Sdfr return; 720178825Sdfr } 721233294Sstas 722178825Sdfr if(argc == 2 || strncasecmp(argv[1], "data", strlen(argv[1])) == 0) { 723178825Sdfr if(sec_prot_internal(level) < 0){ 724178825Sdfr code = -1; 725178825Sdfr return; 726178825Sdfr } 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 733178825Sdfr goto usage; 734178825Sdfr code = 0; 735178825Sdfr return; 736178825Sdfr usage: 737178825Sdfr printf("usage: %s [command|data] [clear|safe|confidential|private]\n", 738178825Sdfr argv[0]); 739178825Sdfr code = -1; 740178825Sdfr} 741178825Sdfr 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 782178825Sdfrstatic enum protection_level request_data_prot; 783178825Sdfr 784178825Sdfrvoid 785178825Sdfrsec_set_protection_level(void) 786178825Sdfr{ 787178825Sdfr if(sec_complete && data_prot != request_data_prot) 788178825Sdfr sec_prot_internal(request_data_prot); 789178825Sdfr} 790178825Sdfr 791178825Sdfr 792178825Sdfrint 793178825Sdfrsec_request_prot(char *level) 794178825Sdfr{ 795178825Sdfr int l = name_to_level(level); 796178825Sdfr if(l == -1) 797178825Sdfr return -1; 798178825Sdfr request_data_prot = (enum protection_level)l; 799178825Sdfr return 0; 800178825Sdfr} 801178825Sdfr 802178825Sdfrint 803178825Sdfrsec_login(char *host) 804178825Sdfr{ 805178825Sdfr int ret; 806178825Sdfr struct sec_client_mech **m; 807178825Sdfr int old_verbose = verbose; 808178825Sdfr 809178825Sdfr verbose = -1; /* shut up all messages this will produce (they 810178825Sdfr are usually not very user friendly) */ 811233294Sstas 812178825Sdfr for(m = mechs; *m && (*m)->name; m++) { 813178825Sdfr void *tmp; 814178825Sdfr 815178825Sdfr tmp = realloc(app_data, (*m)->size); 816178825Sdfr if (tmp == NULL) { 817178825Sdfr warnx ("realloc %lu failed", (unsigned long)(*m)->size); 818178825Sdfr return -1; 819178825Sdfr } 820178825Sdfr app_data = tmp; 821233294Sstas 822178825Sdfr if((*m)->init && (*(*m)->init)(app_data) != 0) { 823178825Sdfr printf("Skipping %s...\n", (*m)->name); 824178825Sdfr continue; 825178825Sdfr } 826178825Sdfr printf("Trying %s...\n", (*m)->name); 827178825Sdfr ret = command("AUTH %s", (*m)->name); 828178825Sdfr if(ret != CONTINUE){ 829178825Sdfr if(code == 504){ 830178825Sdfr printf("%s is not supported by the server.\n", (*m)->name); 831178825Sdfr }else if(code == 534){ 832178825Sdfr printf("%s rejected as security mechanism.\n", (*m)->name); 833178825Sdfr }else if(ret == ERROR) { 834178825Sdfr printf("The server doesn't support the FTP " 835178825Sdfr "security extensions.\n"); 836178825Sdfr verbose = old_verbose; 837178825Sdfr return -1; 838178825Sdfr } 839178825Sdfr continue; 840178825Sdfr } 841178825Sdfr 842178825Sdfr ret = (*(*m)->auth)(app_data, host); 843233294Sstas 844178825Sdfr if(ret == AUTH_CONTINUE) 845178825Sdfr continue; 846178825Sdfr else if(ret != AUTH_OK){ 847178825Sdfr /* mechanism is supposed to output error string */ 848178825Sdfr verbose = old_verbose; 849178825Sdfr return -1; 850178825Sdfr } 851178825Sdfr mech = *m; 852178825Sdfr 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 } 859178825Sdfr break; 860178825Sdfr } 861233294Sstas 862178825Sdfr verbose = old_verbose; 863178825Sdfr return *m == NULL; 864178825Sdfr} 865178825Sdfr 866178825Sdfrvoid 867178825Sdfrsec_end(void) 868178825Sdfr{ 869178825Sdfr if (mech != NULL) { 870178825Sdfr if(mech->end) 871178825Sdfr (*mech->end)(app_data); 872178825Sdfr if (app_data != NULL) { 873178825Sdfr memset(app_data, 0, mech->size); 874178825Sdfr free(app_data); 875178825Sdfr app_data = NULL; 876178825Sdfr } 877178825Sdfr } 878178825Sdfr sec_complete = 0; 879178825Sdfr data_prot = (enum protection_level)0; 880178825Sdfr} 881178825Sdfr 882178825Sdfr#endif /* FTP_SERVER */ 883178825Sdfr 884