63
64
#include "private/svn_cmdline_private.h"
64
65
#include "private/svn_utf_private.h"
66
#include "private/svn_sorts_private.h"
65
67
#include "private/svn_string_private.h"
67
69
#include "svn_private_config.h"
69
71
#include "win32_crashrpt.h"
73
#if defined(WIN32) && defined(_MSC_VER) && (_MSC_VER < 1400)
74
/* Before Visual Studio 2005, the C runtime didn't handle encodings for the
75
for the stdio output handling. */
76
#define CMDLINE_USE_CUSTOM_ENCODING
71
78
/* The stdin encoding. If null, it's the same as the native encoding. */
72
79
static const char *input_encoding = NULL;
74
81
/* The stdout encoding. If null, it's the same as the native encoding. */
75
82
static const char *output_encoding = NULL;
83
#elif defined(WIN32) && defined(_MSC_VER)
84
/* For now limit this code to Visual C++, as the result is highly dependent
85
on the CRT implementation */
86
#define USE_WIN32_CONSOLE_SHORTCUT
88
/* When TRUE, stdout/stderr is directly connected to a console */
89
static svn_boolean_t shortcut_stdout_to_console = FALSE;
90
static svn_boolean_t shortcut_stderr_to_console = FALSE;
128
144
"CP%u", (unsigned) GetConsoleOutputCP());
129
145
output_encoding = output_encoding_buffer;
131
#endif /* _MSC_VER < 1400 */
147
#endif /* CMDLINE_USE_CUSTOM_ENCODING */
133
149
#ifdef SVN_USE_WIN32_CRASHHANDLER
134
/* Attach (but don't load) the crash handler */
135
SetUnhandledExceptionFilter(svn__unhandled_exception_filter);
150
if (!getenv("SVN_CMDLINE_DISABLE_CRASH_HANDLER"))
152
/* Attach (but don't load) the crash handler */
153
SetUnhandledExceptionFilter(svn__unhandled_exception_filter);
137
155
#if _MSC_VER >= 1400
138
/* ### This should work for VC++ 2002 (=1300) and later */
139
/* Show the abort message on STDERR instead of a dialog to allow
140
scripts (e.g. our testsuite) to continue after an abort without
141
user intervention. Allow overriding for easier debugging. */
142
if (!getenv("SVN_CMDLINE_USE_DIALOG_FOR_ABORT"))
144
/* In release mode: Redirect abort() errors to stderr */
145
_set_error_mode(_OUT_TO_STDERR);
156
/* ### This should work for VC++ 2002 (=1300) and later */
157
/* Show the abort message on STDERR instead of a dialog to allow
158
scripts (e.g. our testsuite) to continue after an abort without
159
user intervention. Allow overriding for easier debugging. */
160
if (!getenv("SVN_CMDLINE_USE_DIALOG_FOR_ABORT"))
162
/* In release mode: Redirect abort() errors to stderr */
163
_set_error_mode(_OUT_TO_STDERR);
147
/* In _DEBUG mode: Redirect all debug output (E.g. assert() to stderr.
148
(Ignored in release builds) */
149
_CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR);
150
_CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR);
151
_CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR);
152
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
153
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
154
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
165
/* In _DEBUG mode: Redirect all debug output (E.g. assert() to stderr.
166
(Ignored in release builds) */
167
_CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR);
168
_CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR);
169
_CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR);
170
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
171
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
172
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
156
174
#endif /* _MSC_VER >= 1400 */
158
176
#endif /* SVN_USE_WIN32_CRASHHANDLER */
160
178
#endif /* WIN32 */
247
265
return EXIT_FAILURE;
268
#ifdef USE_WIN32_CONSOLE_SHORTCUT
269
if (_isatty(STDOUT_FILENO))
272
HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
274
/* stdout is a char device handle, but is it the console? */
275
if (GetConsoleMode(stdout_handle, &ignored))
276
shortcut_stdout_to_console = TRUE;
278
/* Don't close stdout_handle */
280
if (_isatty(STDERR_FILENO))
283
HANDLE stderr_handle = GetStdHandle(STD_ERROR_HANDLE);
285
/* stderr is a char device handle, but is it the console? */
286
if (GetConsoleMode(stderr_handle, &ignored))
287
shortcut_stderr_to_console = TRUE;
289
/* Don't close stderr_handle */
250
293
return EXIT_SUCCESS;
336
383
svn_error_t *err;
386
#ifdef USE_WIN32_CONSOLE_SHORTCUT
387
/* For legacy reasons the Visual C++ runtime converts output to the console
388
from the native 'ansi' encoding, to unicode, then back to 'ansi' and then
389
onwards to the console which is implemented as unicode.
391
For operations like 'svn status -v' this may cause about 70% of the total
392
processing time, with absolutely no gain.
394
For this specific scenario this shortcut exists. It has the nice side
395
effect of allowing full unicode output to the console.
397
Note that this shortcut is not used when the output is redirected, as in
398
that case the data is put on the pipe/file after the first conversion to
399
ansi. In this case the most expensive conversion is already avoided.
401
if ((stream == stdout && shortcut_stdout_to_console)
402
|| (stream == stderr && shortcut_stderr_to_console))
406
if (string[0] == '\0')
409
SVN_ERR(svn_cmdline_fflush(stream)); /* Flush existing output */
411
SVN_ERR(svn_utf__win32_utf8_to_utf16(&result, string, NULL, pool));
415
if (apr_get_os_error())
417
return svn_error_wrap_apr(apr_get_os_error(), _("Write error"));
339
425
err = svn_cmdline_cstring_from_utf8(&out, string, pool);
419
507
return EXIT_FAILURE;
510
struct trust_server_cert_non_interactive_baton {
511
svn_boolean_t trust_server_cert_unknown_ca;
512
svn_boolean_t trust_server_cert_cn_mismatch;
513
svn_boolean_t trust_server_cert_expired;
514
svn_boolean_t trust_server_cert_not_yet_valid;
515
svn_boolean_t trust_server_cert_other_failure;
422
518
/* This implements 'svn_auth_ssl_server_trust_prompt_func_t'.
424
520
Don't actually prompt. Instead, set *CRED_P to valid credentials
425
iff FAILURES is empty or is exactly SVN_AUTH_SSL_UNKNOWNCA. If
426
there are any other failure bits, then set *CRED_P to null (that
427
is, reject the cert).
521
iff FAILURES is empty or may be accepted according to the flags
522
in BATON. If there are any other failure bits, then set *CRED_P
523
to null (that is, reject the cert).
429
525
Ignore MAY_SAVE; we don't save certs we never prompted for.
431
Ignore BATON, REALM, and CERT_INFO,
527
Ignore REALM and CERT_INFO,
433
529
Ignore any further films by George Lucas. */
434
530
static svn_error_t *
435
ssl_trust_unknown_server_cert
436
(svn_auth_cred_ssl_server_trust_t **cred_p,
439
apr_uint32_t failures,
440
const svn_auth_ssl_server_cert_info_t *cert_info,
441
svn_boolean_t may_save,
531
trust_server_cert_non_interactive(svn_auth_cred_ssl_server_trust_t **cred_p,
534
apr_uint32_t failures,
535
const svn_auth_ssl_server_cert_info_t
537
svn_boolean_t may_save,
540
struct trust_server_cert_non_interactive_baton *b = baton;
541
apr_uint32_t non_ignored_failures;
446
if (failures == 0 || failures == SVN_AUTH_SSL_UNKNOWNCA)
544
/* Mask away bits we are instructed to ignore. */
545
non_ignored_failures = failures & ~(
546
(b->trust_server_cert_unknown_ca ? SVN_AUTH_SSL_UNKNOWNCA : 0)
547
| (b->trust_server_cert_cn_mismatch ? SVN_AUTH_SSL_CNMISMATCH : 0)
548
| (b->trust_server_cert_expired ? SVN_AUTH_SSL_EXPIRED : 0)
549
| (b->trust_server_cert_not_yet_valid ? SVN_AUTH_SSL_NOTYETVALID : 0)
550
| (b->trust_server_cert_other_failure ? SVN_AUTH_SSL_OTHER : 0)
553
/* If no failures remain, accept the certificate. */
554
if (non_ignored_failures == 0)
448
556
*cred_p = apr_pcalloc(pool, sizeof(**cred_p));
449
557
(*cred_p)->may_save = FALSE;
457
svn_cmdline_create_auth_baton(svn_auth_baton_t **ab,
458
svn_boolean_t non_interactive,
459
const char *auth_username,
460
const char *auth_password,
461
const char *config_dir,
462
svn_boolean_t no_auth_cache,
463
svn_boolean_t trust_server_cert,
465
svn_cancel_func_t cancel_func,
565
svn_cmdline_create_auth_baton2(svn_auth_baton_t **ab,
566
svn_boolean_t non_interactive,
567
const char *auth_username,
568
const char *auth_password,
569
const char *config_dir,
570
svn_boolean_t no_auth_cache,
571
svn_boolean_t trust_server_cert_unknown_ca,
572
svn_boolean_t trust_server_cert_cn_mismatch,
573
svn_boolean_t trust_server_cert_expired,
574
svn_boolean_t trust_server_cert_not_yet_valid,
575
svn_boolean_t trust_server_cert_other_failure,
577
svn_cancel_func_t cancel_func,
469
582
svn_boolean_t store_password_val = TRUE;
470
583
svn_boolean_t store_auth_creds_val = TRUE;
505
618
svn_auth_get_username_provider(&provider, pool);
506
619
APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
508
/* The windows ssl server certificate CRYPTOAPI provider. */
509
SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
515
APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
517
/* The windows ssl authority certificate CRYPTOAPI provider. */
518
SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
520
"ssl_server_authority",
524
APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
526
621
svn_auth_get_ssl_server_trust_file_provider(&provider, pool);
527
622
APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
528
623
svn_auth_get_ssl_client_cert_file_provider(&provider, pool);
583
678
APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
586
else if (trust_server_cert)
681
else if (trust_server_cert_unknown_ca || trust_server_cert_cn_mismatch ||
682
trust_server_cert_expired || trust_server_cert_not_yet_valid ||
683
trust_server_cert_other_failure)
685
struct trust_server_cert_non_interactive_baton *b;
687
b = apr_palloc(pool, sizeof(*b));
688
b->trust_server_cert_unknown_ca = trust_server_cert_unknown_ca;
689
b->trust_server_cert_cn_mismatch = trust_server_cert_cn_mismatch;
690
b->trust_server_cert_expired = trust_server_cert_expired;
691
b->trust_server_cert_not_yet_valid = trust_server_cert_not_yet_valid;
692
b->trust_server_cert_other_failure = trust_server_cert_other_failure;
588
694
/* Remember, only register this provider if non_interactive. */
589
695
svn_auth_get_ssl_server_trust_prompt_provider
590
(&provider, ssl_trust_unknown_server_cert, NULL, pool);
696
(&provider, trust_server_cert_non_interactive, b, pool);
591
697
APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
689
795
outstr, pool, svn_xml_protect_pcdata,
690
796
inherited_prop ? "inherited_property" : "property",
691
797
"name", propname,
692
"encoding", encoding, NULL);
798
"encoding", encoding, SVN_VA_NULL);
694
800
svn_xml_make_open_tag(
695
801
outstr, pool, svn_xml_protect_pcdata,
696
802
inherited_prop ? "inherited_property" : "property",
697
"name", propname, NULL);
803
"name", propname, SVN_VA_NULL);
699
805
svn_stringbuf_appendcstr(*outstr, xml_safe);
814
/* Return the most similar string to NEEDLE in HAYSTACK, which contains
815
* HAYSTACK_LEN elements. Return NULL if no string is sufficiently similar.
817
/* See svn_cl__similarity_check() for a more general solution. */
819
most_similar(const char *needle_cstr,
820
const char **haystack,
821
apr_size_t haystack_len,
822
apr_pool_t *scratch_pool)
824
const char *max_similar;
825
apr_size_t max_score = 0;
828
svn_string_t *needle_str = svn_string_create(needle_cstr, scratch_pool);
830
svn_membuf__create(&membuf, 64, scratch_pool);
832
for (i = 0; i < haystack_len; i++)
835
svn_string_t *hay = svn_string_create(haystack[i], scratch_pool);
837
score = svn_string__similarity(needle_str, hay, &membuf, NULL);
839
/* If you update this factor, consider updating
840
* svn_cl__similarity_check(). */
841
if (score >= (2 * SVN_STRING__SIM_RANGE_MAX + 1) / 3
842
&& score > max_score)
845
max_similar = haystack[i];
855
/* Verify that NEEDLE is in HAYSTACK, which contains HAYSTACK_LEN elements. */
857
string_in_array(const char *needle,
858
const char **haystack,
859
apr_size_t haystack_len,
860
apr_pool_t *scratch_pool)
862
const char *next_of_kin;
864
for (i = 0; i < haystack_len; i++)
866
if (!strcmp(needle, haystack[i]))
871
next_of_kin = most_similar(needle, haystack, haystack_len, scratch_pool);
873
return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
874
_("Ignoring unknown value '%s'; "
875
"did you mean '%s'?"),
876
needle, next_of_kin);
878
return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
879
_("Ignoring unknown value '%s'"),
883
#include "config_keys.inc"
885
/* Validate the FILE, SECTION, and OPTION components of CONFIG_OPTION are
886
* known. Warn to stderr if not. (An unknown value may be either a typo
887
* or added in a newer minor version of Subversion.) */
889
validate_config_option(svn_cmdline__config_argument_t *config_option,
890
apr_pool_t *scratch_pool)
892
svn_boolean_t arbitrary_keys = FALSE;
894
/* TODO: some day, we could also verify that OPTION is valid for SECTION;
895
i.e., forbid invalid combinations such as config:auth:diff-extensions. */
897
#define ARRAYLEN(x) ( sizeof((x)) / sizeof((x)[0]) )
899
SVN_ERR(string_in_array(config_option->file, svn__valid_config_files,
900
ARRAYLEN(svn__valid_config_files),
902
SVN_ERR(string_in_array(config_option->section, svn__valid_config_sections,
903
ARRAYLEN(svn__valid_config_sections),
906
/* Don't validate option names for sections such as servers[group],
907
* config[tunnels], and config[auto-props] that permit arbitrary options. */
911
for (i = 0; i < ARRAYLEN(svn__empty_config_sections); i++)
913
if (!strcmp(config_option->section, svn__empty_config_sections[i]))
914
arbitrary_keys = TRUE;
918
if (! arbitrary_keys)
919
SVN_ERR(string_in_array(config_option->option, svn__valid_config_options,
920
ARRAYLEN(svn__valid_config_options),
709
929
svn_cmdline__parse_config_option(apr_array_header_t *config_options,
710
930
const char *opt_arg,
711
932
apr_pool_t *pool)
713
934
svn_cmdline__config_argument_t *config_option;
729
952
config_option->option = apr_pstrndup(pool, second_colon + 1,
730
953
equals_sign - second_colon - 1);
955
warning = validate_config_option(config_option, pool);
958
svn_handle_warning2(stderr, warning, prefix);
959
svn_error_clear(warning);
732
962
if (! (strchr(config_option->option, ':')))
734
964
config_option->value = apr_pstrndup(pool, equals_sign + 1,
1320
1550
return svn_error_trace(err);
1554
svn_cmdline__parse_trust_options(
1555
svn_boolean_t *trust_server_cert_unknown_ca,
1556
svn_boolean_t *trust_server_cert_cn_mismatch,
1557
svn_boolean_t *trust_server_cert_expired,
1558
svn_boolean_t *trust_server_cert_not_yet_valid,
1559
svn_boolean_t *trust_server_cert_other_failure,
1560
const char *opt_arg,
1561
apr_pool_t *scratch_pool)
1563
apr_array_header_t *failures;
1566
*trust_server_cert_unknown_ca = FALSE;
1567
*trust_server_cert_cn_mismatch = FALSE;
1568
*trust_server_cert_expired = FALSE;
1569
*trust_server_cert_not_yet_valid = FALSE;
1570
*trust_server_cert_other_failure = FALSE;
1572
failures = svn_cstring_split(opt_arg, ", \n\r\t\v", TRUE, scratch_pool);
1574
for (i = 0; i < failures->nelts; i++)
1576
const char *value = APR_ARRAY_IDX(failures, i, const char *);
1577
if (!strcmp(value, "unknown-ca"))
1578
*trust_server_cert_unknown_ca = TRUE;
1579
else if (!strcmp(value, "cn-mismatch"))
1580
*trust_server_cert_cn_mismatch = TRUE;
1581
else if (!strcmp(value, "expired"))
1582
*trust_server_cert_expired = TRUE;
1583
else if (!strcmp(value, "not-yet-valid"))
1584
*trust_server_cert_not_yet_valid = TRUE;
1585
else if (!strcmp(value, "other"))
1586
*trust_server_cert_other_failure = TRUE;
1588
return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
1589
_("Unknown value '%s' for %s.\n"
1590
"Supported values: %s"),
1592
"--trust-server-cert-failures",
1593
"unknown-ca, cn-mismatch, expired, "
1594
"not-yet-valid, other");
1597
return SVN_NO_ERROR;