2 * prompt.c -- ask the user for authentication information.
4 * ====================================================================
5 * Copyright (c) 2000-2006 CollabNet. All rights reserved.
7 * This software is licensed as described in the file COPYING, which
8 * you should have received as part of this distribution. The terms
9 * are also available at http://subversion.tigris.org/license-1.html.
10 * If newer versions of this license are posted there, you may use a
11 * newer version instead, at your option.
13 * This software consists of voluntary contributions made by many
14 * individuals. For exact contribution history, see the revision
15 * history and logs, available at http://subversion.tigris.org/.
16 * ====================================================================
19 /* ==================================================================== */
28 #include "svn_cmdline.h"
29 #include "svn_string.h"
31 #include "svn_error.h"
33 #include "svn_private_config.h"
37 /* Wait for input on @a *f. Doing all allocations
38 * in @a pool. This functions is based on apr_wait_for_io_or_timeout().
39 * Note that this will return an EINTR on a signal.
41 * ### FIX: When APR gives us a better way of doing this use it. */
42 static apr_status_t
wait_for_input(apr_file_t
*f
,
48 /* APR specs say things that are unimplemented are supposed to return
49 * APR_ENOTIMPL. But when trying to use APR_POLL_FILE with apr_poll
50 * on Windows it returns APR_EBADF instead. So just return APR_ENOTIMPL
57 pollset
.desc_type
= APR_POLL_FILE
;
60 pollset
.reqevents
= APR_POLLIN
;
63 srv
= apr_poll(&pollset
, 1, &n
, -1);
65 /* OS400 requires a pool argument for apr_poll(). */
66 srv
= apr_poll(&pollset
, 1, &n
, -1, pool
);
69 if (n
== 1 && pollset
.rtnevents
& APR_POLLIN
)
75 /* Set @a *result to the result of prompting the user with @a
76 * prompt_msg. Use @ *pb to get the cancel_func and cancel_baton.
77 * Do not call the cancel_func if @a *pb is NULL.
78 * Allocate @a *result in @a pool.
80 * If @a hide is true, then try to avoid displaying the user's input.
83 prompt(const char **result
,
84 const char *prompt_msg
,
86 svn_cmdline_prompt_baton_t
*pb
,
93 svn_stringbuf_t
*strbuf
= svn_stringbuf_create("", pool
);
95 status
= apr_file_open_stdin(&fp
, pool
);
97 return svn_error_wrap_apr(status
, _("Can't open stdin"));
101 svn_boolean_t saw_first_half_of_eol
= FALSE
;
102 SVN_ERR(svn_cmdline_fputs(prompt_msg
, stderr
, pool
));
107 /* Hack to allow us to not block for io on the prompt, so
110 SVN_ERR(pb
->cancel_func(pb
->cancel_baton
));
111 status
= wait_for_input(fp
, pool
);
112 if (APR_STATUS_IS_EINTR(status
))
114 else if (status
&& status
!= APR_ENOTIMPL
)
115 return svn_error_wrap_apr(status
, _("Can't read stdin"));
117 status
= apr_file_getc(&c
, fp
);
119 return svn_error_wrap_apr(status
, _("Can't read stdin"));
121 if (saw_first_half_of_eol
)
123 if (c
== APR_EOL_STR
[1])
126 saw_first_half_of_eol
= FALSE
;
128 else if (c
== APR_EOL_STR
[0])
130 if (sizeof(APR_EOL_STR
) == 3)
132 saw_first_half_of_eol
= TRUE
;
135 else if (sizeof(APR_EOL_STR
) == 2)
138 /* ### APR_EOL_STR holds more than two chars? Who
139 ever heard of such a thing? */
143 svn_stringbuf_appendbytes(strbuf
, &c
, 1);
148 const char *prompt_stdout
;
149 size_t bufsize
= 300;
150 SVN_ERR(svn_cmdline_cstring_from_utf8(&prompt_stdout
, prompt_msg
,
152 svn_stringbuf_ensure(strbuf
, bufsize
);
154 status
= apr_password_get(prompt_stdout
, strbuf
->data
, &bufsize
);
156 return svn_error_wrap_apr(status
, _("Can't get password"));
159 SVN_ERR(svn_cmdline_cstring_to_utf8(result
, strbuf
->data
, pool
));
166 /** Prompt functions for auth providers. **/
168 /* Helper function for auth provider prompters: mention the
169 * authentication @a realm on stderr, in a manner appropriate for
170 * preceding a prompt; or if @a realm is null, then do nothing.
173 maybe_print_realm(const char *realm
, apr_pool_t
*pool
)
177 SVN_ERR(svn_cmdline_fprintf(stderr
, pool
,
178 _("Authentication realm: %s\n"), realm
));
186 /* This implements 'svn_auth_simple_prompt_func_t'. */
188 svn_cmdline_auth_simple_prompt(svn_auth_cred_simple_t
**cred_p
,
191 const char *username
,
192 svn_boolean_t may_save
,
195 svn_auth_cred_simple_t
*ret
= apr_pcalloc(pool
, sizeof(*ret
));
196 const char *pass_prompt
;
197 svn_cmdline_prompt_baton_t
*pb
= baton
;
199 SVN_ERR(maybe_print_realm(realm
, pool
));
202 ret
->username
= apr_pstrdup(pool
, username
);
204 SVN_ERR(prompt(&(ret
->username
), _("Username: "), FALSE
, pb
, pool
));
206 pass_prompt
= apr_psprintf(pool
, _("Password for '%s': "), ret
->username
);
207 SVN_ERR(prompt(&(ret
->password
), pass_prompt
, TRUE
, pb
, pool
));
208 ret
->may_save
= may_save
;
214 /* This implements 'svn_auth_username_prompt_func_t'. */
216 svn_cmdline_auth_username_prompt(svn_auth_cred_username_t
**cred_p
,
219 svn_boolean_t may_save
,
222 svn_auth_cred_username_t
*ret
= apr_pcalloc(pool
, sizeof(*ret
));
223 svn_cmdline_prompt_baton_t
*pb
= baton
;
225 SVN_ERR(maybe_print_realm(realm
, pool
));
227 SVN_ERR(prompt(&(ret
->username
), _("Username: "), FALSE
, pb
, pool
));
228 ret
->may_save
= may_save
;
234 /* This implements 'svn_auth_ssl_server_trust_prompt_func_t'. */
236 svn_cmdline_auth_ssl_server_trust_prompt
237 (svn_auth_cred_ssl_server_trust_t
**cred_p
,
240 apr_uint32_t failures
,
241 const svn_auth_ssl_server_cert_info_t
*cert_info
,
242 svn_boolean_t may_save
,
246 svn_stringbuf_t
*msg
;
247 svn_cmdline_prompt_baton_t
*pb
= baton
;
248 svn_stringbuf_t
*buf
= svn_stringbuf_createf
249 (pool
, _("Error validating server certificate for '%s':\n"), realm
);
251 if (failures
& SVN_AUTH_SSL_UNKNOWNCA
)
253 svn_stringbuf_appendcstr
255 _(" - The certificate is not issued by a trusted authority. Use the\n"
256 " fingerprint to validate the certificate manually!\n"));
259 if (failures
& SVN_AUTH_SSL_CNMISMATCH
)
261 svn_stringbuf_appendcstr
262 (buf
, _(" - The certificate hostname does not match.\n"));
265 if (failures
& SVN_AUTH_SSL_NOTYETVALID
)
267 svn_stringbuf_appendcstr
268 (buf
, _(" - The certificate is not yet valid.\n"));
271 if (failures
& SVN_AUTH_SSL_EXPIRED
)
273 svn_stringbuf_appendcstr
274 (buf
, _(" - The certificate has expired.\n"));
277 if (failures
& SVN_AUTH_SSL_OTHER
)
279 svn_stringbuf_appendcstr
280 (buf
, _(" - The certificate has an unknown error.\n"));
283 msg
= svn_stringbuf_createf
285 _("Certificate information:\n"
287 " - Valid: from %s until %s\n"
289 " - Fingerprint: %s\n"),
291 cert_info
->valid_from
,
292 cert_info
->valid_until
,
293 cert_info
->issuer_dname
,
294 cert_info
->fingerprint
);
295 svn_stringbuf_appendstr(buf
, msg
);
299 svn_stringbuf_appendcstr
300 (buf
, _("(R)eject, accept (t)emporarily or accept (p)ermanently? "));
304 svn_stringbuf_appendcstr(buf
, _("(R)eject or accept (t)emporarily? "));
306 SVN_ERR(prompt(&choice
, buf
->data
, FALSE
, pb
, pool
));
308 if (choice
[0] == 't' || choice
[0] == 'T')
310 *cred_p
= apr_pcalloc(pool
, sizeof(**cred_p
));
311 (*cred_p
)->may_save
= FALSE
;
312 (*cred_p
)->accepted_failures
= failures
;
314 else if (may_save
&& (choice
[0] == 'p' || choice
[0] == 'P'))
316 *cred_p
= apr_pcalloc(pool
, sizeof(**cred_p
));
317 (*cred_p
)->may_save
= TRUE
;
318 (*cred_p
)->accepted_failures
= failures
;
329 /* This implements 'svn_auth_ssl_client_cert_prompt_func_t'. */
331 svn_cmdline_auth_ssl_client_cert_prompt
332 (svn_auth_cred_ssl_client_cert_t
**cred_p
,
335 svn_boolean_t may_save
,
338 svn_auth_cred_ssl_client_cert_t
*cred
= NULL
;
339 const char *cert_file
= NULL
;
340 svn_cmdline_prompt_baton_t
*pb
= baton
;
342 SVN_ERR(maybe_print_realm(realm
, pool
));
343 SVN_ERR(prompt(&cert_file
, _("Client certificate filename: "),
346 cred
= apr_palloc(pool
, sizeof(*cred
));
347 cred
->cert_file
= cert_file
;
348 cred
->may_save
= may_save
;
355 /* This implements 'svn_auth_ssl_client_cert_pw_prompt_func_t'. */
357 svn_cmdline_auth_ssl_client_cert_pw_prompt
358 (svn_auth_cred_ssl_client_cert_pw_t
**cred_p
,
361 svn_boolean_t may_save
,
364 svn_auth_cred_ssl_client_cert_pw_t
*cred
= NULL
;
366 const char *text
= apr_psprintf(pool
, _("Passphrase for '%s': "), realm
);
367 svn_cmdline_prompt_baton_t
*pb
= baton
;
369 SVN_ERR(prompt(&result
, text
, TRUE
, pb
, pool
));
371 cred
= apr_pcalloc(pool
, sizeof(*cred
));
372 cred
->password
= result
;
373 cred
->may_save
= may_save
;
381 /** Generic prompting. **/
384 svn_cmdline_prompt_user2(const char **result
,
385 const char *prompt_str
,
386 svn_cmdline_prompt_baton_t
*baton
,
389 return prompt(result
, prompt_str
, FALSE
/* don't hide input */, baton
, pool
);
394 svn_cmdline_prompt_user(const char **result
,
395 const char *prompt_str
,
398 return svn_cmdline_prompt_user2(result
, prompt_str
, NULL
, pool
);