2 * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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
35 #include "ftpd_locl.h"
41 __RCSID("$Heimdal: krb4.c 17450 2006-05-05 11:11:43Z lha $"
45 #define LOCAL_ADDR ctrl_addr
46 #define REMOTE_ADDR his_addr
48 #define LOCAL_ADDR myctladdr
49 #define REMOTE_ADDR hisctladdr
52 extern struct sockaddr
*LOCAL_ADDR
, *REMOTE_ADDR
;
56 des_key_schedule schedule
;
58 char instance
[INST_SZ
];
63 krb4_check_prot(void *app_data
, int level
)
65 if(level
== prot_confidential
)
71 krb4_decode(void *app_data
, void *buf
, int len
, int level
)
75 struct krb4_data
*d
= app_data
;
77 if(level
== prot_safe
)
78 e
= krb_rd_safe(buf
, len
, &d
->key
,
79 (struct sockaddr_in
*)REMOTE_ADDR
,
80 (struct sockaddr_in
*)LOCAL_ADDR
, &m
);
82 e
= krb_rd_priv(buf
, len
, d
->schedule
, &d
->key
,
83 (struct sockaddr_in
*)REMOTE_ADDR
,
84 (struct sockaddr_in
*)LOCAL_ADDR
, &m
);
86 syslog(LOG_ERR
, "krb4_decode: %s", krb_get_err_text(e
));
89 memmove(buf
, m
.app_data
, m
.app_length
);
94 krb4_overhead(void *app_data
, int level
, int len
)
100 krb4_encode(void *app_data
, void *from
, int length
, int level
, void **to
)
102 struct krb4_data
*d
= app_data
;
103 *to
= malloc(length
+ 31);
104 if(level
== prot_safe
)
105 return krb_mk_safe(from
, *to
, length
, &d
->key
,
106 (struct sockaddr_in
*)LOCAL_ADDR
,
107 (struct sockaddr_in
*)REMOTE_ADDR
);
108 else if(level
== prot_private
)
109 return krb_mk_priv(from
, *to
, length
, d
->schedule
, &d
->key
,
110 (struct sockaddr_in
*)LOCAL_ADDR
,
111 (struct sockaddr_in
*)REMOTE_ADDR
);
119 krb4_adat(void *app_data
, void *buf
, size_t len
)
126 char msg
[35]; /* size of encrypted block */
128 struct krb4_data
*d
= app_data
;
130 struct sockaddr_in
*his_addr_sin
= (struct sockaddr_in
*)his_addr
;
132 memcpy(tkt
.dat
, buf
, len
);
135 k_getsockinst(0, inst
, sizeof(inst
));
136 kerror
= krb_rd_req(&tkt
, "ftp", inst
,
137 his_addr_sin
->sin_addr
.s_addr
, &auth_dat
, "");
138 if(kerror
== RD_AP_UNDEC
){
139 k_getsockinst(0, inst
, sizeof(inst
));
140 kerror
= krb_rd_req(&tkt
, "rcmd", inst
,
141 his_addr_sin
->sin_addr
.s_addr
, &auth_dat
, "");
145 reply(535, "Error reading request: %s.", krb_get_err_text(kerror
));
149 memcpy(d
->key
, auth_dat
.session
, sizeof(d
->key
));
150 des_set_key(&d
->key
, d
->schedule
);
152 strlcpy(d
->name
, auth_dat
.pname
, sizeof(d
->name
));
153 strlcpy(d
->instance
, auth_dat
.pinst
, sizeof(d
->instance
));
154 strlcpy(d
->realm
, auth_dat
.prealm
, sizeof(d
->instance
));
156 cs
= auth_dat
.checksum
+ 1;
158 unsigned char tmp
[4];
159 KRB_PUT_INT(cs
, tmp
, 4, sizeof(tmp
));
160 tmp_len
= krb_mk_safe(tmp
, msg
, 4, &d
->key
,
161 (struct sockaddr_in
*)LOCAL_ADDR
,
162 (struct sockaddr_in
*)REMOTE_ADDR
);
165 reply(535, "Error creating reply: %s.", strerror(errno
));
169 if(base64_encode(msg
, len
, &p
) < 0) {
170 reply(535, "Out of memory base64-encoding.");
173 reply(235, "ADAT=%s", p
);
180 krb4_userok(void *app_data
, char *user
)
182 struct krb4_data
*d
= app_data
;
183 return krb_kuserok(d
->name
, d
->instance
, d
->realm
, user
);
186 struct sec_server_mech krb4_server_mech
= {
188 sizeof(struct krb4_data
),
203 #else /* FTP_SERVER */
206 krb4_init(void *app_data
)
208 return !use_kerberos
;
212 mk_auth(struct krb4_data
*d
, KTEXT adat
,
213 char *service
, char *host
, int checksum
)
217 char sname
[SNAME_SZ
], inst
[INST_SZ
], realm
[REALM_SZ
];
219 strlcpy(sname
, service
, sizeof(sname
));
220 strlcpy(inst
, krb_get_phost(host
), sizeof(inst
));
221 strlcpy(realm
, krb_realmofhost(host
), sizeof(realm
));
222 ret
= krb_mk_req(adat
, sname
, inst
, realm
, checksum
);
225 strlcpy(sname
, service
, sizeof(sname
));
226 strlcpy(inst
, krb_get_phost(host
), sizeof(inst
));
227 strlcpy(realm
, krb_realmofhost(host
), sizeof(realm
));
228 ret
= krb_get_cred(sname
, inst
, realm
, &cred
);
229 memmove(&d
->key
, &cred
.session
, sizeof(des_cblock
));
230 des_key_sched(&d
->key
, d
->schedule
);
231 memset(&cred
, 0, sizeof(cred
));
236 krb4_auth(void *app_data
, char *host
)
245 struct krb4_data
*d
= app_data
;
246 struct sockaddr_in
*localaddr
= (struct sockaddr_in
*)LOCAL_ADDR
;
247 struct sockaddr_in
*remoteaddr
= (struct sockaddr_in
*)REMOTE_ADDR
;
250 ret
= mk_auth(d
, &adat
, "ftp", host
, checksum
);
251 if(ret
== KDC_PR_UNKNOWN
)
252 ret
= mk_auth(d
, &adat
, "rcmd", host
, checksum
);
254 printf("%s\n", krb_get_err_text(ret
));
255 return AUTH_CONTINUE
;
258 #ifdef HAVE_KRB_GET_OUR_IP_FOR_REALM
259 if (krb_get_config_bool("nat_in_use")) {
260 struct in_addr natAddr
;
262 if (krb_get_our_ip_for_realm(krb_realmofhost(host
),
263 &natAddr
) != KSUCCESS
264 && krb_get_our_ip_for_realm(NULL
, &natAddr
) != KSUCCESS
)
265 printf("Can't get address for realm %s\n",
266 krb_realmofhost(host
));
268 if (natAddr
.s_addr
!= localaddr
->sin_addr
.s_addr
) {
269 printf("Using NAT IP address (%s) for kerberos 4\n",
271 localaddr
->sin_addr
= natAddr
;
274 * This not the best place to do this, but it
275 * is here we know that (probably) NAT is in
280 printf("Setting: Passive mode on.\n");
286 printf("Local address is %s\n", inet_ntoa(localaddr
->sin_addr
));
287 printf("Remote address is %s\n", inet_ntoa(remoteaddr
->sin_addr
));
289 if(base64_encode(adat
.dat
, adat
.length
, &p
) < 0) {
290 printf("Out of memory base64-encoding.\n");
291 return AUTH_CONTINUE
;
293 ret
= command("ADAT %s", p
);
297 printf("Server didn't accept auth data.\n");
301 p
= strstr(reply_string
, "ADAT=");
303 printf("Remote host didn't send adat reply.\n");
307 len
= base64_decode(p
, adat
.dat
);
309 printf("Failed to decode base64 from server.\n");
313 ret
= krb_rd_safe(adat
.dat
, adat
.length
, &d
->key
,
314 (struct sockaddr_in
*)hisctladdr
,
315 (struct sockaddr_in
*)myctladdr
, &msg_data
);
317 printf("Error reading reply from server: %s.\n",
318 krb_get_err_text(ret
));
321 krb_get_int(msg_data
.app_data
, &cs
, 4, 0);
322 if(cs
- checksum
!= 1){
323 printf("Bad checksum returned from server.\n");
329 struct sec_client_mech krb4_client_mech
= {
331 sizeof(struct krb4_data
),
332 krb4_init
, /* init */
341 #endif /* FTP_SERVER */