Resync
[CMakeLuaTailorHgBridge.git] / CMakeLua / Utilities / cmcurl-7.19.0 / lib / krb4.c
blob348c0a898c1d7264ca9058a531f9e6007d348605
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
6 * name space and more.
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
15 * are met:
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
38 * SUCH DAMAGE.
40 * $Id: krb4.c,v 1.1.1.1 2008-09-23 16:32:05 hoffman Exp $
43 #include "setup.h"
45 #ifndef CURL_DISABLE_FTP
46 #ifdef HAVE_KRB4
48 #include <stdlib.h>
49 #ifdef HAVE_NETDB_H
50 #include <netdb.h>
51 #endif
52 #include <string.h>
53 #include <krb.h>
54 #include <des.h>
56 #ifdef HAVE_UNISTD_H
57 #include <unistd.h> /* for getpid() */
58 #endif
60 #include "urldata.h"
61 #include "curl_base64.h"
62 #include "ftp.h"
63 #include "sendf.h"
64 #include "krb4.h"
65 #include "memory.h"
67 #if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
68 #include "inet_ntoa_r.h"
69 #endif
71 /* The last #include file should be: */
72 #include "memdebug.h"
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
79 struct krb4_data {
80 des_cblock key;
81 des_key_schedule schedule;
82 char name[ANAME_SZ];
83 char instance[INST_SZ];
84 char realm[REALM_SZ];
87 #ifndef HAVE_STRLCPY
88 /* if it ever goes non-static, make it Curl_ prefixed! */
89 static size_t
90 strlcpy (char *dst, const char *src, size_t dst_sz)
92 size_t n;
93 char *p;
95 for (p = dst, n = 0;
96 n + 1 < dst_sz && *src != '\0';
97 ++p, ++src, ++n)
98 *p = *src;
99 *p = '\0';
100 if(*src == '\0')
101 return n;
102 else
103 return n + strlen (src);
105 #else
106 size_t strlcpy (char *dst, const char *src, size_t dst_sz);
107 #endif
109 static int
110 krb4_check_prot(void *app_data, int level)
112 app_data = NULL; /* prevent compiler warning */
113 if(level == prot_confidential)
114 return -1;
115 return 0;
118 static int
119 krb4_decode(void *app_data, void *buf, int len, int level,
120 struct connectdata *conn)
122 MSG_DAT m;
123 int e;
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);
130 else
131 e = krb_rd_priv(buf, len, d->schedule, &d->key,
132 (struct sockaddr_in *)REMOTE_ADDR,
133 (struct sockaddr_in *)LOCAL_ADDR, &m);
134 if(e) {
135 struct SessionHandle *data = conn->data;
136 infof(data, "krb4_decode: %s\n", krb_get_err_text(e));
137 return -1;
139 memmove(buf, m.app_data, m.app_length);
140 return m.app_length;
143 static int
144 krb4_overhead(void *app_data, int level, int len)
146 /* no arguments are used, just init them to prevent compiler warnings */
147 app_data = NULL;
148 level = 0;
149 len = 0;
150 return 31;
153 static int
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
161 * input buffer
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);
170 else
171 return -1;
174 static int
175 mk_auth(struct krb4_data *d, KTEXT adat,
176 const char *service, char *host, int checksum)
178 int ret;
179 CREDENTIALS cred;
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);
186 if(ret)
187 return ret;
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));
195 return ret;
198 #ifdef HAVE_KRB_GET_OUR_IP_FOR_REALM
199 int krb_get_our_ip_for_realm(char *, struct in_addr *);
200 #endif
202 static int
203 krb4_auth(void *app_data, struct connectdata *conn)
205 int ret;
206 char *p;
207 unsigned char *ptr;
208 size_t len;
209 KTEXT_ST adat;
210 MSG_DAT msg_data;
211 int checksum;
212 u_int32_t cs;
213 struct krb4_data *d = app_data;
214 char *host = conn->host.name;
215 ssize_t nread;
216 int l = sizeof(conn->local_addr);
217 struct SessionHandle *data = conn->data;
218 CURLcode result;
220 if(getsockname(conn->sock[FIRSTSOCKET],
221 (struct sockaddr *)LOCAL_ADDR, &l) < 0)
222 perror("getsockname()");
224 checksum = getpid();
225 ret = mk_auth(d, &adat, "ftp", host, checksum);
226 if(ret == KDC_PR_UNKNOWN)
227 ret = mk_auth(d, &adat, "rcmd", host, checksum);
228 if(ret) {
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));
243 else {
244 if(natAddr.s_addr != localaddr->sin_addr.s_addr) {
245 #ifdef HAVE_INET_NTOA_R
246 char ntoa_buf[64];
247 char *ip = (char *)inet_ntoa_r(natAddr, ntoa_buf, sizeof(ntoa_buf));
248 #else
249 char *ip = (char *)inet_ntoa(natAddr);
250 #endif
251 infof(data, "Using NAT IP address (%s) for kerberos 4\n", ip);
252 localaddr->sin_addr = natAddr;
256 #endif
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);
265 free(p);
267 if(result)
268 return -2;
270 if(Curl_GetFTPResponse(&nread, conn, NULL))
271 return -1;
273 if(data->state.buffer[0] != '2'){
274 Curl_failf(data, "Server didn't accept auth data");
275 return AUTH_ERROR;
278 p = strstr(data->state.buffer, "ADAT=");
279 if(!p) {
280 Curl_failf(data, "Remote host didn't send adat reply");
281 return AUTH_ERROR;
283 p += 5;
284 len = Curl_base64_decode(p, &ptr);
285 if(len > sizeof(adat.dat)-1) {
286 free(ptr);
287 len=0;
289 if(!len || !ptr) {
290 Curl_failf(data, "Failed to decode base64 from server");
291 return AUTH_ERROR;
293 memcpy((char *)adat.dat, ptr, len);
294 free(ptr);
295 adat.length = len;
296 ret = krb_rd_safe(adat.dat, adat.length, &d->key,
297 (struct sockaddr_in *)hisctladdr,
298 (struct sockaddr_in *)myctladdr, &msg_data);
299 if(ret) {
300 Curl_failf(data, "Error reading reply from server: %s",
301 krb_get_err_text(ret));
302 return AUTH_ERROR;
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");
307 return AUTH_ERROR;
309 return AUTH_OK;
312 struct Curl_sec_client_mech Curl_krb4_client_mech = {
313 "KERBEROS_V4",
314 sizeof(struct krb4_data),
315 NULL, /* init */
316 krb4_auth,
317 NULL, /* end */
318 krb4_check_prot,
319 krb4_overhead,
320 krb4_encode,
321 krb4_decode
324 CURLcode Curl_krb_kauth(struct connectdata *conn)
326 des_cblock key;
327 des_key_schedule schedule;
328 KTEXT_ST tkt, tktcopy;
329 char *name;
330 char *p;
331 char passwd[100];
332 size_t tmp;
333 ssize_t nread;
334 int save;
335 CURLcode result;
336 unsigned char *ptr;
338 save = Curl_set_command_prot(conn, prot_private);
340 result = Curl_ftpsendf(conn, "SITE KAUTH %s", conn->user);
342 if(result)
343 return result;
345 result = Curl_GetFTPResponse(&nread, conn, NULL);
346 if(result)
347 return result;
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=");
355 if(!p) {
356 Curl_failf(conn->data, "Bad reply from server");
357 Curl_set_command_prot(conn, save);
358 return CURLE_FTP_WEIRD_SERVER_REPLY;
361 p += 2;
362 tmp = Curl_base64_decode(p, &ptr);
363 if(tmp >= sizeof(tkt.dat)) {
364 free(ptr);
365 tmp=0;
367 if(!tmp || !ptr) {
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);
373 free(ptr);
374 tkt.length = tmp;
375 tktcopy.length = tkt.length;
377 p = strstr(conn->data->state.buffer, "P=");
378 if(!p) {
379 Curl_failf(conn->data, "Bad reply from server");
380 Curl_set_command_prot(conn, save);
381 return CURLE_FTP_WEIRD_SERVER_REPLY;
383 name = p + 2;
384 for(; *p && *p != ' ' && *p != '\r' && *p != '\n'; p++);
385 *p = 0;
387 des_string_to_key (conn->passwd, &key);
388 des_key_sched(&key, schedule);
390 des_pcbc_encrypt((void *)tkt.dat, (void *)tktcopy.dat,
391 tkt.length,
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),
397 &key);
398 des_key_sched(&key, schedule);
399 des_pcbc_encrypt((void *)tkt.dat, (void *)tktcopy.dat,
400 tkt.length,
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)
407 < 1) {
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);
415 free(p);
416 if(result)
417 return result;
419 result = Curl_GetFTPResponse(&nread, conn, NULL);
420 if(result)
421 return result;
422 Curl_set_command_prot(conn, save);
424 return CURLE_OK;
427 #endif /* HAVE_KRB4 */
428 #endif /* CURL_DISABLE_FTP */