Compare commits
200 Commits
curl-7_30_
...
curl-7_31_
Author | SHA1 | Date | |
---|---|---|---|
![]() |
85c710e11e | ||
![]() |
0de7249bb3 | ||
![]() |
192c4f788d | ||
![]() |
da0db499fd | ||
![]() |
88c5c63ffc | ||
![]() |
a9f5ad0e2a | ||
![]() |
e305f5ec71 | ||
![]() |
7ac3e9f1ba | ||
![]() |
03a3dd9ee3 | ||
![]() |
5fc24a5297 | ||
![]() |
b1a295ac4e | ||
![]() |
1826c768ab | ||
![]() |
9c3e098259 | ||
![]() |
0feeab7802 | ||
![]() |
f24dc09d20 | ||
![]() |
9e10963c20 | ||
![]() |
10b6d81c64 | ||
![]() |
8026bd7abd | ||
![]() |
9b8df58169 | ||
![]() |
529a2e9110 | ||
![]() |
21091549c0 | ||
![]() |
7b97f03f09 | ||
![]() |
ce362e8eb9 | ||
![]() |
a4decb49a6 | ||
![]() |
c53fb36b0c | ||
![]() |
dc19e656b5 | ||
![]() |
87cf677eca | ||
![]() |
5657c56f63 | ||
![]() |
51b3445e84 | ||
![]() |
a7452b8b8c | ||
![]() |
0bf5ce77aa | ||
![]() |
159d34b58e | ||
![]() |
29bf0598aa | ||
![]() |
239b58d34d | ||
![]() |
74f1810546 | ||
![]() |
f4b08b8f40 | ||
![]() |
6691fdf517 | ||
![]() |
7d8d2a54ba | ||
![]() |
9986c6cb2b | ||
![]() |
ba9a66663a | ||
![]() |
ac419bf562 | ||
![]() |
520833cbe1 | ||
![]() |
e58d9c87f7 | ||
![]() |
84f7991474 | ||
![]() |
85b9dc8023 | ||
![]() |
7d4d4892d8 | ||
![]() |
fc4759af9d | ||
![]() |
ee84c47655 | ||
![]() |
ce32176db7 | ||
![]() |
04f52e9b4d | ||
![]() |
100a33f7ff | ||
![]() |
7ed25ccf0d | ||
![]() |
01eede2662 | ||
![]() |
ae26ee3489 | ||
![]() |
992bee504d | ||
![]() |
01a2abedd7 | ||
![]() |
a45e3f93e4 | ||
![]() |
bdb396ef2a | ||
![]() |
6add1901a1 | ||
![]() |
51b0f09b5e | ||
![]() |
8dac7be438 | ||
![]() |
bcf1b9dec1 | ||
![]() |
b045d079f8 | ||
![]() |
683f2b8323 | ||
![]() |
2de20dd9a1 | ||
![]() |
b47cf4f688 | ||
![]() |
a15b2b6c62 | ||
![]() |
42e01cff9a | ||
![]() |
865d4138a0 | ||
![]() |
35874298e4 | ||
![]() |
52d72e66c2 | ||
![]() |
f3d10aa0d4 | ||
![]() |
7632bc911b | ||
![]() |
92ef5f19c8 | ||
![]() |
99b4045183 | ||
![]() |
087f9bb20a | ||
![]() |
e2c7e19144 | ||
![]() |
f5c3d95384 | ||
![]() |
6b10f5b963 | ||
![]() |
ee74b77d45 | ||
![]() |
734bdb68c2 | ||
![]() |
514817669e | ||
![]() |
cb9c0ac7d7 | ||
![]() |
1c435295b8 | ||
![]() |
46d26a0e77 | ||
![]() |
f4e3cae8a7 | ||
![]() |
b52cf5d2cd | ||
![]() |
073e83b543 | ||
![]() |
c3e6d69acb | ||
![]() |
b56e3d43e5 | ||
![]() |
f317ffb7bb | ||
![]() |
9ea5145952 | ||
![]() |
1d7c38e1f0 | ||
![]() |
18bfc8f2d7 | ||
![]() |
945246988d | ||
![]() |
a5c0e20939 | ||
![]() |
128517649c | ||
![]() |
219358b93d | ||
![]() |
f133719f73 | ||
![]() |
f4e6e201b1 | ||
![]() |
790b2086d7 | ||
![]() |
f9b691cdb0 | ||
![]() |
4118c30261 | ||
![]() |
dacbdaab94 | ||
![]() |
70e30f6caa | ||
![]() |
7cb6c31370 | ||
![]() |
5d3a031ca7 | ||
![]() |
a846fbbe2a | ||
![]() |
6420672879 | ||
![]() |
c4067a5678 | ||
![]() |
0523152ad6 | ||
![]() |
b37b5233ca | ||
![]() |
c68c7e588e | ||
![]() |
1498a0073e | ||
![]() |
27777949a0 | ||
![]() |
4dc2d965d6 | ||
![]() |
70bbbccc39 | ||
![]() |
0dd470fc61 | ||
![]() |
89acdf50fa | ||
![]() |
c0d502785f | ||
![]() |
a8c92cb608 | ||
![]() |
53fda844cc | ||
![]() |
bbf63b0faa | ||
![]() |
2af9fd4960 | ||
![]() |
2c0d65785f | ||
![]() |
d791179d7f | ||
![]() |
c49ed0b6c0 | ||
![]() |
868d8e6831 | ||
![]() |
e3aca1b2ce | ||
![]() |
ddac43b38e | ||
![]() |
416ecc1584 | ||
![]() |
455ba691a7 | ||
![]() |
11332577b3 | ||
![]() |
702b0dd408 | ||
![]() |
e8a9f794f0 | ||
![]() |
bddf3d4705 | ||
![]() |
e99c81a07c | ||
![]() |
fe880475ed | ||
![]() |
5821d5f111 | ||
![]() |
d535c4a2e1 | ||
![]() |
ca8f17a303 | ||
![]() |
fddb7b44a7 | ||
![]() |
49184c3723 | ||
![]() |
cc7f6a2ddf | ||
![]() |
90fe59b829 | ||
![]() |
7b074a460b | ||
![]() |
993cdcd6ee | ||
![]() |
8763374f0e | ||
![]() |
63388fe1f3 | ||
![]() |
b75a88aa72 | ||
![]() |
bb20989a63 | ||
![]() |
0d49e408a4 | ||
![]() |
90c87f311e | ||
![]() |
da06ac7f3f | ||
![]() |
6d9236e805 | ||
![]() |
c306d2e42f | ||
![]() |
f737e3a3dd | ||
![]() |
686586b0f9 | ||
![]() |
e621a5f6ea | ||
![]() |
8093f9541e | ||
![]() |
68e7fb499d | ||
![]() |
d9569720dd | ||
![]() |
1c40685d32 | ||
![]() |
31c6e7af6a | ||
![]() |
552ba67bb1 | ||
![]() |
651254dcc7 | ||
![]() |
26bdafcbf9 | ||
![]() |
02dc9e788f | ||
![]() |
e11c6e9961 | ||
![]() |
e4eaa92728 | ||
![]() |
577f8e5ac6 | ||
![]() |
95ba6cdd54 | ||
![]() |
7ce6cb9ab4 | ||
![]() |
8723cade21 | ||
![]() |
d956d9db47 | ||
![]() |
ecf93ac986 | ||
![]() |
b3a01be2f3 | ||
![]() |
00045a3009 | ||
![]() |
3f7188dd94 | ||
![]() |
720218fea1 | ||
![]() |
73aa95592f | ||
![]() |
ad3fdbc0a4 | ||
![]() |
73cbd21b5e | ||
![]() |
c5ba0c2f54 | ||
![]() |
edddf394b8 | ||
![]() |
61d259f950 | ||
![]() |
c01735865f | ||
![]() |
ca46c5dbe2 | ||
![]() |
2da127abb5 | ||
![]() |
bc33f2200d | ||
![]() |
fd399cde00 | ||
![]() |
00c74019f4 | ||
![]() |
9d0063befa | ||
![]() |
01e55ebb26 | ||
![]() |
4bbad1dac7 | ||
![]() |
ddbda328b3 | ||
![]() |
8ffbeeda80 | ||
![]() |
1d1ffaf912 | ||
![]() |
e0cff02061 | ||
![]() |
7fe95bb0d5 |
@@ -103,7 +103,7 @@ if test ! -z $SDK32; then
|
||||
ln -fs ${FRAMEWORK_VERSION}/Resources Resources
|
||||
ln -fs ${FRAMEWORK_VERSION}/Headers Headers
|
||||
cd Versions
|
||||
ln -fs ${FRAMEWORK_VERSION} Current
|
||||
ln -fs $(basename "${FRAMEWORK_VERSION}") Current
|
||||
|
||||
echo Testing for SDK64
|
||||
if test -d $SDK64_DIR; then
|
||||
|
189
RELEASE-NOTES
189
RELEASE-NOTES
@@ -1,6 +1,6 @@
|
||||
Curl and libcurl 7.30.0
|
||||
Curl and libcurl 7.31.0
|
||||
|
||||
Public curl releases: 132
|
||||
Public curl releases: 133
|
||||
Command line options: 152
|
||||
curl_easy_setopt() options: 199
|
||||
Public functions in libcurl: 58
|
||||
@@ -14,75 +14,58 @@ Curl and libcurl 7.30.0
|
||||
|
||||
This release includes the following changes:
|
||||
|
||||
o imap: Changed response tag generation to be completely unique
|
||||
o imap: Added support for SASL-IR extension
|
||||
o imap: Added support for the list command
|
||||
o imap: Added support for the append command
|
||||
o imap: Added custom request parsing
|
||||
o imap: Added support to the fetch command for UID and SECTION properties
|
||||
o imap: Added parsing and verification of the UIDVALIDITY mailbox attribute
|
||||
o darwinssl: Make certificate errors less techy
|
||||
o imap/pop3/smtp: Added support for the STARTTLS capability
|
||||
o checksrc: ban use of sprintf, vsprintf, strcat, strncat and gets
|
||||
o curl_global_init() now accepts the CURL_GLOBAL_ACK_EINTR flag [10]
|
||||
o Added CURLMOPT_MAX_HOST_CONNECTIONS, CURLMOPT_MAX_TOTAL_CONNECTIONS for
|
||||
new multi interface connection handling
|
||||
o Added CURLMOPT_MAX_PIPELINE_LENGTH, CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE,
|
||||
CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE, CURLMOPT_PIPELINING_SITE_BL and
|
||||
CURLMOPT_PIPELINING_SERVER_BL for new pipelining control [15]
|
||||
o darwinssl: add TLS session resumption
|
||||
o darwinssl: add TLS crypto authentication
|
||||
o imap/pop3/smtp: Added support for ;auth=<mech> in the URL
|
||||
o imap/pop3/smtp: Added support for ;auth=<mech> to CURLOPT_USERPWD
|
||||
o usercertinmem.c: add example showing user cert in memory
|
||||
o url: Added smtp and pop3 hostnames to the protocol detection list
|
||||
o imap/pop3/smtp: Added support for enabling the SASL initial response [8]
|
||||
o curl -E: allow to use ':' in certificate nicknames [10]
|
||||
|
||||
This release includes the following bugfixes:
|
||||
|
||||
o SECURITY ADVISORY: cookie tailmatching to avoid cross-domain leakage [25]
|
||||
o darwinssl: Fix build under Leopard
|
||||
o DONE: consider callback-aborted transfers premature [1]
|
||||
o ntlm: Fixed memory leaks
|
||||
o smtp: Fixed an issue when processing EHLO failure responses
|
||||
o pop3: Fixed incorrect return value from pop3_endofresp()
|
||||
o pop3: Fixed SASL authentication capability detection
|
||||
o pop3: Fixed blocking SSL connect when connecting via POP3S
|
||||
o imap: Fixed memory leak when performing multiple selects
|
||||
o nss: fix misplaced code enabling non-blocking socket mode
|
||||
o AddFormData: prevent only directories from being posted [2]
|
||||
o darwinssl: fix infinite loop if server disconnected abruptly [3]
|
||||
o metalink: fix improbable crash parsing metalink filename
|
||||
o show proper host name on failed resolve
|
||||
o MacOSX-Framework: Make script work in Xcode 4.0 and later
|
||||
o strlcat: remove function [4]
|
||||
o darwinssl: Fix send glitchiness with data > 32 or so KB [5]
|
||||
o polarssl: better 1.1.x and 1.2.x support
|
||||
o various documentation improvements
|
||||
o multi: NULL pointer reference when closing an unused multi handle [9]
|
||||
o SOCKS: fix socks proxy when noproxy matched [7]
|
||||
o install-sh: updated to support multiple source files as arguments [6]
|
||||
o PolarSSL: added human readable error strings
|
||||
o resolver_error: remove wrong error message output
|
||||
o docs: updates HTML index and general improvements
|
||||
o curlbuild.h.dist: enhance non-configure GCC ABI detection logic
|
||||
o sasl: Fixed null pointer reference when decoding empty digest challenge [8]
|
||||
o easy: do not ignore poll() failures other than EINTR
|
||||
o darwinssl: disable ECC ciphers under Mountain Lion by default
|
||||
o CONNECT: count received headers [11]
|
||||
o build: fixes for VMS
|
||||
o CONNECT: clear 'rewindaftersend' on success [12]
|
||||
o HTTP proxy: insert slash in URL if missing [13]
|
||||
o hiperfifo: updated to use current libevent API [14]
|
||||
o getinmemory.c: abort the transfer nicely if not enough memory
|
||||
o improved win32 memorytracking
|
||||
o corrected proxy header response headers count [16]
|
||||
o FTP quote operations on re-used connection [17]
|
||||
o tcpkeepalive on win32 [18]
|
||||
o tcpkeepalive on Mac OS X [23]
|
||||
o easy: acknowledge the CURLOPT_MAXCONNECTS option properly [19]
|
||||
o easy interface: restore default MAXCONNECTS to 5
|
||||
o win32: don't set SO_SNDBUF for windows vista or later versions [20]
|
||||
o HTTP: made cookie sort function more deterministic
|
||||
o winssl: Fixed memory leak if connection was not successful
|
||||
o FTP: wait on both connections during active STOR state [21]
|
||||
o connect: treat a failed local bind of an interface as a non-fatal error [22]
|
||||
o darwinssl: disable insecure ciphers by default
|
||||
o FTP: handle "rubbish" in front of directory name in 257 responses [24]
|
||||
o mk-ca-bundle: Fixed lost OpenSSL output with "-t"
|
||||
o SECURITY VULNERABILITY: curl_easy_unescape() may parse data beyond the end
|
||||
of the input buffer [26]
|
||||
|
||||
o FTP: access files in root dir correctly [1]
|
||||
o configure: try pthread_create without -lpthread [2]
|
||||
o FTP: handle a 230 welcome response [3]
|
||||
o curl-config: don't output static libs when they are disabled
|
||||
o CURL_CHECK_CA_BUNDLE: don't check for paths when cross-compiling [4]
|
||||
o Various documentation updates
|
||||
o getinfo.c: reset timecond when clearing session-info variables [5]
|
||||
o FILE: prevent an artificial timeout event due to stale speed-check data [6]
|
||||
o ftp_state_pasv_resp: connect through proxy also when set by env [7]
|
||||
o sshserver: disable StrictHostKeyChecking
|
||||
o ftpserver: Fixed imap logout confirmation data
|
||||
o curl_easy_init: use less mallocs
|
||||
o smtp: Fixed unknown percentage complete in progress bar
|
||||
o smtp: Fixed sending of double CRLF caused by first in EOB
|
||||
o bindlocal: move brace out of #ifdef [9]
|
||||
o winssl: Fixed invalid memory access during SSL shutdown [11]
|
||||
o OS X framework: fix invalid symbolic link
|
||||
o OpenSSL: allow empty server certificate subject [12]
|
||||
o axtls: prevent memleaks on SSL handshake failures
|
||||
o cookies: only consider full path matches
|
||||
o Revert win32 MemoryTracking: wcsdup() _wcsdup() and _tcsdup() [13]
|
||||
o Curl_cookie_add: handle IPv6 hosts [14]
|
||||
o ossl_send: SSL_write() returning 0 is an error too
|
||||
o ossl_recv: SSL_read() returning 0 is an error too
|
||||
o Digest auth: escape user names with \ or " in them [15]
|
||||
o curl_formadd.3: fixed wrong "end-marker" syntax [16]
|
||||
o libcurl-tutorial.3: fix incorrect backslash [17]
|
||||
o curl_multi_wait: reduce timeout if the multi handle wants to [18]
|
||||
o tests/Makefile: typo in the perlcheck target [19]
|
||||
o axtls: honor disabled VERIFYHOST
|
||||
o OpenSSL: avoid double free in the PKCS12 certificate code [20]
|
||||
o multi_socket: reduce timeout inaccuracy margin [21]
|
||||
o digest: support auth-int for empty entity body [22]
|
||||
o axtls: now done non-blocking
|
||||
o lib1900: use tutil_tvnow instead of gettimeofday
|
||||
o curl_easy_perform: avoid busy-looping [23]
|
||||
o CURLOPT_COOKIELIST: take cookie share lock [24]
|
||||
o multi_socket: react on socket close immediately [25]
|
||||
|
||||
This release includes the following known bugs:
|
||||
|
||||
@@ -91,43 +74,43 @@ This release includes the following known bugs:
|
||||
This release would not have looked like this without help, code, reports and
|
||||
advice from friends like these:
|
||||
|
||||
Kamil Dudka, Steve Holme, Nick Zitzmann, Patricia Muscalu, Dan Fandrich,
|
||||
Gisle Vanem, Guenter Knauf, Yang Tse, Oliver Gondža, Aki Koskinen,
|
||||
Alexander Klauer, Kim Vandry, Willem Sparreboom, Jeremy Huddleston,
|
||||
Bruno de Carvalho, Rainer Jung, Jeremy Huddleston, Kim Vandry, Jiri Hruska,
|
||||
Alexander Klauer, Saran Neti, Alessandro Ghedini, Linus Nielsen Feltzing,
|
||||
Martin Jansen, John E. Malmberg, Tom Grace, Patrick Monnerat,
|
||||
Zdenek Pavlas, Myk Taylor, Cédric Deltheil, Robert Wruck, Sam Deane,
|
||||
Clemens Gruber, Marc Hoersken, Tomas Mlcoch, Fredrik Thulin, Steven Gu,
|
||||
Andrew Kurushin, Christian Hägele, Daniel Theron, Bill Middlecamp,
|
||||
Richard Michael, Yamada Yasuharu
|
||||
David Strauss, Kamil Dudka, Steve Holme, Nick Zitzmann, Sam Deane, Duncan,
|
||||
Anders Havn, Dan Fandrich, Paul Howarth, Dave Reisner, Wouter Van Rooy,
|
||||
Linus Nielsen Feltzing, Ishan SinghLevett, Alessandro Ghedini,
|
||||
Ludovico Cavedon, Zdenek Pavlas, Zekun Ni, Lars Johannesen, Marc Hoersken,
|
||||
Renaud Guillard, John Gardiner Myers, Jared Jennings, Eric Hu,
|
||||
Yamada Yasuharu, Stefan Neis, Mike Giancola, Eric S. Raymond, Andrii Moiseiev,
|
||||
Christian Weisgerber, Peter Gal, Aleksey Tulinov, Hang Su, Sergei Nikulov,
|
||||
Miguel Angel, Nach M. S., Benjamin Gilbert, Erik Johansson, Timo Sirainen,
|
||||
Guenter Knauf
|
||||
|
||||
Thanks! (and sorry if I forgot to mention someone)
|
||||
|
||||
References to bug reports and discussions on issues:
|
||||
|
||||
[1] = http://curl.haxx.se/bug/view.cgi?id=1184
|
||||
[2] = http://curl.haxx.se/mail/archive-2013-02/0040.html
|
||||
[3] = http://curl.haxx.se/mail/lib-2013-03/0014.html
|
||||
[4] = http://curl.haxx.se/bug/view.cgi?id=1192
|
||||
[5] = http://curl.haxx.se/mail/lib-2013-02/0145.html
|
||||
[6] = http://curl.haxx.se/bug/view.cgi?id=1195
|
||||
[7] = http://curl.haxx.se/bug/view.cgi?id=1190
|
||||
[8] = http://curl.haxx.se/bug/view.cgi?id=1193
|
||||
[9] = http://curl.haxx.se/bug/view.cgi?id=1194
|
||||
[10] = http://curl.haxx.se/bug/view.cgi?id=1168
|
||||
[11] = http://curl.haxx.se/bug/view.cgi?id=1204
|
||||
[12] = https://groups.google.com/d/msg/msysgit/B31LNftR4BI/KhRTz0iuGmUJ
|
||||
[13] = http://curl.haxx.se/bug/view.cgi?id=1206
|
||||
[14] = http://curl.haxx.se/bug/view.cgi?id=1199
|
||||
[15] = http://daniel.haxx.se/blog/2013/03/26/better-pipelining-in-libcurl-7-30-0/
|
||||
[16] = http://curl.haxx.se/bug/view.cgi?id=1204
|
||||
[17] = http://curl.haxx.se/mail/lib-2013-03/0319.html
|
||||
[18] = http://curl.haxx.se/bug/view.cgi?id=1209
|
||||
[19] = http://curl.haxx.se/bug/view.cgi?id=1212
|
||||
[20] = http://curl.haxx.se/bug/view.cgi?id=1188
|
||||
[21] = http://curl.haxx.se/bug/view.cgi?id=1183
|
||||
[22] = http://curl.haxx.se/bug/view.cgi?id=1189
|
||||
[23] = http://curl.haxx.se/bug/view.cgi?id=1214
|
||||
[24] = http://curl.haxx.se/mail/lib-2013-04/0113.html
|
||||
[25] = http://curl.haxx.se/docs/adv_20130412.html
|
||||
[1] = http://curl.haxx.se/mail/lib-2013-04/0142.html
|
||||
[2] = http://curl.haxx.se/bug/view.cgi?id=1216
|
||||
[3] = http://curl.haxx.se/mail/lib-2013-02/0102.html
|
||||
[4] = http://curl.haxx.se/mail/lib-2013-04/0294.html
|
||||
[5] = http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=705783
|
||||
[6] = https://bugzilla.redhat.com/906031
|
||||
[7] = http://curl.haxx.se/bug/view.cgi?id=1218
|
||||
[8] = http://curl.haxx.se/mail/lib-2012-03/0114.html
|
||||
[9] = http://curl.haxx.se/mail/lib-2013-05/0000.html
|
||||
[10] = http://curl.haxx.se/bug/view.cgi?id=1196
|
||||
[11] = http://curl.haxx.se/bug/view.cgi?id=1219
|
||||
[12] = http://curl.haxx.se/bug/view.cgi?id=1220
|
||||
[13] = http://curl.haxx.se/mail/lib-2013-05/0070.html
|
||||
[14] = http://curl.haxx.se/bug/view.cgi?id=1221
|
||||
[15] = http://curl.haxx.se/bug/view.cgi?id=1230
|
||||
[16] = http://curl.haxx.se/bug/view.cgi?id=1233
|
||||
[17] = http://curl.haxx.se/bug/view.cgi?id=1234
|
||||
[18] = http://curl.haxx.se/bug/view.cgi?id=1224
|
||||
[19] = http://curl.haxx.se/bug/view.cgi?id=1239
|
||||
[20] = http://curl.haxx.se/bug/view.cgi?id=1236
|
||||
[21] = http://curl.haxx.se/bug/view.cgi?id=1228
|
||||
[22] = http://curl.haxx.se/bug/view.cgi?id=1235
|
||||
[23] = http://curl.haxx.se/bug/view.cgi?id=1238
|
||||
[24] = http://curl.haxx.se/bug/view.cgi?id=1215
|
||||
[25] = http://curl.haxx.se/bug/view.cgi?id=1248
|
||||
[26] = http://curl.haxx.se/docs/adv_20130622.html
|
||||
|
11
acinclude.m4
11
acinclude.m4
@@ -2619,8 +2619,10 @@ AC_HELP_STRING([--without-ca-path], [Don't use a default CA path]),
|
||||
fi
|
||||
capath="$want_capath"
|
||||
ca="no"
|
||||
else
|
||||
dnl neither of --with-ca-* given
|
||||
elif test "x$cross_compiling" != "xyes"; then
|
||||
dnl NOT cross-compiling and...
|
||||
dnl neither of the --with-ca-* options are provided
|
||||
|
||||
dnl first try autodetecting a CA bundle , then a CA path
|
||||
dnl both autodetections can be skipped by --without-ca-*
|
||||
ca="no"
|
||||
@@ -2656,10 +2658,11 @@ AC_HELP_STRING([--without-ca-path], [Don't use a default CA path]),
|
||||
fi
|
||||
done
|
||||
fi
|
||||
else
|
||||
dnl no option given and cross-compiling
|
||||
AC_MSG_WARN([skipped the ca-cert path detection when cross-compiling])
|
||||
fi
|
||||
|
||||
|
||||
|
||||
if test "x$ca" != "xno"; then
|
||||
CURL_CA_BUNDLE='"'$ca'"'
|
||||
AC_DEFINE_UNQUOTED(CURL_CA_BUNDLE, "$ca", [Location of default ca bundle])
|
||||
|
33
configure.ac
33
configure.ac
@@ -3158,14 +3158,26 @@ if test "$want_thres" = "yes"; then
|
||||
AC_CHECK_HEADER(pthread.h,
|
||||
[ AC_DEFINE(HAVE_PTHREAD_H, 1, [if you have <pthread.h>])
|
||||
save_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -pthread"
|
||||
AC_CHECK_LIB(pthread, pthread_create,
|
||||
[ AC_MSG_NOTICE([using POSIX threaded DNS lookup])
|
||||
AC_DEFINE(USE_THREADS_POSIX, 1, [if you want POSIX threaded DNS lookup])
|
||||
USE_THREADS_POSIX=1
|
||||
curl_res_msg="threaded"
|
||||
],
|
||||
[ CFLAGS="$save_CFLAGS"])
|
||||
|
||||
dnl first check for function without lib
|
||||
AC_CHECK_FUNC(pthread_create, [USE_THREADS_POSIX=1] )
|
||||
|
||||
dnl if it wasn't found without lib, search for it in pthread lib
|
||||
if test "$USE_THREADS_POSIX" != "1"
|
||||
then
|
||||
CFLAGS="$CFLAGS -pthread"
|
||||
AC_CHECK_LIB(pthread, pthread_create,
|
||||
[USE_THREADS_POSIX=1],
|
||||
[ CFLAGS="$save_CFLAGS"])
|
||||
fi
|
||||
|
||||
if test "x$USE_THREADS_POSIX" = "x1"
|
||||
then
|
||||
AC_DEFINE(USE_THREADS_POSIX, 1, [if you want POSIX threaded DNS lookup])
|
||||
curl_res_msg="POSIX threaded"
|
||||
fi
|
||||
|
||||
|
||||
])
|
||||
fi
|
||||
|
||||
@@ -3338,6 +3350,11 @@ dnl yes or no
|
||||
ENABLE_SHARED="$enable_shared"
|
||||
AC_SUBST(ENABLE_SHARED)
|
||||
|
||||
dnl to let curl-config output the static libraries correctly
|
||||
ENABLE_STATIC="$enable_static"
|
||||
AC_SUBST(ENABLE_STATIC)
|
||||
|
||||
|
||||
dnl
|
||||
dnl For keeping supported features and protocols also in pkg-config file
|
||||
dnl since it is more cross-compile friendly than curl-config
|
||||
|
@@ -155,7 +155,12 @@ while test $# -gt 0; do
|
||||
;;
|
||||
|
||||
--static-libs)
|
||||
echo @libdir@/libcurl.@libext@ @LDFLAGS@ @LIBCURL_LIBS@
|
||||
if test "X@ENABLE_STATIC@" != "Xno" ; then
|
||||
echo @libdir@/libcurl.@libext@ @LDFLAGS@ @LIBCURL_LIBS@
|
||||
else
|
||||
echo "curl was built with static libraries disabled" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
|
||||
--configure)
|
||||
|
16
docs/FAQ
16
docs/FAQ
@@ -728,7 +728,7 @@ FAQ
|
||||
When passing on a URL to curl to use, it may respond that the particular
|
||||
protocol is not supported or disabled. The particular way this error message
|
||||
is phrased is because curl doesn't make a distinction internally of whether
|
||||
a particular protocol is not supported (ie never got any code added that
|
||||
a particular protocol is not supported (i.e. never got any code added that
|
||||
knows how to speak that protocol) or if it was explicitly disabled. curl can
|
||||
be built to only support a given set of protocols, and the rest would then
|
||||
be disabled or not supported.
|
||||
@@ -1055,11 +1055,11 @@ FAQ
|
||||
|
||||
4.19 Why doesn't cURL return an error when the network cable is unplugged?
|
||||
|
||||
Unplugging the cable is not an error situation. The TCP/IP protocol stack
|
||||
Unplugging a cable is not an error situation. The TCP/IP protocol stack
|
||||
was designed to be fault tolerant, so even though there may be a physical
|
||||
break somewhere the connection shouldn't be affected, just possibly
|
||||
delayed. Eventually, the physical break will be fixed or the data will be
|
||||
re-routed around the physical problem.
|
||||
re-routed around the physical problem through another path.
|
||||
|
||||
In such cases, the TCP/IP stack is responsible for detecting when the
|
||||
network connection is irrevocably lost. Since with some protocols it is
|
||||
@@ -1077,6 +1077,12 @@ FAQ
|
||||
falls too low, and --connect-timeout and --max-time can be used to put an
|
||||
overall timeout on the connection phase or the entire transfer.
|
||||
|
||||
A libcurl-using application running in a known physical environment (e.g.
|
||||
an embedded device with only a single network connection) may want to act
|
||||
immediately if its lone network connection goes down. That can be achieved
|
||||
by having the application monitor the network connection on its own using an
|
||||
OS-specific mechanism, then signalling libcurl to abort (see also item 5.13).
|
||||
|
||||
|
||||
5. libcurl Issues
|
||||
|
||||
@@ -1086,7 +1092,9 @@ FAQ
|
||||
|
||||
We have written the libcurl code specifically adjusted for multi-threaded
|
||||
programs. libcurl will use thread-safe functions instead of non-safe ones if
|
||||
your system has such.
|
||||
your system has such. Note that you must never share the same handle in
|
||||
multiple threads.
|
||||
|
||||
|
||||
If you use a OpenSSL-powered libcurl in a multi-threaded environment, you
|
||||
need to provide one or two locking functions:
|
||||
|
14
docs/HISTORY
14
docs/HISTORY
@@ -7,19 +7,19 @@
|
||||
How cURL Became Like This
|
||||
|
||||
|
||||
In the second half of 1997, Daniel Stenberg came up with the idea to make
|
||||
Towards the end of 1996, Daniel Stenberg came up with the idea to make
|
||||
currency-exchange calculations available to Internet Relay Chat (IRC)
|
||||
users. All the necessary data are published on the Web; he just needed to
|
||||
automate their retrieval.
|
||||
|
||||
Daniel simply adopted an existing command-line open-source tool, httpget, that
|
||||
Brazilian Rafael Sagula had written. After a few minor adjustments, it did
|
||||
just what he needed.
|
||||
Brazilian Rafael Sagula had written and recently release version 0.1 of. After
|
||||
a few minor adjustments, it did just what he needed. HttpGet 1.0 was released
|
||||
on April 8th 1997 with brand new HTTP proxy support.
|
||||
|
||||
Soon, he found currencies on a GOPHER site, so support for that had to go in,
|
||||
and not before long FTP download support was added as well. The name of the
|
||||
project was changed to urlget to better fit what it actually did now, since
|
||||
the http-only days were already passed.
|
||||
We soon found and fixed support for getting currencies over GOPHER. Once FTP
|
||||
download support was added, the name of the project was changed and urlget 2.0
|
||||
was released in August 1997. The http-only days were already passed.
|
||||
|
||||
The project slowly grew bigger. When upload capabilities were added and the
|
||||
name once again was misleading, a second name change was made and on March 20,
|
||||
|
@@ -220,7 +220,7 @@ Win32
|
||||
adjust as necessary. It is also possible to override these paths with
|
||||
environment variables, for example:
|
||||
|
||||
set ZLIB_PATH=c:\zlib-1.2.7
|
||||
set ZLIB_PATH=c:\zlib-1.2.8
|
||||
set OPENSSL_PATH=c:\openssl-0.9.8y
|
||||
set LIBSSH2_PATH=c:\libssh2-1.4.3
|
||||
|
||||
@@ -323,7 +323,7 @@ Win32
|
||||
documentation on how to compile zlib. Define the ZLIB_PATH environment
|
||||
variable to the location of zlib.h and zlib.lib, for example:
|
||||
|
||||
set ZLIB_PATH=c:\zlib-1.2.7
|
||||
set ZLIB_PATH=c:\zlib-1.2.8
|
||||
|
||||
Then run 'nmake vc-zlib' in curl's root directory.
|
||||
|
||||
|
@@ -3,6 +3,17 @@ join in and help us correct one or more of these! Also be sure to check the
|
||||
changelog of the current development status, as one or more of these problems
|
||||
may have been fixed since this was written!
|
||||
|
||||
82. When building with the Windows Borland compiler, it fails because the
|
||||
"tlib" tool doesn't support hyphens (minus signs) in file names and we have
|
||||
such in the build.
|
||||
http://curl.haxx.se/bug/view.cgi?id=1222
|
||||
|
||||
81. When using -J (with -O), automaticly resumed downloading together with "-C
|
||||
-" fails. Without -J the same command line works! This happens because the
|
||||
resume logic is worked out before the target file name (and thus its
|
||||
pre-transfer size) has been figured out!
|
||||
http://curl.haxx.se/bug/view.cgi?id=1169
|
||||
|
||||
80. Curl doesn't recognize certificates in DER format in keychain, but it
|
||||
works with PEM.
|
||||
http://curl.haxx.se/bug/view.cgi?id=3439999
|
||||
|
28
docs/THANKS
28
docs/THANKS
@@ -13,9 +13,9 @@ Adam Tkac
|
||||
Adrian Schuur
|
||||
Adriano Meirelles
|
||||
Ajit Dhumale
|
||||
Aki Koskinen
|
||||
Akos Pasztory
|
||||
Alan Pinstein
|
||||
Albert Chin
|
||||
Albert Chin-A-Young
|
||||
Albert Choy
|
||||
Ale Vesely
|
||||
@@ -31,6 +31,7 @@ Alex Suykov
|
||||
Alex Vinnik
|
||||
Alex aka WindEagle
|
||||
Alexander Beedie
|
||||
Alexander Klauer
|
||||
Alexander Kourakos
|
||||
Alexander Krasnostavsky
|
||||
Alexander Lazic
|
||||
@@ -64,6 +65,7 @@ Andrew Biggs
|
||||
Andrew Bushnell
|
||||
Andrew Francis
|
||||
Andrew Fuller
|
||||
Andrew Kurushin
|
||||
Andrew Moise
|
||||
Andrew Wansink
|
||||
Andrew de los Reyes
|
||||
@@ -107,6 +109,7 @@ Bernhard Reutner-Fischer
|
||||
Bertrand Demiddelaer
|
||||
Bill Egert
|
||||
Bill Hoffman
|
||||
Bill Middlecamp
|
||||
Bjoern Sikora
|
||||
Bjorn Augustsson
|
||||
Bjorn Reese
|
||||
@@ -153,7 +156,6 @@ Chris Maltby
|
||||
Chris Mumford
|
||||
Chris Smowton
|
||||
Christian Grothoff
|
||||
Christian Hagele
|
||||
Christian Hägele
|
||||
Christian Krause
|
||||
Christian Kurz
|
||||
@@ -169,6 +171,7 @@ Christopher Stone
|
||||
Ciprian Badescu
|
||||
Claes Jakobsson
|
||||
Clarence Gardner
|
||||
Clemens Gruber
|
||||
Clifford Wolf
|
||||
Cody Jones
|
||||
Colin Hogben
|
||||
@@ -180,10 +183,10 @@ Craig A West
|
||||
Craig Davison
|
||||
Craig Markwardt
|
||||
Cris Bailiff
|
||||
Cristian Rodriguez
|
||||
Cristian Rodríguez
|
||||
Curt Bogmine
|
||||
Cyrill Osterwalder
|
||||
Cédric Deltheil
|
||||
Dag Ekengren
|
||||
Dagobert Michelsen
|
||||
Damien Adant
|
||||
@@ -317,6 +320,7 @@ Fred Machado
|
||||
Fred New
|
||||
Fred Noz
|
||||
Frederic Lepied
|
||||
Fredrik Thulin
|
||||
Gabriel Kuri
|
||||
Gabriel Sjoberg
|
||||
Garrett Holmstrom
|
||||
@@ -438,6 +442,7 @@ Jeff Pohlmeyer
|
||||
Jeff Weber
|
||||
Jeffrey Pohlmeyer
|
||||
Jeremy Friesner
|
||||
Jeremy Huddleston
|
||||
Jerome Muffat-Meridol
|
||||
Jerome Vouillon
|
||||
Jerry Wu
|
||||
@@ -449,8 +454,8 @@ Jim Drash
|
||||
Jim Freeman
|
||||
Jim Hollinger
|
||||
Jim Meyering
|
||||
Jiri Jaburek
|
||||
Jiri Hruska
|
||||
Jiri Jaburek
|
||||
Jocelyn Jaubert
|
||||
Joe Halpin
|
||||
Joe Malicki
|
||||
@@ -534,6 +539,7 @@ Kevin Lussier
|
||||
Kevin Reed
|
||||
Kevin Roth
|
||||
Kim Rinnewitz
|
||||
Kim Vandry
|
||||
Kimmo Kinnunen
|
||||
Kjell Ericson
|
||||
Kjetil Jacobsen
|
||||
@@ -614,6 +620,7 @@ Martin C. Martin
|
||||
Martin Drasar
|
||||
Martin Hager
|
||||
Martin Hedenfalk
|
||||
Martin Jansen
|
||||
Martin Lemke
|
||||
Martin Skinner
|
||||
Martin Storsjo
|
||||
@@ -676,6 +683,7 @@ Mitz Wark
|
||||
Mohamed Lrhazi
|
||||
Mohun Biswas
|
||||
Moonesamy
|
||||
Myk Taylor
|
||||
Nathan Coulter
|
||||
Nathan O'Sullivan
|
||||
Nathanael Nerode
|
||||
@@ -709,6 +717,7 @@ Ofer
|
||||
Olaf Flebbe
|
||||
Olaf Stueben
|
||||
Olaf Stüben
|
||||
Oliver Gondža
|
||||
Olivier Berger
|
||||
Oren Tirosh
|
||||
Ori Avtalion
|
||||
@@ -720,6 +729,7 @@ Pascal Terjan
|
||||
Pasha Kuznetsov
|
||||
Pat Ray
|
||||
Patrice Guerin
|
||||
Patricia Muscalu
|
||||
Patrick Bihan-Faou
|
||||
Patrick Monnerat
|
||||
Patrick Scott
|
||||
@@ -779,6 +789,7 @@ Quinn Slack
|
||||
Rafa Muyo
|
||||
Rafael Sagula
|
||||
Rainer Canavan
|
||||
Rainer Jung
|
||||
Rainer Koenig
|
||||
Rajesh Naganathan
|
||||
Ralf S. Engelschall
|
||||
@@ -806,6 +817,7 @@ Richard Bramante
|
||||
Richard Clayton
|
||||
Richard Cooper
|
||||
Richard Gorton
|
||||
Richard Michael
|
||||
Richard Prescott
|
||||
Richard Silverman
|
||||
Rick Jones
|
||||
@@ -822,6 +834,7 @@ Robert Iakobashvili
|
||||
Robert Olson
|
||||
Robert Schumann
|
||||
Robert Weaver
|
||||
Robert Wruck
|
||||
Robin Cornelius
|
||||
Robin Johnson
|
||||
Robin Kay
|
||||
@@ -846,6 +859,7 @@ Ryan Schmidt
|
||||
S. Moonesamy
|
||||
Salvador Dávila
|
||||
Salvatore Sorrentino
|
||||
Sam Deane
|
||||
Sam Listopad
|
||||
Sampo Kellomaki
|
||||
Samuel Díaz García
|
||||
@@ -856,6 +870,7 @@ Sandor Feldi
|
||||
Santhana Todatry
|
||||
Saqib Ali
|
||||
Sara Golemon
|
||||
Saran Neti
|
||||
Saul good
|
||||
Scott Bailey
|
||||
Scott Barrett
|
||||
@@ -906,6 +921,7 @@ Steve Oliphant
|
||||
Steve Roskowski
|
||||
Steven Bazyl
|
||||
Steven G. Johnson
|
||||
Steven Gu
|
||||
Steven M. Schweda
|
||||
Steven Parkes
|
||||
Stoned Elipot
|
||||
@@ -943,6 +959,7 @@ Todd Ouska
|
||||
Todd Vierling
|
||||
Tom Benoist
|
||||
Tom Donovan
|
||||
Tom Grace
|
||||
Tom Lee
|
||||
Tom Mattison
|
||||
Tom Moers
|
||||
@@ -994,9 +1011,11 @@ Wesley Laxton
|
||||
Wesley Miaw
|
||||
Wez Furlong
|
||||
Wilfredo Sanchez
|
||||
Willem Sparreboom
|
||||
Wojciech Zwiefka
|
||||
Wu Yongzheng
|
||||
Xavier Bouchoux
|
||||
Yamada Yasuharu
|
||||
Yang Tse
|
||||
Yarram Sunil
|
||||
Yehoshua Hershberg
|
||||
@@ -1004,6 +1023,7 @@ Yukihiro Kawada
|
||||
Yuriy Sosov
|
||||
Yves Arrouye
|
||||
Yves Lejeune
|
||||
Zdenek Pavlas
|
||||
Zmey Petroff
|
||||
Zvi Har'El
|
||||
nk
|
||||
|
96
docs/TODO
96
docs/TODO
@@ -38,6 +38,7 @@
|
||||
5.1 Better persistency for HTTP 1.0
|
||||
5.2 support FF3 sqlite cookie files
|
||||
5.3 Rearrange request header order
|
||||
5.4 HTTP2/SPDY
|
||||
|
||||
6. TELNET
|
||||
6.1 ditch stdin
|
||||
@@ -46,19 +47,18 @@
|
||||
6.4 send data in chunks
|
||||
|
||||
7. SMTP
|
||||
7.1 Specify the preferred authentication mechanism
|
||||
7.2 Initial response
|
||||
7.3 Pipelining
|
||||
7.4 Graceful base64 decoding failure
|
||||
7.1 Pipelining
|
||||
7.2 Graceful base64 decoding failure
|
||||
7.3 Enhanced capability support
|
||||
|
||||
8. POP3
|
||||
8.1 auth= in URLs
|
||||
8.2 Initial response
|
||||
8.3 Graceful base64 decoding failure
|
||||
8.1 Pipelining
|
||||
8.2 Graceful base64 decoding failure
|
||||
8.3 Enhanced capability support
|
||||
|
||||
9. IMAP
|
||||
9.1 auth= in URLs
|
||||
9.2 Graceful base64 decoding failure
|
||||
9.1 Graceful base64 decoding failure
|
||||
9.2 Enhanced capability support
|
||||
|
||||
10. LDAP
|
||||
10.1 SASL based authentication mechanisms
|
||||
@@ -269,6 +269,25 @@
|
||||
headers use a default value so only headers that need to be moved have to be
|
||||
specified.
|
||||
|
||||
5.4 HTTP2/SPDY
|
||||
|
||||
The first drafts for HTTP2 have been published
|
||||
(http://tools.ietf.org/html/draft-ietf-httpbis-http2-03) and is so far based
|
||||
on SPDY (http://www.chromium.org/spdy) designs and experiences. Chances are
|
||||
it will end up in that style. Chrome and Firefox already support SPDY and
|
||||
lots of web services do.
|
||||
|
||||
It would make sense to implement SPDY support now and later transition into
|
||||
or add HTTP2 support as well.
|
||||
|
||||
We should base or HTTP2/SPDY work on a 3rd party library for the protocol
|
||||
fiddling. The Spindy library (http://spindly.haxx.se/) was an attempt to make
|
||||
such a library with an API suitable for use by libcurl but that effort has
|
||||
more or less stalled. spdylay (https://github.com/tatsuhiro-t/spdylay) may
|
||||
be a better option, either used directly or wrapped with a more spindly-like
|
||||
API.
|
||||
|
||||
|
||||
6. TELNET
|
||||
|
||||
6.1 ditch stdin
|
||||
@@ -295,65 +314,54 @@ to provide the data to send.
|
||||
|
||||
7. SMTP
|
||||
|
||||
7.1 Specify the preferred authentication mechanism
|
||||
|
||||
Add the ability to specify the preferred authentication mechanism or a list
|
||||
of mechanisms that should be used. Not only that, but the order that is
|
||||
returned by the server during the EHLO response should be honored by curl.
|
||||
|
||||
7.2 Initial response
|
||||
|
||||
Add the ability for the user to specify whether the initial response is
|
||||
included in the AUTH command. Some email servers, such as Microsoft
|
||||
Exchange, can work with either whilst others need to have the initial
|
||||
response sent separately:
|
||||
|
||||
http://curl.haxx.se/mail/lib-2012-03/0114.html
|
||||
|
||||
7.3 Pipelining
|
||||
7.1 Pipelining
|
||||
|
||||
Add support for pipelining emails.
|
||||
|
||||
7.4 Graceful base64 decoding failure
|
||||
7.2 Graceful base64 decoding failure
|
||||
|
||||
Rather than shutting down the session and returning an error when the
|
||||
decoding of a base64 encoded authentication response fails, we should
|
||||
gracefully shutdown the authentication process by sending a * response to the
|
||||
server as per RFC4954.
|
||||
|
||||
7.3 Enhanced capability support
|
||||
|
||||
Add the ability, for an application that uses libcurl, to obtain the list of
|
||||
capabilities returned from the EHLO command.
|
||||
|
||||
8. POP3
|
||||
|
||||
8.1 auth= in URLs
|
||||
8.1 Pipelining
|
||||
|
||||
Being able to specify the preferred authentication mechanism in the URL as
|
||||
per RFC2384.
|
||||
Add support for pipelining commands.
|
||||
|
||||
8.2 Initial response
|
||||
|
||||
Add the ability for the user to specify whether the initial response is
|
||||
included in the AUTH command as per RFC5034.
|
||||
|
||||
8.3 Graceful base64 decoding failure
|
||||
8.2 Graceful base64 decoding failure
|
||||
|
||||
Rather than shutting down the session and returning an error when the
|
||||
decoding of a base64 encoded authentication response fails, we should
|
||||
gracefully shutdown the authentication process by sending a * response to the
|
||||
server as per RFC5034.
|
||||
|
||||
8.3 Enhanced capability support
|
||||
|
||||
Add the ability, for an application that uses libcurl, to obtain the list of
|
||||
capabilities returned from the CAPA command.
|
||||
|
||||
9. IMAP
|
||||
|
||||
9.1 auth= in URLs
|
||||
|
||||
Being able to specify the preferred authentication mechanism in the URL as
|
||||
per RFC5092.
|
||||
|
||||
9.2 Graceful base64 decoding failure
|
||||
9.1 Graceful base64 decoding failure
|
||||
|
||||
Rather than shutting down the session and returning an error when the
|
||||
decoding of a base64 encoded authentication response fails, we should
|
||||
gracefully shutdown the authentication process by sending a * response to the
|
||||
server as per RFC3501.
|
||||
|
||||
9.2 Enhanced capability support
|
||||
|
||||
Add the ability, for an application that uses libcurl, to obtain the list of
|
||||
capabilities returned from the CAPABILITY command.
|
||||
|
||||
10. LDAP
|
||||
|
||||
10.1 SASL based authentication mechanisms
|
||||
@@ -429,6 +437,12 @@ to provide the data to send.
|
||||
keys and certs over DNS using DNSSEC as an alternative to the CA model.
|
||||
http://www.rfc-editor.org/rfc/rfc6698.txt
|
||||
|
||||
An initial patch was posted by Suresh Krishnaswamy on March 7th 2013
|
||||
(http://curl.haxx.se/mail/lib-2013-03/0075.html) but it was a too simple
|
||||
approach. See Daniel's comments:
|
||||
http://curl.haxx.se/mail/lib-2013-03/0103.html . libunbound may be the
|
||||
correct library to base this development on.
|
||||
|
||||
13. GnuTLS
|
||||
|
||||
13.1 SSL engine stuff
|
||||
|
14
docs/curl.1
14
docs/curl.1
@@ -5,7 +5,7 @@
|
||||
.\" * | (__| |_| | _ <| |___
|
||||
.\" * \___|\___/|_| \_\_____|
|
||||
.\" *
|
||||
.\" * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
.\" * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
.\" *
|
||||
.\" * This software is licensed as described in the file COPYING, which
|
||||
.\" * you should have received as part of this distribution. The terms
|
||||
@@ -388,7 +388,12 @@ curl the nickname of the certificate to use within the NSS database defined
|
||||
by the environment variable SSL_DIR (or by default /etc/pki/nssdb). If the
|
||||
NSS PEM PKCS#11 module (libnsspem.so) is available then PEM files may be
|
||||
loaded. If you want to use a file from the current directory, please precede
|
||||
it with "./" prefix, in order to avoid confusion with a nickname.
|
||||
it with "./" prefix, in order to avoid confusion with a nickname. If the
|
||||
nickname contains ":", it needs to be preceded by "\\" so that it is not
|
||||
recognized as password delimiter. If the nickname contains "\\", it needs to
|
||||
be escaped as "\\\\" so that it is not recognized as an escape character.
|
||||
|
||||
(iOS and Mac OS X only) If curl is built against Secure Transport, then the certificate string must match the name of a certificate that's in the system or user keychain. The private key corresponding to the certificate, and certificate chain (if any), must also be present in the keychain.
|
||||
|
||||
If this option is used several times, the last one will be used.
|
||||
.IP "--engine <name>"
|
||||
@@ -1272,8 +1277,9 @@ Set this option to zero to not timeout retries. (Added in 7.12.3)
|
||||
|
||||
If this option is used several times, the last one will be used.
|
||||
.IP "-s, --silent"
|
||||
Silent or quiet mode. Don't show progress meter or error messages. Makes
|
||||
Curl mute.
|
||||
Silent or quiet mode. Don't show progress meter or error messages. Makes Curl
|
||||
mute. It will still output the data you ask for, potentially even to the
|
||||
terminal/stdout unless you redirect it.
|
||||
.IP "-S, --show-error"
|
||||
When used with \fI-s\fP it makes curl show an error message if it fails.
|
||||
.IP "--ssl"
|
||||
|
2
docs/examples/.gitignore
vendored
2
docs/examples/.gitignore
vendored
@@ -43,3 +43,5 @@ simplessl
|
||||
smtp-multi
|
||||
smtp-tls
|
||||
url2file
|
||||
usercertinmem
|
||||
xmlstream
|
||||
|
@@ -5,7 +5,8 @@ check_PROGRAMS = 10-at-a-time anyauthput cookie_interface debug fileupload \
|
||||
persistant post-callback postit2 sepheaders simple simplepost simplessl \
|
||||
sendrecv httpcustomheader certinfo chkspeed ftpgetinfo ftp-wildcard \
|
||||
smtp-multi simplesmtp smtp-tls rtsp externalsocket resolve \
|
||||
progressfunc pop3s pop3slist imap url2file sftpget ftpsget
|
||||
progressfunc pop3s pop3slist imap url2file sftpget ftpsget \
|
||||
usercertinmem
|
||||
|
||||
# These examples require external dependencies that may not be commonly
|
||||
# available on POSIX systems, so don't bother attempting to compile them here.
|
||||
@@ -13,4 +14,4 @@ COMPLICATED_EXAMPLES = curlgtk.c curlx.c htmltitle.cpp cacertinmem.c \
|
||||
ftpuploadresume.c ghiper.c hiperfifo.c htmltidy.c multithread.c \
|
||||
opensslthreadlock.c sampleconv.c synctime.c threaded-ssl.c evhiperfifo.c \
|
||||
smooth-gtk-thread.c version-check.pl href_extractor.c asiohiper.cpp \
|
||||
multi-uv.c
|
||||
multi-uv.c xmlstream.c
|
||||
|
@@ -27,14 +27,14 @@
|
||||
## Example: mingw32-make -f Makefile.m32 CFG=-zlib-ssl-spi-winidn
|
||||
##
|
||||
## Hint: you can also set environment vars to control the build, f.e.:
|
||||
## set ZLIB_PATH=c:/zlib-1.2.7
|
||||
## set ZLIB_PATH=c:/zlib-1.2.8
|
||||
## set ZLIB=1
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
# Edit the path below to point to the base of your Zlib sources.
|
||||
ifndef ZLIB_PATH
|
||||
ZLIB_PATH = ../../../zlib-1.2.7
|
||||
ZLIB_PATH = ../../../zlib-1.2.8
|
||||
endif
|
||||
# Edit the path below to point to the base of your OpenSSL package.
|
||||
ifndef OPENSSL_PATH
|
||||
|
@@ -14,7 +14,7 @@ endif
|
||||
|
||||
# Edit the path below to point to the base of your Zlib sources.
|
||||
ifndef ZLIB_PATH
|
||||
ZLIB_PATH = ../../../zlib-1.2.7
|
||||
ZLIB_PATH = ../../../zlib-1.2.8
|
||||
endif
|
||||
|
||||
# Edit the path below to point to the base of your OpenSSL package.
|
||||
|
@@ -78,4 +78,5 @@ simplepost.c - HTTP POST
|
||||
simplessl.c - HTTPS example with certificates many options set
|
||||
synctime.c - Sync local time by extracting date from remote HTTP servers
|
||||
url2file.c - download a document and store it in a file
|
||||
xmlstream.c - Stream-parse a document using the streaming Expat parser
|
||||
10-at-a-time.c - Download many files simultaneously, 10 at a time.
|
||||
|
@@ -54,23 +54,22 @@ int main(void)
|
||||
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_data);
|
||||
|
||||
/* open the files */
|
||||
headerfile = fopen(headerfilename,"w");
|
||||
headerfile = fopen(headerfilename,"wb");
|
||||
if (headerfile == NULL) {
|
||||
curl_easy_cleanup(curl_handle);
|
||||
return -1;
|
||||
}
|
||||
bodyfile = fopen(bodyfilename,"w");
|
||||
bodyfile = fopen(bodyfilename,"wb");
|
||||
if (bodyfile == NULL) {
|
||||
curl_easy_cleanup(curl_handle);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* we want the headers to this file handle */
|
||||
/* we want the headers be written to this file handle */
|
||||
curl_easy_setopt(curl_handle, CURLOPT_WRITEHEADER, headerfile);
|
||||
|
||||
/*
|
||||
* Notice here that if you want the actual data sent anywhere else but
|
||||
* stdout, you should consider using the CURLOPT_WRITEDATA option. */
|
||||
/* we want the body be written to this file handle instead of stdout */
|
||||
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, bodyfile);
|
||||
|
||||
/* get it! */
|
||||
curl_easy_perform(curl_handle);
|
||||
@@ -78,6 +77,9 @@ int main(void)
|
||||
/* close the header file */
|
||||
fclose(headerfile);
|
||||
|
||||
/* close the body file */
|
||||
fclose(bodyfile);
|
||||
|
||||
/* cleanup curl stuff */
|
||||
curl_easy_cleanup(curl_handle);
|
||||
|
||||
|
211
docs/examples/usercertinmem.c
Normal file
211
docs/examples/usercertinmem.c
Normal file
@@ -0,0 +1,211 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at http://curl.haxx.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
***************************************************************************/
|
||||
/* Example using an in memory PEM user certificate and RSA key to retrieve an
|
||||
* https page.
|
||||
* Written by Ishan SinghLevett, based on Theo Borm's cacertinmem.c.
|
||||
* Note this example does not use a CA certificate, however one should be used
|
||||
* if you want a properly secure connection
|
||||
*/
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <curl/curl.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static size_t writefunction(void *ptr, size_t size, size_t nmemb, void *stream)
|
||||
{
|
||||
fwrite(ptr,size,nmemb,stream);
|
||||
return(nmemb*size);
|
||||
}
|
||||
|
||||
static CURLcode sslctx_function(CURL *curl, void *sslctx, void *parm)
|
||||
{
|
||||
X509 *cert = NULL;
|
||||
BIO *bio = NULL;
|
||||
BIO *kbio = NULL;
|
||||
RSA *rsa = NULL;
|
||||
int ret;
|
||||
|
||||
const char *mypem = /* www.cacert.org */
|
||||
"-----BEGIN CERTIFICATE-----\n"\
|
||||
"MIIHPTCCBSWgAwIBAgIBADANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290\n"\
|
||||
"IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB\n"\
|
||||
"IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA\n"\
|
||||
"Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO\n"\
|
||||
"BgNVBAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEi\n"\
|
||||
"MCAGA1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJ\n"\
|
||||
"ARYSc3VwcG9ydEBjYWNlcnQub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC\n"\
|
||||
"CgKCAgEAziLA4kZ97DYoB1CW8qAzQIxL8TtmPzHlawI229Z89vGIj053NgVBlfkJ\n"\
|
||||
"8BLPRoZzYLdufujAWGSuzbCtRRcMY/pnCujW0r8+55jE8Ez64AO7NV1sId6eINm6\n"\
|
||||
"zWYyN3L69wj1x81YyY7nDl7qPv4coRQKFWyGhFtkZip6qUtTefWIonvuLwphK42y\n"\
|
||||
"fk1WpRPs6tqSnqxEQR5YYGUFZvjARL3LlPdCfgv3ZWiYUQXw8wWRBB0bF4LsyFe7\n"\
|
||||
"w2t6iPGwcswlWyCR7BYCEo8y6RcYSNDHBS4CMEK4JZwFaz+qOqfrU0j36NK2B5jc\n"\
|
||||
"G8Y0f3/JHIJ6BVgrCFvzOKKrF11myZjXnhCLotLddJr3cQxyYN/Nb5gznZY0dj4k\n"\
|
||||
"epKwDpUeb+agRThHqtdB7Uq3EvbXG4OKDy7YCbZZ16oE/9KTfWgu3YtLq1i6L43q\n"\
|
||||
"laegw1SJpfvbi1EinbLDvhG+LJGGi5Z4rSDTii8aP8bQUWWHIbEZAWV/RRyH9XzQ\n"\
|
||||
"QUxPKZgh/TMfdQwEUfoZd9vUFBzugcMd9Zi3aQaRIt0AUMyBMawSB3s42mhb5ivU\n"\
|
||||
"fslfrejrckzzAeVLIL+aplfKkQABi6F1ITe1Yw1nPkZPcCBnzsXWWdsC4PDSy826\n"\
|
||||
"YreQQejdIOQpvGQpQsgi3Hia/0PsmBsJUUtaWsJx8cTLc6nloQsCAwEAAaOCAc4w\n"\
|
||||
"ggHKMB0GA1UdDgQWBBQWtTIb1Mfz4OaO873SsDrusjkY0TCBowYDVR0jBIGbMIGY\n"\
|
||||
"gBQWtTIb1Mfz4OaO873SsDrusjkY0aF9pHsweTEQMA4GA1UEChMHUm9vdCBDQTEe\n"\
|
||||
"MBwGA1UECxMVaHR0cDovL3d3dy5jYWNlcnQub3JnMSIwIAYDVQQDExlDQSBDZXJ0\n"\
|
||||
"IFNpZ25pbmcgQXV0aG9yaXR5MSEwHwYJKoZIhvcNAQkBFhJzdXBwb3J0QGNhY2Vy\n"\
|
||||
"dC5vcmeCAQAwDwYDVR0TAQH/BAUwAwEB/zAyBgNVHR8EKzApMCegJaAjhiFodHRw\n"\
|
||||
"czovL3d3dy5jYWNlcnQub3JnL3Jldm9rZS5jcmwwMAYJYIZIAYb4QgEEBCMWIWh0\n"\
|
||||
"dHBzOi8vd3d3LmNhY2VydC5vcmcvcmV2b2tlLmNybDA0BglghkgBhvhCAQgEJxYl\n"\
|
||||
"aHR0cDovL3d3dy5jYWNlcnQub3JnL2luZGV4LnBocD9pZD0xMDBWBglghkgBhvhC\n"\
|
||||
"AQ0ESRZHVG8gZ2V0IHlvdXIgb3duIGNlcnRpZmljYXRlIGZvciBGUkVFIGhlYWQg\n"\
|
||||
"b3ZlciB0byBodHRwOi8vd3d3LmNhY2VydC5vcmcwDQYJKoZIhvcNAQEEBQADggIB\n"\
|
||||
"ACjH7pyCArpcgBLKNQodgW+JapnM8mgPf6fhjViVPr3yBsOQWqy1YPaZQwGjiHCc\n"\
|
||||
"nWKdpIevZ1gNMDY75q1I08t0AoZxPuIrA2jxNGJARjtT6ij0rPtmlVOKTV39O9lg\n"\
|
||||
"18p5aTuxZZKmxoGCXJzN600BiqXfEVWqFcofN8CCmHBh22p8lqOOLlQ+TyGpkO/c\n"\
|
||||
"gr/c6EWtTZBzCDyUZbAEmXZ/4rzCahWqlwQ3JNgelE5tDlG+1sSPypZt90Pf6DBl\n"\
|
||||
"Jzt7u0NDY8RD97LsaMzhGY4i+5jhe1o+ATc7iwiwovOVThrLm82asduycPAtStvY\n"\
|
||||
"sONvRUgzEv/+PDIqVPfE94rwiCPCR/5kenHA0R6mY7AHfqQv0wGP3J8rtsYIqQ+T\n"\
|
||||
"SCX8Ev2fQtzzxD72V7DX3WnRBnc0CkvSyqD/HMaMyRa+xMwyN2hzXwj7UfdJUzYF\n"\
|
||||
"CpUCTPJ5GhD22Dp1nPMd8aINcGeGG7MW9S/lpOt5hvk9C8JzC6WZrG/8Z7jlLwum\n"\
|
||||
"GCSNe9FINSkYQKyTYOGWhlC0elnYjyELn8+CkcY7v2vcB5G5l1YjqrZslMZIBjzk\n"\
|
||||
"zk6q5PYvCdxTby78dOs6Y5nCpqyJvKeyRKANihDjbPIky/qbn3BHLt4Ui9SyIAmW\n"\
|
||||
"omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD\n"\
|
||||
"-----END CERTIFICATE-----\n";
|
||||
|
||||
/*replace the XXX with the actual RSA key*/
|
||||
const char *mykey =
|
||||
"-----BEGIN RSA PRIVATE KEY-----\n"\
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
|
||||
"-----END RSA PRIVATE KEY-----\n";
|
||||
|
||||
(void)curl; /* avoid warnings */
|
||||
(void)parm; /* avoid warnings */
|
||||
|
||||
/* get a BIO */
|
||||
bio = BIO_new_mem_buf((char *)mypem, -1);
|
||||
|
||||
if (bio == NULL) {
|
||||
printf("BIO_new_mem_buf failed\n");
|
||||
}
|
||||
|
||||
/* use it to read the PEM formatted certificate from memory into an X509
|
||||
* structure that SSL can use
|
||||
*/
|
||||
cert = PEM_read_bio_X509(bio, NULL, 0, NULL);
|
||||
if (cert == NULL) {
|
||||
printf("PEM_read_bio_X509 failed...\n");
|
||||
}
|
||||
|
||||
/*tell SSL to use the X509 certificate*/
|
||||
ret = SSL_CTX_use_certificate((SSL_CTX*)sslctx, cert);
|
||||
if (ret != 1) {
|
||||
printf("Use certificate failed\n");
|
||||
}
|
||||
|
||||
/*create a bio for the RSA key*/
|
||||
kbio = BIO_new_mem_buf((char *)mykey, -1);
|
||||
if (kbio == NULL) {
|
||||
printf("BIO_new_mem_buf failed\n");
|
||||
}
|
||||
|
||||
/*read the key bio into an RSA object*/
|
||||
rsa = PEM_read_bio_RSAPrivateKey(kbio, NULL, 0, NULL);
|
||||
if (rsa == NULL) {
|
||||
printf("Failed to create key bio\n");
|
||||
}
|
||||
|
||||
/*tell SSL to use the RSA key from memory*/
|
||||
ret = SSL_CTX_use_RSAPrivateKey((SSL_CTX*)sslctx, rsa);
|
||||
if (ret != 1) {
|
||||
printf("Use Key failed\n");
|
||||
}
|
||||
|
||||
|
||||
/* all set to go */
|
||||
return CURLE_OK ;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
CURL *ch;
|
||||
CURLcode rv;
|
||||
|
||||
rv = curl_global_init(CURL_GLOBAL_ALL);
|
||||
ch = curl_easy_init();
|
||||
rv = curl_easy_setopt(ch,CURLOPT_VERBOSE, 0L);
|
||||
rv = curl_easy_setopt(ch,CURLOPT_HEADER, 0L);
|
||||
rv = curl_easy_setopt(ch,CURLOPT_NOPROGRESS, 1L);
|
||||
rv = curl_easy_setopt(ch,CURLOPT_NOSIGNAL, 1L);
|
||||
rv = curl_easy_setopt(ch,CURLOPT_WRITEFUNCTION, *writefunction);
|
||||
rv = curl_easy_setopt(ch,CURLOPT_WRITEDATA, stdout);
|
||||
rv = curl_easy_setopt(ch,CURLOPT_HEADERFUNCTION, *writefunction);
|
||||
rv = curl_easy_setopt(ch,CURLOPT_WRITEHEADER, stderr);
|
||||
rv = curl_easy_setopt(ch,CURLOPT_SSLCERTTYPE,"PEM");
|
||||
|
||||
/* both VERIFYPEER and VERIFYHOST are set to 0 in this case because there is
|
||||
no CA certificate*/
|
||||
|
||||
rv = curl_easy_setopt(ch,CURLOPT_SSL_VERIFYPEER, 0L);
|
||||
rv = curl_easy_setopt(ch,CURLOPT_SSL_VERIFYHOST, 0L);
|
||||
rv = curl_easy_setopt(ch, CURLOPT_URL, "https://www.example.com/");
|
||||
rv = curl_easy_setopt(ch, CURLOPT_SSLKEYTYPE, "PEM");
|
||||
|
||||
/* first try: retrieve page without user certificate and key -> will fail
|
||||
*/
|
||||
rv = curl_easy_perform(ch);
|
||||
if (rv==CURLE_OK) {
|
||||
printf("*** transfer succeeded ***\n");
|
||||
}
|
||||
else {
|
||||
printf("*** transfer failed ***\n");
|
||||
}
|
||||
|
||||
/* second try: retrieve page using user certificate and key -> will succeed
|
||||
* load the certificate and key by installing a function doing the necessary
|
||||
* "modifications" to the SSL CONTEXT just before link init
|
||||
*/
|
||||
rv = curl_easy_setopt(ch,CURLOPT_SSL_CTX_FUNCTION, *sslctx_function);
|
||||
rv = curl_easy_perform(ch);
|
||||
if (rv==CURLE_OK) {
|
||||
printf("*** transfer succeeded ***\n");
|
||||
}
|
||||
else {
|
||||
printf("*** transfer failed ***\n");
|
||||
}
|
||||
|
||||
curl_easy_cleanup(ch);
|
||||
curl_global_cleanup();
|
||||
return rv;
|
||||
}
|
158
docs/examples/xmlstream.c
Normal file
158
docs/examples/xmlstream.c
Normal file
@@ -0,0 +1,158 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at http://curl.haxx.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
***************************************************************************/
|
||||
/* Stream-parse a document using the streaming Expat parser.
|
||||
* Written by David Strauss
|
||||
*
|
||||
* Expat => http://www.libexpat.org/
|
||||
*
|
||||
* gcc -Wall -I/usr/local/include xmlstream.c -lcurl -lexpat -o xmlstream
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <expat.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
struct MemoryStruct {
|
||||
char *memory;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
struct ParserStruct {
|
||||
int ok;
|
||||
size_t tags;
|
||||
size_t depth;
|
||||
struct MemoryStruct characters;
|
||||
};
|
||||
|
||||
static void startElement(void *userData, const XML_Char *name, const XML_Char **atts)
|
||||
{
|
||||
struct ParserStruct *state = (struct ParserStruct *) userData;
|
||||
state->tags++;
|
||||
state->depth++;
|
||||
|
||||
/* Get a clean slate for reading in character data. */
|
||||
free(state->characters.memory);
|
||||
state->characters.memory = NULL;
|
||||
state->characters.size = 0;
|
||||
}
|
||||
|
||||
static void characterDataHandler(void *userData, const XML_Char *s, int len)
|
||||
{
|
||||
struct ParserStruct *state = (struct ParserStruct *) userData;
|
||||
struct MemoryStruct *mem = &state->characters;
|
||||
|
||||
mem->memory = realloc(mem->memory, mem->size + len + 1);
|
||||
if(mem->memory == NULL) {
|
||||
/* Out of memory. */
|
||||
fprintf(stderr, "Not enough memory (realloc returned NULL).\n");
|
||||
state->ok = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&(mem->memory[mem->size]), s, len);
|
||||
mem->size += len;
|
||||
mem->memory[mem->size] = 0;
|
||||
}
|
||||
|
||||
static void endElement(void *userData, const XML_Char *name)
|
||||
{
|
||||
struct ParserStruct *state = (struct ParserStruct *) userData;
|
||||
state->depth--;
|
||||
|
||||
printf("%5lu %10lu %s\n", state->depth, state->characters.size, name);
|
||||
}
|
||||
|
||||
static size_t parseStreamCallback(void *contents, size_t length, size_t nmemb, void *userp)
|
||||
{
|
||||
XML_Parser parser = (XML_Parser) userp;
|
||||
size_t real_size = length * nmemb;
|
||||
struct ParserStruct *state = (struct ParserStruct *) XML_GetUserData(parser);
|
||||
|
||||
/* Only parse if we're not already in a failure state. */
|
||||
if (state->ok && XML_Parse(parser, contents, real_size, 0) == 0) {
|
||||
int error_code = XML_GetErrorCode(parser);
|
||||
fprintf(stderr, "Parsing response buffer of length %lu failed with error code %d (%s).\n",
|
||||
real_size, error_code, XML_ErrorString(error_code));
|
||||
state->ok = 0;
|
||||
}
|
||||
|
||||
return real_size;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
CURL *curl_handle;
|
||||
CURLcode res;
|
||||
XML_Parser parser;
|
||||
struct ParserStruct state;
|
||||
|
||||
/* Initialize the state structure for parsing. */
|
||||
memset(&state, 0, sizeof(struct ParserStruct));
|
||||
state.ok = 1;
|
||||
|
||||
/* Initialize a namespace-aware parser. */
|
||||
parser = XML_ParserCreateNS(NULL, '\0');
|
||||
XML_SetUserData(parser, &state);
|
||||
XML_SetElementHandler(parser, startElement, endElement);
|
||||
XML_SetCharacterDataHandler(parser, characterDataHandler);
|
||||
|
||||
/* Initalize a libcurl handle. */
|
||||
curl_global_init(CURL_GLOBAL_ALL ^ CURL_GLOBAL_SSL);
|
||||
curl_handle = curl_easy_init();
|
||||
curl_easy_setopt(curl_handle, CURLOPT_URL, "http://www.w3schools.com/xml/simple.xml");
|
||||
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, parseStreamCallback);
|
||||
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)parser);
|
||||
|
||||
printf("Depth Characters Closing Tag\n");
|
||||
|
||||
/* Perform the request and any follow-up parsing. */
|
||||
res = curl_easy_perform(curl_handle);
|
||||
if(res != CURLE_OK) {
|
||||
fprintf(stderr, "curl_easy_perform() failed: %s\n",
|
||||
curl_easy_strerror(res));
|
||||
}
|
||||
else if (state.ok) {
|
||||
/* Expat requires one final call to finalize parsing. */
|
||||
if (XML_Parse(parser, NULL, 0, 1) == 0) {
|
||||
int error_code = XML_GetErrorCode(parser);
|
||||
fprintf(stderr, "Finalizing parsing failed with error code %d (%s).\n",
|
||||
error_code, XML_ErrorString(error_code));
|
||||
}
|
||||
else {
|
||||
printf(" --------------\n");
|
||||
printf(" %lu tags total\n", state.tags);
|
||||
}
|
||||
}
|
||||
|
||||
/* Clean up. */
|
||||
free(state.characters.memory);
|
||||
XML_ParserFree(parser);
|
||||
curl_easy_cleanup(curl_handle);
|
||||
curl_global_cleanup();
|
||||
|
||||
return 0;
|
||||
}
|
@@ -342,15 +342,34 @@ argument in the closesocket callback set with
|
||||
The default value of this parameter is unspecified.
|
||||
(Option added in 7.21.7)
|
||||
.IP CURLOPT_PROGRESSFUNCTION
|
||||
Pass a pointer to a function that matches the following prototype: \fBint
|
||||
function(void *clientp, double dltotal, double dlnow, double ultotal, double
|
||||
ulnow); \fP. This function gets called by libcurl instead of its internal
|
||||
equivalent with a frequent interval during operation (roughly once per second
|
||||
or sooner) no matter if data is being transferred or not. Unknown/unused
|
||||
argument values passed to the callback will be set to zero (like if you only
|
||||
download data, the upload size will remain 0). Returning a non-zero value from
|
||||
this callback will cause libcurl to abort the transfer and return
|
||||
\fICURLE_ABORTED_BY_CALLBACK\fP.
|
||||
Pass a pointer to a function that matches the following prototype:
|
||||
|
||||
\fBint function(void *clientp, double dltotal, double dlnow, double ultotal,
|
||||
double ulnow);\fP
|
||||
|
||||
This function gets called by libcurl instead of its internal equivalent with a
|
||||
frequent interval. While data is being transferred it will be called very
|
||||
frequently, and during slow periods like when nothing is being transferred it
|
||||
can slow down to about one call per second.
|
||||
|
||||
\fIclientp\fP is the pointer set with \fICURLOPT_PROGRESSDATA\fP, it is not
|
||||
actually used by libcurl but is only passed along from the application to the
|
||||
callback.
|
||||
|
||||
The callback gets told how much data libcurl will transfer and has
|
||||
transferred, in number of bytes. \fIdltotal\fP is the total number of bytes
|
||||
libcurl expects to download in this transfer. \fIdlnow\fP is the number of
|
||||
bytes downloaded so far. \fIultotal\fP is the total number of bytes libcurl
|
||||
expects to upload in this transfer. \fIulnow\fP is the number of bytes
|
||||
uploaded so far.
|
||||
|
||||
Unknown/unused argument values passed to the callback will be set to zero
|
||||
(like if you only download data, the upload size will remain 0). Many times
|
||||
the callback will be called one or more times first, before it knows the data
|
||||
sizes so a program must be made to handle that.
|
||||
|
||||
Returning a non-zero value from this callback will cause libcurl to abort the
|
||||
transfer and return \fICURLE_ABORTED_BY_CALLBACK\fP.
|
||||
|
||||
If you transfer data with the multi interface, this function will not be
|
||||
called during periods of idleness unless you call the appropriate libcurl
|
||||
@@ -620,12 +639,20 @@ scheme://host:port/path
|
||||
|
||||
For a greater explanation of the format please see RFC3986.
|
||||
|
||||
If the given URL lacks the scheme, or protocol, part ("http://" or "ftp://"
|
||||
etc), libcurl will attempt to resolve which protocol to use based on the
|
||||
given host mame. If the protocol is not supported, libcurl will return
|
||||
(\fICURLE_UNSUPPORTED_PROTOCOL\fP) when you call \fIcurl_easy_perform(3)\fP
|
||||
or \fIcurl_multi_perform(3)\fP. Use \fIcurl_version_info(3)\fP for detailed
|
||||
information on which protocols are supported.
|
||||
If the given URL lacks the scheme (such as "http://" or "ftp://" etc) then
|
||||
libcurl will attempt to resolve the protocol based on one of the following
|
||||
given host names:
|
||||
|
||||
HTTP, FTP, DICT, LDAP, IMAP, POP3 or SMTP
|
||||
|
||||
(POP3 and SMTP added in 7.31.0)
|
||||
|
||||
Should the protocol, either that specified by the scheme or deduced by libcurl
|
||||
from the host name, not be supported by libcurl then
|
||||
(\fICURLE_UNSUPPORTED_PROTOCOL\fP) will be returned from either the
|
||||
\fIcurl_easy_perform(3)\fP or \fIcurl_multi_perform(3)\fP functions when you
|
||||
call them. Use \fIcurl_version_info(3)\fP for detailed information of which
|
||||
protocols are supported by the build of libcurl you are using.
|
||||
|
||||
The host part of the URL contains the address of the server that you want to
|
||||
connect to. This can be the fully qualified domain name of the server, the
|
||||
@@ -640,17 +667,23 @@ http://192.168.0.1/
|
||||
|
||||
http://[2001:1890:1112:1::20]/
|
||||
|
||||
It is also possible to specify the user name and password as part of the
|
||||
host, for some protocols, when connecting to servers that require
|
||||
authentication.
|
||||
|
||||
For example the following types of authentication support this:
|
||||
It is also possible to specify the user name, password and any supported login
|
||||
options as part of the host, for the following protocols, when connecting to
|
||||
servers that require authentication:
|
||||
|
||||
http://user:password@www.example.com
|
||||
|
||||
ftp://user:password@ftp.example.com
|
||||
|
||||
pop3://user:password@mail.example.com
|
||||
imap://user:password;options@mail.example.com
|
||||
|
||||
pop3://user:password;options@mail.example.com
|
||||
|
||||
smtp://user:password;options@mail.example.com
|
||||
|
||||
At present only IMAP, POP3 and SMTP support login options as part of the host.
|
||||
For more information about the login options in URL syntax please see RFC2384,
|
||||
RFC5092 and IETF draft draft-earhart-url-smtp-00.txt (Added in 7.31.0).
|
||||
|
||||
The port is optional and when not specified libcurl will use the default port
|
||||
based on the determined or specified protocol: 80 for HTTP, 21 for FTP and 25
|
||||
@@ -1040,8 +1073,8 @@ the full path name to the file you want libcurl to use as .netrc file. If this
|
||||
option is omitted, and \fICURLOPT_NETRC\fP is set, libcurl will attempt to
|
||||
find a .netrc file in the current user's home directory. (Added in 7.10.9)
|
||||
.IP CURLOPT_USERPWD
|
||||
Pass a char * as parameter, which should be [user name]:[password] to use for
|
||||
the connection. Use \fICURLOPT_HTTPAUTH\fP to decide the authentication method.
|
||||
Pass a char * as parameter, pointing to a zero terminated login details string
|
||||
for the connection. The format of which is: [user name]:[password];[options].
|
||||
|
||||
When using NTLM, you can set the domain by prepending it to the user name and
|
||||
separating the domain and name with a forward (/) or backward slash (\\). Like
|
||||
@@ -1054,10 +1087,18 @@ and password information to hosts using the initial host name (unless
|
||||
\fICURLOPT_UNRESTRICTED_AUTH\fP is set), so if libcurl follows locations to
|
||||
other hosts it will not send the user and password to those. This is enforced
|
||||
to prevent accidental information leakage.
|
||||
|
||||
At present only IMAP, POP3 and SMTP support login options as part of the
|
||||
details string. For more information about the login options please see
|
||||
RFC2384, RFC5092 and IETF draft draft-earhart-url-smtp-00.txt (Added in 7.31.0).
|
||||
|
||||
Use \fICURLOPT_HTTPAUTH\fP to specify the authentication method for HTTP based
|
||||
connections.
|
||||
.IP CURLOPT_PROXYUSERPWD
|
||||
Pass a char * as parameter, which should be [user name]:[password] to use for
|
||||
the connection to the HTTP proxy. Use \fICURLOPT_PROXYAUTH\fP to decide
|
||||
the authentication method.
|
||||
the connection to the HTTP proxy.
|
||||
|
||||
Use \fICURLOPT_PROXYAUTH\fP to specify the authentication method.
|
||||
.IP CURLOPT_USERNAME
|
||||
Pass a char * as parameter, which should be pointing to the zero terminated
|
||||
user name to use for the transfer.
|
||||
@@ -1134,7 +1175,7 @@ Microsoft. It uses a challenge-response and hash concept similar to Digest, to
|
||||
prevent the password from being eavesdropped.
|
||||
|
||||
You need to build libcurl with either OpenSSL, GnuTLS or NSS support for this
|
||||
option to work, or build libcurl on Windows.
|
||||
option to work, or build libcurl on Windows with SSPI support.
|
||||
.IP CURLAUTH_NTLM_WB
|
||||
NTLM delegating to winbind helper. Authentication is performed by a separate
|
||||
binary application that is executed when needed. The name of the application
|
||||
@@ -1195,6 +1236,15 @@ actual name and password with the \fICURLOPT_PROXYUSERPWD\fP option. The
|
||||
bitmask can be constructed by or'ing together the bits listed above for the
|
||||
\fICURLOPT_HTTPAUTH\fP option. As of this writing, only Basic, Digest and NTLM
|
||||
work. (Added in 7.10.7)
|
||||
.IP CURLOPT_SASL_IR
|
||||
Pass a long. If the value is 1, curl will send the initial response to the
|
||||
server in the first authentication packet in order to reduce the number of
|
||||
ping pong requests. Only applicable to supporting SASL authentication
|
||||
mechanisms and to the IMAP, POP3 and SMTP protocols. (Added in 7.31.0)
|
||||
|
||||
Note: Whilst IMAP supports this option there is no need to explicitly set it,
|
||||
as libcurl can determine the feature itself when the server supports the
|
||||
SASL-IR CAPABILITY.
|
||||
.SH HTTP OPTIONS
|
||||
.IP CURLOPT_AUTOREFERER
|
||||
Pass a parameter set to 1 to enable this. When enabled, libcurl will
|
||||
@@ -1392,10 +1442,12 @@ internally, your added one will be used instead. If you add a header with no
|
||||
content as in 'Accept:' (no data on the right side of the colon), the
|
||||
internally used header will get disabled. Thus, using this option you can add
|
||||
new headers, replace internal headers and remove internal headers. To add a
|
||||
header with no content, make the content be two quotes: \&"". The headers
|
||||
included in the linked list must not be CRLF-terminated, because curl adds
|
||||
CRLF after each header item. Failure to comply with this will result in
|
||||
strange bugs because the server will most likely ignore part of the headers
|
||||
header with no content (nothing to the right side of the colon), use the
|
||||
form 'MyHeader;' (note the ending semicolon).
|
||||
|
||||
The headers included in the linked list must not be CRLF-terminated, because
|
||||
curl adds CRLF after each header item. Failure to comply with this will result
|
||||
in strange bugs because the server will most likely ignore part of the headers
|
||||
you specified.
|
||||
|
||||
The first line in a request (containing the method, usually a GET or POST) is
|
||||
@@ -2208,6 +2260,12 @@ changed with \fICURLOPT_SSLCERTTYPE\fP.
|
||||
With NSS this can also be the nickname of the certificate you wish to
|
||||
authenticate with. If you want to use a file from the current directory, please
|
||||
precede it with "./" prefix, in order to avoid confusion with a nickname.
|
||||
|
||||
(iOS and Mac OS X only) With Secure Transport, this string must match the name
|
||||
of a certificate that's in the system or user keychain. You should encode this
|
||||
string in UTF-8 format in case it contains non-ASCII characters. The private
|
||||
key corresponding to the certificate, and certificate chain (if any), must
|
||||
also be present in the keychain. (Added in 7.31.0)
|
||||
.IP CURLOPT_SSLCERTTYPE
|
||||
Pass a pointer to a zero terminated string as parameter. The string should be
|
||||
the format of your certificate. Supported formats are "PEM" and "DER". (Added
|
||||
@@ -2216,6 +2274,10 @@ in 7.9.3)
|
||||
Pass a pointer to a zero terminated string as parameter. The string should be
|
||||
the file name of your private key. The default format is "PEM" and can be
|
||||
changed with \fICURLOPT_SSLKEYTYPE\fP.
|
||||
|
||||
(iOS and Mac OS X only) This option is ignored if curl was built against Secure
|
||||
Transport. Secure Transport expects the private key to be already present in
|
||||
the keychain containing the certificate.
|
||||
.IP CURLOPT_SSLKEYTYPE
|
||||
Pass a pointer to a zero terminated string as parameter. The string should be
|
||||
the format of your private key. Supported formats are "PEM", "DER" and "ENG".
|
||||
|
@@ -5,7 +5,7 @@
|
||||
.\" * | (__| |_| | _ <| |___
|
||||
.\" * \___|\___/|_| \_\_____|
|
||||
.\" *
|
||||
.\" * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
.\" * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
.\" *
|
||||
.\" * This software is licensed as described in the file COPYING, which
|
||||
.\" * you should have received as part of this distribution. The terms
|
||||
@@ -42,7 +42,7 @@ After the \fIlastitem\fP pointer follow the real arguments.
|
||||
The pointers \fIfirstitem\fP and \fIlastitem\fP should both be pointing to
|
||||
NULL in the first call to this function. All list-data will be allocated by
|
||||
the function itself. You must call \fIcurl_formfree(3)\fP on the
|
||||
\fIfirstitem\P after the form post has been done to free the resources.
|
||||
\fIfirstitem\fP after the form post has been done to free the resources.
|
||||
|
||||
Using POST with HTTP 1.1 implies the use of a "Expect: 100-continue" header.
|
||||
You can disable this header with \fICURLOPT_HTTPHEADER\fP as usual.
|
||||
|
@@ -74,9 +74,9 @@ The socket \fBcallback\fP function uses a prototype like this
|
||||
int action, /* see values below */
|
||||
void *userp, /* private callback pointer */
|
||||
void *socketp); /* private socket pointer,
|
||||
\fBNULL\fI if not
|
||||
\fBNULL\fP if not
|
||||
previously assigned with
|
||||
\fIcurl_multi_assign(3)\fP */
|
||||
\fBcurl_multi_assign(3)\fP */
|
||||
|
||||
.fi
|
||||
The callback MUST return 0.
|
||||
|
@@ -5,7 +5,7 @@
|
||||
.\" * | (__| |_| | _ <| |___
|
||||
.\" * \___|\___/|_| \_\_____|
|
||||
.\" *
|
||||
.\" * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
.\" * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
.\" *
|
||||
.\" * This software is licensed as described in the file COPYING, which
|
||||
.\" * you should have received as part of this distribution. The terms
|
||||
@@ -36,12 +36,17 @@ CURLMcode curl_multi_wait(CURLM *multi_handle,
|
||||
This function polls on all file descriptors used by the curl easy handles
|
||||
contained in the given multi handle set. It will block until activity is
|
||||
detected on at least one of the handles or \fItimeout_ms\fP has passed.
|
||||
Alternatively, if the multi handle has a pending internal timeout that has a
|
||||
shorter expiry time than \fItimeout_ms\fP, that shorter time will be used
|
||||
instead to make sure timeout accuracy is reasonably kept.
|
||||
|
||||
The calling application may pass additional curl_waitfd structures which are
|
||||
similar to \fIpoll(2)\fP's pollfd structure to be waited on in the same call.
|
||||
|
||||
On completion, if \fInumfds\fP is supplied, it will be populated with the
|
||||
number of file descriptors on which interesting events occured.
|
||||
total number of file descriptors on which interesting events occured. This
|
||||
number can include both libcurl internal descriptors as well as descriptors
|
||||
provided in \fIextra_fds\fP.
|
||||
|
||||
If no extra file descriptors are provided and libcurl has no file descriptor
|
||||
to offer to wait for, this function will return immediately.
|
||||
|
@@ -34,8 +34,10 @@ The share interface was added to enable sharing of data between curl
|
||||
\&"handles".
|
||||
.SH "ONE SET OF DATA - MANY TRANSFERS"
|
||||
You can have multiple easy handles share data between them. Have them update
|
||||
and use the \fBsame\fP cookie database or DNS cache! This way, each single
|
||||
transfer will take advantage from data updates made by the other transfer(s).
|
||||
and use the \fBsame\fP cookie database, DNS cache, TLS session cache! This
|
||||
way, each single transfer will take advantage from data updates made by the
|
||||
other transfer(s). The sharing interface, however, does not share active or
|
||||
persistent connections between different easy handles.
|
||||
.SH "SHARE OBJECT"
|
||||
You create a shared object with \fIcurl_share_init(3)\fP. It returns a handle
|
||||
for a newly created one.
|
||||
|
@@ -5,7 +5,7 @@
|
||||
.\" * | (__| |_| | _ <| |___
|
||||
.\" * \___|\___/|_| \_\_____|
|
||||
.\" *
|
||||
.\" * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
.\" * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
.\" *
|
||||
.\" * This software is licensed as described in the file COPYING, which
|
||||
.\" * you should have received as part of this distribution. The terms
|
||||
@@ -1157,13 +1157,13 @@ and install a CURLOPT_OPENSOCKETFUNCTION callback function in which addresses
|
||||
are sanitized before use.
|
||||
|
||||
.IP "Private Resources"
|
||||
A user who can control the DNS server of a domain being passed in within
|
||||
a URL can change the address of the host to a local, private address
|
||||
which the libcurl application will then use. e.g. The innocuous URL
|
||||
http://fuzzybunnies.example.com/ could actually resolve to the IP address
|
||||
of a server behind a firewall, such as 127.0.0.1 or 10.1.2.3
|
||||
Apps can mitigate against this by setting a CURLOPT_OPENSOCKETFUNCTION
|
||||
and checking the address before a connection.
|
||||
A user who can control the DNS server of a domain being passed in within a URL
|
||||
can change the address of the host to a local, private address which a
|
||||
server-side libcurl-using application could then use. e.g. the innocuous URL
|
||||
http://fuzzybunnies.example.com/ could actually resolve to the IP address of a
|
||||
server behind a firewall, such as 127.0.0.1 or 10.1.2.3. Apps can mitigate
|
||||
against this by setting a CURLOPT_OPENSOCKETFUNCTION and checking the address
|
||||
before a connection.
|
||||
|
||||
All the malicious scenarios regarding redirected URLs apply just as well
|
||||
to non-redirected URLs, if the user is allowed to specify an arbitrary URL
|
||||
@@ -1178,6 +1178,19 @@ IP address and port number for a server local to the app running libcurl
|
||||
but behind a firewall. Apps can mitigate against this by using the
|
||||
CURLOPT_FTP_SKIP_PASV_IP option or CURLOPT_FTPPORT.
|
||||
|
||||
.IP "IPv6 Addresses"
|
||||
libcurl will normally handle IPv6 addresses transparently and just as easily
|
||||
as IPv4 addresses. That means that a sanitizing function that filters out
|
||||
addressses like 127.0.0.1 isn't sufficient--the equivalent IPv6 addresses ::1,
|
||||
::, 0:00::0:1, ::127.0.0.1 and ::ffff:7f00:1 supplied somehow by an attacker
|
||||
would all bypass a naive filter and could allow access to undesired local
|
||||
resources. IPv6 also has special address blocks like link-local and site-local
|
||||
that generally shouldn't be accessed by a server-side libcurl-using
|
||||
application. A poorly-configured firewall installed in a data center,
|
||||
organization or server may also be configured to limit IPv4 connections but
|
||||
leave IPv6 connections wide open. In some cases, the CURL_IPRESOLVE_V4 option
|
||||
can be used to limit resolved addresses to IPv4 only and bypass these issues.
|
||||
|
||||
.IP Uploads
|
||||
When uploading, a redirect can cause a local (or remote) file to be
|
||||
overwritten. Apps must not allow any unsanitized URL to be passed in
|
||||
@@ -1250,7 +1263,7 @@ using the Content-disposition: header to generate a file name. An application
|
||||
could also use CURLINFO_EFFECTIVE_URL to generate a file name from a
|
||||
server-supplied redirect URL. Special care must be taken to sanitize such
|
||||
names to avoid the possibility of a malicious server supplying one like
|
||||
"/etc/passwd", "\autoexec.bat" or even ".bashrc".
|
||||
"/etc/passwd", "\\autoexec.bat", "prn:" or even ".bashrc".
|
||||
|
||||
.IP "Server Certificates"
|
||||
A secure application should never use the CURLOPT_SSL_VERIFYPEER option to
|
||||
@@ -1263,10 +1276,15 @@ validated certificates is potentially as insecure as a plain HTTP connection.
|
||||
On a related issue, be aware that even in situations like when you have
|
||||
problems with libcurl and ask someone for help, everything you reveal in order
|
||||
to get best possible help might also impose certain security related
|
||||
risks. Host names, user names, paths, operating system specifics, etc (not to
|
||||
risks. Host names, user names, paths, operating system specifics, etc. (not to
|
||||
mention passwords of course) may in fact be used by intruders to gain
|
||||
additional information of a potential target.
|
||||
|
||||
Be sure to limit access to application logs if they could hold private or
|
||||
security-related data. Besides the obvious candidates like user names and
|
||||
passwords, things like URLs, cookies or even file names could also hold
|
||||
sensitive data.
|
||||
|
||||
To avoid this problem, you must of course use your common sense. Often, you
|
||||
can just edit out the sensitive data or just search/replace your true
|
||||
information with faked data.
|
||||
@@ -1347,10 +1365,10 @@ automatically share a lot of the data that otherwise would be kept on a
|
||||
per-easy handle basis when the easy interface is used.
|
||||
|
||||
The DNS cache is shared between handles within a multi handle, making
|
||||
subsequent name resolvings faster and the connection pool that is kept to
|
||||
better allow persistent connections and connection re-use is shared. If you're
|
||||
using the easy interface, you can still share these between specific easy
|
||||
handles by using the share interface, see \fIlibcurl-share(3)\fP.
|
||||
subsequent name resolving faster, and the connection pool that is kept to
|
||||
better allow persistent connections and connection re-use is also shared. If
|
||||
you're using the easy interface, you can still share these between specific
|
||||
easy handles by using the share interface, see \fIlibcurl-share(3)\fP.
|
||||
|
||||
Some things are never shared automatically, not within multi handles, like for
|
||||
example cookies so the only way to share that is with the share interface.
|
||||
|
@@ -456,6 +456,7 @@ CURLOPT_RTSP_SERVER_CSEQ 7.20.0
|
||||
CURLOPT_RTSP_SESSION_ID 7.20.0
|
||||
CURLOPT_RTSP_STREAM_URI 7.20.0
|
||||
CURLOPT_RTSP_TRANSPORT 7.20.0
|
||||
CURLOPT_SASL_IR 7.31.0
|
||||
CURLOPT_SEEKDATA 7.18.0
|
||||
CURLOPT_SEEKFUNCTION 7.18.0
|
||||
CURLOPT_SERVER_RESPONSE_TIMEOUT 7.20.0
|
||||
|
@@ -1527,9 +1527,12 @@ typedef enum {
|
||||
/* Enable/disable specific SSL features with a bitmask, see CURLSSLOPT_* */
|
||||
CINIT(SSL_OPTIONS, LONG, 216),
|
||||
|
||||
/* set the SMTP auth originator */
|
||||
/* Set the SMTP auth originator */
|
||||
CINIT(MAIL_AUTH, OBJECTPOINT, 217),
|
||||
|
||||
/* Enable/disable SASL initial response */
|
||||
CINIT(SASL_IR, LONG, 218),
|
||||
|
||||
CURLOPT_LASTENTRY /* the last unused */
|
||||
} CURLoption;
|
||||
|
||||
|
@@ -30,12 +30,12 @@
|
||||
|
||||
/* This is the version number of the libcurl package from which this header
|
||||
file origins: */
|
||||
#define LIBCURL_VERSION "7.30.0-DEV"
|
||||
#define LIBCURL_VERSION "7.31.0-DEV"
|
||||
|
||||
/* The numeric version number is also available "in parts" by using these
|
||||
defines: */
|
||||
#define LIBCURL_VERSION_MAJOR 7
|
||||
#define LIBCURL_VERSION_MINOR 30
|
||||
#define LIBCURL_VERSION_MINOR 31
|
||||
#define LIBCURL_VERSION_PATCH 0
|
||||
|
||||
/* This is the numeric version of the libcurl version number, meant for easier
|
||||
@@ -53,7 +53,7 @@
|
||||
and it is always a greater number in a more recent release. It makes
|
||||
comparisons with greater than and less than work.
|
||||
*/
|
||||
#define LIBCURL_VERSION_NUM 0x071e00
|
||||
#define LIBCURL_VERSION_NUM 0x071f00
|
||||
|
||||
/*
|
||||
* This is the date and time when the full source package was created. The
|
||||
|
@@ -83,7 +83,7 @@ CFLAGS += -dWANT_IDN_PROTOTYPES
|
||||
!ifdef %zlib_root
|
||||
ZLIB_ROOT = $(%zlib_root)
|
||||
!else
|
||||
ZLIB_ROOT = ..$(DS)..$(DS)zlib-1.2.7
|
||||
ZLIB_ROOT = ..$(DS)..$(DS)zlib-1.2.8
|
||||
!endif
|
||||
|
||||
!ifdef %libssh2_root
|
||||
|
@@ -22,7 +22,7 @@ BCCDIR = $(MAKEDIR)\..
|
||||
|
||||
# Edit the path below to point to the base of your Zlib sources.
|
||||
!ifndef ZLIB_PATH
|
||||
ZLIB_PATH = ..\..\zlib-1.2.7
|
||||
ZLIB_PATH = ..\..\zlib-1.2.8
|
||||
!endif
|
||||
|
||||
# Edit the path below to point to the base of your OpenSSL package.
|
||||
|
@@ -7,14 +7,14 @@
|
||||
## Example: mingw32-make -f Makefile.m32 CFG=-zlib-ssl-sspi-winidn
|
||||
##
|
||||
## Hint: you can also set environment vars to control the build, f.e.:
|
||||
## set ZLIB_PATH=c:/zlib-1.2.7
|
||||
## set ZLIB_PATH=c:/zlib-1.2.8
|
||||
## set ZLIB=1
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
# Edit the path below to point to the base of your Zlib sources.
|
||||
ifndef ZLIB_PATH
|
||||
ZLIB_PATH = ../../zlib-1.2.7
|
||||
ZLIB_PATH = ../../zlib-1.2.8
|
||||
endif
|
||||
# Edit the path below to point to the base of your OpenSSL package.
|
||||
ifndef OPENSSL_PATH
|
||||
|
@@ -14,7 +14,7 @@ endif
|
||||
|
||||
# Edit the path below to point to the base of your Zlib sources.
|
||||
ifndef ZLIB_PATH
|
||||
ZLIB_PATH = ../../zlib-1.2.7
|
||||
ZLIB_PATH = ../../zlib-1.2.8
|
||||
endif
|
||||
|
||||
# Edit the path below to point to the base of your OpenSSL package.
|
||||
|
@@ -73,7 +73,7 @@ LIBSSH2_PATH = ../../libssh2-1.4.3
|
||||
!ENDIF
|
||||
|
||||
!IFNDEF ZLIB_PATH
|
||||
ZLIB_PATH = ../../zlib-1.2.7
|
||||
ZLIB_PATH = ../../zlib-1.2.8
|
||||
!ENDIF
|
||||
|
||||
!IFNDEF MACHINE
|
||||
|
@@ -35,8 +35,8 @@ USER_CFLAGS:=
|
||||
# directories where to seek for includes and libraries
|
||||
OPENSSL_INC := D:/libraries/openssl/openssl-0.9.8y-vxWorks6.3/include
|
||||
OPENSSL_LIB := D:/libraries/openssl/openssl-0.9.8y-vxWorks6.3
|
||||
ZLIB_INC := D:/libraries/zlib/zlib-1.2.7-VxWorks6.3/zlib-1.2.7
|
||||
ZLIB_LIB := D:/libraries/zlib/zlib-1.2.7-VxWorks6.3/binaries/vxworks_3.1_gnu/Debug/lib
|
||||
ZLIB_INC := D:/libraries/zlib/zlib-1.2.8-VxWorks6.3/zlib-1.2.8
|
||||
ZLIB_LIB := D:/libraries/zlib/zlib-1.2.8-VxWorks6.3/binaries/vxworks_3.1_gnu/Debug/lib
|
||||
ARES_INC :=
|
||||
ARES_LIB :=
|
||||
|
||||
|
272
lib/axtls.c
272
lib/axtls.c
@@ -41,26 +41,12 @@
|
||||
#define _MPRINTF_REPLACE /* use our functions only */
|
||||
#include <curl/mprintf.h>
|
||||
#include "curl_memory.h"
|
||||
#include <unistd.h>
|
||||
/* The last #include file should be: */
|
||||
#include "memdebug.h"
|
||||
#include "hostcheck.h"
|
||||
|
||||
|
||||
/* SSL_read is opied from axTLS compat layer */
|
||||
static int SSL_read(SSL *ssl, void *buf, int num)
|
||||
{
|
||||
uint8_t *read_buf;
|
||||
int ret;
|
||||
|
||||
while((ret = ssl_read(ssl, &read_buf)) == SSL_OK);
|
||||
|
||||
if(ret > SSL_OK) {
|
||||
memcpy(buf, read_buf, ret > num ? num : ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Global axTLS init, called from Curl_ssl_init() */
|
||||
int Curl_axtls_init(void)
|
||||
{
|
||||
@@ -131,31 +117,40 @@ static CURLcode map_error_to_curl(int axtls_err)
|
||||
static Curl_recv axtls_recv;
|
||||
static Curl_send axtls_send;
|
||||
|
||||
/*
|
||||
* This function is called after the TCP connect has completed. Setup the TLS
|
||||
* layer and do all necessary magic.
|
||||
*/
|
||||
CURLcode
|
||||
Curl_axtls_connect(struct connectdata *conn,
|
||||
int sockindex)
|
||||
static void free_ssl_structs(struct ssl_connect_data *connssl)
|
||||
{
|
||||
if(connssl->ssl) {
|
||||
ssl_free (connssl->ssl);
|
||||
connssl->ssl = NULL;
|
||||
}
|
||||
if(connssl->ssl_ctx) {
|
||||
ssl_ctx_free(connssl->ssl_ctx);
|
||||
connssl->ssl_ctx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For both blocking and non-blocking connects, this function sets up the
|
||||
* ssl context and state. This function is called after the TCP connect
|
||||
* has completed.
|
||||
*/
|
||||
static CURLcode connect_prep(struct connectdata *conn, int sockindex)
|
||||
{
|
||||
struct SessionHandle *data = conn->data;
|
||||
SSL_CTX *ssl_ctx;
|
||||
SSL *ssl;
|
||||
SSL *ssl = NULL;
|
||||
int cert_types[] = {SSL_OBJ_X509_CERT, SSL_OBJ_PKCS12, 0};
|
||||
int key_types[] = {SSL_OBJ_RSA_KEY, SSL_OBJ_PKCS8, SSL_OBJ_PKCS12, 0};
|
||||
int i, ssl_fcn_return;
|
||||
const uint8_t *ssl_sessionid;
|
||||
size_t ssl_idsize;
|
||||
const char *peer_CN;
|
||||
uint32_t dns_altname_index;
|
||||
const char *dns_altname;
|
||||
int8_t found_subject_alt_names = 0;
|
||||
int8_t found_subject_alt_name_matching_conn = 0;
|
||||
|
||||
/* Assuming users will not compile in custom key/cert to axTLS */
|
||||
uint32_t client_option = SSL_NO_DEFAULT_KEY|SSL_SERVER_VERIFY_LATER;
|
||||
/* Assuming users will not compile in custom key/cert to axTLS.
|
||||
* Also, even for blocking connects, use axTLS non-blocking feature.
|
||||
*/
|
||||
uint32_t client_option = SSL_NO_DEFAULT_KEY |
|
||||
SSL_SERVER_VERIFY_LATER |
|
||||
SSL_CONNECT_IN_PARTS;
|
||||
|
||||
if(conn->ssl[sockindex].state == ssl_connection_complete)
|
||||
/* to make us tolerant against being called more than once for the
|
||||
@@ -184,6 +179,9 @@ Curl_axtls_connect(struct connectdata *conn,
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
|
||||
conn->ssl[sockindex].ssl_ctx = ssl_ctx;
|
||||
conn->ssl[sockindex].ssl = NULL;
|
||||
|
||||
/* Load the trusted CA cert bundle file */
|
||||
if(data->set.ssl.CAfile) {
|
||||
if(ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CACERT, data->set.ssl.CAfile, NULL)
|
||||
@@ -191,7 +189,6 @@ Curl_axtls_connect(struct connectdata *conn,
|
||||
infof(data, "error reading ca cert file %s \n",
|
||||
data->set.ssl.CAfile);
|
||||
if(data->set.ssl.verifypeer) {
|
||||
Curl_axtls_close(conn, sockindex);
|
||||
return CURLE_SSL_CACERT_BADFILE;
|
||||
}
|
||||
}
|
||||
@@ -225,7 +222,6 @@ Curl_axtls_connect(struct connectdata *conn,
|
||||
if(cert_types[i] == 0) {
|
||||
failf(data, "%s is not x509 or pkcs12 format",
|
||||
data->set.str[STRING_CERT]);
|
||||
Curl_axtls_close(conn, sockindex);
|
||||
return CURLE_SSL_CERTPROBLEM;
|
||||
}
|
||||
}
|
||||
@@ -250,7 +246,6 @@ Curl_axtls_connect(struct connectdata *conn,
|
||||
if(key_types[i] == 0) {
|
||||
failf(data, "Failure: %s is not a supported key file",
|
||||
data->set.str[STRING_KEY]);
|
||||
Curl_axtls_close(conn, sockindex);
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
}
|
||||
@@ -271,14 +266,25 @@ Curl_axtls_connect(struct connectdata *conn,
|
||||
else
|
||||
ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], NULL, 0);
|
||||
|
||||
/* Check to make sure handshake was ok. */
|
||||
ssl_fcn_return = ssl_handshake_status(ssl);
|
||||
if(ssl_fcn_return != SSL_OK) {
|
||||
Curl_axtls_close(conn, sockindex);
|
||||
ssl_display_error(ssl_fcn_return); /* goes to stdout. */
|
||||
return map_error_to_curl(ssl_fcn_return);
|
||||
}
|
||||
infof (data, "handshake completed successfully\n");
|
||||
conn->ssl[sockindex].ssl = ssl;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* For both blocking and non-blocking connects, this function finalizes the
|
||||
* SSL connection.
|
||||
*/
|
||||
static CURLcode connect_finish(struct connectdata *conn, int sockindex)
|
||||
{
|
||||
struct SessionHandle *data = conn->data;
|
||||
SSL *ssl = conn->ssl[sockindex].ssl;
|
||||
const uint8_t *ssl_sessionid;
|
||||
size_t ssl_idsize;
|
||||
const char *peer_CN;
|
||||
uint32_t dns_altname_index;
|
||||
const char *dns_altname;
|
||||
int8_t found_subject_alt_names = 0;
|
||||
int8_t found_subject_alt_name_matching_conn = 0;
|
||||
|
||||
/* Here, gtls.c gets the peer certificates and fails out depending on
|
||||
* settings in "data." axTLS api doesn't have get cert chain fcn, so omit?
|
||||
@@ -289,7 +295,7 @@ Curl_axtls_connect(struct connectdata *conn,
|
||||
if(ssl_verify_cert(ssl) != SSL_OK) {
|
||||
Curl_axtls_close(conn, sockindex);
|
||||
failf(data, "server cert verify failed");
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
return CURLE_PEER_FAILED_VERIFICATION;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -306,7 +312,6 @@ Curl_axtls_connect(struct connectdata *conn,
|
||||
* this, but a couple fields are available.
|
||||
*/
|
||||
|
||||
|
||||
/* There is no (DNS) Altnames count in the version 1.4.8 API. There is a
|
||||
risk of an inifite loop */
|
||||
for(dns_altname_index = 0; ; dns_altname_index++) {
|
||||
@@ -326,20 +331,29 @@ Curl_axtls_connect(struct connectdata *conn,
|
||||
|
||||
/* RFC2818 checks */
|
||||
if(found_subject_alt_names && !found_subject_alt_name_matching_conn) {
|
||||
/* Break connection ! */
|
||||
Curl_axtls_close(conn, sockindex);
|
||||
failf(data, "\tsubjectAltName(s) do not match %s\n", conn->host.dispname);
|
||||
return CURLE_PEER_FAILED_VERIFICATION;
|
||||
if(data->set.ssl.verifyhost) {
|
||||
/* Break connection ! */
|
||||
Curl_axtls_close(conn, sockindex);
|
||||
failf(data, "\tsubjectAltName(s) do not match %s\n",
|
||||
conn->host.dispname);
|
||||
return CURLE_PEER_FAILED_VERIFICATION;
|
||||
}
|
||||
else
|
||||
infof(data, "\tsubjectAltName(s) do not match %s\n",
|
||||
conn->host.dispname);
|
||||
}
|
||||
else if(found_subject_alt_names == 0) {
|
||||
/* Per RFC2818, when no Subject Alt Names were available, examine the peer
|
||||
CN as a legacy fallback */
|
||||
peer_CN = ssl_get_cert_dn(ssl, SSL_X509_CERT_COMMON_NAME);
|
||||
if(peer_CN == NULL) {
|
||||
/* Similar behaviour to the OpenSSL interface */
|
||||
Curl_axtls_close(conn, sockindex);
|
||||
failf(data, "unable to obtain common name from peer certificate");
|
||||
return CURLE_PEER_FAILED_VERIFICATION;
|
||||
if(data->set.ssl.verifyhost) {
|
||||
Curl_axtls_close(conn, sockindex);
|
||||
failf(data, "unable to obtain common name from peer certificate");
|
||||
return CURLE_PEER_FAILED_VERIFICATION;
|
||||
}
|
||||
else
|
||||
infof(data, "unable to obtain common name from peer certificate");
|
||||
}
|
||||
else {
|
||||
if(!Curl_cert_hostcheck((const char *)peer_CN, conn->host.name)) {
|
||||
@@ -359,8 +373,6 @@ Curl_axtls_connect(struct connectdata *conn,
|
||||
|
||||
/* General housekeeping */
|
||||
conn->ssl[sockindex].state = ssl_connection_complete;
|
||||
conn->ssl[sockindex].ssl = ssl;
|
||||
conn->ssl[sockindex].ssl_ctx = ssl_ctx;
|
||||
conn->recv[sockindex] = axtls_recv;
|
||||
conn->send[sockindex] = axtls_send;
|
||||
|
||||
@@ -374,6 +386,107 @@ Curl_axtls_connect(struct connectdata *conn,
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use axTLS's non-blocking connection feature to open an SSL connection.
|
||||
* This is called after a TCP connection is already established.
|
||||
*/
|
||||
CURLcode Curl_axtls_connect_nonblocking(
|
||||
struct connectdata *conn,
|
||||
int sockindex,
|
||||
bool *done)
|
||||
{
|
||||
CURLcode conn_step;
|
||||
int ssl_fcn_return;
|
||||
|
||||
*done = FALSE;
|
||||
/* connectdata is calloc'd and connecting_state is only changed in this
|
||||
function, so this is safe, as the state is effectively initialized. */
|
||||
if(conn->ssl[sockindex].connecting_state == ssl_connect_1) {
|
||||
conn_step = connect_prep(conn, sockindex);
|
||||
if(conn_step != CURLE_OK) {
|
||||
Curl_axtls_close(conn, sockindex);
|
||||
return conn_step;
|
||||
}
|
||||
conn->ssl[sockindex].connecting_state = ssl_connect_2;
|
||||
}
|
||||
|
||||
if(conn->ssl[sockindex].connecting_state == ssl_connect_2) {
|
||||
/* Check to make sure handshake was ok. */
|
||||
if(ssl_handshake_status(conn->ssl[sockindex].ssl) != SSL_OK) {
|
||||
ssl_fcn_return = ssl_read(conn->ssl[sockindex].ssl, NULL);
|
||||
if(ssl_fcn_return < 0) {
|
||||
Curl_axtls_close(conn, sockindex);
|
||||
ssl_display_error(ssl_fcn_return); /* goes to stdout. */
|
||||
return map_error_to_curl(ssl_fcn_return);
|
||||
}
|
||||
else {
|
||||
return CURLE_OK; /* Return control to caller for retries */
|
||||
}
|
||||
}
|
||||
infof (conn->data, "handshake completed successfully\n");
|
||||
conn->ssl[sockindex].connecting_state = ssl_connect_3;
|
||||
}
|
||||
|
||||
if(conn->ssl[sockindex].connecting_state == ssl_connect_3) {
|
||||
conn_step = connect_finish(conn, sockindex);
|
||||
if(conn_step != CURLE_OK) {
|
||||
Curl_axtls_close(conn, sockindex);
|
||||
return conn_step;
|
||||
}
|
||||
|
||||
/* Reset connect state */
|
||||
conn->ssl[sockindex].connecting_state = ssl_connect_1;
|
||||
|
||||
*done = TRUE;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/* Unrecognized state. Things are very bad. */
|
||||
conn->ssl[sockindex].state = ssl_connection_none;
|
||||
conn->ssl[sockindex].connecting_state = ssl_connect_1;
|
||||
/* Return value perhaps not strictly correct, but distinguishes the issue.*/
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is called after the TCP connect has completed. Setup the TLS
|
||||
* layer and do all necessary magic for a blocking connect.
|
||||
*/
|
||||
CURLcode
|
||||
Curl_axtls_connect(struct connectdata *conn,
|
||||
int sockindex)
|
||||
|
||||
{
|
||||
CURLcode conn_step = connect_prep(conn, sockindex);
|
||||
int ssl_fcn_return;
|
||||
SSL *ssl = conn->ssl[sockindex].ssl;
|
||||
|
||||
if(conn_step != CURLE_OK) {
|
||||
Curl_axtls_close(conn, sockindex);
|
||||
return conn_step;
|
||||
}
|
||||
|
||||
/* Check to make sure handshake was ok. */
|
||||
while(ssl_handshake_status(ssl) != SSL_OK) {
|
||||
ssl_fcn_return = ssl_read(ssl, NULL);
|
||||
if(ssl_fcn_return < 0) {
|
||||
Curl_axtls_close(conn, sockindex);
|
||||
ssl_display_error(ssl_fcn_return); /* goes to stdout. */
|
||||
return map_error_to_curl(ssl_fcn_return);
|
||||
}
|
||||
usleep(10000);
|
||||
}
|
||||
infof (conn->data, "handshake completed successfully\n");
|
||||
|
||||
conn_step = connect_finish(conn, sockindex);
|
||||
if(conn_step != CURLE_OK) {
|
||||
Curl_axtls_close(conn, sockindex);
|
||||
return conn_step;
|
||||
}
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/* return number of sent (non-SSL) bytes */
|
||||
static ssize_t axtls_send(struct connectdata *conn,
|
||||
@@ -407,7 +520,7 @@ void Curl_axtls_close(struct connectdata *conn, int sockindex)
|
||||
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
|
||||
|
||||
infof(conn->data, " Curl_axtls_close\n");
|
||||
if(connssl->ssl) {
|
||||
|
||||
/* line from ssluse.c: (void)SSL_shutdown(connssl->ssl);
|
||||
axTLS compat layer does nothing for SSL_shutdown */
|
||||
|
||||
@@ -415,13 +528,7 @@ void Curl_axtls_close(struct connectdata *conn, int sockindex)
|
||||
equivalent. ssl_free and ssl_ctx_free close things.
|
||||
SSL_set_connect_state(connssl->handle); */
|
||||
|
||||
ssl_free (connssl->ssl);
|
||||
connssl->ssl = NULL;
|
||||
}
|
||||
if(connssl->ssl_ctx) {
|
||||
ssl_ctx_free (connssl->ssl_ctx);
|
||||
connssl->ssl_ctx = NULL;
|
||||
}
|
||||
free_ssl_structs(connssl);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -436,8 +543,7 @@ int Curl_axtls_shutdown(struct connectdata *conn, int sockindex)
|
||||
int retval = 0;
|
||||
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
|
||||
struct SessionHandle *data = conn->data;
|
||||
char buf[120]; /* We will use this for the OpenSSL error buffer, so it has
|
||||
to be at least 120 bytes long. */
|
||||
uint8_t *buf;
|
||||
ssize_t nread;
|
||||
|
||||
infof(conn->data, " Curl_axtls_shutdown\n");
|
||||
@@ -457,9 +563,10 @@ int Curl_axtls_shutdown(struct connectdata *conn, int sockindex)
|
||||
CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
|
||||
if(what > 0) {
|
||||
/* Something to read, let's do it and hope that it is the close
|
||||
notify alert from the server */
|
||||
nread = (ssize_t)SSL_read(conn->ssl[sockindex].ssl, buf,
|
||||
sizeof(buf));
|
||||
notify alert from the server. buf is managed internally by
|
||||
axTLS and will be released upon calling ssl_free via
|
||||
free_ssl_structs. */
|
||||
nread = (ssize_t)ssl_read(connssl->ssl, &buf);
|
||||
|
||||
if(nread < SSL_OK) {
|
||||
failf(data, "close notify alert not received during shutdown");
|
||||
@@ -476,8 +583,7 @@ int Curl_axtls_shutdown(struct connectdata *conn, int sockindex)
|
||||
retval = -1;
|
||||
}
|
||||
|
||||
ssl_free (connssl->ssl);
|
||||
connssl->ssl = NULL;
|
||||
free_ssl_structs(connssl);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
@@ -490,26 +596,36 @@ static ssize_t axtls_recv(struct connectdata *conn, /* connection data */
|
||||
{
|
||||
struct ssl_connect_data *connssl = &conn->ssl[num];
|
||||
ssize_t ret = 0;
|
||||
uint8_t *read_buf;
|
||||
|
||||
infof(conn->data, " axtls_recv\n");
|
||||
|
||||
*err = CURLE_OK;
|
||||
if(connssl) {
|
||||
ret = (ssize_t)SSL_read(conn->ssl[num].ssl, buf, (int)buffersize);
|
||||
|
||||
/* axTLS isn't terribly generous about error reporting */
|
||||
/* With patched axTLS, SSL_CLOSE_NOTIFY=-3. Hard-coding until axTLS
|
||||
team approves proposed fix. */
|
||||
if(ret == -3 ) {
|
||||
ret = ssl_read(connssl->ssl, &read_buf);
|
||||
if(ret > SSL_OK) {
|
||||
/* ssl_read returns SSL_OK if there is more data to read, so if it is
|
||||
larger, then all data has been read already. */
|
||||
memcpy(buf, read_buf,
|
||||
(size_t)ret > buffersize ? buffersize : (size_t)ret);
|
||||
}
|
||||
else if(ret == SSL_OK) {
|
||||
/* more data to be read, signal caller to call again */
|
||||
*err = CURLE_AGAIN;
|
||||
ret = -1;
|
||||
}
|
||||
else if(ret == -3) {
|
||||
/* With patched axTLS, SSL_CLOSE_NOTIFY=-3. Hard-coding until axTLS
|
||||
team approves proposed fix. */
|
||||
Curl_axtls_close(conn, num);
|
||||
}
|
||||
else if(ret < 0) {
|
||||
failf(conn->data, "axTLS recv error (%d)", (int)ret);
|
||||
else {
|
||||
failf(conn->data, "axTLS recv error (%d)", ret);
|
||||
*err = map_error_to_curl(ret);
|
||||
return -1;
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
*err = CURLE_OK;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@@ -30,6 +30,10 @@
|
||||
int Curl_axtls_init(void);
|
||||
int Curl_axtls_cleanup(void);
|
||||
CURLcode Curl_axtls_connect(struct connectdata *conn, int sockindex);
|
||||
CURLcode Curl_axtls_connect_nonblocking(
|
||||
struct connectdata *conn,
|
||||
int sockindex,
|
||||
bool *done);
|
||||
|
||||
/* tell axTLS to close down all open information regarding connections (and
|
||||
thus session ID caching etc) */
|
||||
@@ -47,6 +51,7 @@ int Curl_axtls_check_cxn(struct connectdata *conn);
|
||||
#define curlssl_init Curl_axtls_init
|
||||
#define curlssl_cleanup Curl_axtls_cleanup
|
||||
#define curlssl_connect Curl_axtls_connect
|
||||
#define curlssl_connect_nonblocking Curl_axtls_connect_nonblocking
|
||||
#define curlssl_session_free(x) Curl_axtls_session_free(x)
|
||||
#define curlssl_close_all Curl_axtls_close_all
|
||||
#define curlssl_close Curl_axtls_close
|
||||
|
@@ -38,8 +38,6 @@
|
||||
/* The last #include file should be: */
|
||||
#include "memdebug.h"
|
||||
|
||||
#define CONNECTION_HASH_SIZE 97
|
||||
|
||||
static void free_bundle_hash_entry(void *freethis)
|
||||
{
|
||||
struct connectbundle *b = (struct connectbundle *) freethis;
|
||||
@@ -47,7 +45,7 @@ static void free_bundle_hash_entry(void *freethis)
|
||||
Curl_bundle_destroy(b);
|
||||
}
|
||||
|
||||
struct conncache *Curl_conncache_init(void)
|
||||
struct conncache *Curl_conncache_init(int size)
|
||||
{
|
||||
struct conncache *connc;
|
||||
|
||||
@@ -55,7 +53,7 @@ struct conncache *Curl_conncache_init(void)
|
||||
if(!connc)
|
||||
return NULL;
|
||||
|
||||
connc->hash = Curl_hash_alloc(CONNECTION_HASH_SIZE, Curl_hash_str,
|
||||
connc->hash = Curl_hash_alloc(size, Curl_hash_str,
|
||||
Curl_str_key_compare, free_bundle_hash_entry);
|
||||
|
||||
if(!connc->hash) {
|
||||
|
@@ -27,7 +27,7 @@ struct conncache {
|
||||
size_t num_connections;
|
||||
};
|
||||
|
||||
struct conncache *Curl_conncache_init(void);
|
||||
struct conncache *Curl_conncache_init(int size);
|
||||
|
||||
void Curl_conncache_destroy(struct conncache *connc);
|
||||
|
||||
|
@@ -413,23 +413,22 @@ static CURLcode bindlocal(struct connectdata *conn,
|
||||
if(af == AF_INET6) {
|
||||
#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
|
||||
char *scope_ptr = strchr(myhost, '%');
|
||||
|
||||
if(scope_ptr) *(scope_ptr++) = 0;
|
||||
if(scope_ptr)
|
||||
*(scope_ptr++) = 0;
|
||||
#endif
|
||||
if(Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0) {
|
||||
si6->sin6_family = AF_INET6;
|
||||
si6->sin6_port = htons(port);
|
||||
#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
|
||||
if(scope_ptr) {
|
||||
/* The "myhost" string either comes from Curl_if2ip or
|
||||
from Curl_printable_address. The latter returns only
|
||||
numeric scope IDs and the former returns none at all.
|
||||
So the scope ID, if present, is known to be numeric */
|
||||
if(scope_ptr)
|
||||
/* The "myhost" string either comes from Curl_if2ip or from
|
||||
Curl_printable_address. The latter returns only numeric scope
|
||||
IDs and the former returns none at all. So the scope ID, if
|
||||
present, is known to be numeric */
|
||||
si6->sin6_scope_id = atoi(scope_ptr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
sizeof_sa = sizeof(struct sockaddr_in6);
|
||||
}
|
||||
sizeof_sa = sizeof(struct sockaddr_in6);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@@ -1240,7 +1239,7 @@ curl_socket_t Curl_getconnectinfo(struct SessionHandle *data,
|
||||
* 'conn' can be NULL, beware!
|
||||
*/
|
||||
int Curl_closesocket(struct connectdata *conn,
|
||||
curl_socket_t sock)
|
||||
curl_socket_t sock)
|
||||
{
|
||||
if(conn && conn->fclosesocket) {
|
||||
if((sock == conn->sock[SECONDARYSOCKET]) &&
|
||||
@@ -1252,7 +1251,13 @@ int Curl_closesocket(struct connectdata *conn,
|
||||
else
|
||||
return conn->fclosesocket(conn->closesocket_client, sock);
|
||||
}
|
||||
return sclose(sock);
|
||||
sclose(sock);
|
||||
|
||||
if(conn)
|
||||
/* tell the multi-socket code about this */
|
||||
Curl_multi_closed(conn, sock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
229
lib/cookie.c
229
lib/cookie.c
@@ -106,6 +106,8 @@ static void freecookie(struct Cookie *co)
|
||||
free(co->domain);
|
||||
if(co->path)
|
||||
free(co->path);
|
||||
if(co->spath)
|
||||
free(co->spath);
|
||||
if(co->name)
|
||||
free(co->name);
|
||||
if(co->value)
|
||||
@@ -143,6 +145,116 @@ static bool tailmatch(const char *cooke_domain, const char *hostname)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* matching cookie path and url path
|
||||
* RFC6265 5.1.4 Paths and Path-Match
|
||||
*/
|
||||
static bool pathmatch(const char* cookie_path, const char* request_uri)
|
||||
{
|
||||
size_t cookie_path_len;
|
||||
size_t uri_path_len;
|
||||
char* uri_path = NULL;
|
||||
char* pos;
|
||||
bool ret = FALSE;
|
||||
|
||||
/* cookie_path must not have last '/' separator. ex: /sample */
|
||||
cookie_path_len = strlen(cookie_path);
|
||||
if(1 == cookie_path_len) {
|
||||
/* cookie_path must be '/' */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
uri_path = strdup(request_uri);
|
||||
if(!uri_path)
|
||||
return FALSE;
|
||||
pos = strchr(uri_path, '?');
|
||||
if(pos)
|
||||
*pos = 0x0;
|
||||
|
||||
/* #-fragments are already cut off! */
|
||||
if(0 == strlen(uri_path) || uri_path[0] != '/') {
|
||||
free(uri_path);
|
||||
uri_path = strdup("/");
|
||||
if(!uri_path)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* here, RFC6265 5.1.4 says
|
||||
4. Output the characters of the uri-path from the first character up
|
||||
to, but not including, the right-most %x2F ("/").
|
||||
but URL path /hoge?fuga=xxx means /hoge/index.cgi?fuga=xxx in some site
|
||||
without redirect.
|
||||
Ignore this algorithm because /hoge is uri path for this case
|
||||
(uri path is not /).
|
||||
*/
|
||||
|
||||
uri_path_len = strlen(uri_path);
|
||||
|
||||
if(uri_path_len < cookie_path_len) {
|
||||
ret = FALSE;
|
||||
goto pathmatched;
|
||||
}
|
||||
|
||||
/* not using checkprefix() because matching should be case-sensitive */
|
||||
if(strncmp(cookie_path, uri_path, cookie_path_len)) {
|
||||
ret = FALSE;
|
||||
goto pathmatched;
|
||||
}
|
||||
|
||||
/* The cookie-path and the uri-path are identical. */
|
||||
if(cookie_path_len == uri_path_len) {
|
||||
ret = TRUE;
|
||||
goto pathmatched;
|
||||
}
|
||||
|
||||
/* here, cookie_path_len < url_path_len */
|
||||
if(uri_path[cookie_path_len] == '/') {
|
||||
ret = TRUE;
|
||||
goto pathmatched;
|
||||
}
|
||||
|
||||
ret = FALSE;
|
||||
|
||||
pathmatched:
|
||||
free(uri_path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* cookie path sanitize
|
||||
*/
|
||||
static char *sanitize_cookie_path(const char *cookie_path)
|
||||
{
|
||||
size_t len;
|
||||
char *new_path = strdup(cookie_path);
|
||||
if(!new_path)
|
||||
return NULL;
|
||||
|
||||
/* some stupid site sends path attribute with '"'. */
|
||||
if(new_path[0] == '\"') {
|
||||
memmove((void *)new_path, (const void *)(new_path + 1), strlen(new_path));
|
||||
}
|
||||
if(new_path[strlen(new_path) - 1] == '\"') {
|
||||
new_path[strlen(new_path) - 1] = 0x0;
|
||||
}
|
||||
|
||||
/* RFC6265 5.2.4 The Path Attribute */
|
||||
if(new_path[0] != '/') {
|
||||
/* Let cookie-path be the default-path. */
|
||||
free(new_path);
|
||||
new_path = strdup("/");
|
||||
return new_path;
|
||||
}
|
||||
|
||||
/* convert /hoge/ to /hoge */
|
||||
len = strlen(new_path);
|
||||
if(1 < len && new_path[len - 1] == '/') {
|
||||
new_path[len - 1] = 0x0;
|
||||
}
|
||||
|
||||
return new_path;
|
||||
}
|
||||
|
||||
/*
|
||||
* Load cookies from all given cookie files (CURLOPT_COOKIEFILE).
|
||||
*/
|
||||
@@ -184,6 +296,9 @@ static void strstore(char **str, const char *newstr)
|
||||
*
|
||||
* Add a single cookie line to the cookie keeping object.
|
||||
*
|
||||
* Be aware that sometimes we get an IP-only host name, and that might also be
|
||||
* a numerical IPv6 address.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
struct Cookie *
|
||||
@@ -288,72 +403,39 @@ Curl_cookie_add(struct SessionHandle *data,
|
||||
badcookie = TRUE; /* out of memory bad */
|
||||
break;
|
||||
}
|
||||
co->spath = sanitize_cookie_path(co->path);
|
||||
if(!co->spath) {
|
||||
badcookie = TRUE; /* out of memory bad */
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(Curl_raw_equal("domain", name)) {
|
||||
/* note that this name may or may not have a preceding dot, but
|
||||
we don't care about that, we treat the names the same anyway */
|
||||
|
||||
const char *domptr=whatptr;
|
||||
const char *nextptr;
|
||||
int dotcount=1;
|
||||
|
||||
/* Count the dots, we need to make sure that there are enough
|
||||
of them. */
|
||||
/* Now, we make sure that our host is within the given domain,
|
||||
or the given domain is not valid and thus cannot be set. */
|
||||
|
||||
if('.' == whatptr[0])
|
||||
/* don't count the initial dot, assume it */
|
||||
domptr++;
|
||||
whatptr++; /* ignore preceding dot */
|
||||
|
||||
do {
|
||||
nextptr = strchr(domptr, '.');
|
||||
if(nextptr) {
|
||||
if(domptr != nextptr)
|
||||
dotcount++;
|
||||
domptr = nextptr+1;
|
||||
if(!domain || tailmatch(whatptr, domain)) {
|
||||
const char *tailptr=whatptr;
|
||||
if(tailptr[0] == '.')
|
||||
tailptr++;
|
||||
strstore(&co->domain, tailptr); /* don't prefix w/dots
|
||||
internally */
|
||||
if(!co->domain) {
|
||||
badcookie = TRUE;
|
||||
break;
|
||||
}
|
||||
} while(nextptr);
|
||||
|
||||
/* The original Netscape cookie spec defined that this domain name
|
||||
MUST have three dots (or two if one of the seven holy TLDs),
|
||||
but it seems that these kinds of cookies are in use "out there"
|
||||
so we cannot be that strict. I've therefore lowered the check
|
||||
to not allow less than two dots. */
|
||||
|
||||
if(dotcount < 2) {
|
||||
/* Received and skipped a cookie with a domain using too few
|
||||
dots. */
|
||||
badcookie=TRUE; /* mark this as a bad cookie */
|
||||
infof(data, "skipped cookie with illegal dotcount domain: %s\n",
|
||||
whatptr);
|
||||
co->tailmatch=TRUE; /* we always do that if the domain name was
|
||||
given */
|
||||
}
|
||||
else {
|
||||
/* Now, we make sure that our host is within the given domain,
|
||||
or the given domain is not valid and thus cannot be set. */
|
||||
|
||||
if('.' == whatptr[0])
|
||||
whatptr++; /* ignore preceding dot */
|
||||
|
||||
if(!domain || tailmatch(whatptr, domain)) {
|
||||
const char *tailptr=whatptr;
|
||||
if(tailptr[0] == '.')
|
||||
tailptr++;
|
||||
strstore(&co->domain, tailptr); /* don't prefix w/dots
|
||||
internally */
|
||||
if(!co->domain) {
|
||||
badcookie = TRUE;
|
||||
break;
|
||||
}
|
||||
co->tailmatch=TRUE; /* we always do that if the domain name was
|
||||
given */
|
||||
}
|
||||
else {
|
||||
/* we did not get a tailmatch and then the attempted set domain
|
||||
is not a domain to which the current host belongs. Mark as
|
||||
bad. */
|
||||
badcookie=TRUE;
|
||||
infof(data, "skipped cookie with bad tailmatch domain: %s\n",
|
||||
whatptr);
|
||||
}
|
||||
/* we did not get a tailmatch and then the attempted set domain
|
||||
is not a domain to which the current host belongs. Mark as
|
||||
bad. */
|
||||
badcookie=TRUE;
|
||||
infof(data, "skipped cookie with bad tailmatch domain: %s\n",
|
||||
whatptr);
|
||||
}
|
||||
}
|
||||
else if(Curl_raw_equal("version", name)) {
|
||||
@@ -461,6 +543,9 @@ Curl_cookie_add(struct SessionHandle *data,
|
||||
if(co->path) {
|
||||
memcpy(co->path, path, pathlen);
|
||||
co->path[pathlen]=0; /* zero terminate */
|
||||
co->spath = sanitize_cookie_path(co->path);
|
||||
if(!co->spath)
|
||||
badcookie = TRUE; /* out of memory bad */
|
||||
}
|
||||
else
|
||||
badcookie = TRUE;
|
||||
@@ -512,12 +597,6 @@ Curl_cookie_add(struct SessionHandle *data,
|
||||
|
||||
firstptr=strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */
|
||||
|
||||
/* Here's a quick check to eliminate normal HTTP-headers from this */
|
||||
if(!firstptr || strchr(firstptr, ':')) {
|
||||
free(co);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Now loop through the fields and init the struct we already have
|
||||
allocated */
|
||||
for(ptr=firstptr, fields=0; ptr && !badcookie;
|
||||
@@ -552,12 +631,21 @@ Curl_cookie_add(struct SessionHandle *data,
|
||||
co->path = strdup(ptr);
|
||||
if(!co->path)
|
||||
badcookie = TRUE;
|
||||
else {
|
||||
co->spath = sanitize_cookie_path(co->path);
|
||||
if(!co->spath) {
|
||||
badcookie = TRUE; /* out of memory bad */
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* this doesn't look like a path, make one up! */
|
||||
co->path = strdup("/");
|
||||
if(!co->path)
|
||||
badcookie = TRUE;
|
||||
co->spath = strdup("/");
|
||||
if(!co->spath)
|
||||
badcookie = TRUE;
|
||||
fields++; /* add a field and fall down to secure */
|
||||
/* FALLTHROUGH */
|
||||
case 3:
|
||||
@@ -628,14 +716,14 @@ Curl_cookie_add(struct SessionHandle *data,
|
||||
if(replace_old) {
|
||||
/* the domains were identical */
|
||||
|
||||
if(clist->path && co->path) {
|
||||
if(Curl_raw_equal(clist->path, co->path)) {
|
||||
if(clist->spath && co->spath) {
|
||||
if(Curl_raw_equal(clist->spath, co->spath)) {
|
||||
replace_old = TRUE;
|
||||
}
|
||||
else
|
||||
replace_old = FALSE;
|
||||
}
|
||||
else if(!clist->path && !co->path)
|
||||
else if(!clist->spath && !co->spath)
|
||||
replace_old = TRUE;
|
||||
else
|
||||
replace_old = FALSE;
|
||||
@@ -664,6 +752,8 @@ Curl_cookie_add(struct SessionHandle *data,
|
||||
free(clist->domain);
|
||||
if(clist->path)
|
||||
free(clist->path);
|
||||
if(clist->spath)
|
||||
free(clist->spath);
|
||||
if(clist->expirestr)
|
||||
free(clist->expirestr);
|
||||
|
||||
@@ -858,10 +948,7 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
|
||||
|
||||
/* now check the left part of the path with the cookies path
|
||||
requirement */
|
||||
if(!co->path ||
|
||||
/* not using checkprefix() because matching should be
|
||||
case-sensitive */
|
||||
!strncmp(co->path, path, strlen(co->path)) ) {
|
||||
if(!co->spath || pathmatch(co->spath, path) ) {
|
||||
|
||||
/* and now, we know this is a match and we should create an
|
||||
entry for the return-linked-list */
|
||||
|
@@ -29,7 +29,8 @@ struct Cookie {
|
||||
struct Cookie *next; /* next in the chain */
|
||||
char *name; /* <this> = value */
|
||||
char *value; /* name = <this> */
|
||||
char *path; /* path = <this> */
|
||||
char *path; /* path = <this> which is in Set-Cookie: */
|
||||
char *spath; /* sanitized cookie path */
|
||||
char *domain; /* domain = <this> */
|
||||
curl_off_t expires; /* expires = <this> */
|
||||
char *expirestr; /* the plain text version */
|
||||
|
@@ -691,6 +691,101 @@ CF_INLINE CFStringRef CopyCertSubject(SecCertificateRef cert)
|
||||
return server_cert_summary;
|
||||
}
|
||||
|
||||
#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
|
||||
static OSStatus CopyIdentityWithLabelOldSchool(char *label,
|
||||
SecIdentityRef *out_c_a_k)
|
||||
{
|
||||
OSStatus status = errSecItemNotFound;
|
||||
/* The SecKeychainSearch API was deprecated in Lion, and using it will raise
|
||||
deprecation warnings, so let's not compile this unless it's necessary: */
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
|
||||
SecKeychainAttributeList attr_list;
|
||||
SecKeychainAttribute attr;
|
||||
SecKeychainSearchRef search = NULL;
|
||||
SecCertificateRef cert = NULL;
|
||||
|
||||
/* Set up the attribute list: */
|
||||
attr_list.count = 1L;
|
||||
attr_list.attr = &attr;
|
||||
|
||||
/* Set up our lone search criterion: */
|
||||
attr.tag = kSecLabelItemAttr;
|
||||
attr.data = label;
|
||||
attr.length = (UInt32)strlen(label);
|
||||
|
||||
/* Start searching: */
|
||||
status = SecKeychainSearchCreateFromAttributes(NULL,
|
||||
kSecCertificateItemClass,
|
||||
&attr_list,
|
||||
&search);
|
||||
if(status == noErr) {
|
||||
status = SecKeychainSearchCopyNext(search,
|
||||
(SecKeychainItemRef *)&cert);
|
||||
if(status == noErr && cert) {
|
||||
/* If we found a certificate, does it have a private key? */
|
||||
status = SecIdentityCreateWithCertificate(NULL, cert, out_c_a_k);
|
||||
CFRelease(cert);
|
||||
}
|
||||
}
|
||||
|
||||
if(search)
|
||||
CFRelease(search);
|
||||
#else
|
||||
#pragma unused(label, out_c_a_k)
|
||||
#endif /* MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7 */
|
||||
return status;
|
||||
}
|
||||
#endif /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */
|
||||
|
||||
static OSStatus CopyIdentityWithLabel(char *label,
|
||||
SecIdentityRef *out_cert_and_key)
|
||||
{
|
||||
OSStatus status = errSecItemNotFound;
|
||||
|
||||
#if defined(__MAC_10_6) || defined(__IPHONE_2_0)
|
||||
/* SecItemCopyMatching() was introduced in iOS and Snow Leopard. If it
|
||||
exists, let's use that to find the certificate. */
|
||||
if(SecItemCopyMatching != NULL) {
|
||||
CFTypeRef keys[4];
|
||||
CFTypeRef values[4];
|
||||
CFDictionaryRef query_dict;
|
||||
CFStringRef label_cf = CFStringCreateWithCString(NULL, label,
|
||||
kCFStringEncodingUTF8);
|
||||
|
||||
/* Set up our search criteria and expected results: */
|
||||
values[0] = kSecClassIdentity; /* we want a certificate and a key */
|
||||
keys[0] = kSecClass;
|
||||
values[1] = kCFBooleanTrue; /* we want a reference */
|
||||
keys[1] = kSecReturnRef;
|
||||
values[2] = kSecMatchLimitOne; /* one is enough, thanks */
|
||||
keys[2] = kSecMatchLimit;
|
||||
/* identity searches need a SecPolicyRef in order to work */
|
||||
values[3] = SecPolicyCreateSSL(false, label_cf);
|
||||
keys[3] = kSecMatchPolicy;
|
||||
query_dict = CFDictionaryCreate(NULL, (const void **)keys,
|
||||
(const void **)values, 4L,
|
||||
&kCFCopyStringDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
CFRelease(values[3]);
|
||||
CFRelease(label_cf);
|
||||
|
||||
/* Do we have a match? */
|
||||
status = SecItemCopyMatching(query_dict, (CFTypeRef *)out_cert_and_key);
|
||||
CFRelease(query_dict);
|
||||
}
|
||||
else {
|
||||
#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
|
||||
/* On Leopard, fall back to SecKeychainSearch. */
|
||||
status = CopyIdentityWithLabelOldSchool(label, out_cert_and_key);
|
||||
#endif /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */
|
||||
}
|
||||
#elif (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
|
||||
/* For developers building on Leopard, we have no choice but to fall back. */
|
||||
status = CopyIdentityWithLabelOldSchool(label, out_cert_and_key);
|
||||
#endif /* defined(__MAC_10_6) || defined(__IPHONE_2_0) */
|
||||
return status;
|
||||
}
|
||||
|
||||
static CURLcode darwinssl_connect_step1(struct connectdata *conn,
|
||||
int sockindex)
|
||||
{
|
||||
@@ -704,6 +799,8 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
|
||||
#endif
|
||||
size_t all_ciphers_count = 0UL, allowed_ciphers_count = 0UL, i;
|
||||
SSLCipherSuite *all_ciphers = NULL, *allowed_ciphers = NULL;
|
||||
char *ssl_sessionid;
|
||||
size_t ssl_sessionid_len;
|
||||
OSStatus err = noErr;
|
||||
#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
|
||||
int darwinver_maj = 0, darwinver_min = 0;
|
||||
@@ -839,8 +936,57 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
|
||||
}
|
||||
#endif /* defined(__MAC_10_8) || defined(__IPHONE_5_0) */
|
||||
|
||||
/* No need to load certificates here. SecureTransport uses the Keychain
|
||||
* (which is also part of the Security framework) to evaluate trust. */
|
||||
if(data->set.str[STRING_KEY]) {
|
||||
infof(data, "WARNING: SSL: CURLOPT_SSLKEY is ignored by Secure "
|
||||
"Transport. The private key must be in the Keychain.");
|
||||
}
|
||||
|
||||
if(data->set.str[STRING_CERT]) {
|
||||
SecIdentityRef cert_and_key = NULL;
|
||||
|
||||
/* User wants to authenticate with a client cert. Look for it: */
|
||||
err = CopyIdentityWithLabel(data->set.str[STRING_CERT], &cert_and_key);
|
||||
if(err == noErr) {
|
||||
SecCertificateRef cert = NULL;
|
||||
CFTypeRef certs_c[1];
|
||||
CFArrayRef certs;
|
||||
|
||||
/* If we found one, print it out: */
|
||||
err = SecIdentityCopyCertificate(cert_and_key, &cert);
|
||||
if(err == noErr) {
|
||||
CFStringRef cert_summary = CopyCertSubject(cert);
|
||||
char cert_summary_c[128];
|
||||
|
||||
if(cert_summary) {
|
||||
memset(cert_summary_c, 0, 128);
|
||||
if(CFStringGetCString(cert_summary,
|
||||
cert_summary_c,
|
||||
128,
|
||||
kCFStringEncodingUTF8)) {
|
||||
infof(data, "Client certificate: %s\n", cert_summary_c);
|
||||
}
|
||||
CFRelease(cert_summary);
|
||||
CFRelease(cert);
|
||||
}
|
||||
}
|
||||
certs_c[0] = cert_and_key;
|
||||
certs = CFArrayCreate(NULL, (const void **)certs_c, 1L,
|
||||
&kCFTypeArrayCallBacks);
|
||||
err = SSLSetCertificate(connssl->ssl_ctx, certs);
|
||||
if(certs)
|
||||
CFRelease(certs);
|
||||
if(err != noErr) {
|
||||
failf(data, "SSL: SSLSetCertificate() failed: OSStatus %d", err);
|
||||
return CURLE_SSL_CERTPROBLEM;
|
||||
}
|
||||
CFRelease(cert_and_key);
|
||||
}
|
||||
else {
|
||||
failf(data, "SSL: Can't find the certificate \"%s\" and its private key "
|
||||
"in the Keychain.", data->set.str[STRING_CERT]);
|
||||
return CURLE_SSL_CERTPROBLEM;
|
||||
}
|
||||
}
|
||||
|
||||
/* SSL always tries to verify the peer, this only says whether it should
|
||||
* fail to connect if the verification fails, or if it should continue
|
||||
@@ -990,6 +1136,38 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
|
||||
Curl_safefree(all_ciphers);
|
||||
Curl_safefree(allowed_ciphers);
|
||||
|
||||
/* Check if there's a cached ID we can/should use here! */
|
||||
if(!Curl_ssl_getsessionid(conn, (void **)&ssl_sessionid,
|
||||
&ssl_sessionid_len)) {
|
||||
/* we got a session id, use it! */
|
||||
err = SSLSetPeerID(connssl->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
|
||||
if(err != noErr) {
|
||||
failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err);
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
/* Informational message */
|
||||
infof(data, "SSL re-using session ID\n");
|
||||
}
|
||||
/* If there isn't one, then let's make one up! This has to be done prior
|
||||
to starting the handshake. */
|
||||
else {
|
||||
CURLcode retcode;
|
||||
|
||||
ssl_sessionid = malloc(256*sizeof(char));
|
||||
ssl_sessionid_len = snprintf(ssl_sessionid, 256, "curl:%s:%hu",
|
||||
conn->host.name, conn->remote_port);
|
||||
err = SSLSetPeerID(connssl->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
|
||||
if(err != noErr) {
|
||||
failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err);
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
retcode = Curl_ssl_addsessionid(conn, ssl_sessionid, ssl_sessionid_len);
|
||||
if(retcode!= CURLE_OK) {
|
||||
failf(data, "failed to store ssl session");
|
||||
return retcode;
|
||||
}
|
||||
}
|
||||
|
||||
err = SSLSetIOFuncs(connssl->ssl_ctx, SocketRead, SocketWrite);
|
||||
if(err != noErr) {
|
||||
failf(data, "SSL: SSLSetIOFuncs() failed: OSStatus %d", err);
|
||||
@@ -1059,6 +1237,20 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex)
|
||||
"certificate format");
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
|
||||
/* These are all certificate problems with the client: */
|
||||
case errSecAuthFailed:
|
||||
failf(data, "SSL authentication failed");
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
case errSSLPeerHandshakeFail:
|
||||
failf(data, "SSL peer handshake failed, the server most likely "
|
||||
"requires a client certificate to connect");
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
case errSSLPeerUnknownCA:
|
||||
failf(data, "SSL server rejected the client certificate due to "
|
||||
"the certificate being signed by an unknown certificate "
|
||||
"authority");
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
|
||||
/* This error is raised if the server's cert didn't match the server's
|
||||
host name: */
|
||||
case errSSLHostNameMismatch:
|
||||
@@ -1462,6 +1654,17 @@ int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex)
|
||||
return rc;
|
||||
}
|
||||
|
||||
void Curl_darwinssl_session_free(void *ptr)
|
||||
{
|
||||
/* ST, as of iOS 5 and Mountain Lion, has no public method of deleting a
|
||||
cached session ID inside the Security framework. There is a private
|
||||
function that does this, but I don't want to have to explain to you why I
|
||||
got your application rejected from the App Store due to the use of a
|
||||
private API, so the best we can do is free up our own char array that we
|
||||
created way back in darwinssl_connect_step1... */
|
||||
Curl_safefree(ptr);
|
||||
}
|
||||
|
||||
size_t Curl_darwinssl_version(char *buffer, size_t size)
|
||||
{
|
||||
return snprintf(buffer, size, "SecureTransport");
|
||||
|
@@ -37,6 +37,7 @@ void Curl_darwinssl_close_all(struct SessionHandle *data);
|
||||
/* close a SSL connection */
|
||||
void Curl_darwinssl_close(struct connectdata *conn, int sockindex);
|
||||
|
||||
void Curl_darwinssl_session_free(void *ptr);
|
||||
size_t Curl_darwinssl_version(char *buffer, size_t size);
|
||||
int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex);
|
||||
int Curl_darwinssl_check_cxn(struct connectdata *conn);
|
||||
@@ -56,7 +57,7 @@ void Curl_darwinssl_md5sum(unsigned char *tmp, /* input */
|
||||
#define curlssl_cleanup() Curl_nop_stmt
|
||||
#define curlssl_connect Curl_darwinssl_connect
|
||||
#define curlssl_connect_nonblocking Curl_darwinssl_connect_nonblocking
|
||||
#define curlssl_session_free(x) Curl_nop_stmt
|
||||
#define curlssl_session_free(x) Curl_darwinssl_session_free(x)
|
||||
#define curlssl_close_all Curl_darwinssl_close_all
|
||||
#define curlssl_close Curl_darwinssl_close
|
||||
#define curlssl_shutdown(x,y) 0
|
||||
|
@@ -87,9 +87,6 @@ extern curl_free_callback Curl_cfree;
|
||||
extern curl_realloc_callback Curl_crealloc;
|
||||
extern curl_strdup_callback Curl_cstrdup;
|
||||
extern curl_calloc_callback Curl_ccalloc;
|
||||
#ifdef WIN32
|
||||
extern curl_wcsdup_callback Curl_cwcsdup;
|
||||
#endif
|
||||
|
||||
#ifndef CURLDEBUG
|
||||
|
||||
@@ -113,19 +110,6 @@ extern curl_wcsdup_callback Curl_cwcsdup;
|
||||
#undef free
|
||||
#define free(ptr) Curl_cfree(ptr)
|
||||
|
||||
#ifdef WIN32
|
||||
# undef wcsdup
|
||||
# define wcsdup(ptr) Curl_cwcsdup(ptr)
|
||||
# undef _wcsdup
|
||||
# define _wcsdup(ptr) Curl_cwcsdup(ptr)
|
||||
# undef _tcsdup
|
||||
# ifdef UNICODE
|
||||
# define _tcsdup(ptr) Curl_cwcsdup(ptr)
|
||||
# else
|
||||
# define _tcsdup(ptr) Curl_cstrdup(ptr)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif /* CURLDEBUG */
|
||||
|
||||
#else /* CURLX_NO_MEMORY_CALLBACKS */
|
||||
|
@@ -25,13 +25,17 @@
|
||||
#include "pingpong.h"
|
||||
|
||||
/* Authentication mechanism flags */
|
||||
#define SASL_MECH_LOGIN 0x0001
|
||||
#define SASL_MECH_PLAIN 0x0002
|
||||
#define SASL_MECH_CRAM_MD5 0x0004
|
||||
#define SASL_MECH_DIGEST_MD5 0x0008
|
||||
#define SASL_MECH_GSSAPI 0x0010
|
||||
#define SASL_MECH_EXTERNAL 0x0020
|
||||
#define SASL_MECH_NTLM 0x0040
|
||||
#define SASL_MECH_LOGIN (1 << 0)
|
||||
#define SASL_MECH_PLAIN (1 << 1)
|
||||
#define SASL_MECH_CRAM_MD5 (1 << 2)
|
||||
#define SASL_MECH_DIGEST_MD5 (1 << 3)
|
||||
#define SASL_MECH_GSSAPI (1 << 4)
|
||||
#define SASL_MECH_EXTERNAL (1 << 5)
|
||||
#define SASL_MECH_NTLM (1 << 6)
|
||||
|
||||
/* Authentication mechanism values */
|
||||
#define SASL_AUTH_NONE 0
|
||||
#define SASL_AUTH_ANY ~0
|
||||
|
||||
/* This is used to generate a base64 encoded PLAIN authentication message */
|
||||
CURLcode Curl_sasl_create_plain_message(struct SessionHandle *data,
|
||||
|
@@ -534,6 +534,7 @@ schannel_connect_step3(struct connectdata *conn, int sockindex)
|
||||
return retcode;
|
||||
}
|
||||
else {
|
||||
connssl->cred->cached = TRUE;
|
||||
infof(data, "schannel: stored credential handle in session cache\n");
|
||||
}
|
||||
}
|
||||
@@ -1063,7 +1064,6 @@ int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
|
||||
*/
|
||||
struct SessionHandle *data = conn->data;
|
||||
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
|
||||
struct curl_schannel_cred *cached_cred = NULL;
|
||||
|
||||
infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu\n",
|
||||
conn->host.name, conn->remote_port);
|
||||
@@ -1141,17 +1141,11 @@ int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
|
||||
connssl->cred->refcount);
|
||||
}
|
||||
|
||||
/* if the handle refcount is zero, check if we have not cached it */
|
||||
if(connssl->cred->refcount == 0) {
|
||||
if(Curl_ssl_getsessionid(conn, (void**)&cached_cred, NULL)) {
|
||||
cached_cred = NULL;
|
||||
}
|
||||
/* if the handle was not cached, it is stale to be freed */
|
||||
if(connssl->cred != cached_cred) {
|
||||
infof(data, "schannel: clear credential handle\n");
|
||||
s_pSecFn->FreeCredentialsHandle(&connssl->cred->cred_handle);
|
||||
Curl_safefree(connssl->cred);
|
||||
}
|
||||
/* if the handle was not cached and the refcount is zero */
|
||||
if(!connssl->cred->cached && connssl->cred->refcount == 0) {
|
||||
infof(data, "schannel: clear credential handle\n");
|
||||
s_pSecFn->FreeCredentialsHandle(&connssl->cred->cred_handle);
|
||||
Curl_safefree(connssl->cred);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1177,7 +1171,7 @@ void Curl_schannel_session_free(void *ptr)
|
||||
{
|
||||
struct curl_schannel_cred *cred = ptr;
|
||||
|
||||
if(cred && cred->refcount == 0) {
|
||||
if(cred && cred->cached && cred->refcount == 0) {
|
||||
s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
|
||||
Curl_safefree(cred);
|
||||
}
|
||||
|
@@ -270,7 +270,6 @@
|
||||
# endif
|
||||
# endif
|
||||
# include <tchar.h>
|
||||
typedef wchar_t *(*curl_wcsdup_callback)(const wchar_t *str);
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -369,7 +368,9 @@
|
||||
# include <sys/stat.h>
|
||||
# undef lseek
|
||||
# define lseek(fdes,offset,whence) _lseeki64(fdes, offset, whence)
|
||||
# undef fstat
|
||||
# define fstat(fdes,stp) _fstati64(fdes, stp)
|
||||
# undef stat
|
||||
# define stat(fname,stp) _stati64(fname, stp)
|
||||
# define struct_stat struct _stati64
|
||||
# define LSEEK_ERROR (__int64)-1
|
||||
|
36
lib/easy.c
36
lib/easy.c
@@ -73,6 +73,7 @@
|
||||
#include "non-ascii.h"
|
||||
#include "warnless.h"
|
||||
#include "conncache.h"
|
||||
#include "multiif.h"
|
||||
|
||||
#define _MPRINTF_REPLACE /* use our functions only */
|
||||
#include <curl/mprintf.h>
|
||||
@@ -197,9 +198,6 @@ curl_free_callback Curl_cfree = (curl_free_callback)free;
|
||||
curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc;
|
||||
curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)system_strdup;
|
||||
curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc;
|
||||
#ifdef WIN32
|
||||
curl_wcsdup_callback Curl_cwcsdup = (curl_wcsdup_callback)wcsdup;
|
||||
#endif
|
||||
#else
|
||||
/*
|
||||
* Symbian OS doesn't support initialization to code in writeable static data.
|
||||
@@ -231,9 +229,6 @@ CURLcode curl_global_init(long flags)
|
||||
Curl_crealloc = (curl_realloc_callback)realloc;
|
||||
Curl_cstrdup = (curl_strdup_callback)system_strdup;
|
||||
Curl_ccalloc = (curl_calloc_callback)calloc;
|
||||
#ifdef WIN32
|
||||
Curl_cwcsdup = (curl_wcsdup_callback)wcsdup;
|
||||
#endif
|
||||
|
||||
if(flags & CURL_GLOBAL_SSL)
|
||||
if(!Curl_ssl_init()) {
|
||||
@@ -425,6 +420,9 @@ CURLcode curl_easy_perform(CURL *easy)
|
||||
bool done = FALSE;
|
||||
int rc;
|
||||
struct SessionHandle *data = easy;
|
||||
int without_fds = 0; /* count number of consecutive returns from
|
||||
curl_multi_wait() without any filedescriptors */
|
||||
struct timeval before;
|
||||
|
||||
if(!easy)
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
@@ -437,7 +435,9 @@ CURLcode curl_easy_perform(CURL *easy)
|
||||
if(data->multi_easy)
|
||||
multi = data->multi_easy;
|
||||
else {
|
||||
multi = curl_multi_init();
|
||||
/* this multi handle will only ever have a single easy handled attached
|
||||
to it, so make it use minimal hashes */
|
||||
multi = Curl_multi_handle(1, 3);
|
||||
if(!multi)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
data->multi_easy = multi;
|
||||
@@ -463,6 +463,7 @@ CURLcode curl_easy_perform(CURL *easy)
|
||||
int still_running;
|
||||
int ret;
|
||||
|
||||
before = curlx_tvnow();
|
||||
mcode = curl_multi_wait(multi, NULL, 0, 1000, &ret);
|
||||
|
||||
if(mcode == CURLM_OK) {
|
||||
@@ -471,6 +472,27 @@ CURLcode curl_easy_perform(CURL *easy)
|
||||
code = CURLE_RECV_ERROR;
|
||||
break;
|
||||
}
|
||||
else if(ret == 0) {
|
||||
struct timeval after = curlx_tvnow();
|
||||
/* If it returns without any filedescriptor instantly, we need to
|
||||
avoid busy-looping during periods where it has nothing particular
|
||||
to wait for */
|
||||
if(curlx_tvdiff(after, before) <= 10) {
|
||||
without_fds++;
|
||||
if(without_fds > 2) {
|
||||
int sleep_ms = without_fds * 50;
|
||||
if(sleep_ms > 1000)
|
||||
sleep_ms = 1000;
|
||||
Curl_wait_ms(sleep_ms);
|
||||
}
|
||||
}
|
||||
else
|
||||
/* it wasn't "instant", restart counter */
|
||||
without_fds = 0;
|
||||
}
|
||||
else
|
||||
/* got file descriptor, restart counter */
|
||||
without_fds = 0;
|
||||
|
||||
mcode = curl_multi_perform(multi, &still_running);
|
||||
}
|
||||
|
@@ -5,7 +5,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -159,7 +159,8 @@ CURLcode Curl_urldecode(struct SessionHandle *data,
|
||||
|
||||
while(--alloc > 0) {
|
||||
in = *string;
|
||||
if(('%' == in) && ISXDIGIT(string[1]) && ISXDIGIT(string[2])) {
|
||||
if(('%' == in) && (alloc > 2) &&
|
||||
ISXDIGIT(string[1]) && ISXDIGIT(string[2])) {
|
||||
/* this is two hexadecimal digits following a '%' */
|
||||
char hexstr[3];
|
||||
char *ptr;
|
||||
|
32
lib/ftp.c
32
lib/ftp.c
@@ -1951,13 +1951,11 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
|
||||
return CURLE_FTP_WEIRD_PASV_REPLY;
|
||||
}
|
||||
|
||||
if(data->set.str[STRING_PROXY] && *data->set.str[STRING_PROXY]) {
|
||||
if(conn->bits.proxy) {
|
||||
/*
|
||||
* This is a tunnel through a http proxy and we need to connect to the
|
||||
* proxy again here.
|
||||
*
|
||||
* We don't want to rely on a former host lookup that might've expired
|
||||
* now, instead we remake the lookup here and now!
|
||||
* This connection uses a proxy and we need to connect to the proxy again
|
||||
* here. We don't want to rely on a former host lookup that might've
|
||||
* expired now, instead we remake the lookup here and now!
|
||||
*/
|
||||
rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &addr);
|
||||
if(rc == CURLRESOLV_PENDING)
|
||||
@@ -2711,7 +2709,10 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
|
||||
/* we have now received a full FTP server response */
|
||||
switch(ftpc->state) {
|
||||
case FTP_WAIT220:
|
||||
if(ftpcode != 220) {
|
||||
if(ftpcode == 230)
|
||||
/* 230 User logged in - already! */
|
||||
return ftp_state_user_resp(conn, ftpcode, ftpc->state);
|
||||
else if(ftpcode != 220) {
|
||||
failf(data, "Got a %03d ftp-server response when 220 was expected",
|
||||
ftpcode);
|
||||
return CURLE_FTP_WEIRD_SERVER_REPLY;
|
||||
@@ -4316,13 +4317,17 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
|
||||
}
|
||||
slash_pos=strrchr(cur_pos, '/');
|
||||
if(slash_pos || !*cur_pos) {
|
||||
size_t dirlen = slash_pos-cur_pos;
|
||||
|
||||
ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0]));
|
||||
if(!ftpc->dirs)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
if(!dirlen)
|
||||
dirlen++;
|
||||
|
||||
ftpc->dirs[0] = curl_easy_unescape(conn->data, slash_pos ? cur_pos : "/",
|
||||
slash_pos ?
|
||||
curlx_sztosi(slash_pos-cur_pos) : 1,
|
||||
slash_pos ? curlx_sztosi(dirlen) : 1,
|
||||
NULL);
|
||||
if(!ftpc->dirs[0]) {
|
||||
freedirs(ftpc);
|
||||
@@ -4377,6 +4382,15 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
|
||||
}
|
||||
else {
|
||||
cur_pos = slash_pos + 1; /* jump to the rest of the string */
|
||||
if(!ftpc->dirdepth) {
|
||||
/* path starts with a slash, add that as a directory */
|
||||
ftpc->dirs[ftpc->dirdepth] = strdup("/");
|
||||
if(!ftpc->dirs[ftpc->dirdepth++]) { /* run out of memory ... */
|
||||
failf(data, "no memory");
|
||||
freedirs(ftpc);
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@@ -55,6 +55,7 @@ CURLcode Curl_initinfo(struct SessionHandle *data)
|
||||
info->httpcode = 0;
|
||||
info->httpversion=0;
|
||||
info->filetime=-1; /* -1 is an illegal time and thus means unknown */
|
||||
info->timecond=0;
|
||||
|
||||
if(info->contenttype)
|
||||
free(info->contenttype);
|
||||
|
@@ -267,6 +267,38 @@ static void md5_to_ascii(unsigned char *source, /* 16 bytes */
|
||||
snprintf((char *)&dest[i*2], 3, "%02x", source[i]);
|
||||
}
|
||||
|
||||
/* Perform quoted-string escaping as described in RFC2616 and its errata */
|
||||
static char *string_quoted(const char *source)
|
||||
{
|
||||
char *dest, *d;
|
||||
const char *s = source;
|
||||
size_t n = 1; /* null terminator */
|
||||
|
||||
/* Calculate size needed */
|
||||
while(*s) {
|
||||
++n;
|
||||
if(*s == '"' || *s == '\\') {
|
||||
++n;
|
||||
}
|
||||
++s;
|
||||
}
|
||||
|
||||
dest = (char *)malloc(n);
|
||||
if(dest) {
|
||||
s = source;
|
||||
d = dest;
|
||||
while(*s) {
|
||||
if(*s == '"' || *s == '\\') {
|
||||
*d++ = '\\';
|
||||
}
|
||||
*d++ = *s++;
|
||||
}
|
||||
*d = 0;
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
CURLcode Curl_output_digest(struct connectdata *conn,
|
||||
bool proxy,
|
||||
const unsigned char *request,
|
||||
@@ -289,6 +321,7 @@ CURLcode Curl_output_digest(struct connectdata *conn,
|
||||
char **allocuserpwd;
|
||||
size_t userlen;
|
||||
const char *userp;
|
||||
char *userp_quoted;
|
||||
const char *passwdp;
|
||||
struct auth *authp;
|
||||
|
||||
@@ -425,16 +458,20 @@ CURLcode Curl_output_digest(struct connectdata *conn,
|
||||
else
|
||||
md5this = (unsigned char *)aprintf("%s:%s", request, uripath);
|
||||
|
||||
if(d->qop && Curl_raw_equal(d->qop, "auth-int")) {
|
||||
/* We don't support auth-int for PUT or POST at the moment.
|
||||
TODO: replace md5 of empty string with entity-body for PUT/POST */
|
||||
unsigned char *md5this2 = (unsigned char *)
|
||||
aprintf("%s:%s", md5this, "d41d8cd98f00b204e9800998ecf8427e");
|
||||
free(md5this);
|
||||
md5this = md5this2;
|
||||
}
|
||||
|
||||
if(!md5this) {
|
||||
free(ha1);
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if(d->qop && Curl_raw_equal(d->qop, "auth-int")) {
|
||||
/* We don't support auth-int at the moment. I can't see a easy way to get
|
||||
entity-body here */
|
||||
/* TODO: Append H(entity-body)*/
|
||||
}
|
||||
CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
|
||||
Curl_md5it(md5buf, md5this);
|
||||
free(md5this); /* free this again */
|
||||
@@ -468,7 +505,18 @@ CURLcode Curl_output_digest(struct connectdata *conn,
|
||||
|
||||
Authorization: Digest username="testuser", realm="testrealm", \
|
||||
nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca"
|
||||
|
||||
Digest parameters are all quoted strings. Username which is provided by
|
||||
the user will need double quotes and backslashes within it escaped. For
|
||||
the other fields, this shouldn't be an issue. realm, nonce, and opaque
|
||||
are copied as is from the server, escapes and all. cnonce is generated
|
||||
with web-safe characters. uri is already percent encoded. nc is 8 hex
|
||||
characters. algorithm and qop with standard values only contain web-safe
|
||||
chracters.
|
||||
*/
|
||||
userp_quoted = string_quoted(userp);
|
||||
if(!*userp_quoted)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
if(d->qop) {
|
||||
*allocuserpwd =
|
||||
@@ -482,7 +530,7 @@ CURLcode Curl_output_digest(struct connectdata *conn,
|
||||
"qop=%s, "
|
||||
"response=\"%s\"",
|
||||
proxy?"Proxy-":"",
|
||||
userp,
|
||||
userp_quoted,
|
||||
d->realm,
|
||||
d->nonce,
|
||||
uripath, /* this is the PATH part of the URL */
|
||||
@@ -505,12 +553,13 @@ CURLcode Curl_output_digest(struct connectdata *conn,
|
||||
"uri=\"%s\", "
|
||||
"response=\"%s\"",
|
||||
proxy?"Proxy-":"",
|
||||
userp,
|
||||
userp_quoted,
|
||||
d->realm,
|
||||
d->nonce,
|
||||
uripath, /* this is the PATH part of the URL */
|
||||
request_digest);
|
||||
}
|
||||
free(userp_quoted);
|
||||
if(!*allocuserpwd)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
|
562
lib/imap.c
562
lib/imap.c
@@ -86,8 +86,6 @@
|
||||
#include "memdebug.h"
|
||||
|
||||
/* Local API functions */
|
||||
static CURLcode imap_parse_url_path(struct connectdata *conn);
|
||||
static CURLcode imap_parse_custom_request(struct connectdata *conn);
|
||||
static CURLcode imap_regular_transfer(struct connectdata *conn, bool *done);
|
||||
static CURLcode imap_do(struct connectdata *conn, bool *done);
|
||||
static CURLcode imap_done(struct connectdata *conn, CURLcode status,
|
||||
@@ -99,6 +97,11 @@ static int imap_getsock(struct connectdata *conn, curl_socket_t *socks,
|
||||
int numsocks);
|
||||
static CURLcode imap_doing(struct connectdata *conn, bool *dophase_done);
|
||||
static CURLcode imap_setup_connection(struct connectdata *conn);
|
||||
static char *imap_atom(const char *str);
|
||||
static CURLcode imap_sendf(struct connectdata *conn, const char *fmt, ...);
|
||||
static CURLcode imap_parse_url_options(struct connectdata *conn);
|
||||
static CURLcode imap_parse_url_path(struct connectdata *conn);
|
||||
static CURLcode imap_parse_custom_request(struct connectdata *conn);
|
||||
|
||||
/*
|
||||
* IMAP protocol handler.
|
||||
@@ -213,119 +216,6 @@ static void imap_to_imaps(struct connectdata *conn)
|
||||
#define imap_to_imaps(x) Curl_nop_stmt
|
||||
#endif
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* imap_sendf()
|
||||
*
|
||||
* Sends the formated string as an IMAP command to the server.
|
||||
*
|
||||
* Designed to never block.
|
||||
*/
|
||||
static CURLcode imap_sendf(struct connectdata *conn, const char *fmt, ...)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct imap_conn *imapc = &conn->proto.imapc;
|
||||
char *taggedfmt;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
|
||||
/* Calculate the next command ID wrapping at 3 digits */
|
||||
imapc->cmdid = (imapc->cmdid + 1) % 1000;
|
||||
|
||||
/* Calculate the tag based on the connection ID and command ID */
|
||||
snprintf(imapc->resptag, sizeof(imapc->resptag), "%c%03d",
|
||||
'A' + (conn->connection_id % 26), imapc->cmdid);
|
||||
|
||||
/* Prefix the format with the tag */
|
||||
taggedfmt = aprintf("%s %s", imapc->resptag, fmt);
|
||||
if(!taggedfmt)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
/* Send the data with the tag */
|
||||
result = Curl_pp_vsendf(&imapc->pp, taggedfmt, ap);
|
||||
|
||||
Curl_safefree(taggedfmt);
|
||||
va_end(ap);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* imap_atom()
|
||||
*
|
||||
* Checks the input string for characters that need escaping and returns an
|
||||
* atom ready for sending to the server.
|
||||
*
|
||||
* The returned string needs to be freed.
|
||||
*
|
||||
*/
|
||||
static char *imap_atom(const char *str)
|
||||
{
|
||||
const char *p1;
|
||||
char *p2;
|
||||
size_t backsp_count = 0;
|
||||
size_t quote_count = 0;
|
||||
bool space_exists = FALSE;
|
||||
size_t newlen = 0;
|
||||
char *newstr = NULL;
|
||||
|
||||
if(!str)
|
||||
return NULL;
|
||||
|
||||
/* Count any unescapped characters */
|
||||
p1 = str;
|
||||
while(*p1) {
|
||||
if(*p1 == '\\')
|
||||
backsp_count++;
|
||||
else if(*p1 == '"')
|
||||
quote_count++;
|
||||
else if(*p1 == ' ')
|
||||
space_exists = TRUE;
|
||||
|
||||
p1++;
|
||||
}
|
||||
|
||||
/* Does the input contain any unescapped characters? */
|
||||
if(!backsp_count && !quote_count && !space_exists)
|
||||
return strdup(str);
|
||||
|
||||
/* Calculate the new string length */
|
||||
newlen = strlen(str) + backsp_count + quote_count + (space_exists ? 2 : 0);
|
||||
|
||||
/* Allocate the new string */
|
||||
newstr = (char *) malloc((newlen + 1) * sizeof(char));
|
||||
if(!newstr)
|
||||
return NULL;
|
||||
|
||||
/* Surround the string in quotes if necessary */
|
||||
p2 = newstr;
|
||||
if(space_exists) {
|
||||
newstr[0] = '"';
|
||||
newstr[newlen - 1] = '"';
|
||||
p2++;
|
||||
}
|
||||
|
||||
/* Copy the string, escaping backslash and quote characters along the way */
|
||||
p1 = str;
|
||||
while(*p1) {
|
||||
if(*p1 == '\\' || *p1 == '"') {
|
||||
*p2 = '\\';
|
||||
p2++;
|
||||
}
|
||||
|
||||
*p2 = *p1;
|
||||
|
||||
p1++;
|
||||
p2++;
|
||||
}
|
||||
|
||||
/* Terminate the string */
|
||||
newstr[newlen] = '\0';
|
||||
|
||||
return newstr;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* imap_matchresp()
|
||||
@@ -635,6 +525,7 @@ static CURLcode imap_perform_login(struct connectdata *conn)
|
||||
static CURLcode imap_perform_authenticate(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct SessionHandle *data = conn->data;
|
||||
struct imap_conn *imapc = &conn->proto.imapc;
|
||||
const char *mech = NULL;
|
||||
char *initresp = NULL;
|
||||
@@ -653,12 +544,14 @@ static CURLcode imap_perform_authenticate(struct connectdata *conn)
|
||||
/* Calculate the supported authentication mechanism by decreasing order of
|
||||
security */
|
||||
#ifndef CURL_DISABLE_CRYPTO_AUTH
|
||||
if(imapc->authmechs & SASL_MECH_DIGEST_MD5) {
|
||||
if((imapc->authmechs & SASL_MECH_DIGEST_MD5) &&
|
||||
(imapc->prefmech & SASL_MECH_DIGEST_MD5)) {
|
||||
mech = "DIGEST-MD5";
|
||||
state1 = IMAP_AUTHENTICATE_DIGESTMD5;
|
||||
imapc->authused = SASL_MECH_DIGEST_MD5;
|
||||
}
|
||||
else if(imapc->authmechs & SASL_MECH_CRAM_MD5) {
|
||||
else if((imapc->authmechs & SASL_MECH_CRAM_MD5) &&
|
||||
(imapc->prefmech & SASL_MECH_CRAM_MD5)) {
|
||||
mech = "CRAM-MD5";
|
||||
state1 = IMAP_AUTHENTICATE_CRAMMD5;
|
||||
imapc->authused = SASL_MECH_CRAM_MD5;
|
||||
@@ -666,67 +559,69 @@ static CURLcode imap_perform_authenticate(struct connectdata *conn)
|
||||
else
|
||||
#endif
|
||||
#ifdef USE_NTLM
|
||||
if(imapc->authmechs & SASL_MECH_NTLM) {
|
||||
if((imapc->authmechs & SASL_MECH_NTLM) &&
|
||||
(imapc->prefmech & SASL_MECH_NTLM)) {
|
||||
mech = "NTLM";
|
||||
state1 = IMAP_AUTHENTICATE_NTLM;
|
||||
state2 = IMAP_AUTHENTICATE_NTLM_TYPE2MSG;
|
||||
imapc->authused = SASL_MECH_NTLM;
|
||||
|
||||
if(imapc->ir_supported)
|
||||
if(imapc->ir_supported || data->set.sasl_ir)
|
||||
result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
|
||||
&conn->ntlm,
|
||||
&initresp, &len);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if(imapc->authmechs & SASL_MECH_LOGIN) {
|
||||
if((imapc->authmechs & SASL_MECH_LOGIN) &&
|
||||
(imapc->prefmech & SASL_MECH_LOGIN)) {
|
||||
mech = "LOGIN";
|
||||
state1 = IMAP_AUTHENTICATE_LOGIN;
|
||||
state2 = IMAP_AUTHENTICATE_LOGIN_PASSWD;
|
||||
imapc->authused = SASL_MECH_LOGIN;
|
||||
|
||||
if(imapc->ir_supported)
|
||||
if(imapc->ir_supported || data->set.sasl_ir)
|
||||
result = Curl_sasl_create_login_message(conn->data, conn->user,
|
||||
&initresp, &len);
|
||||
}
|
||||
else if(imapc->authmechs & SASL_MECH_PLAIN) {
|
||||
else if((imapc->authmechs & SASL_MECH_PLAIN) &&
|
||||
(imapc->prefmech & SASL_MECH_PLAIN)) {
|
||||
mech = "PLAIN";
|
||||
state1 = IMAP_AUTHENTICATE_PLAIN;
|
||||
state2 = IMAP_AUTHENTICATE_FINAL;
|
||||
imapc->authused = SASL_MECH_PLAIN;
|
||||
|
||||
if(imapc->ir_supported)
|
||||
if(imapc->ir_supported || data->set.sasl_ir)
|
||||
result = Curl_sasl_create_plain_message(conn->data, conn->user,
|
||||
conn->passwd, &initresp, &len);
|
||||
}
|
||||
|
||||
if(result)
|
||||
return result;
|
||||
if(!result) {
|
||||
if(mech) {
|
||||
/* Perform SASL based authentication */
|
||||
if(initresp) {
|
||||
result = imap_sendf(conn, "AUTHENTICATE %s %s", mech, initresp);
|
||||
|
||||
if(mech) {
|
||||
/* Perform SASL based authentication */
|
||||
if(initresp) {
|
||||
result = imap_sendf(conn, "AUTHENTICATE %s %s", mech, initresp);
|
||||
if(!result)
|
||||
state(conn, state2);
|
||||
}
|
||||
else {
|
||||
result = imap_sendf(conn, "AUTHENTICATE %s", mech);
|
||||
|
||||
if(!result)
|
||||
state(conn, state2);
|
||||
if(!result)
|
||||
state(conn, state1);
|
||||
}
|
||||
|
||||
Curl_safefree(initresp);
|
||||
}
|
||||
else if(!imapc->login_disabled)
|
||||
/* Perform clear text authentication */
|
||||
result = imap_perform_login(conn);
|
||||
else {
|
||||
result = imap_sendf(conn, "AUTHENTICATE %s", mech);
|
||||
|
||||
if(!result)
|
||||
state(conn, state1);
|
||||
/* Other mechanisms not supported */
|
||||
infof(conn->data, "No known authentication mechanisms supported!\n");
|
||||
result = CURLE_LOGIN_DENIED;
|
||||
}
|
||||
|
||||
Curl_safefree(initresp);
|
||||
}
|
||||
else if(!imapc->login_disabled)
|
||||
/* Perform clear text authentication */
|
||||
result = imap_perform_login(conn);
|
||||
else {
|
||||
/* Other mechanisms not supported */
|
||||
infof(conn->data, "No known authentication mechanisms supported!\n");
|
||||
result = CURLE_LOGIN_DENIED;
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -1793,8 +1688,10 @@ static int imap_getsock(struct connectdata *conn, curl_socket_t *socks,
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* imap_connect() should do everything that is to be considered a part of
|
||||
* the connection phase.
|
||||
* imap_connect()
|
||||
*
|
||||
* This function should do everything that is to be considered a part of the
|
||||
* connection phase.
|
||||
*
|
||||
* The variable 'done' points to will be TRUE if the protocol-layer connect
|
||||
* phase is done when this function returns, or FALSE is not. When called as
|
||||
@@ -1826,9 +1723,17 @@ static CURLcode imap_connect(struct connectdata *conn, bool *done)
|
||||
pp->endofresp = imap_endofresp;
|
||||
pp->conn = conn;
|
||||
|
||||
/* Set the default preferred authentication mechanism */
|
||||
imapc->prefmech = SASL_AUTH_ANY;
|
||||
|
||||
/* Initialise the pingpong layer */
|
||||
Curl_pp_init(pp);
|
||||
|
||||
/* Parse the URL options */
|
||||
result = imap_parse_url_options(conn);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
/* Start off waiting for the server greeting response */
|
||||
state(conn, IMAP_SERVERGREET);
|
||||
|
||||
@@ -2044,6 +1949,218 @@ static CURLcode imap_disconnect(struct connectdata *conn, bool dead_connection)
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/* Call this when the DO phase has completed */
|
||||
static CURLcode imap_dophase_done(struct connectdata *conn, bool connected)
|
||||
{
|
||||
struct IMAP *imap = conn->data->state.proto.imap;
|
||||
|
||||
(void)connected;
|
||||
|
||||
if(imap->transfer != FTPTRANSFER_BODY)
|
||||
/* no data to transfer */
|
||||
Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/* Called from multi.c while DOing */
|
||||
static CURLcode imap_doing(struct connectdata *conn, bool *dophase_done)
|
||||
{
|
||||
CURLcode result = imap_multi_statemach(conn, dophase_done);
|
||||
|
||||
if(result)
|
||||
DEBUGF(infof(conn->data, "DO phase failed\n"));
|
||||
else if(*dophase_done) {
|
||||
result = imap_dophase_done(conn, FALSE /* not connected */);
|
||||
|
||||
DEBUGF(infof(conn->data, "DO phase is complete\n"));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* imap_regular_transfer()
|
||||
*
|
||||
* The input argument is already checked for validity.
|
||||
*
|
||||
* Performs all commands done before a regular transfer between a local and a
|
||||
* remote host.
|
||||
*/
|
||||
static CURLcode imap_regular_transfer(struct connectdata *conn,
|
||||
bool *dophase_done)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
bool connected = FALSE;
|
||||
struct SessionHandle *data = conn->data;
|
||||
|
||||
/* Make sure size is unknown at this point */
|
||||
data->req.size = -1;
|
||||
|
||||
/* Set the progress data */
|
||||
Curl_pgrsSetUploadCounter(data, 0);
|
||||
Curl_pgrsSetDownloadCounter(data, 0);
|
||||
Curl_pgrsSetUploadSize(data, 0);
|
||||
Curl_pgrsSetDownloadSize(data, 0);
|
||||
|
||||
/* Carry out the perform */
|
||||
result = imap_perform(conn, &connected, dophase_done);
|
||||
|
||||
/* Perform post DO phase operations if necessary */
|
||||
if(!result && *dophase_done)
|
||||
result = imap_dophase_done(conn, connected);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode imap_setup_connection(struct connectdata *conn)
|
||||
{
|
||||
struct SessionHandle *data = conn->data;
|
||||
|
||||
if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
|
||||
/* Unless we have asked to tunnel IMAP operations through the proxy, we
|
||||
switch and use HTTP operations only */
|
||||
#ifndef CURL_DISABLE_HTTP
|
||||
if(conn->handler == &Curl_handler_imap)
|
||||
conn->handler = &Curl_handler_imap_proxy;
|
||||
else {
|
||||
#ifdef USE_SSL
|
||||
conn->handler = &Curl_handler_imaps_proxy;
|
||||
#else
|
||||
failf(data, "IMAPS not supported!");
|
||||
return CURLE_UNSUPPORTED_PROTOCOL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* We explicitly mark this connection as persistent here as we're doing
|
||||
IMAP over HTTP and thus we accidentally avoid setting this value
|
||||
otherwise */
|
||||
conn->bits.close = FALSE;
|
||||
#else
|
||||
failf(data, "IMAP over http proxy requires HTTP support built-in!");
|
||||
return CURLE_UNSUPPORTED_PROTOCOL;
|
||||
#endif
|
||||
}
|
||||
|
||||
data->state.path++; /* don't include the initial slash */
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* imap_sendf()
|
||||
*
|
||||
* Sends the formated string as an IMAP command to the server.
|
||||
*
|
||||
* Designed to never block.
|
||||
*/
|
||||
static CURLcode imap_sendf(struct connectdata *conn, const char *fmt, ...)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct imap_conn *imapc = &conn->proto.imapc;
|
||||
char *taggedfmt;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
|
||||
/* Calculate the next command ID wrapping at 3 digits */
|
||||
imapc->cmdid = (imapc->cmdid + 1) % 1000;
|
||||
|
||||
/* Calculate the tag based on the connection ID and command ID */
|
||||
snprintf(imapc->resptag, sizeof(imapc->resptag), "%c%03d",
|
||||
'A' + (conn->connection_id % 26), imapc->cmdid);
|
||||
|
||||
/* Prefix the format with the tag */
|
||||
taggedfmt = aprintf("%s %s", imapc->resptag, fmt);
|
||||
if(!taggedfmt)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
/* Send the data with the tag */
|
||||
result = Curl_pp_vsendf(&imapc->pp, taggedfmt, ap);
|
||||
|
||||
Curl_safefree(taggedfmt);
|
||||
va_end(ap);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* imap_atom()
|
||||
*
|
||||
* Checks the input string for characters that need escaping and returns an
|
||||
* atom ready for sending to the server.
|
||||
*
|
||||
* The returned string needs to be freed.
|
||||
*
|
||||
*/
|
||||
static char *imap_atom(const char *str)
|
||||
{
|
||||
const char *p1;
|
||||
char *p2;
|
||||
size_t backsp_count = 0;
|
||||
size_t quote_count = 0;
|
||||
bool space_exists = FALSE;
|
||||
size_t newlen = 0;
|
||||
char *newstr = NULL;
|
||||
|
||||
if(!str)
|
||||
return NULL;
|
||||
|
||||
/* Count any unescapped characters */
|
||||
p1 = str;
|
||||
while(*p1) {
|
||||
if(*p1 == '\\')
|
||||
backsp_count++;
|
||||
else if(*p1 == '"')
|
||||
quote_count++;
|
||||
else if(*p1 == ' ')
|
||||
space_exists = TRUE;
|
||||
|
||||
p1++;
|
||||
}
|
||||
|
||||
/* Does the input contain any unescapped characters? */
|
||||
if(!backsp_count && !quote_count && !space_exists)
|
||||
return strdup(str);
|
||||
|
||||
/* Calculate the new string length */
|
||||
newlen = strlen(str) + backsp_count + quote_count + (space_exists ? 2 : 0);
|
||||
|
||||
/* Allocate the new string */
|
||||
newstr = (char *) malloc((newlen + 1) * sizeof(char));
|
||||
if(!newstr)
|
||||
return NULL;
|
||||
|
||||
/* Surround the string in quotes if necessary */
|
||||
p2 = newstr;
|
||||
if(space_exists) {
|
||||
newstr[0] = '"';
|
||||
newstr[newlen - 1] = '"';
|
||||
p2++;
|
||||
}
|
||||
|
||||
/* Copy the string, escaping backslash and quote characters along the way */
|
||||
p1 = str;
|
||||
while(*p1) {
|
||||
if(*p1 == '\\' || *p1 == '"') {
|
||||
*p2 = '\\';
|
||||
p2++;
|
||||
}
|
||||
|
||||
*p2 = *p1;
|
||||
|
||||
p1++;
|
||||
p2++;
|
||||
}
|
||||
|
||||
/* Terminate the string */
|
||||
newstr[newlen] = '\0';
|
||||
|
||||
return newstr;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* imap_is_bchar()
|
||||
@@ -2082,6 +2199,52 @@ static bool imap_is_bchar(char ch)
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* imap_parse_url_options()
|
||||
*
|
||||
* Parse the URL login options.
|
||||
*/
|
||||
static CURLcode imap_parse_url_options(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct imap_conn *imapc = &conn->proto.imapc;
|
||||
const char *options = conn->options;
|
||||
const char *ptr = options;
|
||||
|
||||
if(options) {
|
||||
const char *key = ptr;
|
||||
|
||||
while(*ptr && *ptr != '=')
|
||||
ptr++;
|
||||
|
||||
if(strnequal(key, "AUTH", 4)) {
|
||||
const char *value = ptr + 1;
|
||||
|
||||
if(strequal(value, "*"))
|
||||
imapc->prefmech = SASL_AUTH_ANY;
|
||||
else if(strequal(value, "LOGIN"))
|
||||
imapc->prefmech = SASL_MECH_LOGIN;
|
||||
else if(strequal(value, "PLAIN"))
|
||||
imapc->prefmech = SASL_MECH_PLAIN;
|
||||
else if(strequal(value, "CRAM-MD5"))
|
||||
imapc->prefmech = SASL_MECH_CRAM_MD5;
|
||||
else if(strequal(value, "DIGEST-MD5"))
|
||||
imapc->prefmech = SASL_MECH_DIGEST_MD5;
|
||||
else if(strequal(value, "GSSAPI"))
|
||||
imapc->prefmech = SASL_MECH_GSSAPI;
|
||||
else if(strequal(value, "NTLM"))
|
||||
imapc->prefmech = SASL_MECH_NTLM;
|
||||
else
|
||||
imapc->prefmech = SASL_AUTH_NONE;
|
||||
}
|
||||
else
|
||||
result = CURLE_URL_MALFORMAT;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* imap_parse_url_path()
|
||||
@@ -2192,6 +2355,12 @@ static CURLcode imap_parse_url_path(struct connectdata *conn)
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* imap_parse_custom_request()
|
||||
*
|
||||
* Parse the custom request.
|
||||
*/
|
||||
static CURLcode imap_parse_custom_request(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
@@ -2223,103 +2392,4 @@ static CURLcode imap_parse_custom_request(struct connectdata *conn)
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Call this when the DO phase has completed */
|
||||
static CURLcode imap_dophase_done(struct connectdata *conn, bool connected)
|
||||
{
|
||||
struct IMAP *imap = conn->data->state.proto.imap;
|
||||
|
||||
(void)connected;
|
||||
|
||||
if(imap->transfer != FTPTRANSFER_BODY)
|
||||
/* no data to transfer */
|
||||
Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/* Called from multi.c while DOing */
|
||||
static CURLcode imap_doing(struct connectdata *conn, bool *dophase_done)
|
||||
{
|
||||
CURLcode result = imap_multi_statemach(conn, dophase_done);
|
||||
|
||||
if(result)
|
||||
DEBUGF(infof(conn->data, "DO phase failed\n"));
|
||||
else if(*dophase_done) {
|
||||
result = imap_dophase_done(conn, FALSE /* not connected */);
|
||||
|
||||
DEBUGF(infof(conn->data, "DO phase is complete\n"));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* imap_regular_transfer()
|
||||
*
|
||||
* The input argument is already checked for validity.
|
||||
*
|
||||
* Performs all commands done before a regular transfer between a local and a
|
||||
* remote host.
|
||||
*/
|
||||
static CURLcode imap_regular_transfer(struct connectdata *conn,
|
||||
bool *dophase_done)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
bool connected = FALSE;
|
||||
struct SessionHandle *data = conn->data;
|
||||
|
||||
/* Make sure size is unknown at this point */
|
||||
data->req.size = -1;
|
||||
|
||||
/* Set the progress data */
|
||||
Curl_pgrsSetUploadCounter(data, 0);
|
||||
Curl_pgrsSetDownloadCounter(data, 0);
|
||||
Curl_pgrsSetUploadSize(data, 0);
|
||||
Curl_pgrsSetDownloadSize(data, 0);
|
||||
|
||||
/* Carry out the perform */
|
||||
result = imap_perform(conn, &connected, dophase_done);
|
||||
|
||||
/* Perform post DO phase operations if necessary */
|
||||
if(!result && *dophase_done)
|
||||
result = imap_dophase_done(conn, connected);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode imap_setup_connection(struct connectdata *conn)
|
||||
{
|
||||
struct SessionHandle *data = conn->data;
|
||||
|
||||
if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
|
||||
/* Unless we have asked to tunnel IMAP operations through the proxy, we
|
||||
switch and use HTTP operations only */
|
||||
#ifndef CURL_DISABLE_HTTP
|
||||
if(conn->handler == &Curl_handler_imap)
|
||||
conn->handler = &Curl_handler_imap_proxy;
|
||||
else {
|
||||
#ifdef USE_SSL
|
||||
conn->handler = &Curl_handler_imaps_proxy;
|
||||
#else
|
||||
failf(data, "IMAPS not supported!");
|
||||
return CURLE_UNSUPPORTED_PROTOCOL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* We explicitly mark this connection as persistent here as we're doing
|
||||
IMAP over HTTP and thus we accidentally avoid setting this value
|
||||
otherwise */
|
||||
conn->bits.close = FALSE;
|
||||
#else
|
||||
failf(data, "IMAP over http proxy requires HTTP support built-in!");
|
||||
return CURLE_UNSUPPORTED_PROTOCOL;
|
||||
#endif
|
||||
}
|
||||
|
||||
data->state.path++; /* don't include the initial slash */
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
#endif /* CURL_DISABLE_IMAP */
|
||||
|
@@ -76,6 +76,7 @@ struct imap_conn {
|
||||
imapstate state; /* Always use imap.c:state() to change state! */
|
||||
bool ssldone; /* Is connect() over SSL done? */
|
||||
unsigned int authmechs; /* Accepted authentication mechanisms */
|
||||
unsigned int prefmech; /* Preferred authentication mechanism */
|
||||
unsigned int authused; /* Auth mechanism used for the connection */
|
||||
int cmdid; /* Last used command ID */
|
||||
char resptag[5]; /* Response tag to wait for */
|
||||
|
@@ -5,7 +5,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -239,32 +239,6 @@ char *curl_dostrdup(const char *str, int line, const char *source)
|
||||
return mem;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
wchar_t *curl_dowcsdup(const wchar_t *str, int line, const char *source)
|
||||
{
|
||||
wchar_t *mem;
|
||||
size_t wsiz, bsiz;
|
||||
|
||||
assert(str != NULL);
|
||||
|
||||
if(countcheck("wcsdup", line, source))
|
||||
return NULL;
|
||||
|
||||
wsiz = wcslen(str) + 1;
|
||||
bsiz = wsiz * sizeof(wchar_t);
|
||||
|
||||
mem = curl_domalloc(bsiz, 0, NULL); /* NULL prevents logging */
|
||||
if(mem)
|
||||
memcpy(mem, str, bsiz);
|
||||
|
||||
if(source)
|
||||
curl_memlog("MEM %s:%d wcsdup(%p) (%zu) = %p\n",
|
||||
source, line, str, bsiz, mem);
|
||||
|
||||
return mem;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* We provide a realloc() that accepts a NULL as pointer, which then
|
||||
performs a malloc(). In order to work with ares. */
|
||||
void *curl_dorealloc(void *ptr, size_t wantedsize,
|
||||
|
@@ -8,7 +8,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -46,11 +46,6 @@ CURL_EXTERN void *curl_dorealloc(void *ptr, size_t size, int line,
|
||||
const char *source);
|
||||
CURL_EXTERN void curl_dofree(void *ptr, int line, const char *source);
|
||||
CURL_EXTERN char *curl_dostrdup(const char *str, int line, const char *source);
|
||||
#ifdef WIN32
|
||||
CURL_EXTERN wchar_t *curl_dowcsdup(const wchar_t *str, int line,
|
||||
const char *source);
|
||||
#endif
|
||||
|
||||
CURL_EXTERN void curl_memdebug(const char *logname);
|
||||
CURL_EXTERN void curl_memlimit(long limit);
|
||||
CURL_EXTERN void curl_memlog(const char *format, ...);
|
||||
@@ -89,19 +84,6 @@ CURL_EXTERN int curl_fclose(FILE *file, int line, const char *source);
|
||||
#define realloc(ptr,size) curl_dorealloc(ptr, size, __LINE__, __FILE__)
|
||||
#define free(ptr) curl_dofree(ptr, __LINE__, __FILE__)
|
||||
|
||||
#ifdef WIN32
|
||||
# undef wcsdup
|
||||
# define wcsdup(ptr) curl_dowcsdup(ptr, __LINE__, __FILE__)
|
||||
# undef _wcsdup
|
||||
# define _wcsdup(ptr) curl_dowcsdup(ptr, __LINE__, __FILE__)
|
||||
# undef _tcsdup
|
||||
# ifdef UNICODE
|
||||
# define _tcsdup(ptr) curl_dowcsdup(ptr, __LINE__, __FILE__)
|
||||
# else
|
||||
# define _tcsdup(ptr) curl_dostrdup(ptr, __LINE__, __FILE__)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define socket(domain,type,protocol)\
|
||||
curl_socket(domain,type,protocol,__LINE__,__FILE__)
|
||||
#undef accept /* for those with accept as a macro */
|
||||
|
103
lib/multi.c
103
lib/multi.c
@@ -58,6 +58,7 @@
|
||||
#define CURL_SOCKET_HASH_TABLE_SIZE 911
|
||||
#endif
|
||||
|
||||
#define CURL_CONNECTION_HASH_SIZE 97
|
||||
|
||||
#define CURL_MULTI_HANDLE 0x000bab1e
|
||||
|
||||
@@ -75,6 +76,8 @@ static bool isHandleAtHead(struct SessionHandle *handle,
|
||||
static CURLMcode add_next_timeout(struct timeval now,
|
||||
struct Curl_multi *multi,
|
||||
struct SessionHandle *d);
|
||||
static CURLMcode multi_timeout(struct Curl_multi *multi,
|
||||
long *timeout_ms);
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
static const char * const statename[]={
|
||||
@@ -246,9 +249,9 @@ static size_t hash_fd(void *key, size_t key_length, size_t slots_num)
|
||||
* per call."
|
||||
*
|
||||
*/
|
||||
static struct curl_hash *sh_init(void)
|
||||
static struct curl_hash *sh_init(int hashsize)
|
||||
{
|
||||
return Curl_hash_alloc(CURL_SOCKET_HASH_TABLE_SIZE, hash_fd, fd_key_compare,
|
||||
return Curl_hash_alloc(hashsize, hash_fd, fd_key_compare,
|
||||
sh_freeentry);
|
||||
}
|
||||
|
||||
@@ -278,7 +281,8 @@ static void multi_freeamsg(void *a, void *b)
|
||||
(void)b;
|
||||
}
|
||||
|
||||
CURLM *curl_multi_init(void)
|
||||
struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
|
||||
int chashsize) /* connection hash */
|
||||
{
|
||||
struct Curl_multi *multi = calloc(1, sizeof(struct Curl_multi));
|
||||
|
||||
@@ -291,11 +295,11 @@ CURLM *curl_multi_init(void)
|
||||
if(!multi->hostcache)
|
||||
goto error;
|
||||
|
||||
multi->sockhash = sh_init();
|
||||
multi->sockhash = sh_init(hashsize);
|
||||
if(!multi->sockhash)
|
||||
goto error;
|
||||
|
||||
multi->conn_cache = Curl_conncache_init();
|
||||
multi->conn_cache = Curl_conncache_init(chashsize);
|
||||
if(!multi->conn_cache)
|
||||
goto error;
|
||||
|
||||
@@ -325,6 +329,13 @@ CURLM *curl_multi_init(void)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CURLM *curl_multi_init(void)
|
||||
{
|
||||
return Curl_multi_handle(CURL_SOCKET_HASH_TABLE_SIZE,
|
||||
CURL_CONNECTION_HASH_SIZE);
|
||||
}
|
||||
|
||||
|
||||
CURLMcode curl_multi_add_handle(CURLM *multi_handle,
|
||||
CURL *easy_handle)
|
||||
{
|
||||
@@ -801,10 +812,18 @@ CURLMcode curl_multi_wait(CURLM *multi_handle,
|
||||
unsigned int nfds = 0;
|
||||
unsigned int curlfds;
|
||||
struct pollfd *ufds = NULL;
|
||||
long timeout_internal;
|
||||
|
||||
if(!GOOD_MULTI_HANDLE(multi))
|
||||
return CURLM_BAD_HANDLE;
|
||||
|
||||
/* If the internally desired timeout is actually shorter than requested from
|
||||
the outside, then use the shorter time! But only if the internal timer
|
||||
is actually larger than 0! */
|
||||
(void)multi_timeout(multi, &timeout_internal);
|
||||
if((timeout_internal > 0) && (timeout_internal < (long)timeout_ms))
|
||||
timeout_ms = (int)timeout_internal;
|
||||
|
||||
/* Count up how many fds we have from the multi handle */
|
||||
easy=multi->easy.next;
|
||||
while(easy != &multi->easy) {
|
||||
@@ -1520,14 +1539,15 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
||||
else
|
||||
follow = FOLLOW_RETRY;
|
||||
easy->result = Curl_done(&easy->easy_conn, CURLE_OK, FALSE);
|
||||
if(easy->result == CURLE_OK)
|
||||
easy->result = Curl_follow(data, newurl, follow);
|
||||
if(CURLE_OK == easy->result) {
|
||||
multistate(easy, CURLM_STATE_CONNECT);
|
||||
result = CURLM_CALL_MULTI_PERFORM;
|
||||
newurl = NULL; /* handed over the memory ownership to
|
||||
Curl_follow(), make sure we don't free() it
|
||||
here */
|
||||
easy->result = Curl_follow(data, newurl, follow);
|
||||
if(CURLE_OK == easy->result) {
|
||||
multistate(easy, CURLM_STATE_CONNECT);
|
||||
result = CURLM_CALL_MULTI_PERFORM;
|
||||
newurl = NULL; /* handed over the memory ownership to
|
||||
Curl_follow(), make sure we don't free() it
|
||||
here */
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -2031,6 +2051,39 @@ static void singlesocket(struct Curl_multi *multi,
|
||||
easy->numsocks = num;
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_multi_closed()
|
||||
*
|
||||
* Used by the connect code to tell the multi_socket code that one of the
|
||||
* sockets we were using have just been closed. This function will then
|
||||
* remove it from the sockethash for this handle to make the multi_socket API
|
||||
* behave properly, especially for the case when libcurl will create another
|
||||
* socket again and it gets the same file descriptor number.
|
||||
*/
|
||||
|
||||
void Curl_multi_closed(struct connectdata *conn, curl_socket_t s)
|
||||
{
|
||||
struct Curl_multi *multi = conn->data->multi;
|
||||
if(multi) {
|
||||
/* this is set if this connection is part of a handle that is added to
|
||||
a multi handle, and only then this is necessary */
|
||||
struct Curl_sh_entry *entry =
|
||||
Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s));
|
||||
|
||||
if(entry) {
|
||||
if(multi->socket_cb)
|
||||
multi->socket_cb(conn->data, s, CURL_POLL_REMOVE,
|
||||
multi->socket_userp,
|
||||
entry->socketp);
|
||||
|
||||
/* now remove it from the socket hash */
|
||||
sh_delentry(multi->sockhash, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* add_next_timeout()
|
||||
*
|
||||
@@ -2086,6 +2139,11 @@ static CURLMcode add_next_timeout(struct timeval now,
|
||||
return CURLM_OK;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
#define TIMEOUT_INACCURACY 40000
|
||||
#else
|
||||
#define TIMEOUT_INACCURACY 3000
|
||||
#endif
|
||||
|
||||
static CURLMcode multi_socket(struct Curl_multi *multi,
|
||||
bool checkall,
|
||||
@@ -2175,8 +2233,25 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
|
||||
}
|
||||
}
|
||||
|
||||
now.tv_usec += 40000; /* compensate for bad precision timers that might've
|
||||
triggered too early */
|
||||
/* Compensate for bad precision timers that might've triggered too early.
|
||||
|
||||
This precaution was added in commit 2c72732ebf3da5e as a result of bad
|
||||
resolution in the windows function use(d).
|
||||
|
||||
The problematic case here is when using the multi_socket API and libcurl
|
||||
has told the application about a timeout, and that timeout is what fires
|
||||
off a bit early. As we don't have any IDs associated with the timeout we
|
||||
can't tell which timeout that fired off but we only have the times to use
|
||||
to check what to do. If it fires off too early, we don't run the correct
|
||||
actions and we don't tell the application again about the same timeout as
|
||||
was already first in the queue...
|
||||
|
||||
Originally we made the timeouts run 40 milliseconds early on all systems,
|
||||
but now we have an #ifdef setup to provide a decent precaution inaccuracy
|
||||
margin.
|
||||
*/
|
||||
|
||||
now.tv_usec += TIMEOUT_INACCURACY;
|
||||
if(now.tv_usec >= 1000000) {
|
||||
now.tv_sec++;
|
||||
now.tv_usec -= 1000000;
|
||||
|
@@ -7,7 +7,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -22,6 +22,8 @@
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Prototypes for library-wide functions provided by multi.c
|
||||
*/
|
||||
@@ -30,6 +32,10 @@ void Curl_expire(struct SessionHandle *data, long milli);
|
||||
bool Curl_multi_pipeline_enabled(const struct Curl_multi* multi);
|
||||
void Curl_multi_handlePipeBreak(struct SessionHandle *data);
|
||||
|
||||
/* Internal version of curl_multi_init() accepts size parameters for the
|
||||
socket and connection hashes */
|
||||
struct Curl_multi *Curl_multi_handle(int hashsize, int chashsize);
|
||||
|
||||
/* the write bits start at bit 16 for the *getsock() bitmap */
|
||||
#define GETSOCK_WRITEBITSTART 16
|
||||
|
||||
@@ -77,4 +83,16 @@ struct curl_llist *Curl_multi_pipelining_server_bl(struct Curl_multi *multi);
|
||||
/* Return the value of the CURLMOPT_MAX_TOTAL_CONNECTIONS option */
|
||||
size_t Curl_multi_max_total_connections(struct Curl_multi *multi);
|
||||
|
||||
/*
|
||||
* Curl_multi_closed()
|
||||
*
|
||||
* Used by the connect code to tell the multi_socket code that one of the
|
||||
* sockets we were using have just been closed. This function will then
|
||||
* remove it from the sockethash for this handle to make the multi_socket API
|
||||
* behave properly, especially for the case when libcurl will create another
|
||||
* socket again and it gets the same file descriptor number.
|
||||
*/
|
||||
|
||||
void Curl_multi_closed(struct connectdata *conn, curl_socket_t s);
|
||||
|
||||
#endif /* HEADER_CURL_MULTIIF_H */
|
||||
|
11
lib/nss.c
11
lib/nss.c
@@ -1482,10 +1482,8 @@ static ssize_t nss_send(struct connectdata *conn, /* connection data */
|
||||
size_t len, /* amount to write */
|
||||
CURLcode *curlcode)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = PR_Send(conn->ssl[sockindex].handle, mem, (int)len, 0, -1);
|
||||
|
||||
ssize_t rc = PR_Send(conn->ssl[sockindex].handle, mem, (int)len, 0,
|
||||
PR_INTERVAL_NO_WAIT);
|
||||
if(rc < 0) {
|
||||
PRInt32 err = PR_GetError();
|
||||
if(err == PR_WOULD_BLOCK_ERROR)
|
||||
@@ -1513,9 +1511,8 @@ static ssize_t nss_recv(struct connectdata * conn, /* connection data */
|
||||
size_t buffersize, /* max amount to read */
|
||||
CURLcode *curlcode)
|
||||
{
|
||||
ssize_t nread;
|
||||
|
||||
nread = PR_Recv(conn->ssl[num].handle, buf, (int)buffersize, 0, -1);
|
||||
ssize_t nread = PR_Recv(conn->ssl[num].handle, buf, (int)buffersize, 0,
|
||||
PR_INTERVAL_NO_WAIT);
|
||||
if(nread < 0) {
|
||||
/* failed SSL read */
|
||||
PRInt32 err = PR_GetError();
|
||||
|
471
lib/pop3.c
471
lib/pop3.c
@@ -90,8 +90,6 @@
|
||||
#include "memdebug.h"
|
||||
|
||||
/* Local API functions */
|
||||
static CURLcode pop3_parse_url_path(struct connectdata *conn);
|
||||
static CURLcode pop3_parse_custom_request(struct connectdata *conn);
|
||||
static CURLcode pop3_regular_transfer(struct connectdata *conn, bool *done);
|
||||
static CURLcode pop3_do(struct connectdata *conn, bool *done);
|
||||
static CURLcode pop3_done(struct connectdata *conn, CURLcode status,
|
||||
@@ -103,6 +101,9 @@ static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks,
|
||||
int numsocks);
|
||||
static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done);
|
||||
static CURLcode pop3_setup_connection(struct connectdata *conn);
|
||||
static CURLcode pop3_parse_url_options(struct connectdata *conn);
|
||||
static CURLcode pop3_parse_url_path(struct connectdata *conn);
|
||||
static CURLcode pop3_parse_custom_request(struct connectdata *conn);
|
||||
|
||||
/*
|
||||
* POP3 protocol handler.
|
||||
@@ -216,10 +217,15 @@ static void pop3_to_pop3s(struct connectdata *conn)
|
||||
#define pop3_to_pop3s(x) Curl_nop_stmt
|
||||
#endif
|
||||
|
||||
/* Function that checks for an ending POP3 status code at the start of the
|
||||
given string, but also detects the APOP timestamp from the server greeting
|
||||
and various capabilities from the CAPA response including the supported
|
||||
authentication types and allowed SASL mechanisms. */
|
||||
/***********************************************************************
|
||||
*
|
||||
* pop3_endofresp()
|
||||
*
|
||||
* Checks for an ending POP3 status code at the start of the given string, but
|
||||
* also detects the APOP timestamp from the server greeting and various
|
||||
* capabilities from the CAPA response including the supported authentication
|
||||
* types and allowed SASL mechanisms.
|
||||
*/
|
||||
static bool pop3_endofresp(struct connectdata *conn, char *line, size_t len,
|
||||
int *resp)
|
||||
{
|
||||
@@ -340,7 +346,12 @@ static bool pop3_endofresp(struct connectdata *conn, char *line, size_t len,
|
||||
return FALSE; /* Nothing for us */
|
||||
}
|
||||
|
||||
/* This is the ONLY way to change POP3 state! */
|
||||
/***********************************************************************
|
||||
*
|
||||
* state()
|
||||
*
|
||||
* This is the ONLY way to change POP3 state!
|
||||
*/
|
||||
static void state(struct connectdata *conn, pop3state newstate)
|
||||
{
|
||||
struct pop3_conn *pop3c = &conn->proto.pop3c;
|
||||
@@ -377,7 +388,14 @@ static void state(struct connectdata *conn, pop3state newstate)
|
||||
pop3c->state = newstate;
|
||||
}
|
||||
|
||||
static CURLcode pop3_state_capa(struct connectdata *conn)
|
||||
/***********************************************************************
|
||||
*
|
||||
* pop3_perform_capa()
|
||||
*
|
||||
* Sends the CAPA command in order to obtain a list of server side supported
|
||||
* capabilities.
|
||||
*/
|
||||
static CURLcode pop3_perform_capa(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct pop3_conn *pop3c = &conn->proto.pop3c;
|
||||
@@ -395,7 +413,13 @@ static CURLcode pop3_state_capa(struct connectdata *conn)
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode pop3_state_starttls(struct connectdata *conn)
|
||||
/***********************************************************************
|
||||
*
|
||||
* pop3_perform_starttls()
|
||||
*
|
||||
* Sends the STLS command to start the upgrade to TLS.
|
||||
*/
|
||||
static CURLcode pop3_perform_starttls(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
@@ -408,7 +432,13 @@ static CURLcode pop3_state_starttls(struct connectdata *conn)
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode pop3_state_upgrade_tls(struct connectdata *conn)
|
||||
/***********************************************************************
|
||||
*
|
||||
* pop3_perform_upgrade_tls()
|
||||
*
|
||||
* Performs the upgrade to TLS.
|
||||
*/
|
||||
static CURLcode pop3_perform_upgrade_tls(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct pop3_conn *pop3c = &conn->proto.pop3c;
|
||||
@@ -422,14 +452,20 @@ static CURLcode pop3_state_upgrade_tls(struct connectdata *conn)
|
||||
|
||||
if(pop3c->ssldone) {
|
||||
pop3_to_pop3s(conn);
|
||||
result = pop3_state_capa(conn);
|
||||
result = pop3_perform_capa(conn);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode pop3_state_user(struct connectdata *conn)
|
||||
/***********************************************************************
|
||||
*
|
||||
* pop3_perform_user()
|
||||
*
|
||||
* Sends a clear text USER command to authenticate with.
|
||||
*/
|
||||
static CURLcode pop3_perform_user(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
@@ -451,7 +487,13 @@ static CURLcode pop3_state_user(struct connectdata *conn)
|
||||
}
|
||||
|
||||
#ifndef CURL_DISABLE_CRYPTO_AUTH
|
||||
static CURLcode pop3_state_apop(struct connectdata *conn)
|
||||
/***********************************************************************
|
||||
*
|
||||
* pop3_perform_apop()
|
||||
*
|
||||
* Sends an APOP command to authenticate with.
|
||||
*/
|
||||
static CURLcode pop3_perform_apop(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct pop3_conn *pop3c = &conn->proto.pop3c;
|
||||
@@ -495,12 +537,26 @@ static CURLcode pop3_state_apop(struct connectdata *conn)
|
||||
}
|
||||
#endif
|
||||
|
||||
static CURLcode pop3_authenticate(struct connectdata *conn)
|
||||
/***********************************************************************
|
||||
*
|
||||
* pop3_perform_authenticate()
|
||||
*
|
||||
* Sends an AUTH command allowing the client to login with the appropriate
|
||||
* SASL authentication mechanism.
|
||||
*
|
||||
* Additionally, the function will perform fallback to APOP and USER commands
|
||||
* should a common mechanism not be available between the client and server.
|
||||
*/
|
||||
static CURLcode pop3_perform_authenticate(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct SessionHandle *data = conn->data;
|
||||
struct pop3_conn *pop3c = &conn->proto.pop3c;
|
||||
const char *mech = NULL;
|
||||
pop3state authstate = POP3_STOP;
|
||||
char *initresp = NULL;
|
||||
size_t len = 0;
|
||||
pop3state state1 = POP3_STOP;
|
||||
pop3state state2 = POP3_STOP;
|
||||
|
||||
/* Check we have a username and password to authenticate with and end the
|
||||
connect phase if we don't */
|
||||
@@ -514,62 +570,158 @@ static CURLcode pop3_authenticate(struct connectdata *conn)
|
||||
security */
|
||||
if(pop3c->authtypes & POP3_TYPE_SASL) {
|
||||
#ifndef CURL_DISABLE_CRYPTO_AUTH
|
||||
if(pop3c->authmechs & SASL_MECH_DIGEST_MD5) {
|
||||
if((pop3c->authmechs & SASL_MECH_DIGEST_MD5) &&
|
||||
(pop3c->prefmech & SASL_MECH_DIGEST_MD5)) {
|
||||
mech = "DIGEST-MD5";
|
||||
authstate = POP3_AUTH_DIGESTMD5;
|
||||
state1 = POP3_AUTH_DIGESTMD5;
|
||||
pop3c->authused = SASL_MECH_DIGEST_MD5;
|
||||
}
|
||||
else if(pop3c->authmechs & SASL_MECH_CRAM_MD5) {
|
||||
else if((pop3c->authmechs & SASL_MECH_CRAM_MD5) &&
|
||||
(pop3c->prefmech & SASL_MECH_CRAM_MD5)) {
|
||||
mech = "CRAM-MD5";
|
||||
authstate = POP3_AUTH_CRAMMD5;
|
||||
state1 = POP3_AUTH_CRAMMD5;
|
||||
pop3c->authused = SASL_MECH_CRAM_MD5;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef USE_NTLM
|
||||
if(pop3c->authmechs & SASL_MECH_NTLM) {
|
||||
if((pop3c->authmechs & SASL_MECH_NTLM) &&
|
||||
(pop3c->prefmech & SASL_MECH_NTLM)) {
|
||||
mech = "NTLM";
|
||||
authstate = POP3_AUTH_NTLM;
|
||||
state1 = POP3_AUTH_NTLM;
|
||||
state2 = POP3_AUTH_NTLM_TYPE2MSG;
|
||||
pop3c->authused = SASL_MECH_NTLM;
|
||||
|
||||
if(data->set.sasl_ir)
|
||||
result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
|
||||
&conn->ntlm,
|
||||
&initresp, &len);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if(pop3c->authmechs & SASL_MECH_LOGIN) {
|
||||
if((pop3c->authmechs & SASL_MECH_LOGIN) &&
|
||||
(pop3c->prefmech & SASL_MECH_LOGIN)) {
|
||||
mech = "LOGIN";
|
||||
authstate = POP3_AUTH_LOGIN;
|
||||
state1 = POP3_AUTH_LOGIN;
|
||||
state2 = POP3_AUTH_LOGIN_PASSWD;
|
||||
pop3c->authused = SASL_MECH_LOGIN;
|
||||
|
||||
if(data->set.sasl_ir)
|
||||
result = Curl_sasl_create_login_message(conn->data, conn->user,
|
||||
&initresp, &len);
|
||||
}
|
||||
else if(pop3c->authmechs & SASL_MECH_PLAIN) {
|
||||
else if((pop3c->authmechs & SASL_MECH_PLAIN) &&
|
||||
(pop3c->prefmech & SASL_MECH_PLAIN)) {
|
||||
mech = "PLAIN";
|
||||
authstate = POP3_AUTH_PLAIN;
|
||||
state1 = POP3_AUTH_PLAIN;
|
||||
state2 = POP3_AUTH_FINAL;
|
||||
pop3c->authused = SASL_MECH_PLAIN;
|
||||
|
||||
if(data->set.sasl_ir)
|
||||
result = Curl_sasl_create_plain_message(conn->data, conn->user,
|
||||
conn->passwd, &initresp,
|
||||
&len);
|
||||
}
|
||||
}
|
||||
|
||||
if(mech) {
|
||||
/* Perform SASL based authentication */
|
||||
result = Curl_pp_sendf(&pop3c->pp, "AUTH %s", mech);
|
||||
if(!result) {
|
||||
if(mech && (pop3c->preftype & POP3_TYPE_SASL)) {
|
||||
/* Perform SASL based authentication */
|
||||
if(initresp &&
|
||||
8 + strlen(mech) + len <= 255) { /* AUTH <mech> ...<crlf> */
|
||||
result = Curl_pp_sendf(&pop3c->pp, "AUTH %s %s", mech, initresp);
|
||||
|
||||
if(!result)
|
||||
state(conn, authstate);
|
||||
}
|
||||
if(!result)
|
||||
state(conn, state2);
|
||||
}
|
||||
else {
|
||||
result = Curl_pp_sendf(&pop3c->pp, "AUTH %s", mech);
|
||||
|
||||
if(!result)
|
||||
state(conn, state1);
|
||||
}
|
||||
|
||||
Curl_safefree(initresp);
|
||||
}
|
||||
#ifndef CURL_DISABLE_CRYPTO_AUTH
|
||||
else if(pop3c->authtypes & POP3_TYPE_APOP)
|
||||
/* Perform APOP authentication */
|
||||
result = pop3_state_apop(conn);
|
||||
else if((pop3c->authtypes & POP3_TYPE_APOP) &&
|
||||
(pop3c->preftype & POP3_TYPE_APOP))
|
||||
/* Perform APOP authentication */
|
||||
result = pop3_perform_apop(conn);
|
||||
#endif
|
||||
else if(pop3c->authtypes & POP3_TYPE_CLEARTEXT)
|
||||
/* Perform clear text authentication */
|
||||
result = pop3_state_user(conn);
|
||||
else {
|
||||
/* Other mechanisms not supported */
|
||||
infof(conn->data, "No known authentication mechanisms supported!\n");
|
||||
result = CURLE_LOGIN_DENIED;
|
||||
else if((pop3c->authtypes & POP3_TYPE_CLEARTEXT) &&
|
||||
(pop3c->preftype & POP3_TYPE_CLEARTEXT))
|
||||
/* Perform clear text authentication */
|
||||
result = pop3_perform_user(conn);
|
||||
else {
|
||||
/* Other mechanisms not supported */
|
||||
infof(conn->data, "No known authentication mechanisms supported!\n");
|
||||
result = CURLE_LOGIN_DENIED;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* pop3_perform_command()
|
||||
*
|
||||
* Sends a POP3 based command.
|
||||
*/
|
||||
static CURLcode pop3_perform_command(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct SessionHandle *data = conn->data;
|
||||
struct POP3 *pop3 = data->state.proto.pop3;
|
||||
const char *command = NULL;
|
||||
|
||||
/* Calculate the default command */
|
||||
if(pop3->id[0] == '\0' || conn->data->set.ftp_list_only) {
|
||||
command = "LIST";
|
||||
|
||||
if(pop3->id[0] != '\0')
|
||||
/* Message specific LIST so skip the BODY transfer */
|
||||
pop3->transfer = FTPTRANSFER_INFO;
|
||||
}
|
||||
else
|
||||
command = "RETR";
|
||||
|
||||
/* Send the command */
|
||||
if(pop3->id[0] != '\0')
|
||||
result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s %s",
|
||||
(pop3->custom && pop3->custom[0] != '\0' ?
|
||||
pop3->custom : command), pop3->id);
|
||||
else
|
||||
result = Curl_pp_sendf(&conn->proto.pop3c.pp,
|
||||
(pop3->custom && pop3->custom[0] != '\0' ?
|
||||
pop3->custom : command));
|
||||
|
||||
if(!result)
|
||||
state(conn, POP3_COMMAND);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* pop3_perform_quit()
|
||||
*
|
||||
* Performs the quit action prior to sclose() be called.
|
||||
*/
|
||||
static CURLcode pop3_perform_quit(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
/* Send the QUIT command */
|
||||
result = Curl_pp_sendf(&conn->proto.pop3c.pp, "QUIT");
|
||||
|
||||
if(!result)
|
||||
state(conn, POP3_QUIT);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* For the initial server greeting */
|
||||
static CURLcode pop3_state_servergreet_resp(struct connectdata *conn,
|
||||
int pop3code,
|
||||
@@ -582,10 +734,10 @@ static CURLcode pop3_state_servergreet_resp(struct connectdata *conn,
|
||||
|
||||
if(pop3code != '+') {
|
||||
failf(data, "Got unexpected pop3-server response");
|
||||
return CURLE_FTP_WEIRD_SERVER_REPLY;
|
||||
result = CURLE_FTP_WEIRD_SERVER_REPLY;
|
||||
}
|
||||
|
||||
result = pop3_state_capa(conn);
|
||||
else
|
||||
result = pop3_perform_capa(conn);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -601,22 +753,22 @@ static CURLcode pop3_state_capa_resp(struct connectdata *conn, int pop3code,
|
||||
(void)instate; /* no use for this yet */
|
||||
|
||||
if(pop3code != '+')
|
||||
result = pop3_state_user(conn);
|
||||
result = pop3_perform_user(conn);
|
||||
else if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
|
||||
/* We don't have a SSL/TLS connection yet, but SSL is requested */
|
||||
if(pop3c->tls_supported)
|
||||
/* Switch to TLS connection now */
|
||||
result = pop3_state_starttls(conn);
|
||||
result = pop3_perform_starttls(conn);
|
||||
else if(data->set.use_ssl == CURLUSESSL_TRY)
|
||||
/* Fallback and carry on with authentication */
|
||||
result = pop3_authenticate(conn);
|
||||
result = pop3_perform_authenticate(conn);
|
||||
else {
|
||||
failf(data, "STLS not supported.");
|
||||
result = CURLE_USE_SSL_FAILED;
|
||||
}
|
||||
}
|
||||
else
|
||||
result = pop3_authenticate(conn);
|
||||
result = pop3_perform_authenticate(conn);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -637,15 +789,15 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn,
|
||||
result = CURLE_USE_SSL_FAILED;
|
||||
}
|
||||
else
|
||||
result = pop3_authenticate(conn);
|
||||
result = pop3_perform_authenticate(conn);
|
||||
}
|
||||
else
|
||||
result = pop3_state_upgrade_tls(conn);
|
||||
result = pop3_perform_upgrade_tls(conn);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* For AUTH PLAIN responses */
|
||||
/* For AUTH PLAIN (without initial response) responses */
|
||||
static CURLcode pop3_state_auth_plain_resp(struct connectdata *conn,
|
||||
int pop3code,
|
||||
pop3state instate)
|
||||
@@ -682,7 +834,7 @@ static CURLcode pop3_state_auth_plain_resp(struct connectdata *conn,
|
||||
return result;
|
||||
}
|
||||
|
||||
/* For AUTH LOGIN responses */
|
||||
/* For AUTH LOGIN (without initial response) responses */
|
||||
static CURLcode pop3_state_auth_login_resp(struct connectdata *conn,
|
||||
int pop3code,
|
||||
pop3state instate)
|
||||
@@ -879,7 +1031,7 @@ static CURLcode pop3_state_auth_digest_resp_resp(struct connectdata *conn,
|
||||
#endif
|
||||
|
||||
#ifdef USE_NTLM
|
||||
/* For AUTH NTLM responses */
|
||||
/* For AUTH NTLM (without initial response) responses */
|
||||
static CURLcode pop3_state_auth_ntlm_resp(struct connectdata *conn,
|
||||
int pop3code,
|
||||
pop3state instate)
|
||||
@@ -980,6 +1132,7 @@ static CURLcode pop3_state_auth_final_resp(struct connectdata *conn,
|
||||
}
|
||||
|
||||
#ifndef CURL_DISABLE_CRYPTO_AUTH
|
||||
/* For APOP responses */
|
||||
static CURLcode pop3_state_apop_resp(struct connectdata *conn, int pop3code,
|
||||
pop3state instate)
|
||||
{
|
||||
@@ -1043,41 +1196,6 @@ static CURLcode pop3_state_pass_resp(struct connectdata *conn, int pop3code,
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Start the DO phase for the command */
|
||||
static CURLcode pop3_command(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct SessionHandle *data = conn->data;
|
||||
struct POP3 *pop3 = data->state.proto.pop3;
|
||||
const char *command = NULL;
|
||||
|
||||
/* Calculate the default command */
|
||||
if(pop3->id[0] == '\0' || conn->data->set.ftp_list_only) {
|
||||
command = "LIST";
|
||||
|
||||
if(pop3->id[0] != '\0')
|
||||
/* Message specific LIST so skip the BODY transfer */
|
||||
pop3->transfer = FTPTRANSFER_INFO;
|
||||
}
|
||||
else
|
||||
command = "RETR";
|
||||
|
||||
/* Send the command */
|
||||
if(pop3->id[0] != '\0')
|
||||
result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s %s",
|
||||
(pop3->custom && pop3->custom[0] != '\0' ?
|
||||
pop3->custom : command), pop3->id);
|
||||
else
|
||||
result = Curl_pp_sendf(&conn->proto.pop3c.pp,
|
||||
(pop3->custom && pop3->custom[0] != '\0' ?
|
||||
pop3->custom : command));
|
||||
|
||||
if(!result)
|
||||
state(conn, POP3_COMMAND);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* For command responses */
|
||||
static CURLcode pop3_state_command_resp(struct connectdata *conn,
|
||||
int pop3code,
|
||||
@@ -1146,7 +1264,7 @@ static CURLcode pop3_statemach_act(struct connectdata *conn)
|
||||
|
||||
/* Busy upgrading the connection; right now all I/O is SSL/TLS, not POP3 */
|
||||
if(pop3c->state == POP3_UPGRADETLS)
|
||||
return pop3_state_upgrade_tls(conn);
|
||||
return pop3_perform_upgrade_tls(conn);
|
||||
|
||||
/* Flush any data that needs to be sent */
|
||||
if(pp->sendleft)
|
||||
@@ -1332,9 +1450,18 @@ static CURLcode pop3_connect(struct connectdata *conn, bool *done)
|
||||
pp->endofresp = pop3_endofresp;
|
||||
pp->conn = conn;
|
||||
|
||||
/* Set the default preferred authentication type and mechanism */
|
||||
pop3c->preftype = POP3_TYPE_ANY;
|
||||
pop3c->prefmech = SASL_AUTH_ANY;
|
||||
|
||||
/* Initialise the pingpong layer */
|
||||
Curl_pp_init(pp);
|
||||
|
||||
/* Parse the URL options */
|
||||
result = pop3_parse_url_options(conn);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
/* Start off waiting for the server greeting response */
|
||||
state(conn, POP3_SERVERGREET);
|
||||
|
||||
@@ -1407,7 +1534,7 @@ static CURLcode pop3_perform(struct connectdata *conn, bool *connected,
|
||||
*dophase_done = FALSE; /* not done yet */
|
||||
|
||||
/* Start the first command in the DO phase */
|
||||
result = pop3_command(conn);
|
||||
result = pop3_perform_command(conn);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
@@ -1461,25 +1588,6 @@ static CURLcode pop3_do(struct connectdata *conn, bool *done)
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* pop3_quit()
|
||||
*
|
||||
* Performs the quit action prior to sclose() be called.
|
||||
*/
|
||||
static CURLcode pop3_quit(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
/* Send the QUIT command */
|
||||
result = Curl_pp_sendf(&conn->proto.pop3c.pp, "QUIT");
|
||||
|
||||
if(!result)
|
||||
state(conn, POP3_QUIT);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* pop3_disconnect()
|
||||
@@ -1499,7 +1607,7 @@ static CURLcode pop3_disconnect(struct connectdata *conn,
|
||||
/* The POP3 session may or may not have been allocated/setup at this
|
||||
point! */
|
||||
if(!dead_connection && pop3c->pp.conn)
|
||||
if(!pop3_quit(conn))
|
||||
if(!pop3_perform_quit(conn))
|
||||
(void)pop3_block_statemach(conn); /* ignore errors on QUIT */
|
||||
|
||||
/* Disconnect from the server */
|
||||
@@ -1514,37 +1622,6 @@ static CURLcode pop3_disconnect(struct connectdata *conn,
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* pop3_parse_url_path()
|
||||
*
|
||||
* Parse the URL path into separate path components.
|
||||
*/
|
||||
static CURLcode pop3_parse_url_path(struct connectdata *conn)
|
||||
{
|
||||
/* The POP3 struct is already initialised in pop3_connect() */
|
||||
struct SessionHandle *data = conn->data;
|
||||
struct POP3 *pop3 = data->state.proto.pop3;
|
||||
const char *path = data->state.path;
|
||||
|
||||
/* URL decode the path for the message ID */
|
||||
return Curl_urldecode(data, path, 0, &pop3->id, NULL, TRUE);
|
||||
}
|
||||
|
||||
static CURLcode pop3_parse_custom_request(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct SessionHandle *data = conn->data;
|
||||
struct POP3 *pop3 = data->state.proto.pop3;
|
||||
const char *custom = data->set.str[STRING_CUSTOMREQUEST];
|
||||
|
||||
/* URL decode the custom request */
|
||||
if(custom)
|
||||
result = Curl_urldecode(data, custom, 0, &pop3->custom, NULL, TRUE);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Call this when the DO phase has completed */
|
||||
static CURLcode pop3_dophase_done(struct connectdata *conn, bool connected)
|
||||
{
|
||||
@@ -1639,8 +1716,116 @@ static CURLcode pop3_setup_connection(struct connectdata *conn)
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/* This function scans the body after the end-of-body and writes everything
|
||||
until the end is found */
|
||||
/***********************************************************************
|
||||
*
|
||||
* pop3_parse_url_options()
|
||||
*
|
||||
* Parse the URL login options.
|
||||
*/
|
||||
static CURLcode pop3_parse_url_options(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct pop3_conn *pop3c = &conn->proto.pop3c;
|
||||
const char *options = conn->options;
|
||||
const char *ptr = options;
|
||||
|
||||
if(options) {
|
||||
const char *key = ptr;
|
||||
|
||||
while(*ptr && *ptr != '=')
|
||||
ptr++;
|
||||
|
||||
if(strnequal(key, "AUTH", 4)) {
|
||||
const char *value = ptr + 1;
|
||||
|
||||
if(strequal(value, "*")) {
|
||||
pop3c->preftype = POP3_TYPE_ANY;
|
||||
pop3c->prefmech = SASL_AUTH_ANY;
|
||||
}
|
||||
else if(strequal(value, "+APOP")) {
|
||||
pop3c->preftype = POP3_TYPE_APOP;
|
||||
pop3c->prefmech = SASL_AUTH_NONE;
|
||||
}
|
||||
else if(strequal(value, "LOGIN")) {
|
||||
pop3c->preftype = POP3_TYPE_SASL;
|
||||
pop3c->prefmech = SASL_MECH_LOGIN;
|
||||
}
|
||||
else if(strequal(value, "PLAIN")) {
|
||||
pop3c->preftype = POP3_TYPE_SASL;
|
||||
pop3c->prefmech = SASL_MECH_PLAIN;
|
||||
}
|
||||
else if(strequal(value, "CRAM-MD5")) {
|
||||
pop3c->preftype = POP3_TYPE_SASL;
|
||||
pop3c->prefmech = SASL_MECH_CRAM_MD5;
|
||||
}
|
||||
else if(strequal(value, "DIGEST-MD5")) {
|
||||
pop3c->preftype = POP3_TYPE_SASL;
|
||||
pop3c->prefmech = SASL_MECH_DIGEST_MD5;
|
||||
}
|
||||
else if(strequal(value, "GSSAPI")) {
|
||||
pop3c->preftype = POP3_TYPE_SASL;
|
||||
pop3c->prefmech = SASL_MECH_GSSAPI;
|
||||
}
|
||||
else if(strequal(value, "NTLM")) {
|
||||
pop3c->preftype = POP3_TYPE_SASL;
|
||||
pop3c->prefmech = SASL_MECH_NTLM;
|
||||
}
|
||||
else {
|
||||
pop3c->preftype = POP3_TYPE_NONE;
|
||||
pop3c->prefmech = SASL_AUTH_NONE;
|
||||
}
|
||||
}
|
||||
else
|
||||
result = CURLE_URL_MALFORMAT;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* pop3_parse_url_path()
|
||||
*
|
||||
* Parse the URL path into separate path components.
|
||||
*/
|
||||
static CURLcode pop3_parse_url_path(struct connectdata *conn)
|
||||
{
|
||||
/* The POP3 struct is already initialised in pop3_connect() */
|
||||
struct SessionHandle *data = conn->data;
|
||||
struct POP3 *pop3 = data->state.proto.pop3;
|
||||
const char *path = data->state.path;
|
||||
|
||||
/* URL decode the path for the message ID */
|
||||
return Curl_urldecode(data, path, 0, &pop3->id, NULL, TRUE);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* pop3_parse_custom_request()
|
||||
*
|
||||
* Parse the custom request.
|
||||
*/
|
||||
static CURLcode pop3_parse_custom_request(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct SessionHandle *data = conn->data;
|
||||
struct POP3 *pop3 = data->state.proto.pop3;
|
||||
const char *custom = data->set.str[STRING_CUSTOMREQUEST];
|
||||
|
||||
/* URL decode the custom request */
|
||||
if(custom)
|
||||
result = Curl_urldecode(data, custom, 0, &pop3->custom, NULL, TRUE);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* Curl_pop3_write()
|
||||
*
|
||||
* This function scans the body after the end-of-body and writes everything
|
||||
* until the end is found.
|
||||
*/
|
||||
CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread)
|
||||
{
|
||||
/* This code could be made into a special function in the handler struct */
|
||||
|
14
lib/pop3.h
14
lib/pop3.h
@@ -72,8 +72,10 @@ struct pop3_conn {
|
||||
have been received so far */
|
||||
size_t strip; /* Number of bytes from the start to ignore as
|
||||
non-body */
|
||||
unsigned int authtypes; /* Supported authentication types */
|
||||
unsigned int authtypes; /* Accepted authentication types */
|
||||
unsigned int authmechs; /* Accepted SASL authentication mechanisms */
|
||||
unsigned int preftype; /* Preferred authentication type */
|
||||
unsigned int prefmech; /* Preferred SASL authentication mechanism */
|
||||
unsigned int authused; /* SASL auth mechanism used for the connection */
|
||||
char *apoptimestamp; /* APOP timestamp from the server greeting */
|
||||
bool tls_supported; /* StartTLS capability supported by server */
|
||||
@@ -83,9 +85,13 @@ extern const struct Curl_handler Curl_handler_pop3;
|
||||
extern const struct Curl_handler Curl_handler_pop3s;
|
||||
|
||||
/* Authentication type flags */
|
||||
#define POP3_TYPE_CLEARTEXT 0x0001
|
||||
#define POP3_TYPE_APOP 0x0002
|
||||
#define POP3_TYPE_SASL 0x0004
|
||||
#define POP3_TYPE_CLEARTEXT (1 << 0)
|
||||
#define POP3_TYPE_APOP (1 << 1)
|
||||
#define POP3_TYPE_SASL (1 << 2)
|
||||
|
||||
/* Authentication type values */
|
||||
#define POP3_TYPE_NONE 0
|
||||
#define POP3_TYPE_ANY ~0
|
||||
|
||||
/* This is the 5-bytes End-Of-Body marker for POP3 */
|
||||
#define POP3_EOB "\x0d\x0a\x2e\x0d\x0a"
|
||||
|
573
lib/smtp.c
573
lib/smtp.c
@@ -26,6 +26,7 @@
|
||||
* RFC4616 PLAIN authentication
|
||||
* RFC4954 SMTP Authentication
|
||||
* RFC5321 SMTP protocol
|
||||
* Draft SMTP URL Interface
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
@@ -99,6 +100,8 @@ static int smtp_getsock(struct connectdata *conn, curl_socket_t *socks,
|
||||
int numsocks);
|
||||
static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done);
|
||||
static CURLcode smtp_setup_connection(struct connectdata *conn);
|
||||
static CURLcode smtp_parse_url_options(struct connectdata *conn);
|
||||
static CURLcode smtp_parse_url_path(struct connectdata *conn);
|
||||
|
||||
/*
|
||||
* SMTP protocol handler.
|
||||
@@ -212,9 +215,14 @@ static void smtp_to_smtps(struct connectdata *conn)
|
||||
#define smtp_to_smtps(x) Curl_nop_stmt
|
||||
#endif
|
||||
|
||||
/* Function that checks for an ending SMTP status code at the start of the
|
||||
given string, but also detects various capabilities from the EHLO response
|
||||
including the supported authentication mechanisms. */
|
||||
/***********************************************************************
|
||||
*
|
||||
* pop3_endofresp()
|
||||
*
|
||||
* Checks for an ending SMTP status code at the start of the given string, but
|
||||
* also detects various capabilities from the EHLO response including the
|
||||
* supported authentication mechanisms.
|
||||
*/
|
||||
static bool smtp_endofresp(struct connectdata *conn, char *line, size_t len,
|
||||
int *resp)
|
||||
{
|
||||
@@ -292,7 +300,12 @@ static bool smtp_endofresp(struct connectdata *conn, char *line, size_t len,
|
||||
return result;
|
||||
}
|
||||
|
||||
/* This is the ONLY way to change SMTP state! */
|
||||
/***********************************************************************
|
||||
*
|
||||
* state()
|
||||
*
|
||||
* This is the ONLY way to change SMTP state!
|
||||
*/
|
||||
static void state(struct connectdata *conn, smtpstate newstate)
|
||||
{
|
||||
struct smtp_conn *smtpc = &conn->proto.smtpc;
|
||||
@@ -330,7 +343,14 @@ static void state(struct connectdata *conn, smtpstate newstate)
|
||||
smtpc->state = newstate;
|
||||
}
|
||||
|
||||
static CURLcode smtp_state_ehlo(struct connectdata *conn)
|
||||
/***********************************************************************
|
||||
*
|
||||
* smtp_perform_ehlo()
|
||||
*
|
||||
* Sends the EHLO command to not only initialise communication with the ESMTP
|
||||
* server but to also obtain a list of server side supported capabilities.
|
||||
*/
|
||||
static CURLcode smtp_perform_ehlo(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct smtp_conn *smtpc = &conn->proto.smtpc;
|
||||
@@ -349,7 +369,13 @@ static CURLcode smtp_state_ehlo(struct connectdata *conn)
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode smtp_state_helo(struct connectdata *conn)
|
||||
/***********************************************************************
|
||||
*
|
||||
* smtp_perform_helo()
|
||||
*
|
||||
* Sends the HELO command to initialise communication with the SMTP server.
|
||||
*/
|
||||
static CURLcode smtp_perform_helo(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct smtp_conn *smtpc = &conn->proto.smtpc;
|
||||
@@ -366,7 +392,13 @@ static CURLcode smtp_state_helo(struct connectdata *conn)
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode smtp_state_starttls(struct connectdata *conn)
|
||||
/***********************************************************************
|
||||
*
|
||||
* smtp_perform_starttls()
|
||||
*
|
||||
* Sends the STLS command to start the upgrade to TLS.
|
||||
*/
|
||||
static CURLcode smtp_perform_starttls(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
@@ -379,7 +411,13 @@ static CURLcode smtp_state_starttls(struct connectdata *conn)
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode smtp_state_upgrade_tls(struct connectdata *conn)
|
||||
/***********************************************************************
|
||||
*
|
||||
* smtp_perform_upgrade_tls()
|
||||
*
|
||||
* Performs the upgrade to TLS.
|
||||
*/
|
||||
static CURLcode smtp_perform_upgrade_tls(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct smtp_conn *smtpc = &conn->proto.smtpc;
|
||||
@@ -393,16 +431,24 @@ static CURLcode smtp_state_upgrade_tls(struct connectdata *conn)
|
||||
|
||||
if(smtpc->ssldone) {
|
||||
smtp_to_smtps(conn);
|
||||
result = smtp_state_ehlo(conn);
|
||||
result = smtp_perform_ehlo(conn);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode smtp_authenticate(struct connectdata *conn)
|
||||
/***********************************************************************
|
||||
*
|
||||
* smtp_perform_authenticate()
|
||||
*
|
||||
* Sends an AUTH command allowing the client to login with the appropriate
|
||||
* SASL authentication mechanism.
|
||||
*/
|
||||
static CURLcode smtp_perform_authenticate(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct SessionHandle *data = conn->data;
|
||||
struct smtp_conn *smtpc = &conn->proto.smtpc;
|
||||
const char *mech = NULL;
|
||||
char *initresp = NULL;
|
||||
@@ -421,12 +467,14 @@ static CURLcode smtp_authenticate(struct connectdata *conn)
|
||||
/* Calculate the supported authentication mechanism, by decreasing order of
|
||||
security, as well as the initial response where appropriate */
|
||||
#ifndef CURL_DISABLE_CRYPTO_AUTH
|
||||
if(smtpc->authmechs & SASL_MECH_DIGEST_MD5) {
|
||||
if((smtpc->authmechs & SASL_MECH_DIGEST_MD5) &&
|
||||
(smtpc->prefmech & SASL_MECH_DIGEST_MD5)) {
|
||||
mech = "DIGEST-MD5";
|
||||
state1 = SMTP_AUTH_DIGESTMD5;
|
||||
smtpc->authused = SASL_MECH_DIGEST_MD5;
|
||||
}
|
||||
else if(smtpc->authmechs & SASL_MECH_CRAM_MD5) {
|
||||
else if((smtpc->authmechs & SASL_MECH_CRAM_MD5) &&
|
||||
(smtpc->prefmech & SASL_MECH_CRAM_MD5)) {
|
||||
mech = "CRAM-MD5";
|
||||
state1 = SMTP_AUTH_CRAMMD5;
|
||||
smtpc->authused = SASL_MECH_CRAM_MD5;
|
||||
@@ -434,61 +482,196 @@ static CURLcode smtp_authenticate(struct connectdata *conn)
|
||||
else
|
||||
#endif
|
||||
#ifdef USE_NTLM
|
||||
if(smtpc->authmechs & SASL_MECH_NTLM) {
|
||||
if((smtpc->authmechs & SASL_MECH_NTLM) &&
|
||||
(smtpc->prefmech & SASL_MECH_NTLM)) {
|
||||
mech = "NTLM";
|
||||
state1 = SMTP_AUTH_NTLM;
|
||||
state2 = SMTP_AUTH_NTLM_TYPE2MSG;
|
||||
smtpc->authused = SASL_MECH_NTLM;
|
||||
result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
|
||||
&conn->ntlm,
|
||||
&initresp, &len);
|
||||
}
|
||||
|
||||
if(data->set.sasl_ir)
|
||||
result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
|
||||
&conn->ntlm,
|
||||
&initresp, &len);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if(smtpc->authmechs & SASL_MECH_LOGIN) {
|
||||
if((smtpc->authmechs & SASL_MECH_LOGIN) &&
|
||||
(smtpc->prefmech & SASL_MECH_LOGIN)) {
|
||||
mech = "LOGIN";
|
||||
state1 = SMTP_AUTH_LOGIN;
|
||||
state2 = SMTP_AUTH_LOGIN_PASSWD;
|
||||
smtpc->authused = SASL_MECH_LOGIN;
|
||||
result = Curl_sasl_create_login_message(conn->data, conn->user,
|
||||
&initresp, &len);
|
||||
|
||||
if(data->set.sasl_ir)
|
||||
result = Curl_sasl_create_login_message(conn->data, conn->user,
|
||||
&initresp, &len);
|
||||
}
|
||||
else if(smtpc->authmechs & SASL_MECH_PLAIN) {
|
||||
else if((smtpc->authmechs & SASL_MECH_PLAIN) &&
|
||||
(smtpc->prefmech & SASL_MECH_PLAIN)) {
|
||||
mech = "PLAIN";
|
||||
state1 = SMTP_AUTH_PLAIN;
|
||||
state2 = SMTP_AUTH_FINAL;
|
||||
smtpc->authused = SASL_MECH_PLAIN;
|
||||
result = Curl_sasl_create_plain_message(conn->data, conn->user,
|
||||
conn->passwd, &initresp, &len);
|
||||
}
|
||||
else {
|
||||
/* Other mechanisms not supported */
|
||||
infof(conn->data, "No known authentication mechanisms supported!\n");
|
||||
result = CURLE_LOGIN_DENIED;
|
||||
|
||||
if(data->set.sasl_ir)
|
||||
result = Curl_sasl_create_plain_message(conn->data, conn->user,
|
||||
conn->passwd, &initresp, &len);
|
||||
}
|
||||
|
||||
if(!result) {
|
||||
/* Perform SASL based authentication */
|
||||
if(initresp &&
|
||||
strlen(mech) + len <= 512 - 8) { /* AUTH <mech> ...<crlf> */
|
||||
result = Curl_pp_sendf(&smtpc->pp, "AUTH %s %s", mech, initresp);
|
||||
if(mech) {
|
||||
/* Perform SASL based authentication */
|
||||
if(initresp &&
|
||||
8 + strlen(mech) + len <= 512) { /* AUTH <mech> ...<crlf> */
|
||||
result = Curl_pp_sendf(&smtpc->pp, "AUTH %s %s", mech, initresp);
|
||||
|
||||
if(!result)
|
||||
state(conn, state2);
|
||||
if(!result)
|
||||
state(conn, state2);
|
||||
}
|
||||
else {
|
||||
result = Curl_pp_sendf(&smtpc->pp, "AUTH %s", mech);
|
||||
|
||||
if(!result)
|
||||
state(conn, state1);
|
||||
}
|
||||
|
||||
Curl_safefree(initresp);
|
||||
}
|
||||
else {
|
||||
result = Curl_pp_sendf(&smtpc->pp, "AUTH %s", mech);
|
||||
|
||||
if(!result)
|
||||
state(conn, state1);
|
||||
/* Other mechanisms not supported */
|
||||
infof(conn->data, "No known authentication mechanisms supported!\n");
|
||||
result = CURLE_LOGIN_DENIED;
|
||||
}
|
||||
|
||||
Curl_safefree(initresp);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* smtp_perform_mail()
|
||||
*
|
||||
* Sends an MAIL command to initiate the upload of a message.
|
||||
*/
|
||||
static CURLcode smtp_perform_mail(struct connectdata *conn)
|
||||
{
|
||||
char *from = NULL;
|
||||
char *auth = NULL;
|
||||
char *size = NULL;
|
||||
CURLcode result = CURLE_OK;
|
||||
struct SessionHandle *data = conn->data;
|
||||
|
||||
/* Calculate the FROM parameter */
|
||||
if(!data->set.str[STRING_MAIL_FROM])
|
||||
/* Null reverse-path, RFC-5321, sect. 3.6.3 */
|
||||
from = strdup("<>");
|
||||
else if(data->set.str[STRING_MAIL_FROM][0] == '<')
|
||||
from = aprintf("%s", data->set.str[STRING_MAIL_FROM]);
|
||||
else
|
||||
from = aprintf("<%s>", data->set.str[STRING_MAIL_FROM]);
|
||||
|
||||
if(!from)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
/* Calculate the optional AUTH parameter */
|
||||
if(data->set.str[STRING_MAIL_AUTH] && conn->proto.smtpc.authused) {
|
||||
if(data->set.str[STRING_MAIL_AUTH][0] != '\0')
|
||||
auth = aprintf("%s", data->set.str[STRING_MAIL_AUTH]);
|
||||
else
|
||||
/* Empty AUTH, RFC-2554, sect. 5 */
|
||||
auth = strdup("<>");
|
||||
|
||||
if(!auth) {
|
||||
Curl_safefree(from);
|
||||
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate the optional SIZE parameter */
|
||||
if(conn->proto.smtpc.size_supported && conn->data->set.infilesize > 0) {
|
||||
size = aprintf("%" FORMAT_OFF_T, data->set.infilesize);
|
||||
|
||||
if(!size) {
|
||||
Curl_safefree(from);
|
||||
Curl_safefree(auth);
|
||||
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
/* Send the MAIL command */
|
||||
if(!auth && !size)
|
||||
result = Curl_pp_sendf(&conn->proto.smtpc.pp,
|
||||
"MAIL FROM:%s", from);
|
||||
else if(auth && !size)
|
||||
result = Curl_pp_sendf(&conn->proto.smtpc.pp,
|
||||
"MAIL FROM:%s AUTH=%s", from, auth);
|
||||
else if(auth && size)
|
||||
result = Curl_pp_sendf(&conn->proto.smtpc.pp,
|
||||
"MAIL FROM:%s AUTH=%s SIZE=%s", from, auth, size);
|
||||
else
|
||||
result = Curl_pp_sendf(&conn->proto.smtpc.pp,
|
||||
"MAIL FROM:%s SIZE=%s", from, size);
|
||||
|
||||
Curl_safefree(from);
|
||||
Curl_safefree(auth);
|
||||
Curl_safefree(size);
|
||||
|
||||
if(!result)
|
||||
state(conn, SMTP_MAIL);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* smtp_perform_rcpt_to()
|
||||
*
|
||||
* Sends a RCPT TO command for a given recipient as part of the message upload
|
||||
* process.
|
||||
*/
|
||||
static CURLcode smtp_perform_rcpt_to(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct SessionHandle *data = conn->data;
|
||||
struct SMTP *smtp = data->state.proto.smtp;
|
||||
|
||||
/* Send the RCPT TO command */
|
||||
if(smtp->rcpt) {
|
||||
if(smtp->rcpt->data[0] == '<')
|
||||
result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:%s",
|
||||
smtp->rcpt->data);
|
||||
else
|
||||
result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:<%s>",
|
||||
smtp->rcpt->data);
|
||||
if(!result)
|
||||
state(conn, SMTP_RCPT);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* smtp_perform_quit()
|
||||
*
|
||||
* Performs the quit action prior to sclose() being called.
|
||||
*/
|
||||
static CURLcode smtp_perform_quit(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
/* Send the QUIT command */
|
||||
result = Curl_pp_sendf(&conn->proto.smtpc.pp, "QUIT");
|
||||
|
||||
if(!result)
|
||||
state(conn, SMTP_QUIT);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* For the initial server greeting */
|
||||
static CURLcode smtp_state_servergreet_resp(struct connectdata *conn,
|
||||
int smtpcode,
|
||||
@@ -501,10 +684,10 @@ static CURLcode smtp_state_servergreet_resp(struct connectdata *conn,
|
||||
|
||||
if(smtpcode/100 != 2) {
|
||||
failf(data, "Got unexpected smtp-server response: %d", smtpcode);
|
||||
return CURLE_FTP_WEIRD_SERVER_REPLY;
|
||||
result = CURLE_FTP_WEIRD_SERVER_REPLY;
|
||||
}
|
||||
|
||||
result = smtp_state_ehlo(conn);
|
||||
else
|
||||
result = smtp_perform_ehlo(conn);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -525,10 +708,10 @@ static CURLcode smtp_state_starttls_resp(struct connectdata *conn,
|
||||
result = CURLE_USE_SSL_FAILED;
|
||||
}
|
||||
else
|
||||
result = smtp_authenticate(conn);
|
||||
result = smtp_perform_authenticate(conn);
|
||||
}
|
||||
else
|
||||
result = smtp_state_upgrade_tls(conn);
|
||||
result = smtp_perform_upgrade_tls(conn);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -546,7 +729,7 @@ static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode,
|
||||
if(smtpcode/100 != 2) {
|
||||
if((data->set.use_ssl <= CURLUSESSL_TRY || conn->ssl[FIRSTSOCKET].use) &&
|
||||
!conn->bits.user_passwd)
|
||||
result = smtp_state_helo(conn);
|
||||
result = smtp_perform_helo(conn);
|
||||
else {
|
||||
failf(data, "Remote access denied: %d", smtpcode);
|
||||
result = CURLE_REMOTE_ACCESS_DENIED;
|
||||
@@ -556,17 +739,17 @@ static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode,
|
||||
/* We don't have a SSL/TLS connection yet, but SSL is requested */
|
||||
if(smtpc->tls_supported)
|
||||
/* Switch to TLS connection now */
|
||||
result = smtp_state_starttls(conn);
|
||||
result = smtp_perform_starttls(conn);
|
||||
else if(data->set.use_ssl == CURLUSESSL_TRY)
|
||||
/* Fallback and carry on with authentication */
|
||||
result = smtp_authenticate(conn);
|
||||
result = smtp_perform_authenticate(conn);
|
||||
else {
|
||||
failf(data, "STARTTLS not supported.");
|
||||
result = CURLE_USE_SSL_FAILED;
|
||||
}
|
||||
}
|
||||
else
|
||||
result = smtp_authenticate(conn);
|
||||
result = smtp_perform_authenticate(conn);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -926,99 +1109,6 @@ static CURLcode smtp_state_auth_final_resp(struct connectdata *conn,
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Start the DO phase */
|
||||
static CURLcode smtp_mail(struct connectdata *conn)
|
||||
{
|
||||
char *from = NULL;
|
||||
char *auth = NULL;
|
||||
char *size = NULL;
|
||||
CURLcode result = CURLE_OK;
|
||||
struct SessionHandle *data = conn->data;
|
||||
|
||||
/* Calculate the FROM parameter */
|
||||
if(!data->set.str[STRING_MAIL_FROM])
|
||||
/* Null reverse-path, RFC-2821, sect. 3.7 */
|
||||
from = strdup("<>");
|
||||
else if(data->set.str[STRING_MAIL_FROM][0] == '<')
|
||||
from = aprintf("%s", data->set.str[STRING_MAIL_FROM]);
|
||||
else
|
||||
from = aprintf("<%s>", data->set.str[STRING_MAIL_FROM]);
|
||||
|
||||
if(!from)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
/* Calculate the optional AUTH parameter */
|
||||
if(data->set.str[STRING_MAIL_AUTH] && conn->proto.smtpc.authused) {
|
||||
if(data->set.str[STRING_MAIL_AUTH][0] != '\0')
|
||||
auth = aprintf("%s", data->set.str[STRING_MAIL_AUTH]);
|
||||
else
|
||||
/* Empty AUTH, RFC-2554, sect. 5 */
|
||||
auth = strdup("<>");
|
||||
|
||||
if(!auth) {
|
||||
Curl_safefree(from);
|
||||
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
/* calculate the optional SIZE parameter */
|
||||
if(conn->proto.smtpc.size_supported && conn->data->set.infilesize > 0) {
|
||||
size = aprintf("%" FORMAT_OFF_T, data->set.infilesize);
|
||||
|
||||
if(!size) {
|
||||
Curl_safefree(from);
|
||||
Curl_safefree(auth);
|
||||
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
/* Send the MAIL command */
|
||||
if(!auth && !size)
|
||||
result = Curl_pp_sendf(&conn->proto.smtpc.pp,
|
||||
"MAIL FROM:%s", from);
|
||||
else if(auth && !size)
|
||||
result = Curl_pp_sendf(&conn->proto.smtpc.pp,
|
||||
"MAIL FROM:%s AUTH=%s", from, auth);
|
||||
else if(auth && size)
|
||||
result = Curl_pp_sendf(&conn->proto.smtpc.pp,
|
||||
"MAIL FROM:%s AUTH=%s SIZE=%s", from, auth, size);
|
||||
else
|
||||
result = Curl_pp_sendf(&conn->proto.smtpc.pp,
|
||||
"MAIL FROM:%s SIZE=%s", from, size);
|
||||
|
||||
Curl_safefree(from);
|
||||
Curl_safefree(auth);
|
||||
Curl_safefree(size);
|
||||
|
||||
if(!result)
|
||||
state(conn, SMTP_MAIL);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode smtp_rcpt_to(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct SessionHandle *data = conn->data;
|
||||
struct SMTP *smtp = data->state.proto.smtp;
|
||||
|
||||
/* Send the RCPT TO command */
|
||||
if(smtp->rcpt) {
|
||||
if(smtp->rcpt->data[0] == '<')
|
||||
result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:%s",
|
||||
smtp->rcpt->data);
|
||||
else
|
||||
result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:<%s>",
|
||||
smtp->rcpt->data);
|
||||
if(!result)
|
||||
state(conn, SMTP_RCPT);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* For MAIL responses */
|
||||
static CURLcode smtp_state_mail_resp(struct connectdata *conn, int smtpcode,
|
||||
smtpstate instate)
|
||||
@@ -1037,7 +1127,7 @@ static CURLcode smtp_state_mail_resp(struct connectdata *conn, int smtpcode,
|
||||
else {
|
||||
smtp->rcpt = data->set.mail_rcpt;
|
||||
|
||||
result = smtp_rcpt_to(conn);
|
||||
result = smtp_perform_rcpt_to(conn);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -1061,7 +1151,7 @@ static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, int smtpcode,
|
||||
else {
|
||||
if(smtp->rcpt) {
|
||||
smtp->rcpt = smtp->rcpt->next;
|
||||
result = smtp_rcpt_to(conn);
|
||||
result = smtp_perform_rcpt_to(conn);
|
||||
|
||||
/* If we failed or still are sending RCPT data then return */
|
||||
if(result || smtp->rcpt)
|
||||
@@ -1082,6 +1172,8 @@ static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, int smtpcode,
|
||||
static CURLcode smtp_state_data_resp(struct connectdata *conn, int smtpcode,
|
||||
smtpstate instate)
|
||||
{
|
||||
struct SessionHandle *data = conn->data;
|
||||
|
||||
(void)instate; /* no use for this yet */
|
||||
|
||||
if(smtpcode != 354) {
|
||||
@@ -1089,6 +1181,9 @@ static CURLcode smtp_state_data_resp(struct connectdata *conn, int smtpcode,
|
||||
return CURLE_SEND_ERROR;
|
||||
}
|
||||
|
||||
/* Set the progress upload size */
|
||||
Curl_pgrsSetUploadSize(data, data->set.infilesize);
|
||||
|
||||
/* SMTP upload */
|
||||
Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL);
|
||||
|
||||
@@ -1129,7 +1224,7 @@ static CURLcode smtp_statemach_act(struct connectdata *conn)
|
||||
|
||||
/* Busy upgrading the connection; right now all I/O is SSL/TLS, not SMTP */
|
||||
if(smtpc->state == SMTP_UPGRADETLS)
|
||||
return smtp_state_upgrade_tls(conn);
|
||||
return smtp_perform_upgrade_tls(conn);
|
||||
|
||||
/* Flush any data that needs to be sent */
|
||||
if(pp->sendleft)
|
||||
@@ -1300,8 +1395,6 @@ static CURLcode smtp_connect(struct connectdata *conn, bool *done)
|
||||
CURLcode result = CURLE_OK;
|
||||
struct smtp_conn *smtpc = &conn->proto.smtpc;
|
||||
struct pingpong *pp = &smtpc->pp;
|
||||
const char *path = conn->data->state.path;
|
||||
char localhost[HOSTNAME_MAX + 1];
|
||||
|
||||
*done = FALSE; /* default to not done yet */
|
||||
|
||||
@@ -1323,19 +1416,19 @@ static CURLcode smtp_connect(struct connectdata *conn, bool *done)
|
||||
pp->endofresp = smtp_endofresp;
|
||||
pp->conn = conn;
|
||||
|
||||
/* Set the default preferred authentication mechanism */
|
||||
smtpc->prefmech = SASL_AUTH_ANY;
|
||||
|
||||
/* Initialise the pingpong layer */
|
||||
Curl_pp_init(pp);
|
||||
|
||||
/* Calculate the path if necessary */
|
||||
if(!*path) {
|
||||
if(!Curl_gethostname(localhost, sizeof(localhost)))
|
||||
path = localhost;
|
||||
else
|
||||
path = "localhost";
|
||||
}
|
||||
/* Parse the URL options */
|
||||
result = smtp_parse_url_options(conn);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
/* URL decode the path and use it as the domain in our EHLO */
|
||||
result = Curl_urldecode(conn->data, path, 0, &smtpc->domain, NULL, TRUE);
|
||||
/* Parse the URL path */
|
||||
result = smtp_parse_url_path(conn);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
@@ -1362,6 +1455,9 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
|
||||
CURLcode result = CURLE_OK;
|
||||
struct SessionHandle *data = conn->data;
|
||||
struct SMTP *smtp = data->state.proto.smtp;
|
||||
struct pingpong *pp = &conn->proto.smtpc.pp;
|
||||
const char *eob;
|
||||
ssize_t len;
|
||||
ssize_t bytes_written;
|
||||
|
||||
(void)premature;
|
||||
@@ -1378,25 +1474,27 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
|
||||
result = status; /* use the already set error code */
|
||||
}
|
||||
else if(!data->set.connect_only) {
|
||||
struct smtp_conn *smtpc = &conn->proto.smtpc;
|
||||
struct pingpong *pp = &smtpc->pp;
|
||||
/* Calculate the EOB taking into account any terminating CRLF from the
|
||||
previous line of the email or the CRLF of the DATA command when there
|
||||
is "no mail data". RFC-5321, sect. 4.1.1.4. */
|
||||
eob = SMTP_EOB;
|
||||
len = SMTP_EOB_LEN;
|
||||
if(smtp->trailing_crlf || !conn->data->set.infilesize) {
|
||||
eob += 2;
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
/* Send the end of block data */
|
||||
result = Curl_write(conn,
|
||||
conn->writesockfd, /* socket to send to */
|
||||
SMTP_EOB, /* buffer pointer */
|
||||
SMTP_EOB_LEN, /* buffer size */
|
||||
&bytes_written); /* actually sent away */
|
||||
|
||||
result = Curl_write(conn, conn->writesockfd, eob, len, &bytes_written);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
if(bytes_written != SMTP_EOB_LEN) {
|
||||
if(bytes_written != len) {
|
||||
/* The whole chunk was not sent so keep it around and adjust the
|
||||
pingpong structure accordingly */
|
||||
pp->sendthis = strdup(SMTP_EOB);
|
||||
pp->sendsize = SMTP_EOB_LEN;
|
||||
pp->sendleft = SMTP_EOB_LEN - bytes_written;
|
||||
pp->sendthis = strdup(eob);
|
||||
pp->sendsize = len;
|
||||
pp->sendleft = len - bytes_written;
|
||||
}
|
||||
else
|
||||
/* Successfully sent so adjust the response timeout relative to now */
|
||||
@@ -1444,7 +1542,7 @@ static CURLcode smtp_perform(struct connectdata *conn, bool *connected,
|
||||
*dophase_done = FALSE; /* not done yet */
|
||||
|
||||
/* Start the first command in the DO phase */
|
||||
result = smtp_mail(conn);
|
||||
result = smtp_perform_mail(conn);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
@@ -1488,25 +1586,6 @@ static CURLcode smtp_do(struct connectdata *conn, bool *done)
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* smtp_quit()
|
||||
*
|
||||
* Performs the quit action prior to sclose() being called.
|
||||
*/
|
||||
static CURLcode smtp_quit(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
/* Send the QUIT command */
|
||||
result = Curl_pp_sendf(&conn->proto.smtpc.pp, "QUIT");
|
||||
|
||||
if(!result)
|
||||
state(conn, SMTP_QUIT);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* smtp_disconnect()
|
||||
@@ -1526,7 +1605,7 @@ static CURLcode smtp_disconnect(struct connectdata *conn,
|
||||
/* The SMTP session may or may not have been allocated/setup at this
|
||||
point! */
|
||||
if(!dead_connection && smtpc->pp.conn)
|
||||
if(!smtp_quit(conn))
|
||||
if(!smtp_perform_quit(conn))
|
||||
(void)smtp_block_statemach(conn); /* ignore errors on QUIT */
|
||||
|
||||
/* Disconnect from the server */
|
||||
@@ -1640,18 +1719,90 @@ static CURLcode smtp_setup_connection(struct connectdata *conn)
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* smtp_parse_url_options()
|
||||
*
|
||||
* Parse the URL login options.
|
||||
*/
|
||||
static CURLcode smtp_parse_url_options(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct smtp_conn *smtpc = &conn->proto.smtpc;
|
||||
const char *options = conn->options;
|
||||
const char *ptr = options;
|
||||
|
||||
if(options) {
|
||||
const char *key = ptr;
|
||||
|
||||
while(*ptr && *ptr != '=')
|
||||
ptr++;
|
||||
|
||||
if(strnequal(key, "AUTH", 4)) {
|
||||
const char *value = ptr + 1;
|
||||
|
||||
if(strequal(value, "*"))
|
||||
smtpc->prefmech = SASL_AUTH_ANY;
|
||||
else if(strequal(value, "LOGIN"))
|
||||
smtpc->prefmech = SASL_MECH_LOGIN;
|
||||
else if(strequal(value, "PLAIN"))
|
||||
smtpc->prefmech = SASL_MECH_PLAIN;
|
||||
else if(strequal(value, "CRAM-MD5"))
|
||||
smtpc->prefmech = SASL_MECH_CRAM_MD5;
|
||||
else if(strequal(value, "DIGEST-MD5"))
|
||||
smtpc->prefmech = SASL_MECH_DIGEST_MD5;
|
||||
else if(strequal(value, "GSSAPI"))
|
||||
smtpc->prefmech = SASL_MECH_GSSAPI;
|
||||
else if(strequal(value, "NTLM"))
|
||||
smtpc->prefmech = SASL_MECH_NTLM;
|
||||
else
|
||||
smtpc->prefmech = SASL_AUTH_NONE;
|
||||
}
|
||||
else
|
||||
result = CURLE_URL_MALFORMAT;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* smtp_parse_url_path()
|
||||
*
|
||||
* Parse the URL path into separate path components.
|
||||
*/
|
||||
static CURLcode smtp_parse_url_path(struct connectdata *conn)
|
||||
{
|
||||
/* The SMTP struct is already initialised in smtp_connect() */
|
||||
struct SessionHandle *data = conn->data;
|
||||
struct smtp_conn *smtpc = &conn->proto.smtpc;
|
||||
const char *path = data->state.path;
|
||||
char localhost[HOSTNAME_MAX + 1];
|
||||
|
||||
/* Calculate the path if necessary */
|
||||
if(!*path) {
|
||||
if(!Curl_gethostname(localhost, sizeof(localhost)))
|
||||
path = localhost;
|
||||
else
|
||||
path = "localhost";
|
||||
}
|
||||
|
||||
/* URL decode the path and use it as the domain in our EHLO */
|
||||
return Curl_urldecode(conn->data, path, 0, &smtpc->domain, NULL, TRUE);
|
||||
}
|
||||
|
||||
CURLcode Curl_smtp_escape_eob(struct connectdata *conn, ssize_t nread)
|
||||
{
|
||||
/* When sending a SMTP payload we must detect CRLF. sequences making sure
|
||||
they are sent as CRLF.. instead, as a . on the beginning of a line will
|
||||
be deleted by the server when not part of an EOB terminator and a
|
||||
genuine CRLF.CRLF which isn't escaped will wrongly be detected as end of
|
||||
data by the server.
|
||||
data by the server
|
||||
*/
|
||||
ssize_t i;
|
||||
ssize_t si;
|
||||
struct smtp_conn *smtpc = &conn->proto.smtpc;
|
||||
struct SessionHandle *data = conn->data;
|
||||
struct SMTP *smtp = data->state.proto.smtp;
|
||||
|
||||
/* Do we need to allocate the scatch buffer? */
|
||||
if(!data->state.scratch) {
|
||||
@@ -1666,36 +1817,46 @@ CURLcode Curl_smtp_escape_eob(struct connectdata *conn, ssize_t nread)
|
||||
/* This loop can be improved by some kind of Boyer-Moore style of
|
||||
approach but that is saved for later... */
|
||||
for(i = 0, si = 0; i < nread; i++) {
|
||||
if(SMTP_EOB[smtpc->eob] == data->req.upload_fromhere[i])
|
||||
smtpc->eob++;
|
||||
else if(smtpc->eob) {
|
||||
if(SMTP_EOB[smtp->eob] == data->req.upload_fromhere[i]) {
|
||||
smtp->eob++;
|
||||
|
||||
/* Is the EOB potentially the terminating CRLF? */
|
||||
if(2 == smtp->eob || SMTP_EOB_LEN == smtp->eob)
|
||||
smtp->trailing_crlf = TRUE;
|
||||
else
|
||||
smtp->trailing_crlf = FALSE;
|
||||
}
|
||||
else if(smtp->eob) {
|
||||
/* A previous substring matched so output that first */
|
||||
memcpy(&data->state.scratch[si], SMTP_EOB, smtpc->eob);
|
||||
si += smtpc->eob;
|
||||
memcpy(&data->state.scratch[si], SMTP_EOB, smtp->eob);
|
||||
si += smtp->eob;
|
||||
|
||||
/* Then compare the first byte */
|
||||
if(SMTP_EOB[0] == data->req.upload_fromhere[i])
|
||||
smtpc->eob = 1;
|
||||
smtp->eob = 1;
|
||||
else
|
||||
smtpc->eob = 0;
|
||||
smtp->eob = 0;
|
||||
|
||||
/* Reset the trailing CRLF flag as there was more data */
|
||||
smtp->trailing_crlf = FALSE;
|
||||
}
|
||||
|
||||
/* Do we have a match for CRLF. as per RFC-2821, sect. 4.5.2 */
|
||||
if(SMTP_EOB_FIND_LEN == smtpc->eob) {
|
||||
/* Do we have a match for CRLF. as per RFC-5321, sect. 4.5.2 */
|
||||
if(SMTP_EOB_FIND_LEN == smtp->eob) {
|
||||
/* Copy the replacement data to the target buffer */
|
||||
memcpy(&data->state.scratch[si], SMTP_EOB_REPL, SMTP_EOB_REPL_LEN);
|
||||
si += SMTP_EOB_REPL_LEN;
|
||||
smtpc->eob = 0;
|
||||
smtp->eob = 0;
|
||||
}
|
||||
else if(!smtpc->eob)
|
||||
else if(!smtp->eob)
|
||||
data->state.scratch[si++] = data->req.upload_fromhere[i];
|
||||
}
|
||||
|
||||
if(smtpc->eob) {
|
||||
if(smtp->eob) {
|
||||
/* A substring matched before processing ended so output that now */
|
||||
memcpy(&data->state.scratch[si], SMTP_EOB, smtpc->eob);
|
||||
si += smtpc->eob;
|
||||
smtpc->eob = 0;
|
||||
memcpy(&data->state.scratch[si], SMTP_EOB, smtp->eob);
|
||||
si += smtp->eob;
|
||||
smtp->eob = 0;
|
||||
}
|
||||
|
||||
if(si != nread) {
|
||||
|
@@ -60,6 +60,9 @@ typedef enum {
|
||||
struct SMTP {
|
||||
curl_pp_transfer transfer;
|
||||
struct curl_slist *rcpt; /* Recipient list */
|
||||
size_t eob; /* Number of bytes of the EOB (End Of Body) that
|
||||
have been received so far */
|
||||
bool trailing_crlf; /* Specifies if the tailing CRLF is present */
|
||||
};
|
||||
|
||||
/* smtp_conn is used for struct connection-oriented data in the connectdata
|
||||
@@ -69,9 +72,8 @@ struct smtp_conn {
|
||||
smtpstate state; /* Always use smtp.c:state() to change state! */
|
||||
bool ssldone; /* Is connect() over SSL done? */
|
||||
char *domain; /* Client address/name to send in the EHLO */
|
||||
size_t eob; /* Number of bytes of the EOB (End Of Body) that
|
||||
have been received so far */
|
||||
unsigned int authmechs; /* Accepted authentication mechanisms */
|
||||
unsigned int prefmech; /* Preferred authentication mechanism */
|
||||
unsigned int authused; /* Auth mechanism used for the connection */
|
||||
bool tls_supported; /* StartTLS capability supported by server */
|
||||
bool size_supported; /* If server supports SIZE extension according to
|
||||
|
62
lib/ssluse.c
62
lib/ssluse.c
@@ -435,7 +435,7 @@ int cert_stuff(struct connectdata *conn,
|
||||
PKCS12_PBE_add();
|
||||
|
||||
if(!PKCS12_parse(p12, data->set.str[STRING_KEY_PASSWD], &pri, &x509,
|
||||
&ca)) {
|
||||
&ca)) {
|
||||
failf(data,
|
||||
"could not parse PKCS12 file, check password, OpenSSL error %s",
|
||||
ERR_error_string(ERR_get_error(), NULL) );
|
||||
@@ -447,54 +447,53 @@ int cert_stuff(struct connectdata *conn,
|
||||
|
||||
if(SSL_CTX_use_certificate(ctx, x509) != 1) {
|
||||
failf(data, SSL_CLIENT_CERT_ERR);
|
||||
EVP_PKEY_free(pri);
|
||||
X509_free(x509);
|
||||
sk_X509_pop_free(ca, X509_free);
|
||||
return 0;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if(SSL_CTX_use_PrivateKey(ctx, pri) != 1) {
|
||||
failf(data, "unable to use private key from PKCS12 file '%s'",
|
||||
cert_file);
|
||||
EVP_PKEY_free(pri);
|
||||
X509_free(x509);
|
||||
sk_X509_pop_free(ca, X509_free);
|
||||
return 0;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if(!SSL_CTX_check_private_key (ctx)) {
|
||||
failf(data, "private key from PKCS12 file '%s' "
|
||||
"does not match certificate in same file", cert_file);
|
||||
EVP_PKEY_free(pri);
|
||||
X509_free(x509);
|
||||
sk_X509_pop_free(ca, X509_free);
|
||||
return 0;
|
||||
goto fail;
|
||||
}
|
||||
/* Set Certificate Verification chain */
|
||||
if(ca && sk_X509_num(ca)) {
|
||||
for(i = 0; i < sk_X509_num(ca); i++) {
|
||||
if(!SSL_CTX_add_extra_chain_cert(ctx,sk_X509_value(ca, i))) {
|
||||
/*
|
||||
* Note that sk_X509_pop() is used below to make sure the cert is
|
||||
* removed from the stack properly before getting passed to
|
||||
* SSL_CTX_add_extra_chain_cert(). Previously we used
|
||||
* sk_X509_value() instead, but then we'd clean it in the subsequent
|
||||
* sk_X509_pop_free() call.
|
||||
*/
|
||||
X509 *x = sk_X509_pop(ca);
|
||||
if(!SSL_CTX_add_extra_chain_cert(ctx, x)) {
|
||||
failf(data, "cannot add certificate to certificate chain");
|
||||
EVP_PKEY_free(pri);
|
||||
X509_free(x509);
|
||||
sk_X509_pop_free(ca, X509_free);
|
||||
return 0;
|
||||
goto fail;
|
||||
}
|
||||
if(!SSL_CTX_add_client_CA(ctx, sk_X509_value(ca, i))) {
|
||||
/* SSL_CTX_add_client_CA() seems to work with either sk_* function,
|
||||
* presumably because it duplicates what we pass to it.
|
||||
*/
|
||||
if(!SSL_CTX_add_client_CA(ctx, x)) {
|
||||
failf(data, "cannot add certificate to client CA list");
|
||||
EVP_PKEY_free(pri);
|
||||
X509_free(x509);
|
||||
sk_X509_pop_free(ca, X509_free);
|
||||
return 0;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cert_done = 1;
|
||||
fail:
|
||||
EVP_PKEY_free(pri);
|
||||
X509_free(x509);
|
||||
sk_X509_pop_free(ca, X509_free);
|
||||
cert_done = 1;
|
||||
break;
|
||||
|
||||
if(!cert_done)
|
||||
return 0; /* failure! */
|
||||
#else
|
||||
failf(data, "file type P12 for certificate not supported");
|
||||
return 0;
|
||||
@@ -2205,14 +2204,7 @@ static CURLcode servercert(struct connectdata *conn,
|
||||
|
||||
rc = x509_name_oneline(X509_get_subject_name(connssl->server_cert),
|
||||
buffer, BUFSIZE);
|
||||
if(rc) {
|
||||
if(strict)
|
||||
failf(data, "SSL: couldn't get X509-subject!");
|
||||
X509_free(connssl->server_cert);
|
||||
connssl->server_cert = NULL;
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
infof(data, "\t subject: %s\n", buffer);
|
||||
infof(data, "\t subject: %s\n", rc?"[NONE]":buffer);
|
||||
|
||||
certdate = X509_get_notBefore(connssl->server_cert);
|
||||
asn1_output(certdate, buffer, BUFSIZE);
|
||||
@@ -2553,7 +2545,7 @@ static ssize_t ossl_send(struct connectdata *conn,
|
||||
memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
|
||||
rc = SSL_write(conn->ssl[sockindex].handle, mem, memlen);
|
||||
|
||||
if(rc < 0) {
|
||||
if(rc <= 0) {
|
||||
err = SSL_get_error(conn->ssl[sockindex].handle, rc);
|
||||
|
||||
switch(err) {
|
||||
@@ -2602,7 +2594,7 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */
|
||||
|
||||
buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
|
||||
nread = (ssize_t)SSL_read(conn->ssl[num].handle, buf, buffsize);
|
||||
if(nread < 0) {
|
||||
if(nread <= 0) {
|
||||
/* failed SSL_read */
|
||||
int err = SSL_get_error(conn->ssl[num].handle, (int)nread);
|
||||
|
||||
|
499
lib/url.c
499
lib/url.c
@@ -141,9 +141,12 @@ find_oldest_idle_connection_in_bundle(struct SessionHandle *data,
|
||||
static void conn_free(struct connectdata *conn);
|
||||
static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke);
|
||||
static CURLcode do_init(struct connectdata *conn);
|
||||
static CURLcode parse_url_userpass(struct SessionHandle *data,
|
||||
struct connectdata *conn,
|
||||
char *user, char *passwd);
|
||||
static CURLcode parse_url_login(struct SessionHandle *data,
|
||||
struct connectdata *conn,
|
||||
char *user, char *passwd, char *options);
|
||||
static CURLcode parse_login_details(const char *login, const size_t len,
|
||||
char **userptr, char **passwdptr,
|
||||
char **optionsptr);
|
||||
/*
|
||||
* Protocol table.
|
||||
*/
|
||||
@@ -261,7 +264,7 @@ static const struct Curl_handler Curl_handler_dummy = {
|
||||
PROTOPT_NONE /* flags */
|
||||
};
|
||||
|
||||
void Curl_freeset(struct SessionHandle * data)
|
||||
void Curl_freeset(struct SessionHandle *data)
|
||||
{
|
||||
/* Free all dynamic strings stored in the data->set substructure. */
|
||||
enum dupstring i;
|
||||
@@ -275,7 +278,7 @@ void Curl_freeset(struct SessionHandle * data)
|
||||
data->change.referer = NULL;
|
||||
}
|
||||
|
||||
static CURLcode setstropt(char **charp, char * s)
|
||||
static CURLcode setstropt(char **charp, char *s)
|
||||
{
|
||||
/* Release the previous storage at `charp' and replace by a dynamic storage
|
||||
copy of `s'. Return CURLE_OK or CURLE_OUT_OF_MEMORY. */
|
||||
@@ -294,48 +297,47 @@ static CURLcode setstropt(char **charp, char * s)
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static CURLcode setstropt_userpwd(char *option, char **user_storage,
|
||||
char **pwd_storage)
|
||||
static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp,
|
||||
char **optionsp)
|
||||
{
|
||||
char* separator;
|
||||
CURLcode result = CURLE_OK;
|
||||
char *user = NULL;
|
||||
char *passwd = NULL;
|
||||
char *options = NULL;
|
||||
|
||||
if(!option) {
|
||||
/* we treat a NULL passed in as a hint to clear existing info */
|
||||
Curl_safefree(*user_storage);
|
||||
*user_storage = (char *) NULL;
|
||||
Curl_safefree(*pwd_storage);
|
||||
*pwd_storage = (char *) NULL;
|
||||
return CURLE_OK;
|
||||
/* Parse the login details if specified. It not then we treat NULL as a hint
|
||||
to clear the existing data */
|
||||
if(option) {
|
||||
result = parse_login_details(option, strlen(option),
|
||||
(userp ? &user : NULL),
|
||||
(passwdp ? &passwd : NULL),
|
||||
(optionsp ? &options : NULL));
|
||||
}
|
||||
|
||||
separator = strchr(option, ':');
|
||||
if(separator != NULL) {
|
||||
|
||||
/* store username part of option */
|
||||
char * p;
|
||||
size_t username_len = (size_t)(separator-option);
|
||||
p = malloc(username_len+1);
|
||||
if(!p)
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
else {
|
||||
memcpy(p, option, username_len);
|
||||
p[username_len] = '\0';
|
||||
Curl_safefree(*user_storage);
|
||||
*user_storage = p;
|
||||
if(!result) {
|
||||
/* Store the username part of option if required */
|
||||
if(userp) {
|
||||
Curl_safefree(*userp);
|
||||
*userp = user;
|
||||
}
|
||||
|
||||
/* store password part of option */
|
||||
if(result == CURLE_OK)
|
||||
result = setstropt(pwd_storage, separator+1);
|
||||
}
|
||||
else {
|
||||
result = setstropt(user_storage, option);
|
||||
/* Store the password part of option if required */
|
||||
if(passwdp) {
|
||||
Curl_safefree(*passwdp);
|
||||
*passwdp = passwd;
|
||||
}
|
||||
|
||||
/* Store the options part of option if required */
|
||||
if(optionsp) {
|
||||
Curl_safefree(*optionsp);
|
||||
*optionsp = options;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
CURLcode Curl_dupset(struct SessionHandle * dst, struct SessionHandle * src)
|
||||
CURLcode Curl_dupset(struct SessionHandle *dst, struct SessionHandle *src)
|
||||
{
|
||||
CURLcode r = CURLE_OK;
|
||||
enum dupstring i;
|
||||
@@ -1135,41 +1137,44 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
|
||||
if(argptr == NULL)
|
||||
break;
|
||||
|
||||
Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
|
||||
|
||||
if(Curl_raw_equal(argptr, "ALL")) {
|
||||
/* clear all cookies */
|
||||
Curl_cookie_clearall(data->cookies);
|
||||
break;
|
||||
}
|
||||
else if(Curl_raw_equal(argptr, "SESS")) {
|
||||
/* clear session cookies */
|
||||
Curl_cookie_clearsess(data->cookies);
|
||||
break;
|
||||
}
|
||||
else if(Curl_raw_equal(argptr, "FLUSH")) {
|
||||
/* flush cookies to file */
|
||||
Curl_flush_cookies(data, 0);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
if(!data->cookies)
|
||||
/* if cookie engine was not running, activate it */
|
||||
data->cookies = Curl_cookie_init(data, NULL, NULL, TRUE);
|
||||
|
||||
if(!data->cookies)
|
||||
/* if cookie engine was not running, activate it */
|
||||
data->cookies = Curl_cookie_init(data, NULL, NULL, TRUE);
|
||||
argptr = strdup(argptr);
|
||||
if(!argptr) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
else {
|
||||
|
||||
argptr = strdup(argptr);
|
||||
if(!argptr) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
break;
|
||||
if(checkprefix("Set-Cookie:", argptr))
|
||||
/* HTTP Header format line */
|
||||
Curl_cookie_add(data, data->cookies, TRUE, argptr + 11, NULL, NULL);
|
||||
|
||||
else
|
||||
/* Netscape format line */
|
||||
Curl_cookie_add(data, data->cookies, FALSE, argptr, NULL, NULL);
|
||||
|
||||
free(argptr);
|
||||
}
|
||||
}
|
||||
Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
|
||||
|
||||
if(checkprefix("Set-Cookie:", argptr))
|
||||
/* HTTP Header format line */
|
||||
Curl_cookie_add(data, data->cookies, TRUE, argptr + 11, NULL, NULL);
|
||||
|
||||
else
|
||||
/* Netscape format line */
|
||||
Curl_cookie_add(data, data->cookies, FALSE, argptr, NULL, NULL);
|
||||
|
||||
free(argptr);
|
||||
break;
|
||||
#endif /* CURL_DISABLE_COOKIES */
|
||||
|
||||
@@ -1534,11 +1539,12 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
|
||||
|
||||
case CURLOPT_USERPWD:
|
||||
/*
|
||||
* user:password to use in the operation
|
||||
* user:password;options to use in the operation
|
||||
*/
|
||||
result = setstropt_userpwd(va_arg(param, char *),
|
||||
&data->set.str[STRING_USERNAME],
|
||||
&data->set.str[STRING_PASSWORD]);
|
||||
&data->set.str[STRING_PASSWORD],
|
||||
&data->set.str[STRING_OPTIONS]);
|
||||
break;
|
||||
case CURLOPT_USERNAME:
|
||||
/*
|
||||
@@ -1611,7 +1617,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
|
||||
*/
|
||||
result = setstropt_userpwd(va_arg(param, char *),
|
||||
&data->set.str[STRING_PROXYUSERNAME],
|
||||
&data->set.str[STRING_PROXYPASSWORD]);
|
||||
&data->set.str[STRING_PROXYPASSWORD], NULL);
|
||||
break;
|
||||
case CURLOPT_PROXYUSERNAME:
|
||||
/*
|
||||
@@ -2243,20 +2249,27 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
|
||||
break;
|
||||
|
||||
case CURLOPT_MAIL_FROM:
|
||||
/* Set the SMTP mail originator */
|
||||
result = setstropt(&data->set.str[STRING_MAIL_FROM],
|
||||
va_arg(param, char *));
|
||||
break;
|
||||
|
||||
case CURLOPT_MAIL_AUTH:
|
||||
/* Set the SMTP auth originator */
|
||||
result = setstropt(&data->set.str[STRING_MAIL_AUTH],
|
||||
va_arg(param, char *));
|
||||
break;
|
||||
|
||||
case CURLOPT_MAIL_RCPT:
|
||||
/* get a list of mail recipients */
|
||||
/* Set the list of mail recipients */
|
||||
data->set.mail_rcpt = va_arg(param, struct curl_slist *);
|
||||
break;
|
||||
|
||||
case CURLOPT_SASL_IR:
|
||||
/* Enable/disable SASL initial response */
|
||||
data->set.sasl_ir = (0 != va_arg(param, long)) ? TRUE : FALSE;
|
||||
break;
|
||||
|
||||
case CURLOPT_RTSP_REQUEST:
|
||||
{
|
||||
/*
|
||||
@@ -2452,6 +2465,7 @@ static void conn_free(struct connectdata *conn)
|
||||
|
||||
Curl_safefree(conn->user);
|
||||
Curl_safefree(conn->passwd);
|
||||
Curl_safefree(conn->options);
|
||||
Curl_safefree(conn->proxyuser);
|
||||
Curl_safefree(conn->proxypasswd);
|
||||
Curl_safefree(conn->allocptr.proxyuserpwd);
|
||||
@@ -3650,8 +3664,7 @@ static CURLcode findprotocol(struct SessionHandle *data,
|
||||
static CURLcode parseurlandfillconn(struct SessionHandle *data,
|
||||
struct connectdata *conn,
|
||||
bool *prot_missing,
|
||||
char *user,
|
||||
char *passwd)
|
||||
char *user, char *passwd, char *options)
|
||||
{
|
||||
char *at;
|
||||
char *fragment;
|
||||
@@ -3768,6 +3781,10 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data,
|
||||
protop = "LDAP";
|
||||
else if(checkprefix("IMAP.", conn->host.name))
|
||||
protop = "IMAP";
|
||||
else if(checkprefix("SMTP.", conn->host.name))
|
||||
protop = "smtp";
|
||||
else if(checkprefix("POP3.", conn->host.name))
|
||||
protop = "pop3";
|
||||
else {
|
||||
protop = "http";
|
||||
}
|
||||
@@ -3865,11 +3882,11 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data,
|
||||
data->change.url_alloc = TRUE; /* free this later */
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* Parse a user name and password in the URL and strip it out
|
||||
* of the host name
|
||||
*************************************************************/
|
||||
result = parse_url_userpass(data, conn, user, passwd);
|
||||
/*
|
||||
* Parse the login details from the URL and strip them out of
|
||||
* the host name
|
||||
*/
|
||||
result = parse_url_login(data, conn, user, passwd, options);
|
||||
if(result != CURLE_OK)
|
||||
return result;
|
||||
|
||||
@@ -4193,34 +4210,37 @@ static CURLcode parse_proxy(struct SessionHandle *data,
|
||||
/* Is there a username and password given in this proxy url? */
|
||||
atsign = strchr(proxyptr, '@');
|
||||
if(atsign) {
|
||||
char proxyuser[MAX_CURL_USER_LENGTH];
|
||||
char proxypasswd[MAX_CURL_PASSWORD_LENGTH];
|
||||
proxypasswd[0] = 0;
|
||||
|
||||
if(1 <= sscanf(proxyptr,
|
||||
"%" MAX_CURL_USER_LENGTH_TXT"[^:@]:"
|
||||
"%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]",
|
||||
proxyuser, proxypasswd)) {
|
||||
CURLcode res = CURLE_OK;
|
||||
CURLcode res = CURLE_OK;
|
||||
char *proxyuser = NULL;
|
||||
char *proxypasswd = NULL;
|
||||
|
||||
res = parse_login_details(proxyptr, atsign - proxyptr,
|
||||
&proxyuser, &proxypasswd, NULL);
|
||||
if(!res) {
|
||||
/* found user and password, rip them out. note that we are
|
||||
unescaping them, as there is otherwise no way to have a
|
||||
username or password with reserved characters like ':' in
|
||||
them. */
|
||||
Curl_safefree(conn->proxyuser);
|
||||
conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL);
|
||||
if(proxyuser && strlen(proxyuser) < MAX_CURL_USER_LENGTH)
|
||||
conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL);
|
||||
else
|
||||
conn->proxyuser = strdup("");
|
||||
|
||||
if(!conn->proxyuser)
|
||||
res = CURLE_OUT_OF_MEMORY;
|
||||
else {
|
||||
Curl_safefree(conn->proxypasswd);
|
||||
conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL);
|
||||
if(proxypasswd && strlen(proxypasswd) < MAX_CURL_PASSWORD_LENGTH)
|
||||
conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL);
|
||||
else
|
||||
conn->proxypasswd = strdup("");
|
||||
|
||||
if(!conn->proxypasswd)
|
||||
res = CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if(CURLE_OK == res) {
|
||||
if(!res) {
|
||||
conn->bits.proxy_user_passwd = TRUE; /* enable it */
|
||||
atsign++; /* the right side of the @-letter */
|
||||
|
||||
@@ -4229,10 +4249,13 @@ static CURLcode parse_proxy(struct SessionHandle *data,
|
||||
else
|
||||
res = CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if(res)
|
||||
return res;
|
||||
}
|
||||
|
||||
Curl_safefree(proxyuser);
|
||||
Curl_safefree(proxypasswd);
|
||||
|
||||
if(res)
|
||||
return res;
|
||||
}
|
||||
|
||||
/* start scanning for port number at this point */
|
||||
@@ -4326,8 +4349,10 @@ static CURLcode parse_proxy_auth(struct SessionHandle *data,
|
||||
#endif /* CURL_DISABLE_PROXY */
|
||||
|
||||
/*
|
||||
* parse_url_login()
|
||||
*
|
||||
* Parse a user name and password in the URL and strip it out of the host name
|
||||
* Parse the login details (user name, password and options) from the URL and
|
||||
* strip them out of the host name
|
||||
*
|
||||
* Inputs: data->set.use_netrc (CURLOPT_NETRC)
|
||||
* conn->host.name
|
||||
@@ -4335,31 +4360,38 @@ static CURLcode parse_proxy_auth(struct SessionHandle *data,
|
||||
* Outputs: (almost :- all currently undefined)
|
||||
* conn->bits.user_passwd - non-zero if non-default passwords exist
|
||||
* user - non-zero length if defined
|
||||
* passwd - ditto
|
||||
* passwd - non-zero length if defined
|
||||
* options - non-zero length if defined
|
||||
* conn->host.name - remove user name and password
|
||||
*/
|
||||
static CURLcode parse_url_userpass(struct SessionHandle *data,
|
||||
struct connectdata *conn,
|
||||
char *user, char *passwd)
|
||||
static CURLcode parse_url_login(struct SessionHandle *data,
|
||||
struct connectdata *conn,
|
||||
char *user, char *passwd, char *options)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
char *userp = NULL;
|
||||
char *passwdp = NULL;
|
||||
char *optionsp = NULL;
|
||||
|
||||
/* At this point, we're hoping all the other special cases have
|
||||
* been taken care of, so conn->host.name is at most
|
||||
* [user[:password]]@]hostname
|
||||
* [user[:password][;options]]@]hostname
|
||||
*
|
||||
* We need somewhere to put the embedded details, so do that first.
|
||||
*/
|
||||
|
||||
char *ptr=strchr(conn->host.name, '@');
|
||||
char *userpass = conn->host.name;
|
||||
char *ptr = strchr(conn->host.name, '@');
|
||||
char *login = conn->host.name;
|
||||
|
||||
user[0] =0; /* to make everything well-defined */
|
||||
passwd[0]=0;
|
||||
user[0] = 0; /* to make everything well-defined */
|
||||
passwd[0] = 0;
|
||||
options[0] = 0;
|
||||
|
||||
/* We will now try to extract the
|
||||
* possible user+password pair in a string like:
|
||||
* possible login information in a string like:
|
||||
* ftp://user:password@ftp.my.site:8021/README */
|
||||
if(ptr != NULL) {
|
||||
/* there's a user+password given here, to the left of the @ */
|
||||
if(ptr) {
|
||||
/* There's login information to the left of the @ */
|
||||
|
||||
conn->host.name = ++ptr;
|
||||
|
||||
@@ -4369,46 +4401,183 @@ static CURLcode parse_url_userpass(struct SessionHandle *data,
|
||||
* set user/passwd, but doing that first adds more cases here :-(
|
||||
*/
|
||||
|
||||
conn->bits.userpwd_in_url = TRUE;
|
||||
if(data->set.use_netrc != CURL_NETRC_REQUIRED) {
|
||||
/* We could use the one in the URL */
|
||||
/* We could use the login information in the URL so extract it */
|
||||
result = parse_login_details(login, ptr - login - 1,
|
||||
&userp, &passwdp, &optionsp);
|
||||
if(!result) {
|
||||
if(userp) {
|
||||
char *newname;
|
||||
|
||||
conn->bits.user_passwd = TRUE; /* enable user+password */
|
||||
/* We have a user in the URL */
|
||||
conn->bits.userpwd_in_url = TRUE;
|
||||
conn->bits.user_passwd = TRUE; /* enable user+password */
|
||||
|
||||
if(*userpass != ':') {
|
||||
/* the name is given, get user+password */
|
||||
sscanf(userpass, "%" MAX_CURL_USER_LENGTH_TXT "[^:@]:"
|
||||
"%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]",
|
||||
user, passwd);
|
||||
/* Decode the user */
|
||||
newname = curl_easy_unescape(data, userp, 0, NULL);
|
||||
if(!newname)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
if(strlen(newname) < MAX_CURL_USER_LENGTH)
|
||||
strcpy(user, newname);
|
||||
|
||||
free(newname);
|
||||
}
|
||||
|
||||
if(passwdp) {
|
||||
/* We have a password in the URL so decode it */
|
||||
char *newpasswd = curl_easy_unescape(data, passwdp, 0, NULL);
|
||||
if(!newpasswd)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
if(strlen(newpasswd) < MAX_CURL_PASSWORD_LENGTH)
|
||||
strcpy(passwd, newpasswd);
|
||||
|
||||
free(newpasswd);
|
||||
}
|
||||
|
||||
if(optionsp) {
|
||||
/* We have an options list in the URL so decode it */
|
||||
char *newoptions = curl_easy_unescape(data, optionsp, 0, NULL);
|
||||
if(!newoptions)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
if(strlen(newoptions) < MAX_CURL_OPTIONS_LENGTH)
|
||||
strcpy(options, newoptions);
|
||||
|
||||
free(newoptions);
|
||||
}
|
||||
}
|
||||
else
|
||||
/* no name given, get the password only */
|
||||
sscanf(userpass, ":%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]", passwd);
|
||||
|
||||
if(user[0]) {
|
||||
char *newname=curl_easy_unescape(data, user, 0, NULL);
|
||||
if(!newname)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
if(strlen(newname) < MAX_CURL_USER_LENGTH)
|
||||
strcpy(user, newname);
|
||||
|
||||
/* if the new name is longer than accepted, then just use
|
||||
the unconverted name, it'll be wrong but what the heck */
|
||||
free(newname);
|
||||
}
|
||||
if(passwd[0]) {
|
||||
/* we have a password found in the URL, decode it! */
|
||||
char *newpasswd=curl_easy_unescape(data, passwd, 0, NULL);
|
||||
if(!newpasswd)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
if(strlen(newpasswd) < MAX_CURL_PASSWORD_LENGTH)
|
||||
strcpy(passwd, newpasswd);
|
||||
|
||||
free(newpasswd);
|
||||
}
|
||||
Curl_safefree(userp);
|
||||
Curl_safefree(passwdp);
|
||||
Curl_safefree(optionsp);
|
||||
}
|
||||
}
|
||||
return CURLE_OK;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* parse_login_details()
|
||||
*
|
||||
* This is used to parse a login string for user name, password and options in
|
||||
* the following formats:
|
||||
*
|
||||
* user
|
||||
* user:password
|
||||
* user:password;options
|
||||
* user;options
|
||||
* user;options:password
|
||||
* :password
|
||||
* :password;options
|
||||
* ;options
|
||||
* ;options:password
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* login [in] - The login string.
|
||||
* len [in] - The length of the login string.
|
||||
* userp [in/out] - The address where a pointer to newly allocated memory
|
||||
* holding the user will be stored upon completion.
|
||||
* passdwp [in/out] - The address where a pointer to newly allocated memory
|
||||
* holding the password will be stored upon completion.
|
||||
* optionsp [in/out] - The address where a pointer to newly allocated memory
|
||||
* holding the options will be stored upon completion.
|
||||
*
|
||||
* Returns CURLE_OK on success.
|
||||
*/
|
||||
static CURLcode parse_login_details(const char *login, const size_t len,
|
||||
char **userp, char **passwdp,
|
||||
char **optionsp)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
char *ubuf = NULL;
|
||||
char *pbuf = NULL;
|
||||
char *obuf = NULL;
|
||||
const char *psep = NULL;
|
||||
const char *osep = NULL;
|
||||
size_t ulen;
|
||||
size_t plen;
|
||||
size_t olen;
|
||||
|
||||
/* Attempt to find the password separator */
|
||||
if(passwdp) {
|
||||
psep = strchr(login, ':');
|
||||
|
||||
/* Within the constraint of the login string */
|
||||
if(psep >= login + len)
|
||||
psep = NULL;
|
||||
}
|
||||
|
||||
/* Attempt to find the options separator */
|
||||
if(optionsp) {
|
||||
osep = strchr(login, ';');
|
||||
|
||||
/* Within the constraint of the login string */
|
||||
if(osep >= login + len)
|
||||
osep = NULL;
|
||||
}
|
||||
|
||||
/* Calculate the portion lengths */
|
||||
ulen = (psep ?
|
||||
(size_t)(osep && psep > osep ? osep - login : psep - login) :
|
||||
(osep ? (size_t)(osep - login) : len));
|
||||
plen = (psep ?
|
||||
(osep && osep > psep ? (size_t)(osep - psep) :
|
||||
(size_t)(login + len - psep)) - 1 : 0);
|
||||
olen = (osep ?
|
||||
(psep && psep > osep ? (size_t)(psep - osep) :
|
||||
(size_t)(login + len - osep)) - 1 : 0);
|
||||
|
||||
/* Allocate the user portion buffer */
|
||||
if(userp && ulen) {
|
||||
ubuf = malloc(ulen + 1);
|
||||
if(!ubuf)
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
/* Allocate the password portion buffer */
|
||||
if(!result && passwdp && plen) {
|
||||
pbuf = malloc(plen + 1);
|
||||
if(!pbuf)
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
/* Allocate the options portion buffer */
|
||||
if(!result && optionsp && olen) {
|
||||
obuf = malloc(olen + 1);
|
||||
if(!obuf)
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if(!result) {
|
||||
/* Store the user portion if necessary */
|
||||
if(ubuf) {
|
||||
memcpy(ubuf, login, ulen);
|
||||
ubuf[ulen] = '\0';
|
||||
Curl_safefree(*userp);
|
||||
*userp = ubuf;
|
||||
}
|
||||
|
||||
/* Store the password portion if necessary */
|
||||
if(pbuf) {
|
||||
memcpy(pbuf, psep + 1, plen);
|
||||
pbuf[plen] = '\0';
|
||||
Curl_safefree(*passwdp);
|
||||
*passwdp = pbuf;
|
||||
}
|
||||
|
||||
/* Store the options portion if necessary */
|
||||
if(obuf) {
|
||||
memcpy(obuf, osep + 1, olen);
|
||||
obuf[olen] = '\0';
|
||||
Curl_safefree(*optionsp);
|
||||
*optionsp = obuf;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
@@ -4531,20 +4700,26 @@ static CURLcode parse_remote_port(struct SessionHandle *data,
|
||||
}
|
||||
|
||||
/*
|
||||
* Override a user name and password from the URL with that in the
|
||||
* CURLOPT_USERPWD option or a .netrc file, if applicable.
|
||||
* Override the login details from the URL with that in the CURLOPT_USERPWD
|
||||
* option or a .netrc file, if applicable.
|
||||
*/
|
||||
static void override_userpass(struct SessionHandle *data,
|
||||
struct connectdata *conn,
|
||||
char *user, char *passwd)
|
||||
static void override_login(struct SessionHandle *data,
|
||||
struct connectdata *conn,
|
||||
char *user, char *passwd, char *options)
|
||||
{
|
||||
if(data->set.str[STRING_USERNAME] != NULL) {
|
||||
if(data->set.str[STRING_USERNAME]) {
|
||||
strncpy(user, data->set.str[STRING_USERNAME], MAX_CURL_USER_LENGTH);
|
||||
user[MAX_CURL_USER_LENGTH-1] = '\0'; /*To be on safe side*/
|
||||
user[MAX_CURL_USER_LENGTH - 1] = '\0'; /* To be on safe side */
|
||||
}
|
||||
if(data->set.str[STRING_PASSWORD] != NULL) {
|
||||
|
||||
if(data->set.str[STRING_PASSWORD]) {
|
||||
strncpy(passwd, data->set.str[STRING_PASSWORD], MAX_CURL_PASSWORD_LENGTH);
|
||||
passwd[MAX_CURL_PASSWORD_LENGTH-1] = '\0'; /*To be on safe side*/
|
||||
passwd[MAX_CURL_PASSWORD_LENGTH - 1] = '\0'; /* To be on safe side */
|
||||
}
|
||||
|
||||
if(data->set.str[STRING_OPTIONS]) {
|
||||
strncpy(options, data->set.str[STRING_OPTIONS], MAX_CURL_OPTIONS_LENGTH);
|
||||
options[MAX_CURL_OPTIONS_LENGTH - 1] = '\0'; /* To be on safe side */
|
||||
}
|
||||
|
||||
conn->bits.netrc = FALSE;
|
||||
@@ -4570,32 +4745,48 @@ static void override_userpass(struct SessionHandle *data,
|
||||
/*
|
||||
* Set password so it's available in the connection.
|
||||
*/
|
||||
static CURLcode set_userpass(struct connectdata *conn,
|
||||
const char *user, const char *passwd)
|
||||
static CURLcode set_login(struct connectdata *conn,
|
||||
const char *user, const char *passwd,
|
||||
const char *options)
|
||||
{
|
||||
/* If our protocol needs a password and we have none, use the defaults */
|
||||
if((conn->handler->flags & PROTOPT_NEEDSPWD) &&
|
||||
!conn->bits.user_passwd) {
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
/* If our protocol needs a password and we have none, use the defaults */
|
||||
if((conn->handler->flags & PROTOPT_NEEDSPWD) && !conn->bits.user_passwd) {
|
||||
/* Store the default user */
|
||||
conn->user = strdup(CURL_DEFAULT_USER);
|
||||
|
||||
/* Store the default password */
|
||||
if(conn->user)
|
||||
conn->passwd = strdup(CURL_DEFAULT_PASSWORD);
|
||||
else
|
||||
conn->passwd = NULL;
|
||||
|
||||
/* This is the default password, so DON'T set conn->bits.user_passwd */
|
||||
}
|
||||
else {
|
||||
/* store user + password, zero-length if not set */
|
||||
/* Store the user, zero-length if not set */
|
||||
conn->user = strdup(user);
|
||||
|
||||
/* Store the password (only if user is present), zero-length if not set */
|
||||
if(conn->user)
|
||||
conn->passwd = strdup(passwd);
|
||||
else
|
||||
conn->passwd = NULL;
|
||||
}
|
||||
if(!conn->user || !conn->passwd)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
return CURLE_OK;
|
||||
if(!conn->user || !conn->passwd)
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
|
||||
/* Store the options, null if not set */
|
||||
if(!result && options[0]) {
|
||||
conn->options = strdup(options);
|
||||
|
||||
if(!conn->options)
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
@@ -4761,12 +4952,13 @@ static CURLcode create_conn(struct SessionHandle *data,
|
||||
struct connectdata **in_connect,
|
||||
bool *async)
|
||||
{
|
||||
CURLcode result=CURLE_OK;
|
||||
CURLcode result = CURLE_OK;
|
||||
struct connectdata *conn;
|
||||
struct connectdata *conn_temp = NULL;
|
||||
size_t urllen;
|
||||
char user[MAX_CURL_USER_LENGTH];
|
||||
char passwd[MAX_CURL_PASSWORD_LENGTH];
|
||||
char options[MAX_CURL_OPTIONS_LENGTH];
|
||||
bool reuse;
|
||||
char *proxy = NULL;
|
||||
bool prot_missing = FALSE;
|
||||
@@ -4835,7 +5027,8 @@ static CURLcode create_conn(struct SessionHandle *data,
|
||||
conn->host.name = conn->host.rawalloc;
|
||||
conn->host.name[0] = 0;
|
||||
|
||||
result = parseurlandfillconn(data, conn, &prot_missing, user, passwd);
|
||||
result = parseurlandfillconn(data, conn, &prot_missing, user, passwd,
|
||||
options);
|
||||
if(result != CURLE_OK)
|
||||
return result;
|
||||
|
||||
@@ -5010,6 +5203,9 @@ static CURLcode create_conn(struct SessionHandle *data,
|
||||
-1, NULL); /* no upload */
|
||||
}
|
||||
|
||||
/* since we skip do_init() */
|
||||
Curl_speedinit(data);
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
@@ -5028,12 +5224,9 @@ static CURLcode create_conn(struct SessionHandle *data,
|
||||
if(result != CURLE_OK)
|
||||
return result;
|
||||
|
||||
/*************************************************************
|
||||
* Check for an overridden user name and password, then set it
|
||||
* for use
|
||||
*************************************************************/
|
||||
override_userpass(data, conn, user, passwd);
|
||||
result = set_userpass(conn, user, passwd);
|
||||
/* Check for overridden login details and set them accordingly */
|
||||
override_login(data, conn, user, passwd, options);
|
||||
result = set_login(conn, user, passwd, options);
|
||||
if(result != CURLE_OK)
|
||||
return result;
|
||||
|
||||
|
@@ -243,6 +243,7 @@ struct curl_schannel_cred {
|
||||
CredHandle cred_handle;
|
||||
TimeStamp time_stamp;
|
||||
int refcount;
|
||||
bool cached;
|
||||
};
|
||||
|
||||
struct curl_schannel_ctxt {
|
||||
@@ -324,6 +325,7 @@ struct ssl_connect_data {
|
||||
#ifdef USE_AXTLS
|
||||
SSL_CTX* ssl_ctx;
|
||||
SSL* ssl;
|
||||
ssl_connect_state connecting_state;
|
||||
#endif /* USE_AXTLS */
|
||||
#ifdef USE_SCHANNEL
|
||||
struct curl_schannel_cred *cred;
|
||||
@@ -859,6 +861,7 @@ struct connectdata {
|
||||
|
||||
char *user; /* user name string, allocated */
|
||||
char *passwd; /* password string, allocated */
|
||||
char *options; /* options string, allocated */
|
||||
|
||||
char *proxyuser; /* proxy user name string, allocated */
|
||||
char *proxypasswd; /* proxy password string, allocated */
|
||||
@@ -1136,8 +1139,7 @@ typedef enum {
|
||||
* Session-data MUST be put in the connectdata struct and here. */
|
||||
#define MAX_CURL_USER_LENGTH 256
|
||||
#define MAX_CURL_PASSWORD_LENGTH 256
|
||||
#define MAX_CURL_USER_LENGTH_TXT "255"
|
||||
#define MAX_CURL_PASSWORD_LENGTH_TXT "255"
|
||||
#define MAX_CURL_OPTIONS_LENGTH 256
|
||||
|
||||
struct auth {
|
||||
unsigned long want; /* Bitmask set to the authentication methods wanted by
|
||||
@@ -1352,6 +1354,7 @@ enum dupstring {
|
||||
STRING_SSL_ISSUERCERT, /* issuer cert file to check certificate */
|
||||
STRING_USERNAME, /* <username>, if used */
|
||||
STRING_PASSWORD, /* <password>, if used */
|
||||
STRING_OPTIONS, /* <options>, if used */
|
||||
STRING_PROXYUSERNAME, /* Proxy <username>, if used */
|
||||
STRING_PROXYPASSWORD, /* Proxy <password>, if used */
|
||||
STRING_NOPROXY, /* List of hosts which should not use the proxy, if
|
||||
@@ -1562,6 +1565,7 @@ struct UserDefined {
|
||||
long socks5_gssapi_nec; /* flag to support nec socks5 server */
|
||||
#endif
|
||||
struct curl_slist *mail_rcpt; /* linked list of mail recipients */
|
||||
bool sasl_ir; /* Enable/disable SASL initial response */
|
||||
/* Common RTSP header options */
|
||||
Curl_RtspReq rtspreq; /* RTSP request type */
|
||||
long rtspversion; /* like httpversion, for RTSP */
|
||||
|
4
maketgz
4
maketgz
@@ -9,7 +9,7 @@
|
||||
# | (__| |_| | _ <| |___
|
||||
# \___|\___/|_| \_\_____|
|
||||
#
|
||||
# Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
# Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
#
|
||||
# This software is licensed as described in the file COPYING, which
|
||||
# you should have received as part of this distribution. The terms
|
||||
@@ -142,7 +142,7 @@ make -s dist VERSION=$version
|
||||
|
||||
bzip2="curl-$version.tar.bz2"
|
||||
echo "Generating $bzip2"
|
||||
gzip -dc $targz | bzip2 --best - > $bzip2
|
||||
gzip -dc $targz | bzip2 --best > $bzip2
|
||||
|
||||
############################################################################
|
||||
#
|
||||
|
@@ -72,7 +72,7 @@ CFLAGS += -d_WIN32_WINNT=0x0501 -dENABLE_IPV6
|
||||
!ifdef %zlib_root
|
||||
ZLIB_ROOT = $(%zlib_root)
|
||||
!else
|
||||
ZLIB_ROOT = ..$(DS)..$(DS)zlib-1.2.7
|
||||
ZLIB_ROOT = ..$(DS)..$(DS)zlib-1.2.8
|
||||
!endif
|
||||
|
||||
!ifdef %libssh2_root
|
||||
|
@@ -66,6 +66,15 @@ curl_LDFLAGS = @LIBMETALINK_LDFLAGS@
|
||||
curl_CPPFLAGS = $(AM_CPPFLAGS) $(LIBMETALINK_CPPFLAGS)
|
||||
curl_DEPENDENCIES = $(top_builddir)/lib/libcurl.la
|
||||
|
||||
# if unit tests are enabled, build a static library to link them with
|
||||
if BUILD_UNITTESTS
|
||||
noinst_LTLIBRARIES = libcurltool.la
|
||||
libcurltool_la_CPPFLAGS = $(LIBMETALINK_CPPFLAGS) $(AM_CPPFLAGS)
|
||||
libcurltool_la_CFLAGS = -DUNITTESTS
|
||||
libcurltool_la_LDFLAGS = -static $(LINKFLAGS)
|
||||
libcurltool_la_SOURCES = $(curl_SOURCES)
|
||||
endif
|
||||
|
||||
BUILT_SOURCES = tool_hugehelp.c
|
||||
CLEANFILES = tool_hugehelp.c
|
||||
# Use the C locale to ensure that only ASCII characters appear in the
|
||||
|
@@ -22,7 +22,7 @@ BCCDIR = $(MAKEDIR)\..
|
||||
|
||||
# Edit the path below to point to the base of your Zlib sources.
|
||||
!ifndef ZLIB_PATH
|
||||
ZLIB_PATH = ..\..\zlib-1.2.7
|
||||
ZLIB_PATH = ..\..\zlib-1.2.8
|
||||
!endif
|
||||
|
||||
# Edit the path below to point to the base of your OpenSSL package.
|
||||
|
@@ -7,14 +7,14 @@
|
||||
## Example: mingw32-make -f Makefile.m32 CFG=-zlib-ssl-spi-winidn
|
||||
##
|
||||
## Hint: you can also set environment vars to control the build, f.e.:
|
||||
## set ZLIB_PATH=c:/zlib-1.2.7
|
||||
## set ZLIB_PATH=c:/zlib-1.2.8
|
||||
## set ZLIB=1
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
# Edit the path below to point to the base of your Zlib sources.
|
||||
ifndef ZLIB_PATH
|
||||
ZLIB_PATH = ../../zlib-1.2.7
|
||||
ZLIB_PATH = ../../zlib-1.2.8
|
||||
endif
|
||||
# Edit the path below to point to the base of your OpenSSL package.
|
||||
ifndef OPENSSL_PATH
|
||||
|
@@ -14,7 +14,7 @@ endif
|
||||
|
||||
# Edit the path below to point to the base of your Zlib sources.
|
||||
ifndef ZLIB_PATH
|
||||
ZLIB_PATH = ../../zlib-1.2.7
|
||||
ZLIB_PATH = ../../zlib-1.2.8
|
||||
endif
|
||||
|
||||
# Edit the path below to point to the base of your OpenSSL package.
|
||||
|
@@ -60,7 +60,7 @@ OPENSSL_PATH = ../../openssl-0.9.8y
|
||||
!ENDIF
|
||||
|
||||
!IFNDEF ZLIB_PATH
|
||||
ZLIB_PATH = ../../zlib-1.2.7
|
||||
ZLIB_PATH = ../../zlib-1.2.8
|
||||
!ENDIF
|
||||
|
||||
!IFNDEF MACHINE
|
||||
|
@@ -80,6 +80,7 @@ struct Configurable {
|
||||
char *mail_from;
|
||||
struct curl_slist *mail_rcpt;
|
||||
char *mail_auth;
|
||||
bool sasl_ir; /* Enable/disable SASL initial response */
|
||||
bool proxytunnel;
|
||||
bool ftp_append; /* APPE on ftp */
|
||||
bool mute; /* don't show messages, --silent given */
|
||||
|
@@ -173,6 +173,7 @@ static const struct LongShort aliases[]= {
|
||||
{"$H", "mail-auth", TRUE},
|
||||
{"$I", "post303", FALSE},
|
||||
{"$J", "metalink", FALSE},
|
||||
{"$K", "sasl-ir", FALSE},
|
||||
{"0", "http1.0", FALSE},
|
||||
{"1", "tlsv1", FALSE},
|
||||
{"2", "sslv2", FALSE},
|
||||
@@ -285,6 +286,105 @@ static const struct feat feats[] = {
|
||||
{"TLS-SRP", CURL_VERSION_TLSAUTH_SRP}
|
||||
};
|
||||
|
||||
/* Split the argument of -E to 'certname' and 'passphrase' separated by colon.
|
||||
* We allow ':' and '\' to be escaped by '\' so that we can use certificate
|
||||
* nicknames containing ':'. See <https://sourceforge.net/p/curl/bugs/1196/>
|
||||
* for details. */
|
||||
#ifndef UNITTESTS
|
||||
static
|
||||
#endif
|
||||
void parse_cert_parameter(const char *cert_parameter,
|
||||
char **certname,
|
||||
char **passphrase)
|
||||
{
|
||||
size_t param_length = strlen(cert_parameter);
|
||||
size_t span;
|
||||
const char *param_place = NULL;
|
||||
char *certname_place = NULL;
|
||||
*certname = NULL;
|
||||
*passphrase = NULL;
|
||||
|
||||
/* most trivial assumption: cert_parameter is empty */
|
||||
if(param_length == 0)
|
||||
return;
|
||||
|
||||
/* next less trivial: cert_parameter contains no colon nor backslash; this
|
||||
* means no passphrase was given and no characters escaped */
|
||||
if(!strpbrk(cert_parameter, ":\\")) {
|
||||
*certname = strdup(cert_parameter);
|
||||
return;
|
||||
}
|
||||
/* deal with escaped chars; find unescaped colon if it exists */
|
||||
certname_place = malloc(param_length + 1);
|
||||
if(!certname_place)
|
||||
return;
|
||||
|
||||
*certname = certname_place;
|
||||
param_place = cert_parameter;
|
||||
while(*param_place) {
|
||||
span = strcspn(param_place, ":\\");
|
||||
strncpy(certname_place, param_place, span);
|
||||
param_place += span;
|
||||
certname_place += span;
|
||||
/* we just ate all the non-special chars. now we're on either a special
|
||||
* char or the end of the string. */
|
||||
switch(*param_place) {
|
||||
case '\0':
|
||||
break;
|
||||
case '\\':
|
||||
param_place++;
|
||||
switch(*param_place) {
|
||||
case '\0':
|
||||
*certname_place++ = '\\';
|
||||
break;
|
||||
case '\\':
|
||||
*certname_place++ = '\\';
|
||||
param_place++;
|
||||
break;
|
||||
case ':':
|
||||
*certname_place++ = ':';
|
||||
param_place++;
|
||||
break;
|
||||
default:
|
||||
*certname_place++ = '\\';
|
||||
*certname_place++ = *param_place;
|
||||
param_place++;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ':':
|
||||
/* Since we live in a world of weirdness and confusion, the win32
|
||||
dudes can use : when using drive letters and thus c:\file:password
|
||||
needs to work. In order not to break compatibility, we still use : as
|
||||
separator, but we try to detect when it is used for a file name! On
|
||||
windows. */
|
||||
#ifdef WIN32
|
||||
if(param_place &&
|
||||
(param_place == &cert_parameter[1]) &&
|
||||
(cert_parameter[2] == '\\' || cert_parameter[2] == '/') &&
|
||||
(ISALPHA(cert_parameter[0])) ) {
|
||||
/* colon in the second column, followed by a backslash, and the
|
||||
first character is an alphabetic letter:
|
||||
|
||||
this is a drive letter colon */
|
||||
*certname_place++ = ':';
|
||||
param_place++;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
/* escaped colons and Windows drive letter colons were handled
|
||||
* above; if we're still here, this is a separating colon */
|
||||
param_place++;
|
||||
if(strlen(param_place) > 0) {
|
||||
*passphrase = strdup(param_place);
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
done:
|
||||
*certname_place = '\0';
|
||||
}
|
||||
|
||||
ParameterError getparameter(char *flag, /* f or -long-flag */
|
||||
char *nextarg, /* NULL if unset */
|
||||
bool *usedarg, /* set to TRUE if the arg
|
||||
@@ -858,6 +958,9 @@ ParameterError getparameter(char *flag, /* f or -long-flag */
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case 'K': /* --sasl-ir */
|
||||
config->sasl_ir = TRUE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case '#': /* --progress-bar */
|
||||
@@ -1203,30 +1306,14 @@ ParameterError getparameter(char *flag, /* f or -long-flag */
|
||||
break;
|
||||
default: /* certificate file */
|
||||
{
|
||||
char *ptr = strchr(nextarg, ':');
|
||||
/* Since we live in a world of weirdness and confusion, the win32
|
||||
dudes can use : when using drive letters and thus
|
||||
c:\file:password needs to work. In order not to break
|
||||
compatibility, we still use : as separator, but we try to detect
|
||||
when it is used for a file name! On windows. */
|
||||
#ifdef WIN32
|
||||
if(ptr &&
|
||||
(ptr == &nextarg[1]) &&
|
||||
(nextarg[2] == '\\' || nextarg[2] == '/') &&
|
||||
(ISALPHA(nextarg[0])) )
|
||||
/* colon in the second column, followed by a backslash, and the
|
||||
first character is an alphabetic letter:
|
||||
|
||||
this is a drive letter colon */
|
||||
ptr = strchr(&nextarg[3], ':'); /* find the next one instead */
|
||||
#endif
|
||||
if(ptr) {
|
||||
/* we have a password too */
|
||||
*ptr = '\0';
|
||||
ptr++;
|
||||
GetStr(&config->key_passwd, ptr);
|
||||
char *certname, *passphrase;
|
||||
parse_cert_parameter(nextarg, &certname, &passphrase);
|
||||
Curl_safefree(config->cert);
|
||||
config->cert = certname;
|
||||
if(passphrase) {
|
||||
Curl_safefree(config->key_passwd);
|
||||
config->key_passwd = passphrase;
|
||||
}
|
||||
GetStr(&config->cert, nextarg);
|
||||
cleanarg(nextarg);
|
||||
}
|
||||
}
|
||||
|
@@ -45,5 +45,11 @@ ParameterError getparameter(char *flag,
|
||||
bool *usedarg,
|
||||
struct Configurable *config);
|
||||
|
||||
#ifdef UNITTESTS
|
||||
void parse_cert_parameter(const char *cert_parameter,
|
||||
char **certname,
|
||||
char **passphrase);
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_GETPARAM_H */
|
||||
|
||||
|
@@ -173,6 +173,7 @@ static const char *const helptext[] = {
|
||||
" --retry-delay SECONDS "
|
||||
"When retrying, wait this many seconds between each",
|
||||
" --retry-max-time SECONDS Retry only within this period",
|
||||
" --sasl-ir Enable initial response in SASL authentication"
|
||||
" -S, --show-error "
|
||||
"Show error. With -s, make curl show errors when they occur",
|
||||
" -s, --silent Silent mode. Don't output anything",
|
||||
|
@@ -55,6 +55,9 @@
|
||||
int vms_show = 0;
|
||||
#endif
|
||||
|
||||
/* if we build a static library for unit tests, there is no main() function */
|
||||
#ifndef UNITTESTS
|
||||
|
||||
/*
|
||||
* Ensure that file descriptors 0, 1 and 2 (stdin, stdout, stderr) are
|
||||
* open before starting to run. Otherwise, the first three network
|
||||
@@ -118,3 +121,4 @@ int main(int argc, char *argv[])
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* ndef UNITTESTS */
|
||||
|
@@ -1320,6 +1320,10 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[])
|
||||
if(config->mail_auth)
|
||||
my_setopt_str(curl, CURLOPT_MAIL_AUTH, config->mail_auth);
|
||||
|
||||
/* new in 7.31.0 */
|
||||
if(config->sasl_ir)
|
||||
my_setopt(curl, CURLOPT_SASL_IR, (long)TRUE);
|
||||
|
||||
/* initialize retry vars for loop below */
|
||||
retry_sleep_default = (config->retry_delay) ?
|
||||
config->retry_delay*1000L : RETRY_SLEEP_DEFAULT; /* ms */
|
||||
|
@@ -5,7 +5,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -322,13 +322,19 @@ ParameterError str2offset(curl_off_t *val, const char *str)
|
||||
ParameterError checkpasswd(const char *kind, /* for what purpose */
|
||||
char **userpwd) /* pointer to allocated string */
|
||||
{
|
||||
char *ptr;
|
||||
char *psep;
|
||||
char *osep;
|
||||
|
||||
if(!*userpwd)
|
||||
return PARAM_OK;
|
||||
|
||||
ptr = strchr(*userpwd, ':');
|
||||
if(!ptr) {
|
||||
/* Attempt to find the password separator */
|
||||
psep = strchr(*userpwd, ':');
|
||||
|
||||
/* Attempt to find the options separator */
|
||||
osep = strchr(*userpwd, ';');
|
||||
|
||||
if(!psep && **userpwd != ';') {
|
||||
/* no password present, prompt for one */
|
||||
char passwd[256] = "";
|
||||
char prompt[256];
|
||||
@@ -336,6 +342,9 @@ ParameterError checkpasswd(const char *kind, /* for what purpose */
|
||||
size_t userlen = strlen(*userpwd);
|
||||
char *passptr;
|
||||
|
||||
if(osep)
|
||||
*osep = '\0';
|
||||
|
||||
/* build a nice-looking prompt */
|
||||
curlx_msnprintf(prompt, sizeof(prompt),
|
||||
"Enter %s password for user '%s':",
|
||||
@@ -345,6 +354,9 @@ ParameterError checkpasswd(const char *kind, /* for what purpose */
|
||||
getpass_r(prompt, passwd, sizeof(passwd));
|
||||
passwdlen = strlen(passwd);
|
||||
|
||||
if(osep)
|
||||
*osep = ';';
|
||||
|
||||
/* extend the allocated memory area to fit the password too */
|
||||
passptr = realloc(*userpwd,
|
||||
passwdlen + 1 + /* an extra for the colon */
|
||||
|
@@ -107,6 +107,8 @@ For FTP/SMTP/POP/IMAP, these are supported:
|
||||
REPLY [command] [return value] [response string]
|
||||
- Changes how the server responds to the [command]. [response string] is
|
||||
evaluated as a perl string, so it can contain embedded \r\n, for example.
|
||||
There's a special [command] named "welcome" (without quotes) which is the
|
||||
string sent immediately on connect as a welcome.
|
||||
COUNT [command] [num]
|
||||
- Do the REPLY change for [command] only [num] times and then go back to the
|
||||
built-in approach
|
||||
@@ -255,7 +257,9 @@ data that is defined within the <reply><data></data></reply> section.
|
||||
If there's no test number found above, the HTTP test server will use the
|
||||
number following the last dot in the given hostname (made so that a CONNECT
|
||||
can still pass on test number) so that "foo.bar.123" gets treated as test case
|
||||
123.
|
||||
123. Alternatively, if an ipv6-address is provided to CONNECT, the last
|
||||
hexadecimal group in the address will be used as the test numer! For example
|
||||
the address "[1234::ff]" would be treated as test case 255.
|
||||
|
||||
Set type="perl" to write the test case as a perl script. It implies that
|
||||
there's no memory debugging and valgrind gets shut off for this test.
|
||||
@@ -314,8 +318,11 @@ Variables are substituted on the contents of the file as in the <command>
|
||||
section.
|
||||
</file>
|
||||
|
||||
<stdin>
|
||||
<stdin [nonewline="yes"]>
|
||||
Pass this given data on stdin to the tool.
|
||||
|
||||
If 'nonewline' is set, we will cut off the trailing newline of this given data
|
||||
before comparing with the one actually received by the client
|
||||
</stdin>
|
||||
|
||||
</client>
|
||||
|
@@ -27,7 +27,7 @@ EXTRA_DIST = ftpserver.pl httpserver.pl secureserver.pl runtests.pl getpart.pm \
|
||||
FILEFORMAT README stunnel.pem memanalyze.pl testcurl.pl valgrind.pm ftp.pm \
|
||||
sshserver.pl sshhelp.pm testcurl.1 runtests.1 $(HTMLPAGES) $(PDFPAGES) \
|
||||
serverhelp.pm tftpserver.pl rtspserver.pl directories.pm symbol-scan.pl \
|
||||
CMakeLists.txt mem-include-scan.pl valgrind.supp
|
||||
CMakeLists.txt mem-include-scan.pl valgrind.supp http_pipe.py
|
||||
|
||||
# we have two variables here to make sure DIST_SUBDIRS won't get 'unit'
|
||||
# added twice as then targets such as 'distclean' misbehave and try to
|
||||
@@ -66,7 +66,7 @@ endif
|
||||
perlcheck:
|
||||
@if ! test -x "$(PERL)"; then echo "No perl!"; exit 2; fi
|
||||
|
||||
test: perhcheck all
|
||||
test: perlcheck all
|
||||
$(TEST)
|
||||
|
||||
quiet-test: perlcheck all
|
||||
|
@@ -61,13 +61,15 @@ test626 test627 test628 test629 test630 test631 test632 test633 test634 \
|
||||
test635 test636 test637 test638 test639 \
|
||||
\
|
||||
test700 test701 test702 test703 test704 test705 test706 test707 test708 \
|
||||
test709 test710 \
|
||||
test709 test710 test711 test712 \
|
||||
\
|
||||
test800 test801 test802 test803 test804 test805 test806 test807 test808 \
|
||||
test809 \
|
||||
\
|
||||
test850 test851 test852 test853 test854 test855 test856 test857 \
|
||||
\
|
||||
test900 test901 test902 test903 test904 test905 test906 \
|
||||
test900 test901 test902 test903 test904 test905 test906 test907 test908 \
|
||||
test909 test910 test911 \
|
||||
\
|
||||
test1000 test1001 test1002 test1003 test1004 test1005 test1006 test1007 \
|
||||
test1008 test1009 test1010 test1011 test1012 test1013 test1014 test1015 \
|
||||
@@ -89,8 +91,9 @@ test1128 test1129 test1130 test1131 test1132 test1133 \
|
||||
\
|
||||
test1200 test1201 test1202 test1203 test1204 test1205 test1206 test1207 \
|
||||
test1208 test1209 test1210 test1211 test1212 test1213 test1214 test1215 \
|
||||
test1216 test1217 test1218 \
|
||||
test1220 test1221 test1222 test1223 \
|
||||
test1216 test1217 test1218 test1219 \
|
||||
test1220 test1221 test1222 test1223 test1224 test1225 test1226 test1227 \
|
||||
test1228 test1229 test1230 \
|
||||
\
|
||||
test1300 test1301 test1302 test1303 test1304 test1305 test1306 test1307 \
|
||||
test1308 test1309 test1310 test1311 test1312 test1313 test1314 test1315 \
|
||||
@@ -103,13 +106,13 @@ test1356 test1357 test1358 test1359 test1360 test1361 test1362 test1363 \
|
||||
test1364 test1365 test1366 test1367 test1368 test1369 test1370 test1371 \
|
||||
test1372 test1373 test1374 test1375 test1376 test1377 test1378 test1379 \
|
||||
test1380 test1381 test1382 test1383 test1384 test1385 test1386 test1387 \
|
||||
test1388 test1389 test1390 test1391 test1392 test1393 \
|
||||
test1388 test1389 test1390 test1391 test1392 test1393 test1394 test1396 \
|
||||
\
|
||||
test1400 test1401 test1402 test1403 test1404 test1405 test1406 test1407 \
|
||||
test1408 test1409 test1410 test1411 test1412 test1413 \
|
||||
test1408 test1409 test1410 test1412 test1413 \
|
||||
\
|
||||
test1500 test1501 test1502 test1503 test1504 test1505 test1506 test1507 \
|
||||
test1508 test1509 test1510 \
|
||||
test1508 test1509 test1510 test1511 \
|
||||
\
|
||||
test1900 test1901 test1902 test1903 \
|
||||
\
|
||||
|
@@ -39,7 +39,8 @@ FTP GET with type=A style ASCII URL using %20 codes
|
||||
USER anonymous
|
||||
PASS ftp@example.com
|
||||
PWD
|
||||
CWD /path with spaces
|
||||
CWD /
|
||||
CWD path with spaces
|
||||
CWD and things2
|
||||
EPSV
|
||||
TYPE A
|
||||
|
@@ -874,7 +874,7 @@ crypto
|
||||
HTTP proxy CONNECT auth Digest, large headers and data
|
||||
</name>
|
||||
<command>
|
||||
http://test.remote.haxx.se.1060:%HTTPPORT/path/10600002 --proxy http://%HOSTIP:%HTTPPORT --proxy-user silly:person --proxy-digest --proxytunnel
|
||||
http://test.remote.haxx.se.1060:8990/path/10600002 --proxy http://%HOSTIP:%HTTPPORT --proxy-user silly:person --proxy-digest --proxytunnel
|
||||
</command>
|
||||
</client>
|
||||
|
||||
@@ -884,17 +884,17 @@ http://test.remote.haxx.se.1060:%HTTPPORT/path/10600002 --proxy http://%HOSTIP:%
|
||||
^User-Agent: curl/.*
|
||||
</strip>
|
||||
<protocol>
|
||||
CONNECT test.remote.haxx.se.1060:%HTTPPORT HTTP/1.1
|
||||
Host: test.remote.haxx.se.1060:%HTTPPORT
|
||||
CONNECT test.remote.haxx.se.1060:8990 HTTP/1.1
|
||||
Host: test.remote.haxx.se.1060:8990
|
||||
Proxy-Connection: Keep-Alive
|
||||
|
||||
CONNECT test.remote.haxx.se.1060:%HTTPPORT HTTP/1.1
|
||||
Host: test.remote.haxx.se.1060:%HTTPPORT
|
||||
Proxy-Authorization: Digest username="silly", realm="weirdorealm", nonce="12345", uri="test.remote.haxx.se.1060:%HTTPPORT", response="e1fbed39c26f4efe284adc0e576ff638"
|
||||
CONNECT test.remote.haxx.se.1060:8990 HTTP/1.1
|
||||
Host: test.remote.haxx.se.1060:8990
|
||||
Proxy-Authorization: Digest username="silly", realm="weirdorealm", nonce="12345", uri="test.remote.haxx.se.1060:8990", response="e1fbed39c26f4efe284adc0e576ff638"
|
||||
Proxy-Connection: Keep-Alive
|
||||
|
||||
GET /path/10600002 HTTP/1.1
|
||||
Host: test.remote.haxx.se.1060:%HTTPPORT
|
||||
Host: test.remote.haxx.se.1060:8990
|
||||
Accept: */*
|
||||
|
||||
</protocol>
|
||||
|
@@ -879,7 +879,7 @@ crypto
|
||||
HTTP proxy CONNECT auth Digest, large headers and chunked data
|
||||
</name>
|
||||
<command>
|
||||
http://test.remote.haxx.se.1061:%HTTPPORT/path/10610002 --proxy http://%HOSTIP:%HTTPPORT --proxy-user silly:person --proxy-digest --proxytunnel
|
||||
http://test.remote.haxx.se.1061:8990/path/10610002 --proxy http://%HOSTIP:%HTTPPORT --proxy-user silly:person --proxy-digest --proxytunnel
|
||||
</command>
|
||||
</client>
|
||||
|
||||
@@ -889,17 +889,17 @@ http://test.remote.haxx.se.1061:%HTTPPORT/path/10610002 --proxy http://%HOSTIP:%
|
||||
^User-Agent: curl/.*
|
||||
</strip>
|
||||
<protocol>
|
||||
CONNECT test.remote.haxx.se.1061:%HTTPPORT HTTP/1.1
|
||||
Host: test.remote.haxx.se.1061:%HTTPPORT
|
||||
CONNECT test.remote.haxx.se.1061:8990 HTTP/1.1
|
||||
Host: test.remote.haxx.se.1061:8990
|
||||
Proxy-Connection: Keep-Alive
|
||||
|
||||
CONNECT test.remote.haxx.se.1061:%HTTPPORT HTTP/1.1
|
||||
Host: test.remote.haxx.se.1061:%HTTPPORT
|
||||
Proxy-Authorization: Digest username="silly", realm="weirdorealm", nonce="12345", uri="test.remote.haxx.se.1061:%HTTPPORT", response="4e23449fa93224834299e7282a70472c"
|
||||
CONNECT test.remote.haxx.se.1061:8990 HTTP/1.1
|
||||
Host: test.remote.haxx.se.1061:8990
|
||||
Proxy-Authorization: Digest username="silly", realm="weirdorealm", nonce="12345", uri="test.remote.haxx.se.1061:8990", response="4e23449fa93224834299e7282a70472c"
|
||||
Proxy-Connection: Keep-Alive
|
||||
|
||||
GET /path/10610002 HTTP/1.1
|
||||
Host: test.remote.haxx.se.1061:%HTTPPORT
|
||||
Host: test.remote.haxx.se.1061:8990
|
||||
Accept: */*
|
||||
|
||||
</protocol>
|
||||
|
49
tests/data/test1219
Normal file
49
tests/data/test1219
Normal file
@@ -0,0 +1,49 @@
|
||||
<testcase>
|
||||
<info>
|
||||
<keywords>
|
||||
FTP
|
||||
PASV
|
||||
RETR
|
||||
</keywords>
|
||||
</info>
|
||||
# Server-side
|
||||
<reply>
|
||||
<data>
|
||||
data
|
||||
to
|
||||
see
|
||||
that FTP
|
||||
works
|
||||
so does it?
|
||||
</data>
|
||||
<servercmd>
|
||||
REPLY welcome 230 welcome without password
|
||||
</servercmd>
|
||||
</reply>
|
||||
|
||||
# Client-side
|
||||
<client>
|
||||
<server>
|
||||
ftp
|
||||
</server>
|
||||
<name>
|
||||
FTP with no user+password required (230 response)
|
||||
</name>
|
||||
<command>
|
||||
ftp://%HOSTIP:%FTPPORT/1219
|
||||
</command>
|
||||
|
||||
</client>
|
||||
|
||||
# Verify data after the test has been "shot"
|
||||
<verify>
|
||||
<protocol>
|
||||
PWD
|
||||
EPSV
|
||||
TYPE I
|
||||
SIZE 1219
|
||||
RETR 1219
|
||||
QUIT
|
||||
</protocol>
|
||||
</verify>
|
||||
</testcase>
|
49
tests/data/test1224
Normal file
49
tests/data/test1224
Normal file
@@ -0,0 +1,49 @@
|
||||
<testcase>
|
||||
<info>
|
||||
<keywords>
|
||||
FTP
|
||||
PASV
|
||||
RETR
|
||||
</keywords>
|
||||
</info>
|
||||
# Server-side
|
||||
<reply>
|
||||
<data>
|
||||
data
|
||||
to
|
||||
see
|
||||
that FTP
|
||||
works
|
||||
so does it?
|
||||
</data>
|
||||
</reply>
|
||||
|
||||
# Client-side
|
||||
<client>
|
||||
<server>
|
||||
ftp
|
||||
</server>
|
||||
<name>
|
||||
FTP fetch a file from the root directory
|
||||
</name>
|
||||
<command>
|
||||
ftp://%HOSTIP:%FTPPORT//1224
|
||||
</command>
|
||||
|
||||
</client>
|
||||
|
||||
# Verify data after the test has been "shot"
|
||||
<verify>
|
||||
<protocol>
|
||||
USER anonymous
|
||||
PASS ftp@example.com
|
||||
PWD
|
||||
CWD /
|
||||
EPSV
|
||||
TYPE I
|
||||
SIZE 1224
|
||||
RETR 1224
|
||||
QUIT
|
||||
</protocol>
|
||||
</verify>
|
||||
</testcase>
|
57
tests/data/test1225
Normal file
57
tests/data/test1225
Normal file
@@ -0,0 +1,57 @@
|
||||
<testcase>
|
||||
<info>
|
||||
<keywords>
|
||||
FTP
|
||||
PASV
|
||||
RETR
|
||||
</keywords>
|
||||
</info>
|
||||
# Server-side
|
||||
<reply>
|
||||
<data>
|
||||
data
|
||||
to
|
||||
see
|
||||
that FTP
|
||||
works
|
||||
so does it?
|
||||
</data>
|
||||
</reply>
|
||||
|
||||
# Client-side
|
||||
<client>
|
||||
<server>
|
||||
ftp
|
||||
</server>
|
||||
<name>
|
||||
FTP fetch two files using absolute paths
|
||||
</name>
|
||||
<command>
|
||||
ftp://%HOSTIP:%FTPPORT//foo/1225 ftp://%HOSTIP:%FTPPORT//foo/bar/1225
|
||||
</command>
|
||||
|
||||
</client>
|
||||
|
||||
# Verify data after the test has been "shot"
|
||||
<verify>
|
||||
<protocol>
|
||||
USER anonymous
|
||||
PASS ftp@example.com
|
||||
PWD
|
||||
CWD /
|
||||
CWD foo
|
||||
EPSV
|
||||
TYPE I
|
||||
SIZE 1225
|
||||
RETR 1225
|
||||
CWD /
|
||||
CWD /
|
||||
CWD foo
|
||||
CWD bar
|
||||
EPSV
|
||||
SIZE 1225
|
||||
RETR 1225
|
||||
QUIT
|
||||
</protocol>
|
||||
</verify>
|
||||
</testcase>
|
49
tests/data/test1226
Normal file
49
tests/data/test1226
Normal file
@@ -0,0 +1,49 @@
|
||||
<testcase>
|
||||
<info>
|
||||
<keywords>
|
||||
FTP
|
||||
PASV
|
||||
RETR
|
||||
</keywords>
|
||||
</info>
|
||||
# Server-side
|
||||
<reply>
|
||||
<data>
|
||||
data
|
||||
to
|
||||
see
|
||||
that FTP
|
||||
works
|
||||
so does it?
|
||||
</data>
|
||||
</reply>
|
||||
|
||||
# Client-side
|
||||
<client>
|
||||
<server>
|
||||
ftp
|
||||
</server>
|
||||
<name>
|
||||
FTP fetch a file from the root directory with singlecwd
|
||||
</name>
|
||||
<command>
|
||||
ftp://%HOSTIP:%FTPPORT//1226 --ftp-method singlecwd
|
||||
</command>
|
||||
|
||||
</client>
|
||||
|
||||
# Verify data after the test has been "shot"
|
||||
<verify>
|
||||
<protocol>
|
||||
USER anonymous
|
||||
PASS ftp@example.com
|
||||
PWD
|
||||
CWD /
|
||||
EPSV
|
||||
TYPE I
|
||||
SIZE 1226
|
||||
RETR 1226
|
||||
QUIT
|
||||
</protocol>
|
||||
</verify>
|
||||
</testcase>
|
48
tests/data/test1227
Normal file
48
tests/data/test1227
Normal file
@@ -0,0 +1,48 @@
|
||||
<testcase>
|
||||
<info>
|
||||
<keywords>
|
||||
FTP
|
||||
PASV
|
||||
RETR
|
||||
</keywords>
|
||||
</info>
|
||||
# Server-side
|
||||
<reply>
|
||||
<data>
|
||||
data
|
||||
to
|
||||
see
|
||||
that FTP
|
||||
works
|
||||
so does it?
|
||||
</data>
|
||||
</reply>
|
||||
|
||||
# Client-side
|
||||
<client>
|
||||
<server>
|
||||
ftp
|
||||
</server>
|
||||
<name>
|
||||
FTP fetch a file from the root directory with nocwd
|
||||
</name>
|
||||
<command>
|
||||
ftp://%HOSTIP:%FTPPORT//1227 --ftp-method nocwd
|
||||
</command>
|
||||
|
||||
</client>
|
||||
|
||||
# Verify data after the test has been "shot"
|
||||
<verify>
|
||||
<protocol>
|
||||
USER anonymous
|
||||
PASS ftp@example.com
|
||||
PWD
|
||||
EPSV
|
||||
TYPE I
|
||||
SIZE /1227
|
||||
RETR /1227
|
||||
QUIT
|
||||
</protocol>
|
||||
</verify>
|
||||
</testcase>
|
54
tests/data/test1228
Normal file
54
tests/data/test1228
Normal file
@@ -0,0 +1,54 @@
|
||||
<testcase>
|
||||
<info>
|
||||
<keywords>
|
||||
HTTP
|
||||
HTTP GET
|
||||
cookies
|
||||
cookie path
|
||||
</keywords>
|
||||
</info>
|
||||
<reply>
|
||||
<data>
|
||||
HTTP/1.1 200 OK
|
||||
Date: Tue, 25 Sep 2001 19:37:44 GMT
|
||||
Set-Cookie: path1=root; domain=.example.fake; path=/;
|
||||
Set-Cookie: path2=depth1; domain=.example.fake; path=/hoge;
|
||||
Content-Length: 34
|
||||
|
||||
This server says cookie path test
|
||||
</data>
|
||||
</reply>
|
||||
|
||||
# Client-side
|
||||
<client>
|
||||
<server>
|
||||
http
|
||||
</server>
|
||||
<name>
|
||||
HTTP cookie path match
|
||||
</name>
|
||||
<command>
|
||||
http://example.fake/hoge/1228 http://example.fake/hogege/ -b nonexisting -x %HOSTIP:%HTTPPORT
|
||||
</command>
|
||||
</client>
|
||||
|
||||
# Verify data after the test has been "shot"
|
||||
<verify>
|
||||
<strip>
|
||||
^User-Agent:.*
|
||||
</strip>
|
||||
<protocol>
|
||||
GET http://example.fake/hoge/1228 HTTP/1.1
|
||||
Host: example.fake
|
||||
Accept: */*
|
||||
Proxy-Connection: Keep-Alive
|
||||
|
||||
GET http://example.fake/hogege/ HTTP/1.1
|
||||
Host: example.fake
|
||||
Accept: */*
|
||||
Proxy-Connection: Keep-Alive
|
||||
Cookie: path1=root
|
||||
|
||||
</protocol>
|
||||
</verify>
|
||||
</testcase>
|
82
tests/data/test1229
Normal file
82
tests/data/test1229
Normal file
@@ -0,0 +1,82 @@
|
||||
<testcase>
|
||||
<info>
|
||||
<keywords>
|
||||
HTTP
|
||||
HTTP GET
|
||||
HTTP Digest auth
|
||||
</keywords>
|
||||
</info>
|
||||
# Server-side
|
||||
<reply>
|
||||
<data>
|
||||
HTTP/1.1 401 Authorization Required swsclose
|
||||
Server: Apache/1.3.27 (Darwin) PHP/4.1.2
|
||||
WWW-Authenticate: Digest realm="testrealm", nonce="1053604145"
|
||||
Content-Type: text/html; charset=iso-8859-1
|
||||
Content-Length: 26
|
||||
|
||||
This is not the real page
|
||||
</data>
|
||||
|
||||
# This is supposed to be returned when the server gets a
|
||||
# Authorization: Digest line passed-in from the client
|
||||
<data1000>
|
||||
HTTP/1.1 200 OK swsclose
|
||||
Server: Apache/1.3.27 (Darwin) PHP/4.1.2
|
||||
Content-Type: text/html; charset=iso-8859-1
|
||||
Content-Length: 23
|
||||
|
||||
This IS the real page!
|
||||
</data1000>
|
||||
|
||||
<datacheck>
|
||||
HTTP/1.1 401 Authorization Required swsclose
|
||||
Server: Apache/1.3.27 (Darwin) PHP/4.1.2
|
||||
WWW-Authenticate: Digest realm="testrealm", nonce="1053604145"
|
||||
Content-Type: text/html; charset=iso-8859-1
|
||||
Content-Length: 26
|
||||
|
||||
HTTP/1.1 200 OK swsclose
|
||||
Server: Apache/1.3.27 (Darwin) PHP/4.1.2
|
||||
Content-Type: text/html; charset=iso-8859-1
|
||||
Content-Length: 23
|
||||
|
||||
This IS the real page!
|
||||
</datacheck>
|
||||
|
||||
</reply>
|
||||
|
||||
# Client-side
|
||||
<client>
|
||||
<server>
|
||||
http
|
||||
</server>
|
||||
<features>
|
||||
crypto
|
||||
</features>
|
||||
<name>
|
||||
HTTP with Digest authorization with user name needing escape
|
||||
</name>
|
||||
<command>
|
||||
http://%5cuser%22:password@%HOSTIP:%HTTPPORT/1229 --digest
|
||||
</command>
|
||||
</client>
|
||||
|
||||
# Verify data after the test has been "shot"
|
||||
<verify>
|
||||
<strip>
|
||||
^User-Agent:.*
|
||||
</strip>
|
||||
<protocol>
|
||||
GET /1229 HTTP/1.1
|
||||
Host: %HOSTIP:%HTTPPORT
|
||||
Accept: */*
|
||||
|
||||
GET /1229 HTTP/1.1
|
||||
Authorization: Digest username="\\user\"", realm="testrealm", nonce="1053604145", uri="/1229", response="f2694d426040712584c156d3de72b8d6"
|
||||
Host: %HOSTIP:%HTTPPORT
|
||||
Accept: */*
|
||||
|
||||
</protocol>
|
||||
</verify>
|
||||
</testcase>
|
79
tests/data/test1230
Normal file
79
tests/data/test1230
Normal file
@@ -0,0 +1,79 @@
|
||||
<testcase>
|
||||
<info>
|
||||
<keywords>
|
||||
HTTP
|
||||
HTTP CONNECT
|
||||
IPv6
|
||||
</keywords>
|
||||
|
||||
</info>
|
||||
#
|
||||
# Server-side
|
||||
<reply>
|
||||
|
||||
<data>
|
||||
HTTP/1.1 200 OK
|
||||
Date: Thu, 09 Nov 2010 14:49:00 GMT
|
||||
Content-Length: 9
|
||||
|
||||
mooooooo
|
||||
</data>
|
||||
|
||||
<connect>
|
||||
HTTP/1.1 200 welcome dear
|
||||
Date: Thu, 09 Nov 2010 14:49:00 GMT
|
||||
Content-Length: 0
|
||||
|
||||
</connect>
|
||||
|
||||
<datacheck>
|
||||
HTTP/1.1 200 welcome dear
|
||||
Date: Thu, 09 Nov 2010 14:49:00 GMT
|
||||
Content-Length: 0
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Date: Thu, 09 Nov 2010 14:49:00 GMT
|
||||
Content-Length: 9
|
||||
|
||||
mooooooo
|
||||
</datacheck>
|
||||
</reply>
|
||||
|
||||
#
|
||||
# Client-side
|
||||
<client>
|
||||
<features>
|
||||
ipv6
|
||||
</features>
|
||||
<server>
|
||||
http-proxy
|
||||
http-ipv6
|
||||
http
|
||||
</server>
|
||||
<name>
|
||||
HTTP CONNECT to IPv6 numerical address
|
||||
</name>
|
||||
# 0x4ce == 1230, the test number
|
||||
<command>
|
||||
-g http://[1234:1234:1234::4ce]:%HTTPPORT/wanted/page/1230 -p -x %HOSTIP:%HTTPPORT
|
||||
</command>
|
||||
</client>
|
||||
|
||||
#
|
||||
# Verify data after the test has been "shot"
|
||||
<verify>
|
||||
<strip>
|
||||
^User-Agent:.*
|
||||
</strip>
|
||||
<protocol>
|
||||
CONNECT [1234:1234:1234::4ce]:%HTTPPORT HTTP/1.1
|
||||
Host: [1234:1234:1234::4ce]:%HTTPPORT
|
||||
Proxy-Connection: Keep-Alive
|
||||
|
||||
GET /wanted/page/1230 HTTP/1.1
|
||||
Host: [1234:1234:1234::4ce]:8990
|
||||
Accept: */*
|
||||
|
||||
</protocol>
|
||||
</verify>
|
||||
</testcase>
|
@@ -29,10 +29,10 @@ http-proxy
|
||||
SMTP send tunneled trough HTTP proxy
|
||||
</name>
|
||||
<stdin>
|
||||
From: different
|
||||
To: another
|
||||
|
||||
body
|
||||
From: different
|
||||
To: another
|
||||
|
||||
body
|
||||
</stdin>
|
||||
<command>
|
||||
smtp://smtp.1320:%SMTPPORT/user --mail-rcpt 1320@foo --mail-rcpt 1320@foobar.example --mail-from 1320@from -T - -p -x %HOSTIP:%PROXYPORT
|
||||
@@ -54,11 +54,10 @@ DATA
|
||||
QUIT
|
||||
</protocol>
|
||||
<upload>
|
||||
From: different
|
||||
To: another
|
||||
|
||||
body
|
||||
From: different
|
||||
To: another
|
||||
|
||||
body
|
||||
.
|
||||
</upload>
|
||||
<proxy>
|
||||
|
30
tests/data/test1394
Normal file
30
tests/data/test1394
Normal file
@@ -0,0 +1,30 @@
|
||||
<testcase>
|
||||
<info>
|
||||
<keywords>
|
||||
unittest
|
||||
</keywords>
|
||||
</info>
|
||||
|
||||
#
|
||||
# Client-side
|
||||
<client>
|
||||
<server>
|
||||
none
|
||||
</server>
|
||||
<features>
|
||||
unittest
|
||||
</features>
|
||||
<name>
|
||||
unit test for parse_cert_parameter()
|
||||
</name>
|
||||
<tool>
|
||||
unit1394
|
||||
</tool>
|
||||
</client>
|
||||
|
||||
<verify>
|
||||
<stdout mode="text">
|
||||
</stdout>
|
||||
</verify>
|
||||
|
||||
</testcase>
|
27
tests/data/test1396
Normal file
27
tests/data/test1396
Normal file
@@ -0,0 +1,27 @@
|
||||
<testcase>
|
||||
<info>
|
||||
<keywords>
|
||||
unittest
|
||||
curl_easy_escape
|
||||
curl_easy_unescape
|
||||
</keywords>
|
||||
</info>
|
||||
|
||||
#
|
||||
# Client-side
|
||||
<client>
|
||||
<server>
|
||||
none
|
||||
</server>
|
||||
<features>
|
||||
unittest
|
||||
</features>
|
||||
<name>
|
||||
curl_easy_escape and curl_easy_unescape
|
||||
</name>
|
||||
<tool>
|
||||
unit1310
|
||||
</tool>
|
||||
</client>
|
||||
|
||||
</testcase>
|
@@ -23,10 +23,10 @@ smtp
|
||||
SMTP
|
||||
</name>
|
||||
<file name="log/test1406.eml">
|
||||
From: different
|
||||
To: another
|
||||
|
||||
body
|
||||
From: different
|
||||
To: another
|
||||
|
||||
body
|
||||
</file>
|
||||
<command>
|
||||
smtp://%HOSTIP:%SMTPPORT/user --mail-rcpt 1406@foo --mail-rcpt 1406@foobar.example --mail-from 1406@from -T log/test1406.eml --libcurl log/test1406.c
|
||||
@@ -38,18 +38,17 @@ smtp://%HOSTIP:%SMTPPORT/user --mail-rcpt 1406@foo --mail-rcpt 1406@foobar.examp
|
||||
<verify>
|
||||
<protocol>
|
||||
EHLO user
|
||||
MAIL FROM:<1406@from> SIZE=34
|
||||
MAIL FROM:<1406@from> SIZE=38
|
||||
RCPT TO:<1406@foo>
|
||||
RCPT TO:<1406@foobar.example>
|
||||
DATA
|
||||
QUIT
|
||||
</protocol>
|
||||
<upload>
|
||||
From: different
|
||||
To: another
|
||||
|
||||
body
|
||||
From: different
|
||||
To: another
|
||||
|
||||
body
|
||||
.
|
||||
</upload>
|
||||
<file name="log/test1406.c" mode="text">
|
||||
@@ -70,7 +69,7 @@ int main(int argc, char *argv[])
|
||||
slist1 = curl_slist_append(slist1, "1406@foobar.example");
|
||||
|
||||
hnd = curl_easy_init();
|
||||
curl_easy_setopt(hnd, CURLOPT_INFILESIZE_LARGE, (curl_off_t)34);
|
||||
curl_easy_setopt(hnd, CURLOPT_INFILESIZE_LARGE, (curl_off_t)38);
|
||||
curl_easy_setopt(hnd, CURLOPT_URL, "smtp://%HOSTIP:%SMTPPORT/user");
|
||||
curl_easy_setopt(hnd, CURLOPT_HEADER, 1L);
|
||||
curl_easy_setopt(hnd, CURLOPT_UPLOAD, 1L);
|
||||
|
62
tests/data/test1511
Normal file
62
tests/data/test1511
Normal file
@@ -0,0 +1,62 @@
|
||||
<testcase>
|
||||
<info>
|
||||
<keywords>
|
||||
HTTP
|
||||
</keywords>
|
||||
</info>
|
||||
|
||||
# Server-side
|
||||
<reply>
|
||||
<data>
|
||||
HTTP/1.1 200
|
||||
Date: Thu, 09 Nov 2010 14:49:00 GMT
|
||||
Server: test-server/fakem
|
||||
Last-Modified: Mon, 22 Apr 2013 17:45:05 GMT
|
||||
Content-Type: text/html
|
||||
Content-Length: 12
|
||||
Connection: close
|
||||
|
||||
Hello World
|
||||
</data>
|
||||
|
||||
<datacheck>
|
||||
HTTP/1.1 200
|
||||
Date: Thu, 09 Nov 2010 14:49:00 GMT
|
||||
Server: test-server/fakem
|
||||
Last-Modified: Mon, 22 Apr 2013 17:45:05 GMT
|
||||
Content-Type: text/html
|
||||
Content-Length: 12
|
||||
Connection: close
|
||||
|
||||
HTTP/1.1 200
|
||||
Date: Thu, 09 Nov 2010 14:49:00 GMT
|
||||
Server: test-server/fakem
|
||||
Last-Modified: Mon, 22 Apr 2013 17:45:05 GMT
|
||||
Content-Type: text/html
|
||||
Content-Length: 12
|
||||
Connection: close
|
||||
|
||||
Hello World
|
||||
</datacheck>
|
||||
|
||||
</reply>
|
||||
|
||||
# Client-side
|
||||
<client>
|
||||
<server>
|
||||
http
|
||||
</server>
|
||||
<features>
|
||||
http
|
||||
</features>
|
||||
<tool>
|
||||
lib1511
|
||||
</tool>
|
||||
<name>
|
||||
HTTP GET time conditions in repeated requests
|
||||
</name>
|
||||
<command>
|
||||
http://%HOSTIP:%HTTPPORT/1511
|
||||
</command>
|
||||
</client>
|
||||
</testcase>
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user