Initial import from FreeBSD RELENG_4:
[games.git] / crypto / kerberosIV / appl / ftp / ftpd / krb4.c
1 /*
2  * Copyright (c) 1995, 1996, 1997 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. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed by the Kungliga Tekniska
20  *      Högskolan and its contributors.
21  * 
22  * 4. Neither the name of the Institute nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  * 
26  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  */
38
39 #ifdef HAVE_CONFIG_H
40 #include <config.h>
41 RCSID("$Id: krb4.c,v 1.19 1997/05/11 09:00:07 assar Exp $");
42 #endif
43
44 #ifdef HAVE_SYS_TYPES_H
45 #include <sys/types.h>
46 #endif
47 #ifdef HAVE_SYS_PARAM_H
48 #include <sys/param.h>
49 #endif
50 #ifdef HAVE_NETINET_IN_h
51 #include <netinet/in.h>
52 #endif
53
54 #include <errno.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <krb.h>
59
60 #include "base64.h"
61 #include "extern.h"
62 #include "auth.h"
63 #include "krb4.h"
64
65 #include <roken.h>
66
67 static AUTH_DAT auth_dat;
68 static des_key_schedule schedule;
69
70 int krb4_auth(char *auth)
71 {
72     auth_complete = 0;
73     reply(334, "Using authentication type %s; ADAT must follow", auth);
74     return 0;
75 }
76
77 int krb4_adat(char *auth)
78 {
79     KTEXT_ST tkt;
80     char *p;
81     int kerror;
82     u_int32_t cs;
83     char msg[35]; /* size of encrypted block */
84     int len;
85
86     char inst[INST_SZ];
87
88     memset(&tkt, 0, sizeof(tkt));
89     len = base64_decode(auth, tkt.dat);
90
91     if(len < 0){
92         reply(501, "Failed to decode base64 data.");
93         return -1;
94     }
95     tkt.length = len;
96
97     k_getsockinst(0, inst, sizeof(inst));
98     kerror = krb_rd_req(&tkt, "ftp", inst, 0, &auth_dat, "");
99     if(kerror == RD_AP_UNDEC){
100         k_getsockinst(0, inst, sizeof(inst));
101         kerror = krb_rd_req(&tkt, "rcmd", inst, 0, &auth_dat, "");
102     }
103
104     if(kerror){
105         reply(535, "Error reading request: %s.", krb_get_err_text(kerror));
106         return -1;
107     }
108   
109     des_set_key(&auth_dat.session, schedule);
110
111     cs = auth_dat.checksum + 1;
112     {
113         unsigned char tmp[4];
114         tmp[0] = (cs >> 24) & 0xff;
115         tmp[1] = (cs >> 16) & 0xff;
116         tmp[2] = (cs >> 8) & 0xff;
117         tmp[3] = cs & 0xff;
118         len = krb_mk_safe(tmp, msg, 4, &auth_dat.session, 
119                           &ctrl_addr, &his_addr);
120     }
121     if(len < 0){
122         reply(535, "Error creating reply: %s.", strerror(errno));
123         return -1;
124     }
125     base64_encode(msg, len, &p);
126     reply(235, "ADAT=%s", p);
127     auth_complete = 1;
128     free(p);
129     return 0;
130 }
131
132 int krb4_pbsz(int size)
133 {
134     if(size > 1048576) /* XXX arbitrary number */
135         size = 1048576;
136     buffer_size = size;
137     reply(200, "OK PBSZ=%d", buffer_size);
138     return 0;
139 }
140
141 int krb4_prot(int level)
142 {
143     if(level == prot_confidential)
144         return -1;
145     return 0;
146 }
147
148 int krb4_ccc(void)
149 {
150     reply(534, "Don't event think about it.");
151     return -1;
152 }
153
154 int krb4_mic(char *msg)
155 {
156     int len;
157     int kerror;
158     MSG_DAT m_data;
159     char *tmp, *cmd;
160   
161     cmd = strdup(msg);
162     
163     len = base64_decode(msg, cmd);
164     if(len < 0){
165         reply(501, "Failed to decode base 64 data.");
166         free(cmd);
167         return -1;
168     }
169     kerror = krb_rd_safe(cmd, len, &auth_dat.session, 
170                          &his_addr, &ctrl_addr, &m_data);
171
172     if(kerror){
173         reply(535, "Error reading request: %s.", krb_get_err_text(kerror));
174         free(cmd);
175         return -1;
176     }
177     
178     tmp = malloc(strlen(msg) + 1);
179     snprintf(tmp, strlen(msg) + 1, "%.*s", (int)m_data.app_length, m_data.app_data);
180     if(!strstr(tmp, "\r\n"))
181         strcat(tmp, "\r\n");
182     new_ftp_command(tmp);
183     free(cmd);
184     return 0;
185 }
186
187 int krb4_conf(char *msg)
188 {
189     prot_level = prot_safe;
190
191     reply(537, "Protection level not supported.");
192     return -1;
193 }
194
195 int krb4_enc(char *msg)
196 {
197     int len;
198     int kerror;
199     MSG_DAT m_data;
200     char *tmp, *cmd;
201   
202     cmd = strdup(msg);
203     
204     len = base64_decode(msg, cmd);
205     if(len < 0){
206         reply(501, "Failed to decode base 64 data.");
207         free(cmd);
208         return -1;
209     }
210     kerror = krb_rd_priv(cmd, len, schedule, &auth_dat.session, 
211                          &his_addr, &ctrl_addr, &m_data);
212
213     if(kerror){
214         reply(535, "Error reading request: %s.", krb_get_err_text(kerror));
215         free(cmd);
216         return -1;
217     }
218     
219     tmp = strdup(msg);
220     snprintf(tmp, strlen(msg) + 1, "%.*s", (int)m_data.app_length, m_data.app_data);
221     if(!strstr(tmp, "\r\n"))
222         strcat(tmp, "\r\n");
223     new_ftp_command(tmp);
224     free(cmd);
225     return 0;
226 }
227
228 int krb4_read(int fd, void *data, int length)
229 {
230     static int left;
231     static char *extra;
232     static int eof;
233     int len, bytes, tx = 0;
234     
235     MSG_DAT m_data;
236     int kerror;
237
238     if(eof){ /* if we haven't reported an end-of-file, do so */
239         eof = 0;
240         return 0;
241     }
242     
243     if(left){
244         if(length > left)
245             bytes = left;
246         else
247             bytes = length;
248         memmove(data, extra, bytes);
249         left -= bytes;
250         if(left)
251             memmove(extra, extra + bytes, left);
252         else
253             free(extra);
254         length -= bytes;
255         tx += bytes;
256     }
257
258     while(length){
259         unsigned char tmp[4];
260         if(krb_net_read(fd, tmp, 4) < 4){
261             reply(400, "Unexpected end of file.\n");
262             return -1;
263         }
264         len = (tmp[0] << 24) | (tmp[1] << 16) | (tmp[2] << 8) | tmp[3];
265         krb_net_read(fd, data_buffer, len);
266         if(data_protection == prot_safe)
267             kerror = krb_rd_safe(data_buffer, len, &auth_dat.session, 
268                                  &his_addr, &ctrl_addr, &m_data);
269         else
270             kerror = krb_rd_priv(data_buffer, len, schedule, &auth_dat.session,
271                                  &his_addr, &ctrl_addr, &m_data);
272         
273         if(kerror){
274             reply(400, "Failed to read data: %s.", krb_get_err_text(kerror));
275             return -1;
276         }
277         
278         bytes = m_data.app_length;
279         if(bytes == 0){
280             if(tx) eof = 1;
281             return  tx;
282         }
283         if(bytes > length){
284             left = bytes - length;
285             bytes = length;
286             extra = malloc(left);
287             memmove(extra, m_data.app_data + bytes, left);
288         }
289         memmove((unsigned char*)data + tx, m_data.app_data, bytes);
290         tx += bytes;
291         length -= bytes;
292     }
293     return tx;
294 }
295
296 int krb4_write(int fd, void *data, int length)
297 {
298     int len, bytes, tx = 0;
299
300     len = buffer_size;
301     if(data_protection == prot_safe)
302         len -= 31; /* always 31 bytes overhead */
303     else
304         len -= 26; /* at most 26 bytes */
305     
306     do{
307         if(length < len)
308             len = length;
309         if(data_protection == prot_safe)
310             bytes = krb_mk_safe(data, data_buffer+4, len, &auth_dat.session,
311                                 &ctrl_addr, &his_addr);
312         else
313             bytes = krb_mk_priv(data, data_buffer+4, len, schedule, 
314                                 &auth_dat.session,
315                                 &ctrl_addr, &his_addr);
316         if(bytes == -1){
317             reply(535, "Failed to make packet: %s.", strerror(errno));
318             return -1;
319         }
320         data_buffer[0] = (bytes >> 24) & 0xff;
321         data_buffer[1] = (bytes >> 16) & 0xff;
322         data_buffer[2] = (bytes >> 8) & 0xff;
323         data_buffer[3] = bytes & 0xff;
324         if(krb_net_write(fd, data_buffer, bytes+4) < 0)
325             return -1;
326         length -= len;
327         data = (unsigned char*)data + len;
328         tx += len;
329     }while(length);
330     return tx;
331 }
332
333 int krb4_userok(char *name)
334 {
335     if(!kuserok(&auth_dat, name)){
336         do_login(232, name);
337     }else{
338         reply(530, "User %s access denied.", name);
339     }
340     return 0;
341 }
342
343
344 int
345 krb4_vprintf(const char *fmt, va_list ap)
346 {
347     char buf[10240];
348     char *p;
349     char *enc;
350     int code;
351     int len;
352   
353     vsnprintf (buf, sizeof(buf), fmt, ap);
354     enc = malloc(strlen(buf) + 31);
355     if(prot_level == prot_safe){
356         len = krb_mk_safe((u_char*)buf, (u_char*)enc, strlen(buf), &auth_dat.session, 
357                           &ctrl_addr, &his_addr); 
358         code = 631;
359     }else if(prot_level == prot_private){
360         len = krb_mk_priv((u_char*)buf, (u_char*)enc, strlen(buf), schedule, 
361                           &auth_dat.session, &ctrl_addr, &his_addr); 
362         code = 632;
363     }else{
364         len = 0; /* XXX */
365         code = 631;
366     }
367     base64_encode(enc, len, &p);
368     fprintf(stdout, "%d %s\r\n", code, p);
369     free(enc);
370     free(p);
371     return 0;
372 }