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