1 /* This source code was modified by Martin Hedenfalk <mhe@stacken.kth.se> for
2 * use in Curl. Martin's latest changes were done 2000-09-18.
4 * It has since been patched away like a madman by Daniel Stenberg to make it
5 * better applied to curl conditions, and to make it not use globals, pollute
8 * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
9 * (Royal Institute of Technology, Stockholm, Sweden).
10 * Copyright (c) 2004 - 2008 Daniel Stenberg
11 * All rights reserved.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in the
22 * documentation and/or other materials provided with the distribution.
24 * 3. Neither the name of the Institute nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 * $Id: krb4.c,v 1.1.1.1 2008-09-23 16:32:05 hoffman Exp $
45 #ifndef CURL_DISABLE_FTP
57 #include <unistd.h> /* for getpid() */
61 #include "curl_base64.h"
67 #if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
68 #include "inet_ntoa_r.h"
71 /* The last #include file should be: */
74 #define LOCAL_ADDR (&conn->local_addr)
75 #define REMOTE_ADDR conn->ip_addr->ai_addr
76 #define myctladdr LOCAL_ADDR
77 #define hisctladdr REMOTE_ADDR
81 des_key_schedule schedule
;
83 char instance
[INST_SZ
];
88 /* if it ever goes non-static, make it Curl_ prefixed! */
90 strlcpy (char *dst
, const char *src
, size_t dst_sz
)
96 n
+ 1 < dst_sz
&& *src
!= '\0';
103 return n
+ strlen (src
);
106 size_t strlcpy (char *dst
, const char *src
, size_t dst_sz
);
110 krb4_check_prot(void *app_data
, int level
)
112 app_data
= NULL
; /* prevent compiler warning */
113 if(level
== prot_confidential
)
119 krb4_decode(void *app_data
, void *buf
, int len
, int level
,
120 struct connectdata
*conn
)
124 struct krb4_data
*d
= app_data
;
126 if(level
== prot_safe
)
127 e
= krb_rd_safe(buf
, len
, &d
->key
,
128 (struct sockaddr_in
*)REMOTE_ADDR
,
129 (struct sockaddr_in
*)LOCAL_ADDR
, &m
);
131 e
= krb_rd_priv(buf
, len
, d
->schedule
, &d
->key
,
132 (struct sockaddr_in
*)REMOTE_ADDR
,
133 (struct sockaddr_in
*)LOCAL_ADDR
, &m
);
135 struct SessionHandle
*data
= conn
->data
;
136 infof(data
, "krb4_decode: %s\n", krb_get_err_text(e
));
139 memmove(buf
, m
.app_data
, m
.app_length
);
144 krb4_overhead(void *app_data
, int level
, int len
)
146 /* no arguments are used, just init them to prevent compiler warnings */
154 krb4_encode(void *app_data
, const void *from
, int length
, int level
, void **to
,
155 struct connectdata
*conn
)
157 struct krb4_data
*d
= app_data
;
158 *to
= malloc(length
+ 31);
159 if(level
== prot_safe
)
160 /* NOTE that the void* cast is safe, krb_mk_safe/priv don't modify the
163 return krb_mk_safe((void*)from
, *to
, length
, &d
->key
,
164 (struct sockaddr_in
*)LOCAL_ADDR
,
165 (struct sockaddr_in
*)REMOTE_ADDR
);
166 else if(level
== prot_private
)
167 return krb_mk_priv((void*)from
, *to
, length
, d
->schedule
, &d
->key
,
168 (struct sockaddr_in
*)LOCAL_ADDR
,
169 (struct sockaddr_in
*)REMOTE_ADDR
);
175 mk_auth(struct krb4_data
*d
, KTEXT adat
,
176 const char *service
, char *host
, int checksum
)
180 char sname
[SNAME_SZ
], inst
[INST_SZ
], realm
[REALM_SZ
];
182 strlcpy(sname
, service
, sizeof(sname
));
183 strlcpy(inst
, krb_get_phost(host
), sizeof(inst
));
184 strlcpy(realm
, krb_realmofhost(host
), sizeof(realm
));
185 ret
= krb_mk_req(adat
, sname
, inst
, realm
, checksum
);
188 strlcpy(sname
, service
, sizeof(sname
));
189 strlcpy(inst
, krb_get_phost(host
), sizeof(inst
));
190 strlcpy(realm
, krb_realmofhost(host
), sizeof(realm
));
191 ret
= krb_get_cred(sname
, inst
, realm
, &cred
);
192 memmove(&d
->key
, &cred
.session
, sizeof(des_cblock
));
193 des_key_sched(&d
->key
, d
->schedule
);
194 memset(&cred
, 0, sizeof(cred
));
198 #ifdef HAVE_KRB_GET_OUR_IP_FOR_REALM
199 int krb_get_our_ip_for_realm(char *, struct in_addr
*);
203 krb4_auth(void *app_data
, struct connectdata
*conn
)
213 struct krb4_data
*d
= app_data
;
214 char *host
= conn
->host
.name
;
216 int l
= sizeof(conn
->local_addr
);
217 struct SessionHandle
*data
= conn
->data
;
220 if(getsockname(conn
->sock
[FIRSTSOCKET
],
221 (struct sockaddr
*)LOCAL_ADDR
, &l
) < 0)
222 perror("getsockname()");
225 ret
= mk_auth(d
, &adat
, "ftp", host
, checksum
);
226 if(ret
== KDC_PR_UNKNOWN
)
227 ret
= mk_auth(d
, &adat
, "rcmd", host
, checksum
);
229 infof(data
, "%s\n", krb_get_err_text(ret
));
230 return AUTH_CONTINUE
;
233 #ifdef HAVE_KRB_GET_OUR_IP_FOR_REALM
234 if(krb_get_config_bool("nat_in_use")) {
235 struct sockaddr_in
*localaddr
= (struct sockaddr_in
*)LOCAL_ADDR
;
236 struct in_addr natAddr
;
238 if(krb_get_our_ip_for_realm(krb_realmofhost(host
),
239 &natAddr
) != KSUCCESS
240 && krb_get_our_ip_for_realm(NULL
, &natAddr
) != KSUCCESS
)
241 infof(data
, "Can't get address for realm %s\n",
242 krb_realmofhost(host
));
244 if(natAddr
.s_addr
!= localaddr
->sin_addr
.s_addr
) {
245 #ifdef HAVE_INET_NTOA_R
247 char *ip
= (char *)inet_ntoa_r(natAddr
, ntoa_buf
, sizeof(ntoa_buf
));
249 char *ip
= (char *)inet_ntoa(natAddr
);
251 infof(data
, "Using NAT IP address (%s) for kerberos 4\n", ip
);
252 localaddr
->sin_addr
= natAddr
;
258 if(Curl_base64_encode(conn
->data
, (char *)adat
.dat
, adat
.length
, &p
) < 1) {
259 Curl_failf(data
, "Out of memory base64-encoding");
260 return AUTH_CONTINUE
;
263 result
= Curl_ftpsendf(conn
, "ADAT %s", p
);
270 if(Curl_GetFTPResponse(&nread
, conn
, NULL
))
273 if(data
->state
.buffer
[0] != '2'){
274 Curl_failf(data
, "Server didn't accept auth data");
278 p
= strstr(data
->state
.buffer
, "ADAT=");
280 Curl_failf(data
, "Remote host didn't send adat reply");
284 len
= Curl_base64_decode(p
, &ptr
);
285 if(len
> sizeof(adat
.dat
)-1) {
290 Curl_failf(data
, "Failed to decode base64 from server");
293 memcpy((char *)adat
.dat
, ptr
, len
);
296 ret
= krb_rd_safe(adat
.dat
, adat
.length
, &d
->key
,
297 (struct sockaddr_in
*)hisctladdr
,
298 (struct sockaddr_in
*)myctladdr
, &msg_data
);
300 Curl_failf(data
, "Error reading reply from server: %s",
301 krb_get_err_text(ret
));
304 krb_get_int(msg_data
.app_data
, &cs
, 4, 0);
305 if(cs
- checksum
!= 1) {
306 Curl_failf(data
, "Bad checksum returned from server");
312 struct Curl_sec_client_mech Curl_krb4_client_mech
= {
314 sizeof(struct krb4_data
),
324 CURLcode
Curl_krb_kauth(struct connectdata
*conn
)
327 des_key_schedule schedule
;
328 KTEXT_ST tkt
, tktcopy
;
338 save
= Curl_set_command_prot(conn
, prot_private
);
340 result
= Curl_ftpsendf(conn
, "SITE KAUTH %s", conn
->user
);
345 result
= Curl_GetFTPResponse(&nread
, conn
, NULL
);
349 if(conn
->data
->state
.buffer
[0] != '3'){
350 Curl_set_command_prot(conn
, save
);
351 return CURLE_FTP_WEIRD_SERVER_REPLY
;
354 p
= strstr(conn
->data
->state
.buffer
, "T=");
356 Curl_failf(conn
->data
, "Bad reply from server");
357 Curl_set_command_prot(conn
, save
);
358 return CURLE_FTP_WEIRD_SERVER_REPLY
;
362 tmp
= Curl_base64_decode(p
, &ptr
);
363 if(tmp
>= sizeof(tkt
.dat
)) {
368 Curl_failf(conn
->data
, "Failed to decode base64 in reply");
369 Curl_set_command_prot(conn
, save
);
370 return CURLE_FTP_WEIRD_SERVER_REPLY
;
372 memcpy((char *)tkt
.dat
, ptr
, tmp
);
375 tktcopy
.length
= tkt
.length
;
377 p
= strstr(conn
->data
->state
.buffer
, "P=");
379 Curl_failf(conn
->data
, "Bad reply from server");
380 Curl_set_command_prot(conn
, save
);
381 return CURLE_FTP_WEIRD_SERVER_REPLY
;
384 for(; *p
&& *p
!= ' ' && *p
!= '\r' && *p
!= '\n'; p
++);
387 des_string_to_key (conn
->passwd
, &key
);
388 des_key_sched(&key
, schedule
);
390 des_pcbc_encrypt((void *)tkt
.dat
, (void *)tktcopy
.dat
,
392 schedule
, &key
, DES_DECRYPT
);
393 if(strcmp ((char*)tktcopy
.dat
+ 8,
394 KRB_TICKET_GRANTING_TICKET
) != 0) {
395 afs_string_to_key(passwd
,
396 krb_realmofhost(conn
->host
.name
),
398 des_key_sched(&key
, schedule
);
399 des_pcbc_encrypt((void *)tkt
.dat
, (void *)tktcopy
.dat
,
401 schedule
, &key
, DES_DECRYPT
);
403 memset(key
, 0, sizeof(key
));
404 memset(schedule
, 0, sizeof(schedule
));
405 memset(passwd
, 0, sizeof(passwd
));
406 if(Curl_base64_encode(conn
->data
, (char *)tktcopy
.dat
, tktcopy
.length
, &p
)
408 failf(conn
->data
, "Out of memory base64-encoding.");
409 Curl_set_command_prot(conn
, save
);
410 return CURLE_OUT_OF_MEMORY
;
412 memset (tktcopy
.dat
, 0, tktcopy
.length
);
414 result
= Curl_ftpsendf(conn
, "SITE KAUTH %s %s", name
, p
);
419 result
= Curl_GetFTPResponse(&nread
, conn
, NULL
);
422 Curl_set_command_prot(conn
, save
);
427 #endif /* HAVE_KRB4 */
428 #endif /* CURL_DISABLE_FTP */