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