xref: /freebsd/crypto/heimdal/appl/ftp/ftpd/security.c (revision 6a068746777241722b2b32c5d0bc443a2a64d80b)
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