El 17/09/17 a las 02:08, Stefan Sperling escribió: > On Sun, Sep 17, 2017 at 01:06:14AM -0700, William Orr wrote: >> Hey, >> >> This is my first patch to subversion, so please bear with me. >> >> This looks to address a very commonly requested feature: providing an >> alternative for automated tools to provide a password to svn via piping >> it in over an fd (similar to gnupg). > > Hi William, > > This looks good to me in principle and I support the idea. > > Will the implementation of read_pass_from_fd() compile and work on Win32? > We usually defer such operations to APR to avoid portability concerns. > However, APR does not seem to offer an API which wraps fdopen(). > Whenever we bypass APR and use system APIs directly we need to support > at least Unix-like systems and Win32. > > We cannot change the parameter list of svn_cmdline_create_auth_baton2(). > The function is already part of a release, so changing it breaks our > ABI compatibility promise. Instead, we can add a new function called > svn_cmdline_create_auth_baton3() which has the additional parameter. > The svn_cmdline_create_auth_baton2() interface can be implemented > as a wrapper around our new version of this function. > > Given that this is feature intends to support non-interactive usage, > I wonder if it should depend on the --non-interactive option as well? > And maybe we could then reduce the new option to --password-from-stdin? > > Some tools already use stdin for a different purpose, though. > E.g. 'svnrdump load' reads a dump file from stdin. But if we also extended > such tools with an option to read their normal input from a file, we could > make this idea work. "svnadmin load" already supports the -F (--file) > option for this purpose. Scripts would have to pass the right combination > of options: --non-interactive --password-from-stdin -F /tmp/my-dump-file > If --password-from-stdin is used without --non-interactive and without > -F then the program should error out and complain. > > This idea also solves the portability question, since svn_stream_for_stdin2() > or apr_file_open_flags_stdin() could be used to read a password from stdin. > And we wouldn't need a new revision of svn_cmdline_create_auth_baton2() > either because the client could pass the password as a string, as it > does for the --password option. > >> One outstanding concern that I couldn't find addressed is clearing out >> memory that once contained passwords (like with memset_s or >> explicit_bzero). If I missed a technique for doing this that exists in >> svn already, please let me know so I can update the diff. > > I don't think we have an API for that either, unfortunately. However, > the same portability concerns apply. In any case, it would be great to > have such an API available in APR. > > Regards, > Stefan > >> Tested on Fedora 25 x86_64 and OpenBSD 6.1 x86_64. >> >> Please CC me; I'm not on this list. >> >> [[[ >> Introduce global opt --password-fd to allow applications to provide a >> password over an already-opened file descriptor. >> >> * subversion/include/svn_cmdline.h >> (svn_cmdline_create_auth_baton2): Add `auth_password_fd` argument >> * subversion/include/svn_error_codes.h >> (SVN_ERR_IO_PIPE_READ_ERROR): Undeprecate, as now used >> * subversion/libsvn_subr/cmdline.c >> (read_pass_from_fd): Add static function to get password from a file >> descriptor >> (svn_cmdline_create_auth_baton2): Add `auth_password_fd` arg and >> trigger read of fd if this arg is not -1 >> * subversion/libsvn_subr/deprecated.c: >> (svn_cmdline_create_auth_baton): Add default val of -1 when calling >> `svn_cmdline_create_auth_baton2` >> * subversion/svn/svn.c >> (svn_cl__longopt_t): Add `opt_auth_password_fd` longopt >> (svn_cl__global_options): Add `opt_auth_password_fd` to global options >> (sub_main): Process global option `opt_auth_password_fd` and pass it >> to `svn_cmdline_create_auth_baton2` >> * subversion/svnmucc/svnmucc.c >> (sub_main): Process global option `opt_auth_password_fd` and pass it >> to `svn_cmdline_create_auth_baton2` >> * subversion/svnrdump/svnrdump.c >> (svn_svnrdump__longopt_t): add `opt_auth_password_fd` >> (svnrdump__options): add help message for `--password-fd` >> (init_client_context): Pass `auth_password_fd` to >> `svn_cmdline_create_auth_baton2` >> (sub_main): Process global option `opt_auth_password_fd` and pass it >> to `init_client_context` >> * subversion/svnsync/svnsync.c >> (svnsync__opt): Add `svnsync_opt_source_password_fd` and >> `svnsync_opt_sync_password_fd` >> (svnsync_options): Add help messages for `--source-password-fd` and >> `--sync-password-fd` >> (opt_baton_t): Add `source_password_fd` and `sync_password_fd` >> (sub_main): Process global option `--source-password-fd` and >> `--sync-password-fd` and pass it to `svn_cmdline_create_auth_baton2` >> invocations >> * subversion/tests/cmdline/atomic-ra-revprop-change.c >> (construct_auth_baton): Pass -1 as the `auth_password_fd` >> * subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout >> (): Add new `--password-fd` option to expected output >> * subversion/tests/libsvn_ra/ra-test.c >> (check_tunnel_callback_test): Pass -1 as the `auth_password_fd` >> (tunnel_callback_test): Pass -1 as the `auth_password_fd` >> (tunnel_run_checkout): Pass -1 as the `auth_password_fd` >> * subversion/tests/svn_test_main.c >> (svn_test__init_auth_baton): Pass -1 as the `auth_password_fd` >> * tools/client-side/svn-mergeinfo-normalizer/mergeinfo-normalizer.h >> (svn_min__opt_state_t): Add `auth_password_fd` >> * tools/client-side/svn-mergeinfo-normalizer/svn-mergeinfo-normalizer.c >> (svn_min__longopt_t) Add `opt_auth_password_fd` >> (sub_main) Process global option `--password-fd` and pass it to >> `svn_cmdline_create_auth_baton2` invocations >> * tools/client-side/svnconflict/svnconflict.c >> (svnconflict_opt_state_t): Add `auth_password_fd` >> (svnconflict_options): Add `--password-fd` documentation >> (svnconflict_global_options): Add `opt_auth_password_fd` >> (sub_main): Process global option `--password-fd` and pass it to >> `svn_cmdline_create_auth_baton2` invocations >> * tools/dev/svnmover/svnmover.c >> (sub_main): Process global option `--password-fd` and pass it to >> `svn_cmdline_create_auth_baton2` invocations >> ]]] >
Hey, Thanks for the feedback. I've finally gotten the chance to update the patch with the suggestions. Lemme know if this addresses your concerns, and I can write up the changelog for it. Thanks, William Orr
Index: subversion/include/svn_io.h =================================================================== --- subversion/include/svn_io.h (revisión: 1811402) +++ subversion/include/svn_io.h (copia de trabajo) @@ -2633,6 +2633,14 @@ svn_io_file_readline(apr_file_t *file, apr_pool_t *result_pool, apr_pool_t *scratch_pool); +/** Reads a string from stdin until a newline or EOF is found + * + * @since New in 1.9. + */ +svn_error_t * +svn_io_stdin_readline(const char **result, + apr_pool_t *pool); + /** @} */ #ifdef __cplusplus Index: subversion/libsvn_subr/io.c =================================================================== --- subversion/libsvn_subr/io.c (revisión: 1811402) +++ subversion/libsvn_subr/io.c (copia de trabajo) @@ -5440,3 +5440,19 @@ svn_io_file_readline(apr_file_t *file, return SVN_NO_ERROR; } + +svn_error_t * +svn_io_stdin_readline(const char **result, + apr_pool_t *pool) +{ + svn_stringbuf_t *buf = NULL; + svn_stream_t *stdin = NULL; + svn_boolean_t oob = FALSE; + + SVN_ERR(svn_stream_for_stdin2(&stdin, TRUE, pool)); + SVN_ERR(svn_stream_readline(stdin, &buf, APR_EOL_STR, &oob, pool)); + + *result = buf->data; + + return SVN_NO_ERROR; +} Index: subversion/svn/cl.h =================================================================== --- subversion/svn/cl.h (revisión: 1811402) +++ subversion/svn/cl.h (copia de trabajo) @@ -178,6 +178,7 @@ typedef struct svn_cl__opt_state_t svn_boolean_t help; /* print usage message */ const char *auth_username; /* auth username */ const char *auth_password; /* auth password */ + svn_boolean_t auth_password_from_stdin; /* fd to read password from */ const char *extensions; /* subprocess extension args */ apr_array_header_t *targets; /* target list from file */ svn_boolean_t xml; /* output in xml, e.g., "svn log --xml" */ Index: subversion/svn/svn.c =================================================================== --- subversion/svn/svn.c (revisión: 1811402) +++ subversion/svn/svn.c (copia de trabajo) @@ -68,6 +68,7 @@ use the short option letter as identifier. */ typedef enum svn_cl__longopt_t { opt_auth_password = SVN_OPT_FIRST_LONGOPT_ID, + opt_auth_password_from_stdin, opt_auth_username, opt_autoprops, opt_changelist, @@ -200,6 +201,9 @@ const apr_getopt_option_t svn_cl__options[] = N_("specify a password ARG (caution: on many operating\n" " " "systems, other users will be able to see this)")}, + {"password-from-stdin", + opt_auth_password_from_stdin, 0, + N_("read password from stdin")}, {"extensions", 'x', 1, N_("Specify differencing options for external diff or\n" " " @@ -495,7 +499,8 @@ const apr_getopt_option_t svn_cl__options[] = command to take these arguments allows scripts to just pass them willy-nilly to every invocation of 'svn') . */ const int svn_cl__global_options[] = -{ opt_auth_username, opt_auth_password, opt_no_auth_cache, opt_non_interactive, +{ opt_auth_username, opt_auth_password, opt_auth_password_from_stdin, + opt_no_auth_cache, opt_non_interactive, opt_force_interactive, opt_trust_server_cert, opt_trust_server_cert_failures, opt_config_dir, opt_config_options, 0 @@ -1959,6 +1964,7 @@ sub_main(int *exit_code, int argc, const char *arg apr_hash_t *changelists; apr_hash_t *cfg_hash; svn_membuf_t buf; + svn_boolean_t read_pass_from_stdin = FALSE; received_opts = apr_array_make(pool, SVN_OPT_MAX_OPTIONS, sizeof(int)); @@ -2251,6 +2257,9 @@ sub_main(int *exit_code, int argc, const char *arg SVN_ERR(svn_utf_cstring_to_utf8(&opt_state.auth_password, opt_arg, pool)); break; + case opt_auth_password_from_stdin: + read_pass_from_stdin = TRUE; + break; case opt_encoding: opt_state.encoding = apr_pstrdup(pool, opt_arg); break; @@ -2745,6 +2754,14 @@ sub_main(int *exit_code, int argc, const char *arg "--non-interactive")); } + /* --password-from-stdin can only be used with --non-interactive */ + if (read_pass_from_stdin && !opt_state.non_interactive) + { + return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, + _("--password-from-stdin requires " + "--non-interactive")); + } + /* Disallow simultaneous use of both --diff-cmd and --internal-diff. */ if (opt_state.diff.diff_cmd && opt_state.diff.internal_diff) @@ -3034,6 +3051,12 @@ sub_main(int *exit_code, int argc, const char *arg conflict_stats, pool)); } + /* Get password from stdin if necessary */ + if (read_pass_from_stdin) + { + svn_io_stdin_readline(&opt_state.auth_password, pool); + } + /* Set up our cancellation support. */ svn_cl__check_cancel = svn_cmdline__setup_cancellation_handler(); ctx->cancel_func = svn_cl__check_cancel; Index: subversion/svnbench/svnbench.c =================================================================== --- subversion/svnbench/svnbench.c (revisión: 1811402) +++ subversion/svnbench/svnbench.c (copia de trabajo) @@ -53,6 +53,7 @@ use the short option letter as identifier. */ typedef enum svn_cl__longopt_t { opt_auth_password = SVN_OPT_FIRST_LONGOPT_ID, + opt_auth_password_from_stdin, opt_auth_username, opt_config_dir, opt_config_options, @@ -112,6 +113,8 @@ const apr_getopt_option_t svn_cl__options[] = {"verbose", 'v', 0, N_("print extra information")}, {"username", opt_auth_username, 1, N_("specify a username ARG")}, {"password", opt_auth_password, 1, N_("specify a password ARG")}, + {"password-from-stdin", + opt_auth_password_from_stdin, 0, N_("read password from stdin")}, {"targets", opt_targets, 1, N_("pass contents of file ARG as additional args")}, {"depth", opt_depth, 1, @@ -197,7 +200,8 @@ const apr_getopt_option_t svn_cl__options[] = command to take these arguments allows scripts to just pass them willy-nilly to every invocation of 'svn') . */ const int svn_cl__global_options[] = -{ opt_auth_username, opt_auth_password, opt_no_auth_cache, opt_non_interactive, +{ opt_auth_username, opt_auth_password, opt_auth_password_from_stdin, + opt_no_auth_cache, opt_non_interactive, opt_trust_server_cert, opt_trust_server_cert_failures, opt_config_dir, opt_config_options, 0 }; @@ -394,6 +398,7 @@ sub_main(int *exit_code, int argc, const char *arg apr_time_t start_time, time_taken; ra_progress_baton_t ra_progress_baton = {0}; svn_membuf_t buf; + svn_boolean_t read_pass_from_stdin = FALSE; received_opts = apr_array_make(pool, SVN_OPT_MAX_OPTIONS, sizeof(int)); @@ -625,6 +630,9 @@ sub_main(int *exit_code, int argc, const char *arg SVN_ERR(svn_utf_cstring_to_utf8(&opt_state.auth_password, opt_arg, pool)); break; + case opt_auth_password_from_stdin: + read_pass_from_stdin = TRUE; + break; case opt_stop_on_copy: opt_state.stop_on_copy = TRUE; break; @@ -842,6 +850,14 @@ sub_main(int *exit_code, int argc, const char *arg "--non-interactive")); } + /* --password-from-stdin can only be used with --non-interactive */ + if (read_pass_from_stdin && !opt_state.non_interactive) + { + return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, + _("--password-from-stdin requires " + "--non-interactive")); + } + /* Ensure that 'revision_ranges' has at least one item, and make 'start_revision' and 'end_revision' match that item. */ if (opt_state.revision_ranges->nelts == 0) @@ -919,6 +935,12 @@ sub_main(int *exit_code, int argc, const char *arg pool)); } + /* Get password from stdin if necessary */ + if (read_pass_from_stdin) + { + svn_io_stdin_readline(&opt_state.auth_password, pool); + } + /* Set up our cancellation support. */ svn_cl__check_cancel = svn_cmdline__setup_cancellation_handler(); ctx->cancel_func = svn_cl__check_cancel; Index: subversion/svnmucc/svnmucc.c =================================================================== --- subversion/svnmucc/svnmucc.c (revisión: 1811402) +++ subversion/svnmucc/svnmucc.c (copia de trabajo) @@ -297,6 +297,7 @@ help(FILE *stream, apr_pool_t *pool) " -F [--file] ARG : read log message from file ARG\n" " -u [--username] ARG : commit the changes as username ARG\n" " -p [--password] ARG : use ARG as the password\n" + " --password-from-stdin : read password from stdin\n" " -U [--root-url] ARG : interpret all action URLs relative to ARG\n" " -r [--revision] ARG : use revision ARG as baseline for changes\n" " --with-revprop ARG : set revision property in the following format:\n" @@ -480,7 +481,8 @@ sub_main(int *exit_code, int argc, const char *arg non_interactive_opt, force_interactive_opt, trust_server_cert_opt, - trust_server_cert_failures_opt + trust_server_cert_failures_opt, + password_from_stdin_opt }; static const apr_getopt_option_t options[] = { {"message", 'm', 1, ""}, @@ -487,6 +489,7 @@ sub_main(int *exit_code, int argc, const char *arg {"file", 'F', 1, ""}, {"username", 'u', 1, ""}, {"password", 'p', 1, ""}, + {"password-from-stdin", password_from_stdin_opt, 0, ""}, {"root-url", 'U', 1, ""}, {"revision", 'r', 1, ""}, {"with-revprop", with_revprop_opt, 1, ""}, @@ -527,6 +530,7 @@ sub_main(int *exit_code, int argc, const char *arg svn_client_ctx_t *ctx; struct log_message_baton lmb; int i; + svn_boolean_t read_pass_from_stdin = FALSE; /* Check library versions */ SVN_ERR(check_lib_versions()); @@ -572,6 +576,9 @@ sub_main(int *exit_code, int argc, const char *arg case 'p': password = apr_pstrdup(pool, arg); break; + case password_from_stdin_opt: + read_pass_from_stdin = TRUE; + break; case 'U': SVN_ERR(svn_utf_cstring_to_utf8(&root_url, arg, pool)); if (! svn_path_is_url(root_url)) @@ -672,6 +679,15 @@ sub_main(int *exit_code, int argc, const char *arg "--non-interactive")); } + /* --password-from-stdin can only be used with --non-interactive */ + if (read_pass_from_stdin && !non_interactive) + { + return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, + _("--password-from-stdin requires " + "--non-interactive")); + } + + /* Copy the rest of our command-line arguments to an array, UTF-8-ing them along the way. */ action_args = apr_array_make(pool, opts->argc, sizeof(const char *)); @@ -721,6 +737,12 @@ sub_main(int *exit_code, int argc, const char *arg "svnmucc: ", "--config-option")); } + /* Get password from stdin if necessary */ + if (read_pass_from_stdin) + { + svn_io_stdin_readline(&password, pool); + } + SVN_ERR(svn_client_create_context2(&ctx, cfg_hash, pool)); cfg_config = svn_hash_gets(cfg_hash, SVN_CONFIG_CATEGORY_CONFIG); Index: subversion/svnrdump/svnrdump.c =================================================================== --- subversion/svnrdump/svnrdump.c (revisión: 1811402) +++ subversion/svnrdump/svnrdump.c (copia de trabajo) @@ -59,6 +59,7 @@ enum svn_svnrdump__longopt_t opt_config_option, opt_auth_username, opt_auth_password, + opt_auth_password_from_stdin, opt_auth_nocache, opt_non_interactive, opt_skip_revprop, @@ -66,7 +67,7 @@ enum svn_svnrdump__longopt_t opt_incremental, opt_trust_server_cert, opt_trust_server_cert_failures, - opt_version + opt_version, }; #define SVN_SVNRDUMP__BASE_OPTIONS opt_config_dir, \ @@ -73,6 +74,7 @@ enum svn_svnrdump__longopt_t opt_config_option, \ opt_auth_username, \ opt_auth_password, \ + opt_auth_password_from_stdin, \ opt_auth_nocache, \ opt_trust_server_cert, \ opt_trust_server_cert_failures, \ @@ -114,6 +116,8 @@ static const apr_getopt_option_t svnrdump__options N_("specify a username ARG")}, {"password", opt_auth_password, 1, N_("specify a password ARG")}, + {"password-from-stdin", opt_auth_password_from_stdin, 0, + N_("read password from stdin")}, {"non-interactive", opt_non_interactive, 0, N_("do no interactive prompting (default is to prompt\n" " " @@ -154,6 +158,7 @@ static const apr_getopt_option_t svnrdump__options "valid certificate) and 'other' (all other not\n" " " "separately classified certificate errors).")}, + {"dumpfile", 'F', 1, N_("Read or write to a dumpfile instead of stdin/stdout")}, {0, 0, 0, 0} }; @@ -174,6 +179,7 @@ typedef struct opt_baton_t { svn_client_ctx_t *ctx; svn_ra_session_t *session; const char *url; + const char *dumpfile; svn_boolean_t help; svn_boolean_t version; svn_opt_revision_t start_revision; @@ -366,7 +372,8 @@ init_client_context(svn_client_ctx_t **ctx_p, /* Default authentication providers for non-interactive use */ SVN_ERR(svn_cmdline_create_auth_baton2(&(ctx->auth_baton), non_interactive, - username, password, config_dir, + username, password, + config_dir, no_auth_cache, trust_unknown_ca, trust_cn_mismatch, trust_expired, trust_not_yet_valid, @@ -463,31 +470,39 @@ replay_revisions(svn_ra_session_t *session, svn_revnum_t end_revision, svn_boolean_t quiet, svn_boolean_t incremental, + const char *dumpfile, apr_pool_t *pool) { struct replay_baton *replay_baton; const char *uuid; - svn_stream_t *stdout_stream; + svn_stream_t *dump_stream; - SVN_ERR(svn_stream_for_stdout(&stdout_stream, pool)); + if (dumpfile) + { + SVN_ERR(svn_stream_open_writable(&dump_stream, dumpfile, pool, pool)); + } + else + { + SVN_ERR(svn_stream_for_stdout(&dump_stream, pool)); + } replay_baton = apr_pcalloc(pool, sizeof(*replay_baton)); - replay_baton->stdout_stream = stdout_stream; + replay_baton->stdout_stream = dump_stream; replay_baton->extra_ra_session = extra_ra_session; replay_baton->quiet = quiet; /* Write the magic header and UUID */ - SVN_ERR(svn_stream_printf(stdout_stream, pool, + SVN_ERR(svn_stream_printf(dump_stream, pool, SVN_REPOS_DUMPFILE_MAGIC_HEADER ": %d\n\n", SVN_REPOS_DUMPFILE_FORMAT_VERSION)); SVN_ERR(svn_ra_get_uuid2(session, &uuid, pool)); - SVN_ERR(svn_stream_printf(stdout_stream, pool, + SVN_ERR(svn_stream_printf(dump_stream, pool, SVN_REPOS_DUMPFILE_UUID ": %s\n\n", uuid)); /* Fake revision 0 if necessary */ if (start_revision == 0) { - SVN_ERR(dump_revision_header(session, stdout_stream, + SVN_ERR(dump_revision_header(session, dump_stream, start_revision, pool)); /* Revision 0 has no tree changes, so we're done. */ @@ -506,7 +521,7 @@ replay_revisions(svn_ra_session_t *session, if (!incremental) { SVN_ERR(dump_initial_full_revision(session, extra_ra_session, - stdout_stream, start_revision, + dump_stream, start_revision, quiet, pool)); start_revision++; } @@ -538,16 +553,23 @@ replay_revisions(svn_ra_session_t *session, static svn_error_t * load_revisions(svn_ra_session_t *session, svn_ra_session_t *aux_session, - const char *url, + const char *dumpfile, svn_boolean_t quiet, apr_hash_t *skip_revprops, apr_pool_t *pool) { - svn_stream_t *stdin_stream; + svn_stream_t *dump_stream; - SVN_ERR(svn_stream_for_stdin2(&stdin_stream, TRUE, pool)); + if (dumpfile) + { + SVN_ERR(svn_stream_open_readonly(&dump_stream, dumpfile, pool, pool)); + } + else + { + SVN_ERR(svn_stream_for_stdin2(&dump_stream, TRUE, pool)); + } - SVN_ERR(svn_rdump__load_dumpstream(stdin_stream, session, aux_session, + SVN_ERR(svn_rdump__load_dumpstream(dump_stream, session, aux_session, quiet, skip_revprops, check_cancel, NULL, pool)); @@ -616,7 +638,8 @@ dump_cmd(apr_getopt_t *os, return replay_revisions(opt_baton->session, extra_ra_session, opt_baton->start_revision.value.number, opt_baton->end_revision.value.number, - opt_baton->quiet, opt_baton->incremental, pool); + opt_baton->quiet, opt_baton->incremental, + opt_baton->dumpfile, pool); } /* Handle the "load" subcommand. Implements `svn_opt_subcommand_t'. */ @@ -630,8 +653,9 @@ load_cmd(apr_getopt_t *os, SVN_ERR(svn_client_open_ra_session2(&aux_session, opt_baton->url, NULL, opt_baton->ctx, pool, pool)); - return load_revisions(opt_baton->session, aux_session, opt_baton->url, - opt_baton->quiet, opt_baton->skip_revprops, pool); + return load_revisions(opt_baton->session, aux_session, + opt_baton->dumpfile, opt_baton->quiet, + opt_baton->skip_revprops, pool); } /* Handle the "help" subcommand. Implements `svn_opt_subcommand_t'. */ @@ -772,6 +796,7 @@ sub_main(int *exit_code, int argc, const char *arg apr_getopt_t *os; apr_array_header_t *received_opts; int i; + svn_boolean_t read_pass_from_stdin = FALSE; opt_baton = apr_pcalloc(pool, sizeof(*opt_baton)); opt_baton->start_revision.kind = svn_opt_revision_unspecified; @@ -778,6 +803,7 @@ sub_main(int *exit_code, int argc, const char *arg opt_baton->end_revision.kind = svn_opt_revision_unspecified; opt_baton->url = NULL; opt_baton->skip_revprops = apr_hash_make(pool); + opt_baton->dumpfile = NULL; SVN_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool)); @@ -850,6 +876,9 @@ sub_main(int *exit_code, int argc, const char *arg case opt_auth_password: SVN_ERR(svn_utf_cstring_to_utf8(&password, opt_arg, pool)); break; + case opt_auth_password_from_stdin: + read_pass_from_stdin = TRUE; + break; case opt_auth_nocache: no_auth_cache = TRUE; break; @@ -890,6 +919,11 @@ sub_main(int *exit_code, int argc, const char *arg opt_arg, "svnrdump: ", pool)); + break; + case 'F': + SVN_ERR(svn_utf_cstring_to_utf8(&opt_arg, opt_arg, pool)); + opt_baton->dumpfile = opt_arg; + break; } } @@ -1005,6 +1039,20 @@ sub_main(int *exit_code, int argc, const char *arg "--non-interactive")); } + if (read_pass_from_stdin && !non_interactive) + { + return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, + _("--password-from-stdin requires " + "--non-interactive")); + } + + if (strcmp(subcommand->name, "load") == 0) + { + if (read_pass_from_stdin) + { + } + } + /* Expect one more non-option argument: the repository URL. */ if (os->ind != os->argc - 1) { @@ -1039,9 +1087,16 @@ sub_main(int *exit_code, int argc, const char *arg force_interactive = (username == NULL || password == NULL); } + /* Get password from stdin if necessary */ + if (read_pass_from_stdin) + { + svn_io_stdin_readline(&password, pool); + } + non_interactive = !svn_cmdline__be_interactive(non_interactive, force_interactive); + SVN_ERR(init_client_context(&(opt_baton->ctx), non_interactive, username, Index: subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout =================================================================== --- subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout (revisión: 1811402) +++ subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout (copia de trabajo) @@ -134,6 +134,7 @@ Global options: --username ARG : specify a username ARG --password ARG : specify a password ARG (caution: on many operating systems, other users will be able to see this) + --password-from-stdin : read password from stdin --no-auth-cache : do not cache authentication tokens --non-interactive : do no interactive prompting (default is to prompt only if standard input is a terminal device) @@ -224,6 +225,7 @@ Global options: --username ARG : specify a username ARG --password ARG : specify a password ARG (caution: on many operating systems, other users will be able to see this) + --password-from-stdin : read password from stdin --no-auth-cache : do not cache authentication tokens --non-interactive : do no interactive prompting (default is to prompt only if standard input is a terminal device) Index: tools/client-side/svn-mergeinfo-normalizer/svn-mergeinfo-normalizer.c =================================================================== --- tools/client-side/svn-mergeinfo-normalizer/svn-mergeinfo-normalizer.c (revisión: 1811402) +++ tools/client-side/svn-mergeinfo-normalizer/svn-mergeinfo-normalizer.c (copia de trabajo) @@ -68,6 +68,7 @@ use the short option letter as identifier. */ typedef enum svn_min__longopt_t { opt_auth_password = SVN_OPT_FIRST_LONGOPT_ID, + opt_auth_password_from_stdin, opt_auth_username, opt_config_dir, opt_config_options, @@ -113,6 +114,9 @@ const apr_getopt_option_t svn_min__options[] = N_("specify a password ARG (caution: on many operating\n" " " "systems, other users will be able to see this)")}, + {"password-from-stdin", + opt_auth_password_from_stdin, 0, + N_("read password from stdin")}, {"targets", opt_targets, 1, N_("pass contents of file ARG as additional args")}, {"depth", opt_depth, 1, @@ -209,11 +213,11 @@ const apr_getopt_option_t svn_min__options[] = command to take these arguments allows scripts to just pass them willy-nilly to every invocation of 'svn') . */ const int svn_min__global_options[] = -{ opt_auth_username, opt_auth_password, opt_no_auth_cache, opt_non_interactive, - opt_force_interactive, opt_trust_server_cert, - opt_trust_server_cert_unknown_ca, opt_trust_server_cert_cn_mismatch, - opt_trust_server_cert_expired, opt_trust_server_cert_not_yet_valid, - opt_trust_server_cert_other_failure, +{ opt_auth_username, opt_auth_password, opt_auth_password_from_stdin, + opt_no_auth_cache, opt_non_interactive, opt_force_interactive, + opt_trust_server_cert, opt_trust_server_cert_unknown_ca, + opt_trust_server_cert_cn_mismatch, opt_trust_server_cert_expired, + opt_trust_server_cert_not_yet_valid, opt_trust_server_cert_other_failure, opt_config_dir, opt_config_options, 0 }; @@ -417,6 +421,7 @@ sub_main(int *exit_code, int argc, const char *arg svn_boolean_t interactive_conflicts = FALSE; svn_boolean_t force_interactive = FALSE; apr_hash_t *cfg_hash; + svn_boolean_t read_pass_from_stdin = FALSE; received_opts = apr_array_make(pool, SVN_OPT_MAX_OPTIONS, sizeof(int)); @@ -528,6 +533,9 @@ sub_main(int *exit_code, int argc, const char *arg SVN_ERR(svn_utf_cstring_to_utf8(&opt_state.auth_password, opt_arg, pool)); break; + case opt_auth_password_from_stdin: + read_pass_from_stdin = TRUE; + break; case opt_no_auth_cache: opt_state.no_auth_cache = TRUE; break; @@ -606,6 +614,14 @@ sub_main(int *exit_code, int argc, const char *arg opt_state.non_interactive, force_interactive); + /* --password-from-stdin can only be used with --non-interactive */ + if (read_pass_from_stdin && !opt_state.non_interactive) + { + return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, + _("--password-from-stdin requires " + "--non-interactive")); + } + /* ### This really belongs in libsvn_client. The trouble is, there's no one place there to run it from, no svn_client_init(). We'd have to add it to all the public @@ -788,6 +804,12 @@ sub_main(int *exit_code, int argc, const char *arg } #endif + /* Get password from stdin if necessary */ + if (read_pass_from_stdin) + { + svn_io_stdin_readline(&opt_state.auth_password, pool); + } + /* Create a client context object. */ command_baton.opt_state = &opt_state; SVN_ERR(svn_client_create_context2(&ctx, cfg_hash, pool)); Index: tools/client-side/svnconflict/svnconflict.c =================================================================== --- tools/client-side/svnconflict/svnconflict.c (revisión: 1811402) +++ tools/client-side/svnconflict/svnconflict.c (copia de trabajo) @@ -78,6 +78,7 @@ typedef struct svnconflict_cmd_baton_t use the short option letter as identifier. */ typedef enum svnconflict_longopt_t { opt_auth_password = SVN_OPT_FIRST_LONGOPT_ID, + opt_auth_password_from_stdin, opt_auth_username, opt_config_dir, opt_config_options, @@ -96,6 +97,9 @@ static const apr_getopt_option_t svnconflict_optio N_("specify a password ARG (caution: on many operating\n" " " "systems, other users will be able to see this)")}, + {"password-from-stdin", + opt_auth_password_from_stdin, 0, + N_("read password from stdin")}, {"config-dir", opt_config_dir, 1, N_("read user configuration files from directory ARG")}, {"config-option", opt_config_options, 1, @@ -141,7 +145,8 @@ static svn_error_t * svnconflict_resolve_tree(apr_ /* Options that apply to all commands. */ static const int svnconflict_global_options[] = -{ opt_auth_username, opt_auth_password, opt_config_dir, opt_config_options, 0 }; +{ opt_auth_username, opt_auth_password, opt_auth_password_from_stdin, + opt_config_dir, opt_config_options, 0 }; static const svn_opt_subcommand_desc2_t svnconflict_cmd_table[] = { @@ -639,6 +644,7 @@ sub_main(int *exit_code, int argc, const char *arg svn_auth_baton_t *ab; svn_config_t *cfg_config; apr_hash_t *cfg_hash; + svn_boolean_t read_pass_from_stdin = FALSE; received_opts = apr_array_make(pool, SVN_OPT_MAX_OPTIONS, sizeof(int)); @@ -704,6 +710,9 @@ sub_main(int *exit_code, int argc, const char *arg SVN_ERR(svn_utf_cstring_to_utf8(&opt_state.auth_password, opt_arg, pool)); break; + case opt_auth_password_from_stdin: + read_pass_from_stdin = TRUE; + break; case opt_config_dir: SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool)); opt_state.config_dir = svn_dirent_internal_style(utf8_opt_arg, pool); @@ -845,6 +854,13 @@ sub_main(int *exit_code, int argc, const char *arg cfg_config = svn_hash_gets(cfg_hash, SVN_CONFIG_CATEGORY_CONFIG); + /* Get password from stdin if necessary */ + if (read_pass_from_stdin) + { + svn_io_stdin_readline(&opt_state.auth_password, pool); + } + + /* Create a client context object. */ command_baton.opt_state = &opt_state; SVN_ERR(svn_client_create_context2(&ctx, cfg_hash, pool)); Index: tools/dev/svnmover/svnmover.c =================================================================== --- tools/dev/svnmover/svnmover.c (revisión: 1811402) +++ tools/dev/svnmover/svnmover.c (copia de trabajo) @@ -4332,7 +4332,8 @@ sub_main(int *exit_code, int argc, const char *arg trust_server_cert_opt, trust_server_cert_failures_opt, ui_opt, - colour_opt + colour_opt, + auth_password_from_stdin_opt }; static const apr_getopt_option_t options[] = { {"verbose", 'v', 0, ""}, @@ -4341,6 +4342,7 @@ sub_main(int *exit_code, int argc, const char *arg {"file", 'F', 1, ""}, {"username", 'u', 1, ""}, {"password", 'p', 1, ""}, + {"password-from-stdin", auth_password_from_stdin_opt, 1, ""}, {"root-url", 'U', 1, ""}, {"revision", 'r', 1, ""}, {"branch-id", 'B', 1, ""}, @@ -4387,6 +4389,7 @@ sub_main(int *exit_code, int argc, const char *arg const char *log_msg; svn_tristate_t coloured_output = svn_tristate_false; svnmover_wc_t *wc; + svn_boolean_t read_pass_from_stdin = FALSE; /* Check library versions */ SVN_ERR(check_lib_versions()); @@ -4431,6 +4434,9 @@ sub_main(int *exit_code, int argc, const char *arg case 'p': password = apr_pstrdup(pool, arg); break; + case auth_password_from_stdin_opt: + read_pass_from_stdin = TRUE; + break; case 'U': SVN_ERR(svn_utf_cstring_to_utf8(&anchor_url, arg, pool)); if (! svn_path_is_url(anchor_url)) @@ -4553,6 +4559,13 @@ sub_main(int *exit_code, int argc, const char *arg "--non-interactive")); } + /* --password-from-stdin can only be used with --non-interactive */ + if (read_pass_from_stdin && !non_interactive) + { + return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, + _("--password-from-stdin requires " + "--non-interactive")); + } /* Now initialize the client context */ @@ -4580,6 +4593,12 @@ sub_main(int *exit_code, int argc, const char *arg "svnmover: ", "--config-option")); } + /* Get password from stdin if necessary */ + if (read_pass_from_stdin) + { + svn_io_stdin_readline(&password, pool); + } + SVN_ERR(svn_client_create_context2(&ctx, cfg_hash, pool)); cfg_config = svn_hash_gets(cfg_hash, SVN_CONFIG_CATEGORY_CONFIG);