#include <apr_lib.h>
#include <apr_poll.h>
#include "svn_cmdline.h"
#include "svn_string.h"
#include "svn_auth.h"
#include "svn_error.h"
#include "svn_path.h"
#include "private/svn_cmdline_private.h"
#include "svn_private_config.h"
static apr_status_t wait_for_input(apr_file_t *f,
apr_pool_t *pool)
{
apr_pollfd_t pollset;
int srv, n;
#ifdef WIN32
return APR_ENOTIMPL;
#endif
pollset.desc_type = APR_POLL_FILE;
pollset.desc.f = f;
pollset.p = pool;
pollset.reqevents = APR_POLLIN;
srv = apr_poll(&pollset, 1, &n, -1);
if (n == 1 && pollset.rtnevents & APR_POLLIN)
return APR_SUCCESS;
return srv;
}
static svn_error_t *
prompt(const char **result,
const char *prompt_msg,
svn_boolean_t hide,
svn_cmdline_prompt_baton2_t *pb,
apr_pool_t *pool)
{
apr_status_t status;
apr_file_t *fp;
char c;
svn_stringbuf_t *strbuf = svn_stringbuf_create("", pool);
status = apr_file_open_stdin(&fp, pool);
if (status)
return svn_error_wrap_apr(status, _("Can't open stdin"));
if (! hide)
{
svn_boolean_t saw_first_half_of_eol = FALSE;
SVN_ERR(svn_cmdline_fputs(prompt_msg, stderr, pool));
fflush(stderr);
while (1)
{
if (pb)
SVN_ERR(pb->cancel_func(pb->cancel_baton));
status = wait_for_input(fp, pool);
if (APR_STATUS_IS_EINTR(status))
continue;
else if (status && status != APR_ENOTIMPL)
return svn_error_wrap_apr(status, _("Can't read stdin"));
status = apr_file_getc(&c, fp);
if (status)
return svn_error_wrap_apr(status, _("Can't read stdin"));
if (saw_first_half_of_eol)
{
if (c == APR_EOL_STR[1])
break;
else
saw_first_half_of_eol = FALSE;
}
else if (c == APR_EOL_STR[0])
{
if (sizeof(APR_EOL_STR) == 3)
{
saw_first_half_of_eol = TRUE;
continue;
}
else if (sizeof(APR_EOL_STR) == 2)
break;
else
SVN_ERR_MALFUNCTION();
}
svn_stringbuf_appendbytes(strbuf, &c, 1);
}
}
else
{
const char *prompt_stdout;
size_t bufsize = 300;
SVN_ERR(svn_cmdline_cstring_from_utf8(&prompt_stdout, prompt_msg,
pool));
svn_stringbuf_ensure(strbuf, bufsize);
status = apr_password_get(prompt_stdout, strbuf->data, &bufsize);
if (status)
return svn_error_wrap_apr(status, _("Can't get password"));
}
return svn_cmdline_cstring_to_utf8(result, strbuf->data, pool);
}
static svn_error_t *
maybe_print_realm(const char *realm, apr_pool_t *pool)
{
if (realm)
{
SVN_ERR(svn_cmdline_fprintf(stderr, pool,
_("Authentication realm: %s\n"), realm));
fflush(stderr);
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_cmdline_auth_simple_prompt(svn_auth_cred_simple_t **cred_p,
void *baton,
const char *realm,
const char *username,
svn_boolean_t may_save,
apr_pool_t *pool)
{
svn_auth_cred_simple_t *ret = apr_pcalloc(pool, sizeof(*ret));
const char *pass_prompt;
svn_cmdline_prompt_baton2_t *pb = baton;
SVN_ERR(maybe_print_realm(realm, pool));
if (username)
ret->username = apr_pstrdup(pool, username);
else
SVN_ERR(prompt(&(ret->username), _("Username: "), FALSE, pb, pool));
pass_prompt = apr_psprintf(pool, _("Password for '%s': "), ret->username);
SVN_ERR(prompt(&(ret->password), pass_prompt, TRUE, pb, pool));
ret->may_save = may_save;
*cred_p = ret;
return SVN_NO_ERROR;
}
svn_error_t *
svn_cmdline_auth_username_prompt(svn_auth_cred_username_t **cred_p,
void *baton,
const char *realm,
svn_boolean_t may_save,
apr_pool_t *pool)
{
svn_auth_cred_username_t *ret = apr_pcalloc(pool, sizeof(*ret));
svn_cmdline_prompt_baton2_t *pb = baton;
SVN_ERR(maybe_print_realm(realm, pool));
SVN_ERR(prompt(&(ret->username), _("Username: "), FALSE, pb, pool));
ret->may_save = may_save;
*cred_p = ret;
return SVN_NO_ERROR;
}
svn_error_t *
svn_cmdline_auth_ssl_server_trust_prompt
(svn_auth_cred_ssl_server_trust_t **cred_p,
void *baton,
const char *realm,
apr_uint32_t failures,
const svn_auth_ssl_server_cert_info_t *cert_info,
svn_boolean_t may_save,
apr_pool_t *pool)
{
const char *choice;
svn_stringbuf_t *msg;
svn_cmdline_prompt_baton2_t *pb = baton;
svn_stringbuf_t *buf = svn_stringbuf_createf
(pool, _("Error validating server certificate for '%s':\n"), realm);
if (failures & SVN_AUTH_SSL_UNKNOWNCA)
{
svn_stringbuf_appendcstr
(buf,
_(" - The certificate is not issued by a trusted authority. Use the\n"
" fingerprint to validate the certificate manually!\n"));
}
if (failures & SVN_AUTH_SSL_CNMISMATCH)
{
svn_stringbuf_appendcstr
(buf, _(" - The certificate hostname does not match.\n"));
}
if (failures & SVN_AUTH_SSL_NOTYETVALID)
{
svn_stringbuf_appendcstr
(buf, _(" - The certificate is not yet valid.\n"));
}
if (failures & SVN_AUTH_SSL_EXPIRED)
{
svn_stringbuf_appendcstr
(buf, _(" - The certificate has expired.\n"));
}
if (failures & SVN_AUTH_SSL_OTHER)
{
svn_stringbuf_appendcstr
(buf, _(" - The certificate has an unknown error.\n"));
}
msg = svn_stringbuf_createf
(pool,
_("Certificate information:\n"
" - Hostname: %s\n"
" - Valid: from %s until %s\n"
" - Issuer: %s\n"
" - Fingerprint: %s\n"),
cert_info->hostname,
cert_info->valid_from,
cert_info->valid_until,
cert_info->issuer_dname,
cert_info->fingerprint);
svn_stringbuf_appendstr(buf, msg);
if (may_save)
{
svn_stringbuf_appendcstr
(buf, _("(R)eject, accept (t)emporarily or accept (p)ermanently? "));
}
else
{
svn_stringbuf_appendcstr(buf, _("(R)eject or accept (t)emporarily? "));
}
SVN_ERR(prompt(&choice, buf->data, FALSE, pb, pool));
if (choice[0] == 't' || choice[0] == 'T')
{
*cred_p = apr_pcalloc(pool, sizeof(**cred_p));
(*cred_p)->may_save = FALSE;
(*cred_p)->accepted_failures = failures;
}
else if (may_save && (choice[0] == 'p' || choice[0] == 'P'))
{
*cred_p = apr_pcalloc(pool, sizeof(**cred_p));
(*cred_p)->may_save = TRUE;
(*cred_p)->accepted_failures = failures;
}
else
{
*cred_p = NULL;
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_cmdline_auth_ssl_client_cert_prompt
(svn_auth_cred_ssl_client_cert_t **cred_p,
void *baton,
const char *realm,
svn_boolean_t may_save,
apr_pool_t *pool)
{
svn_auth_cred_ssl_client_cert_t *cred = NULL;
const char *cert_file = NULL;
const char *abs_cert_file = NULL;
svn_cmdline_prompt_baton2_t *pb = baton;
SVN_ERR(maybe_print_realm(realm, pool));
SVN_ERR(prompt(&cert_file, _("Client certificate filename: "),
FALSE, pb, pool));
SVN_ERR(svn_path_get_absolute(&abs_cert_file, cert_file, pool));
cred = apr_palloc(pool, sizeof(*cred));
cred->cert_file = abs_cert_file;
cred->may_save = may_save;
*cred_p = cred;
return SVN_NO_ERROR;
}
svn_error_t *
svn_cmdline_auth_ssl_client_cert_pw_prompt
(svn_auth_cred_ssl_client_cert_pw_t **cred_p,
void *baton,
const char *realm,
svn_boolean_t may_save,
apr_pool_t *pool)
{
svn_auth_cred_ssl_client_cert_pw_t *cred = NULL;
const char *result;
const char *text = apr_psprintf(pool, _("Passphrase for '%s': "), realm);
svn_cmdline_prompt_baton2_t *pb = baton;
SVN_ERR(prompt(&result, text, TRUE, pb, pool));
cred = apr_pcalloc(pool, sizeof(*cred));
cred->password = result;
cred->may_save = may_save;
*cred_p = cred;
return SVN_NO_ERROR;
}
static svn_error_t *
plaintext_prompt_helper(svn_boolean_t *may_save_plaintext,
const char *realmstring,
const char *prompt_string,
const char *prompt_text,
void *baton,
apr_pool_t *pool)
{
const char *answer = NULL;
svn_boolean_t answered = FALSE;
svn_cmdline_prompt_baton2_t *pb = baton;
const char *config_path = NULL;
if (pb)
SVN_ERR(svn_config_get_user_config_path(&config_path, pb->config_dir,
SVN_CONFIG_CATEGORY_SERVERS, pool));
SVN_ERR(svn_cmdline_fprintf(stderr, pool, prompt_text, realmstring,
config_path));
do
{
svn_error_t *err = prompt(&answer, prompt_string, FALSE, pb, pool);
if (err)
{
if (err->apr_err == SVN_ERR_CANCELLED)
{
svn_error_clear(err);
*may_save_plaintext = FALSE;
return SVN_NO_ERROR;
}
else
return err;
}
if (apr_strnatcasecmp(answer, _("yes")) == 0)
{
*may_save_plaintext = TRUE;
answered = TRUE;
}
else if (apr_strnatcasecmp(answer, _("no")) == 0)
{
*may_save_plaintext = FALSE;
answered = TRUE;
}
else
prompt_string = _("Please type 'yes' or 'no': ");
}
while (! answered);
return SVN_NO_ERROR;
}
svn_error_t *
svn_cmdline_auth_plaintext_prompt(svn_boolean_t *may_save_plaintext,
const char *realmstring,
void *baton,
apr_pool_t *pool)
{
const char *prompt_string = _("Store password unencrypted (yes/no)? ");
const char *prompt_text =
_("\n-----------------------------------------------------------------------"
"\nATTENTION! Your password for authentication realm:\n"
"\n"
" %s\n"
"\n"
"can only be stored to disk unencrypted! You are advised to configure\n"
"your system so that Subversion can store passwords encrypted, if\n"
"possible. See the documentation for details.\n"
"\n"
"You can avoid future appearances of this warning by setting the value\n"
"of the 'store-plaintext-passwords' option to either 'yes' or 'no' in\n"
"'%s'.\n"
"-----------------------------------------------------------------------\n"
);
return plaintext_prompt_helper(may_save_plaintext, realmstring,
prompt_string, prompt_text, baton,
pool);
}
svn_error_t *
svn_cmdline_auth_plaintext_passphrase_prompt(svn_boolean_t *may_save_plaintext,
const char *realmstring,
void *baton,
apr_pool_t *pool)
{
const char *prompt_string = _("Store passphrase unencrypted (yes/no)? ");
const char *prompt_text =
_("\n-----------------------------------------------------------------------\n"
"ATTENTION! Your passphrase for client certificate:\n"
"\n"
" %s\n"
"\n"
"can only be stored to disk unencrypted! You are advised to configure\n"
"your system so that Subversion can store passphrase encrypted, if\n"
"possible. See the documentation for details.\n"
"\n"
"You can avoid future appearances of this warning by setting the value\n"
"of the 'store-ssl-client-cert-pp-plaintext' option to either 'yes' or\n"
"'no' in '%s'.\n"
"-----------------------------------------------------------------------\n"
);
return plaintext_prompt_helper(may_save_plaintext, realmstring,
prompt_string, prompt_text, baton,
pool);
}
svn_error_t *
svn_cmdline_prompt_user2(const char **result,
const char *prompt_str,
svn_cmdline_prompt_baton_t *baton,
apr_pool_t *pool)
{
return prompt(result, prompt_str, FALSE ,
(svn_cmdline_prompt_baton2_t *)baton, pool);
}
svn_error_t *
svn_cmdline__auth_gnome_keyring_unlock_prompt(char **keyring_password,
const char *keyring_name,
void *baton,
apr_pool_t *pool)
{
const char *password;
const char *pass_prompt;
svn_cmdline_prompt_baton2_t *pb = baton;
pass_prompt = apr_psprintf(pool, _("Password for '%s' GNOME keyring: "),
keyring_name);
SVN_ERR(prompt(&password, pass_prompt, TRUE, pb, pool));
*keyring_password = apr_pstrdup(pool, password);
return SVN_NO_ERROR;
}