security.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  1. /* This source code was modified by Martin Hedenfalk <[email protected]> for
  2. * use in Curl. His latest changes were done 2000-09-18.
  3. *
  4. * It has since been patched and modified a lot by Daniel Stenberg
  5. * <[email protected]> to make it better applied to curl conditions, and to make
  6. * it not use globals, pollute name space and more. This source code awaits a
  7. * rewrite to work around the paragraph 2 in the BSD licenses as explained
  8. * below.
  9. *
  10. * Copyright (c) 1998, 1999 Kungliga Tekniska Högskolan
  11. * (Royal Institute of Technology, Stockholm, Sweden).
  12. *
  13. * Copyright (C) 2001 - 2008, Daniel Stenberg, <[email protected]>, et al.
  14. *
  15. * All rights reserved.
  16. *
  17. * Redistribution and use in source and binary forms, with or without
  18. * modification, are permitted provided that the following conditions
  19. * are met:
  20. *
  21. * 1. Redistributions of source code must retain the above copyright
  22. * notice, this list of conditions and the following disclaimer.
  23. *
  24. * 2. Redistributions in binary form must reproduce the above copyright
  25. * notice, this list of conditions and the following disclaimer in the
  26. * documentation and/or other materials provided with the distribution.
  27. *
  28. * 3. Neither the name of the Institute nor the names of its contributors
  29. * may be used to endorse or promote products derived from this software
  30. * without specific prior written permission.
  31. *
  32. * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
  33. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  34. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  35. * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
  36. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  37. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  38. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  39. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  40. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  41. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  42. * SUCH DAMAGE. */
  43. #include "setup.h"
  44. #ifndef CURL_DISABLE_FTP
  45. #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
  46. #define _MPRINTF_REPLACE /* we want curl-functions instead of native ones */
  47. #include <curl/mprintf.h>
  48. #include <stdlib.h>
  49. #include <string.h>
  50. #ifdef HAVE_NETDB_H
  51. #include <netdb.h>
  52. #endif
  53. #ifdef HAVE_UNISTD_H
  54. #include <unistd.h>
  55. #endif
  56. #include "urldata.h"
  57. #include "krb4.h"
  58. #include "curl_base64.h"
  59. #include "sendf.h"
  60. #include "ftp.h"
  61. #include "memory.h"
  62. /* The last #include file should be: */
  63. #include "memdebug.h"
  64. static const struct {
  65. enum protection_level level;
  66. const char *name;
  67. } level_names[] = {
  68. { prot_clear, "clear" },
  69. { prot_safe, "safe" },
  70. { prot_confidential, "confidential" },
  71. { prot_private, "private" }
  72. };
  73. static enum protection_level
  74. name_to_level(const char *name)
  75. {
  76. int i;
  77. for(i = 0; i < (int)sizeof(level_names)/(int)sizeof(level_names[0]); i++)
  78. if(curl_strnequal(level_names[i].name, name, strlen(name)))
  79. return level_names[i].level;
  80. return (enum protection_level)-1;
  81. }
  82. static const struct Curl_sec_client_mech * const mechs[] = {
  83. #ifdef HAVE_GSSAPI
  84. &Curl_krb5_client_mech,
  85. #endif
  86. #ifdef HAVE_KRB4
  87. &Curl_krb4_client_mech,
  88. #endif
  89. NULL
  90. };
  91. int
  92. Curl_sec_getc(struct connectdata *conn, FILE *F)
  93. {
  94. if(conn->sec_complete && conn->data_prot) {
  95. char c;
  96. if(Curl_sec_read(conn, fileno(F), &c, 1) <= 0)
  97. return EOF;
  98. return c;
  99. }
  100. else
  101. return getc(F);
  102. }
  103. static int
  104. block_read(int fd, void *buf, size_t len)
  105. {
  106. unsigned char *p = buf;
  107. int b;
  108. while(len) {
  109. b = read(fd, p, len);
  110. if(b == 0)
  111. return 0;
  112. else if(b < 0 && (errno == EINTR || errno == EAGAIN))
  113. continue;
  114. else if(b < 0)
  115. return -1;
  116. len -= b;
  117. p += b;
  118. }
  119. return p - (unsigned char*)buf;
  120. }
  121. static int
  122. block_write(int fd, const void *buf, size_t len)
  123. {
  124. const unsigned char *p = buf;
  125. int b;
  126. while(len) {
  127. b = write(fd, p, len);
  128. if(b < 0 && (errno == EINTR || errno == EAGAIN))
  129. continue;
  130. else if(b < 0)
  131. return -1;
  132. len -= b;
  133. p += b;
  134. }
  135. return p - (unsigned char*)buf;
  136. }
  137. static int
  138. sec_get_data(struct connectdata *conn,
  139. int fd, struct krb4buffer *buf)
  140. {
  141. int len;
  142. int b;
  143. b = block_read(fd, &len, sizeof(len));
  144. if(b == 0)
  145. return 0;
  146. else if(b < 0)
  147. return -1;
  148. len = ntohl(len);
  149. buf->data = realloc(buf->data, len);
  150. b = buf->data ? block_read(fd, buf->data, len) : -1;
  151. if(b == 0)
  152. return 0;
  153. else if(b < 0)
  154. return -1;
  155. buf->size = (conn->mech->decode)(conn->app_data, buf->data, len,
  156. conn->data_prot, conn);
  157. buf->index = 0;
  158. return 0;
  159. }
  160. static size_t
  161. buffer_read(struct krb4buffer *buf, void *data, size_t len)
  162. {
  163. if(buf->size - buf->index < len)
  164. len = buf->size - buf->index;
  165. memcpy(data, (char*)buf->data + buf->index, len);
  166. buf->index += len;
  167. return len;
  168. }
  169. static size_t
  170. buffer_write(struct krb4buffer *buf, void *data, size_t len)
  171. {
  172. if(buf->index + len > buf->size) {
  173. void *tmp;
  174. if(buf->data == NULL)
  175. tmp = malloc(1024);
  176. else
  177. tmp = realloc(buf->data, buf->index + len);
  178. if(tmp == NULL)
  179. return -1;
  180. buf->data = tmp;
  181. buf->size = buf->index + len;
  182. }
  183. memcpy((char*)buf->data + buf->index, data, len);
  184. buf->index += len;
  185. return len;
  186. }
  187. int
  188. Curl_sec_read(struct connectdata *conn, int fd, void *buffer, int length)
  189. {
  190. size_t len;
  191. int rx = 0;
  192. if(conn->sec_complete == 0 || conn->data_prot == 0)
  193. return read(fd, buffer, length);
  194. if(conn->in_buffer.eof_flag){
  195. conn->in_buffer.eof_flag = 0;
  196. return 0;
  197. }
  198. len = buffer_read(&conn->in_buffer, buffer, length);
  199. length -= len;
  200. rx += len;
  201. buffer = (char*)buffer + len;
  202. while(length) {
  203. if(sec_get_data(conn, fd, &conn->in_buffer) < 0)
  204. return -1;
  205. if(conn->in_buffer.size == 0) {
  206. if(rx)
  207. conn->in_buffer.eof_flag = 1;
  208. return rx;
  209. }
  210. len = buffer_read(&conn->in_buffer, buffer, length);
  211. length -= len;
  212. rx += len;
  213. buffer = (char*)buffer + len;
  214. }
  215. return rx;
  216. }
  217. static int
  218. sec_send(struct connectdata *conn, int fd, const char *from, int length)
  219. {
  220. int bytes;
  221. void *buf;
  222. enum protection_level protlevel = conn->data_prot;
  223. int iscmd = protlevel == prot_cmd;
  224. if(iscmd) {
  225. if(!strncmp(from, "PASS ", 5) || !strncmp(from, "ACCT ", 5))
  226. protlevel = prot_private;
  227. else
  228. protlevel = conn->command_prot;
  229. }
  230. bytes = (conn->mech->encode)(conn->app_data, from, length, protlevel,
  231. &buf, conn);
  232. if(iscmd) {
  233. char *cmdbuf;
  234. bytes = Curl_base64_encode(conn->data, (char *)buf, bytes, &cmdbuf);
  235. if(bytes > 0) {
  236. if(protlevel == prot_private)
  237. block_write(fd, "ENC ", 4);
  238. else
  239. block_write(fd, "MIC ", 4);
  240. block_write(fd, cmdbuf, bytes);
  241. block_write(fd, "\r\n", 2);
  242. Curl_infof(conn->data, "%s %s\n",
  243. protlevel == prot_private ? "ENC" : "MIC", cmdbuf);
  244. free(cmdbuf);
  245. }
  246. }
  247. else {
  248. bytes = htonl(bytes);
  249. block_write(fd, &bytes, sizeof(bytes));
  250. block_write(fd, buf, ntohl(bytes));
  251. }
  252. free(buf);
  253. return length;
  254. }
  255. int
  256. Curl_sec_fflush_fd(struct connectdata *conn, int fd)
  257. {
  258. if(conn->data_prot != prot_clear) {
  259. if(conn->out_buffer.index > 0){
  260. Curl_sec_write(conn, fd,
  261. conn->out_buffer.data, conn->out_buffer.index);
  262. conn->out_buffer.index = 0;
  263. }
  264. sec_send(conn, fd, NULL, 0);
  265. }
  266. return 0;
  267. }
  268. int
  269. Curl_sec_write(struct connectdata *conn, int fd, const char *buffer, int length)
  270. {
  271. int len = conn->buffer_size;
  272. int tx = 0;
  273. if(conn->data_prot == prot_clear)
  274. return write(fd, buffer, length);
  275. len -= (conn->mech->overhead)(conn->app_data, conn->data_prot, len);
  276. if(len <= 0)
  277. len = length;
  278. while(length){
  279. if(length < len)
  280. len = length;
  281. sec_send(conn, fd, buffer, len);
  282. length -= len;
  283. buffer += len;
  284. tx += len;
  285. }
  286. return tx;
  287. }
  288. ssize_t
  289. Curl_sec_send(struct connectdata *conn, int num, const char *buffer, int length)
  290. {
  291. curl_socket_t fd = conn->sock[num];
  292. return (ssize_t)Curl_sec_write(conn, fd, buffer, length);
  293. }
  294. int
  295. Curl_sec_putc(struct connectdata *conn, int c, FILE *F)
  296. {
  297. char ch = c;
  298. if(conn->data_prot == prot_clear)
  299. return putc(c, F);
  300. buffer_write(&conn->out_buffer, &ch, 1);
  301. if(c == '\n' || conn->out_buffer.index >= 1024 /* XXX */) {
  302. Curl_sec_write(conn, fileno(F), conn->out_buffer.data,
  303. conn->out_buffer.index);
  304. conn->out_buffer.index = 0;
  305. }
  306. return c;
  307. }
  308. int
  309. Curl_sec_read_msg(struct connectdata *conn, char *s, int level)
  310. {
  311. int len;
  312. unsigned char *buf;
  313. int code;
  314. len = Curl_base64_decode(s + 4, &buf); /* XXX */
  315. if(len > 0)
  316. len = (conn->mech->decode)(conn->app_data, buf, len, level, conn);
  317. else
  318. return -1;
  319. if(len < 0) {
  320. free(buf);
  321. return -1;
  322. }
  323. if(conn->data->set.verbose) {
  324. buf[len] = '\n';
  325. Curl_debug(conn->data, CURLINFO_HEADER_IN, (char *)buf, len + 1, conn);
  326. }
  327. buf[len] = '\0';
  328. if(buf[3] == '-')
  329. code = 0;
  330. else
  331. sscanf((char *)buf, "%d", &code);
  332. if(buf[len-1] == '\n')
  333. buf[len-1] = '\0';
  334. strcpy(s, (char *)buf);
  335. free(buf);
  336. return code;
  337. }
  338. enum protection_level
  339. Curl_set_command_prot(struct connectdata *conn, enum protection_level level)
  340. {
  341. enum protection_level old = conn->command_prot;
  342. conn->command_prot = level;
  343. return old;
  344. }
  345. static int
  346. sec_prot_internal(struct connectdata *conn, int level)
  347. {
  348. char *p;
  349. unsigned int s = 1048576;
  350. ssize_t nread;
  351. if(!conn->sec_complete){
  352. infof(conn->data, "No security data exchange has taken place.\n");
  353. return -1;
  354. }
  355. if(level){
  356. int code;
  357. if(Curl_ftpsendf(conn, "PBSZ %u", s))
  358. return -1;
  359. if(Curl_GetFTPResponse(&nread, conn, &code))
  360. return -1;
  361. if(code/100 != 2){
  362. failf(conn->data, "Failed to set protection buffer size.");
  363. return -1;
  364. }
  365. conn->buffer_size = s;
  366. p = strstr(conn->data->state.buffer, "PBSZ=");
  367. if(p)
  368. sscanf(p, "PBSZ=%u", &s);
  369. if(s < conn->buffer_size)
  370. conn->buffer_size = s;
  371. }
  372. if(Curl_ftpsendf(conn, "PROT %c", level["CSEP"]))
  373. return -1;
  374. if(Curl_GetFTPResponse(&nread, conn, NULL))
  375. return -1;
  376. if(conn->data->state.buffer[0] != '2'){
  377. failf(conn->data, "Failed to set protection level.");
  378. return -1;
  379. }
  380. conn->data_prot = (enum protection_level)level;
  381. if(level == prot_private)
  382. conn->command_prot = (enum protection_level)level;
  383. return 0;
  384. }
  385. void
  386. Curl_sec_set_protection_level(struct connectdata *conn)
  387. {
  388. if(conn->sec_complete && conn->data_prot != conn->request_data_prot)
  389. sec_prot_internal(conn, conn->request_data_prot);
  390. }
  391. int
  392. Curl_sec_request_prot(struct connectdata *conn, const char *level)
  393. {
  394. int l = name_to_level(level);
  395. if(l == -1)
  396. return -1;
  397. conn->request_data_prot = (enum protection_level)l;
  398. return 0;
  399. }
  400. int
  401. Curl_sec_login(struct connectdata *conn)
  402. {
  403. int ret;
  404. const struct Curl_sec_client_mech * const *m;
  405. ssize_t nread;
  406. struct SessionHandle *data=conn->data;
  407. int ftpcode;
  408. for(m = mechs; *m && (*m)->name; m++) {
  409. void *tmp;
  410. tmp = realloc(conn->app_data, (*m)->size);
  411. if(tmp == NULL) {
  412. failf (data, "realloc %u failed", (*m)->size);
  413. return -1;
  414. }
  415. conn->app_data = tmp;
  416. if((*m)->init && (*(*m)->init)(conn->app_data) != 0) {
  417. infof(data, "Skipping %s...\n", (*m)->name);
  418. continue;
  419. }
  420. infof(data, "Trying %s...\n", (*m)->name);
  421. if(Curl_ftpsendf(conn, "AUTH %s", (*m)->name))
  422. return -1;
  423. if(Curl_GetFTPResponse(&nread, conn, &ftpcode))
  424. return -1;
  425. if(conn->data->state.buffer[0] != '3'){
  426. switch(ftpcode) {
  427. case 504:
  428. infof(data,
  429. "%s is not supported by the server.\n", (*m)->name);
  430. break;
  431. case 534:
  432. infof(data, "%s rejected as security mechanism.\n", (*m)->name);
  433. break;
  434. default:
  435. if(conn->data->state.buffer[0] == '5') {
  436. infof(data, "The server doesn't support the FTP "
  437. "security extensions.\n");
  438. return -1;
  439. }
  440. break;
  441. }
  442. continue;
  443. }
  444. ret = (*(*m)->auth)(conn->app_data, conn);
  445. if(ret == AUTH_CONTINUE)
  446. continue;
  447. else if(ret != AUTH_OK){
  448. /* mechanism is supposed to output error string */
  449. return -1;
  450. }
  451. conn->mech = *m;
  452. conn->sec_complete = 1;
  453. conn->command_prot = prot_safe;
  454. /* Set the requested protection level */
  455. /* BLOCKING */
  456. Curl_sec_set_protection_level(conn);
  457. break;
  458. }
  459. return *m == NULL;
  460. }
  461. void
  462. Curl_sec_end(struct connectdata *conn)
  463. {
  464. if(conn->mech != NULL) {
  465. if(conn->mech->end)
  466. (conn->mech->end)(conn->app_data);
  467. memset(conn->app_data, 0, conn->mech->size);
  468. free(conn->app_data);
  469. conn->app_data = NULL;
  470. }
  471. conn->sec_complete = 0;
  472. conn->data_prot = (enum protection_level)0;
  473. conn->mech=NULL;
  474. }
  475. #endif /* HAVE_KRB4 */
  476. #endif /* CURL_DISABLE_FTP */