#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_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;
#ifndef AS400
srv = apr_poll(&pollset, 1, &n, -1);
#else
srv = apr_poll(&pollset, 1, &n, -1, pool);
#endif
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_baton_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
abort();
}
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"));
}
SVN_ERR(svn_cmdline_cstring_to_utf8(result, strbuf->data, pool));
return SVN_NO_ERROR;
}
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_baton_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_baton_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_baton_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 && (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 && (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;
svn_cmdline_prompt_baton_t *pb = baton;
SVN_ERR(maybe_print_realm(realm, pool));
SVN_ERR(prompt(&cert_file, _("Client certificate filename: "),
FALSE, pb, pool));
cred = apr_palloc(pool, sizeof(*cred));
cred->cert_file = 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_baton_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;
}
svn_error_t *
svn_cmdline_prompt_user(const char **result,
const char *prompt_str,
apr_pool_t *pool)
{
return prompt(result, prompt_str, FALSE , NULL, pool);
}