1 /*
2 * simple_providers.c: providers for SVN_AUTH_CRED_SIMPLE
3 *
4 * ====================================================================
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
20 * under the License.
21 * ====================================================================
22 */
23
24 /* ==================================================================== */
25
26
27
28 /*** Includes. ***/
29
30 #include <apr_pools.h>
31 #include "svn_auth.h"
32 #include "svn_dirent_uri.h"
33 #include "svn_hash.h"
34 #include "svn_pools.h"
35 #include "svn_error.h"
36 #include "svn_utf.h"
37 #include "svn_config.h"
38 #include "svn_user.h"
39
40 #include "private/svn_auth_private.h"
41
42 #include "svn_private_config.h"
43
44 #include "auth.h"
45
46 /*-----------------------------------------------------------------------*/
47 /* File provider */
48 /*-----------------------------------------------------------------------*/
49
50 /* Baton type for the simple provider. */
51 typedef struct simple_provider_baton_t
52 {
53 svn_auth_plaintext_prompt_func_t plaintext_prompt_func;
54 void *prompt_baton;
55 /* We cache the user's answer to the plaintext prompt, keyed
56 * by realm, in case we'll be called multiple times for the
57 * same realm. */
58 apr_hash_t *plaintext_answers;
59 } simple_provider_baton_t;
60
61
62 /* Implementation of svn_auth__password_get_t that retrieves
63 the plaintext password from CREDS. */
64 svn_error_t *
svn_auth__simple_password_get(svn_boolean_t * done,const char ** password,apr_hash_t * creds,const char * realmstring,const char * username,apr_hash_t * parameters,svn_boolean_t non_interactive,apr_pool_t * pool)65 svn_auth__simple_password_get(svn_boolean_t *done,
66 const char **password,
67 apr_hash_t *creds,
68 const char *realmstring,
69 const char *username,
70 apr_hash_t *parameters,
71 svn_boolean_t non_interactive,
72 apr_pool_t *pool)
73 {
74 svn_string_t *str;
75
76 *done = FALSE;
77
78 str = svn_hash_gets(creds, SVN_CONFIG_AUTHN_USERNAME_KEY);
79 if (str && username && strcmp(str->data, username) == 0)
80 {
81 str = svn_hash_gets(creds, SVN_CONFIG_AUTHN_PASSWORD_KEY);
82 if (str && str->data)
83 {
84 *password = str->data;
85 *done = TRUE;
86 }
87 }
88
89 return SVN_NO_ERROR;
90 }
91
92 /* Implementation of svn_auth__password_set_t that stores
93 the plaintext password in CREDS. */
94 svn_error_t *
svn_auth__simple_password_set(svn_boolean_t * done,apr_hash_t * creds,const char * realmstring,const char * username,const char * password,apr_hash_t * parameters,svn_boolean_t non_interactive,apr_pool_t * pool)95 svn_auth__simple_password_set(svn_boolean_t *done,
96 apr_hash_t *creds,
97 const char *realmstring,
98 const char *username,
99 const char *password,
100 apr_hash_t *parameters,
101 svn_boolean_t non_interactive,
102 apr_pool_t *pool)
103 {
104 svn_hash_sets(creds, SVN_CONFIG_AUTHN_PASSWORD_KEY,
105 svn_string_create(password, pool));
106 *done = TRUE;
107
108 return SVN_NO_ERROR;
109 }
110
111 /* Set **USERNAME to the username retrieved from CREDS; ignore
112 other parameters. *USERNAME will have the same lifetime as CREDS. */
113 static svn_boolean_t
simple_username_get(const char ** username,apr_hash_t * creds,const char * realmstring,svn_boolean_t non_interactive)114 simple_username_get(const char **username,
115 apr_hash_t *creds,
116 const char *realmstring,
117 svn_boolean_t non_interactive)
118 {
119 svn_string_t *str;
120 str = svn_hash_gets(creds, SVN_CONFIG_AUTHN_USERNAME_KEY);
121 if (str && str->data)
122 {
123 *username = str->data;
124 return TRUE;
125 }
126 return FALSE;
127 }
128
129
130 svn_error_t *
svn_auth__simple_creds_cache_get(void ** credentials,void ** iter_baton,void * provider_baton,apr_hash_t * parameters,const char * realmstring,svn_auth__password_get_t password_get,const char * passtype,apr_pool_t * pool)131 svn_auth__simple_creds_cache_get(void **credentials,
132 void **iter_baton,
133 void *provider_baton,
134 apr_hash_t *parameters,
135 const char *realmstring,
136 svn_auth__password_get_t password_get,
137 const char *passtype,
138 apr_pool_t *pool)
139 {
140 const char *config_dir = svn_hash_gets(parameters, SVN_AUTH_PARAM_CONFIG_DIR);
141 svn_config_t *cfg = svn_hash_gets(parameters,
142 SVN_AUTH_PARAM_CONFIG_CATEGORY_SERVERS);
143 const char *server_group = svn_hash_gets(parameters,
144 SVN_AUTH_PARAM_SERVER_GROUP);
145 const char *username = svn_hash_gets(parameters,
146 SVN_AUTH_PARAM_DEFAULT_USERNAME);
147 const char *password = svn_hash_gets(parameters,
148 SVN_AUTH_PARAM_DEFAULT_PASSWORD);
149 svn_boolean_t non_interactive = svn_hash_gets(parameters,
150 SVN_AUTH_PARAM_NON_INTERACTIVE)
151 != NULL;
152 const char *default_username = NULL; /* Default username from cache. */
153 const char *default_password = NULL; /* Default password from cache. */
154
155 /* This checks if we should save the CREDS, iff saving the credentials is
156 allowed by the run-time configuration. */
157 svn_boolean_t need_to_save = FALSE;
158 apr_hash_t *creds_hash = NULL;
159 svn_error_t *err;
160 svn_string_t *str;
161
162 /* Try to load credentials from a file on disk, based on the
163 realmstring. Don't throw an error, though: if something went
164 wrong reading the file, no big deal. What really matters is that
165 we failed to get the creds, so allow the auth system to try the
166 next provider. */
167 err = svn_config_read_auth_data(&creds_hash, SVN_AUTH_CRED_SIMPLE,
168 realmstring, config_dir, pool);
169 if (err)
170 {
171 svn_error_clear(err);
172 err = NULL;
173 }
174 else if (creds_hash)
175 {
176 /* We have something in the auth cache for this realm. */
177 svn_boolean_t have_passtype = FALSE;
178
179 /* The password type in the auth data must match the
180 mangler's type, otherwise the password must be
181 interpreted by another provider. */
182 str = svn_hash_gets(creds_hash, SVN_CONFIG_AUTHN_PASSTYPE_KEY);
183 if (str && str->data)
184 if (passtype && (0 == strcmp(str->data, passtype)))
185 have_passtype = TRUE;
186
187 /* See if we need to save this username if it is not present in
188 auth cache. */
189 if (username)
190 {
191 if (!simple_username_get(&default_username, creds_hash, realmstring,
192 non_interactive))
193 {
194 need_to_save = TRUE;
195 }
196 else
197 {
198 if (strcmp(default_username, username) != 0)
199 need_to_save = TRUE;
200 }
201 }
202
203 /* See if we need to save this password if it is not present in
204 auth cache. */
205 if (password)
206 {
207 if (have_passtype)
208 {
209 svn_boolean_t done;
210
211 SVN_ERR(password_get(&done, &default_password, creds_hash,
212 realmstring, username, parameters,
213 non_interactive, pool));
214 if (!done)
215 {
216 need_to_save = TRUE;
217 }
218 else
219 {
220 if (strcmp(default_password, password) != 0)
221 need_to_save = TRUE;
222 }
223 }
224 }
225
226 /* If we don't have a username and a password yet, we try the
227 auth cache */
228 if (! (username && password))
229 {
230 if (! username)
231 if (!simple_username_get(&username, creds_hash, realmstring,
232 non_interactive))
233 username = NULL;
234
235 if (username && ! password)
236 {
237 if (! have_passtype)
238 password = NULL;
239 else
240 {
241 svn_boolean_t done;
242
243 SVN_ERR(password_get(&done, &password, creds_hash,
244 realmstring, username, parameters,
245 non_interactive, pool));
246 if (!done)
247 password = NULL;
248
249 /* If the auth data didn't contain a password type,
250 force a write to upgrade the format of the auth
251 data file. */
252 if (password && ! have_passtype)
253 need_to_save = TRUE;
254 }
255 }
256 }
257 }
258 else
259 {
260 /* Nothing was present in the auth cache, so indicate that these
261 credentials should be saved. */
262 need_to_save = TRUE;
263 }
264
265 /* If we don't have a username yet, check the 'servers' file */
266 if (! username)
267 {
268 username = svn_config_get_server_setting(cfg, server_group,
269 SVN_CONFIG_OPTION_USERNAME,
270 NULL);
271 }
272
273 /* Ask the OS for the username if we have a password but no
274 username. */
275 if (password && ! username)
276 username = svn_user_get_name(pool);
277
278 if (username && password)
279 {
280 svn_auth_cred_simple_t *creds = apr_pcalloc(pool, sizeof(*creds));
281 creds->username = username;
282 creds->password = password;
283 creds->may_save = need_to_save;
284 *credentials = creds;
285 }
286 else
287 *credentials = NULL;
288
289 *iter_baton = NULL;
290
291 return SVN_NO_ERROR;
292 }
293
294
295 svn_error_t *
svn_auth__simple_creds_cache_set(svn_boolean_t * saved,void * credentials,void * provider_baton,apr_hash_t * parameters,const char * realmstring,svn_auth__password_set_t password_set,const char * passtype,apr_pool_t * pool)296 svn_auth__simple_creds_cache_set(svn_boolean_t *saved,
297 void *credentials,
298 void *provider_baton,
299 apr_hash_t *parameters,
300 const char *realmstring,
301 svn_auth__password_set_t password_set,
302 const char *passtype,
303 apr_pool_t *pool)
304 {
305 svn_auth_cred_simple_t *creds = credentials;
306 apr_hash_t *creds_hash = NULL;
307 const char *config_dir;
308 svn_error_t *err;
309 svn_boolean_t dont_store_passwords =
310 svn_hash_gets(parameters, SVN_AUTH_PARAM_DONT_STORE_PASSWORDS) != NULL;
311 svn_boolean_t non_interactive = svn_hash_gets(parameters,
312 SVN_AUTH_PARAM_NON_INTERACTIVE)
313 != NULL;
314 svn_boolean_t no_auth_cache =
315 (! creds->may_save) || (svn_hash_gets(parameters,
316 SVN_AUTH_PARAM_NO_AUTH_CACHE)
317 != NULL);
318
319 /* Make sure we've been passed a passtype. */
320 SVN_ERR_ASSERT(passtype != NULL);
321
322 *saved = FALSE;
323
324 if (no_auth_cache)
325 return SVN_NO_ERROR;
326
327 config_dir = svn_hash_gets(parameters, SVN_AUTH_PARAM_CONFIG_DIR);
328
329 /* Put the username into the credentials hash. */
330 creds_hash = apr_hash_make(pool);
331 svn_hash_sets(creds_hash, SVN_CONFIG_AUTHN_USERNAME_KEY,
332 svn_string_create(creds->username, pool));
333
334 /* Don't store passwords in any form if the user has told
335 * us not to do so. */
336 if (! dont_store_passwords)
337 {
338 svn_boolean_t may_save_password = FALSE;
339
340 /* If the password is going to be stored encrypted, go right
341 * ahead and store it to disk. Else determine whether saving
342 * in plaintext is OK. */
343 if (passtype &&
344 (strcmp(passtype, SVN_AUTH__WINCRYPT_PASSWORD_TYPE) == 0
345 || strcmp(passtype, SVN_AUTH__KEYCHAIN_PASSWORD_TYPE) == 0
346 || strcmp(passtype, SVN_AUTH__KWALLET_PASSWORD_TYPE) == 0
347 || strcmp(passtype, SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE) == 0
348 || strcmp(passtype, SVN_AUTH__GPG_AGENT_PASSWORD_TYPE) == 0))
349 {
350 may_save_password = TRUE;
351 }
352 else
353 {
354 #ifdef SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE
355 may_save_password = FALSE;
356 #else
357 const char *store_plaintext_passwords =
358 svn_hash_gets(parameters, SVN_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS);
359 simple_provider_baton_t *b =
360 (simple_provider_baton_t *)provider_baton;
361
362 if (store_plaintext_passwords
363 && svn_cstring_casecmp(store_plaintext_passwords,
364 SVN_CONFIG_ASK) == 0)
365 {
366 if (non_interactive)
367 /* In non-interactive mode, the default behaviour is
368 * to not store the password, because it is usually
369 * passed on the command line. */
370 may_save_password = FALSE;
371 else if (b->plaintext_prompt_func)
372 {
373 /* We're interactive, and the client provided a
374 * prompt callback. So we can ask the user.
375 *
376 * Check for a cached answer before prompting. */
377 svn_boolean_t *cached_answer;
378 cached_answer = svn_hash_gets(b->plaintext_answers,
379 realmstring);
380 if (cached_answer != NULL)
381 may_save_password = *cached_answer;
382 else
383 {
384 apr_pool_t *cached_answer_pool;
385
386 /* Nothing cached for this realm, prompt the user. */
387 SVN_ERR((*b->plaintext_prompt_func)(&may_save_password,
388 realmstring,
389 b->prompt_baton,
390 pool));
391
392 /* Cache the user's answer in case we're called again
393 * for the same realm.
394 *
395 * We allocate the answer cache in the hash table's pool
396 * to make sure that is has the same life time as the
397 * hash table itself. This means that the answer will
398 * survive across RA sessions -- which is important,
399 * because otherwise we'd prompt users once per RA session.
400 */
401 cached_answer_pool = apr_hash_pool_get(b->plaintext_answers);
402 cached_answer = apr_palloc(cached_answer_pool,
403 sizeof(svn_boolean_t));
404 *cached_answer = may_save_password;
405 svn_hash_sets(b->plaintext_answers, realmstring,
406 cached_answer);
407 }
408 }
409 else
410 {
411 /* TODO: We might want to default to not storing if the
412 * prompt callback is NULL, i.e. have may_save_password
413 * default to FALSE here, in order to force clients to
414 * implement the callback.
415 *
416 * This would change the semantics of old API though.
417 *
418 * So for now, clients that don't implement the callback
419 * and provide no explicit value for
420 * SVN_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS
421 * cause unencrypted passwords to be stored by default.
422 * Needless to say, our own client is sane, but who knows
423 * what other clients are doing.
424 */
425 may_save_password = TRUE;
426 }
427 }
428 else if (store_plaintext_passwords
429 && svn_cstring_casecmp(store_plaintext_passwords,
430 SVN_CONFIG_FALSE) == 0)
431 {
432 may_save_password = FALSE;
433 }
434 else if (!store_plaintext_passwords
435 || svn_cstring_casecmp(store_plaintext_passwords,
436 SVN_CONFIG_TRUE) == 0)
437 {
438 may_save_password = TRUE;
439 }
440 else
441 {
442 return svn_error_createf
443 (SVN_ERR_BAD_CONFIG_VALUE, NULL,
444 _("Config error: invalid value '%s' for option '%s'"),
445 store_plaintext_passwords,
446 SVN_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS);
447 }
448 #endif
449 }
450
451 if (may_save_password)
452 {
453 SVN_ERR(password_set(saved, creds_hash, realmstring,
454 creds->username, creds->password,
455 parameters, non_interactive, pool));
456 if (*saved && passtype)
457 /* Store the password type with the auth data, so that we
458 know which provider owns the password. */
459 svn_hash_sets(creds_hash, SVN_CONFIG_AUTHN_PASSTYPE_KEY,
460 svn_string_create(passtype, pool));
461 }
462 }
463
464 /* Save credentials to disk. */
465 err = svn_config_write_auth_data(creds_hash, SVN_AUTH_CRED_SIMPLE,
466 realmstring, config_dir, pool);
467 if (err)
468 *saved = FALSE;
469
470 /* ### return error? */
471 svn_error_clear(err);
472
473 return SVN_NO_ERROR;
474 }
475
476 /* Get cached (unencrypted) credentials from the simple provider's cache. */
477 static svn_error_t *
simple_first_creds(void ** credentials,void ** iter_baton,void * provider_baton,apr_hash_t * parameters,const char * realmstring,apr_pool_t * pool)478 simple_first_creds(void **credentials,
479 void **iter_baton,
480 void *provider_baton,
481 apr_hash_t *parameters,
482 const char *realmstring,
483 apr_pool_t *pool)
484 {
485 return svn_auth__simple_creds_cache_get(credentials, iter_baton,
486 provider_baton, parameters,
487 realmstring,
488 svn_auth__simple_password_get,
489 SVN_AUTH__SIMPLE_PASSWORD_TYPE,
490 pool);
491 }
492
493 /* Save (unencrypted) credentials to the simple provider's cache. */
494 static svn_error_t *
simple_save_creds(svn_boolean_t * saved,void * credentials,void * provider_baton,apr_hash_t * parameters,const char * realmstring,apr_pool_t * pool)495 simple_save_creds(svn_boolean_t *saved,
496 void *credentials,
497 void *provider_baton,
498 apr_hash_t *parameters,
499 const char *realmstring,
500 apr_pool_t *pool)
501 {
502 return svn_auth__simple_creds_cache_set(saved, credentials, provider_baton,
503 parameters, realmstring,
504 svn_auth__simple_password_set,
505 SVN_AUTH__SIMPLE_PASSWORD_TYPE,
506 pool);
507 }
508
509 static const svn_auth_provider_t simple_provider = {
510 SVN_AUTH_CRED_SIMPLE,
511 simple_first_creds,
512 NULL,
513 simple_save_creds
514 };
515
516
517 /* Public API */
518 void
svn_auth_get_simple_provider2(svn_auth_provider_object_t ** provider,svn_auth_plaintext_prompt_func_t plaintext_prompt_func,void * prompt_baton,apr_pool_t * pool)519 svn_auth_get_simple_provider2
520 (svn_auth_provider_object_t **provider,
521 svn_auth_plaintext_prompt_func_t plaintext_prompt_func,
522 void* prompt_baton,
523 apr_pool_t *pool)
524 {
525 svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
526 simple_provider_baton_t *pb = apr_pcalloc(pool, sizeof(*pb));
527
528 pb->plaintext_prompt_func = plaintext_prompt_func;
529 pb->prompt_baton = prompt_baton;
530 pb->plaintext_answers = apr_hash_make(pool);
531
532 po->vtable = &simple_provider;
533 po->provider_baton = pb;
534 *provider = po;
535 }
536
537
538 /*-----------------------------------------------------------------------*/
539 /* Prompt provider */
540 /*-----------------------------------------------------------------------*/
541
542 /* Baton type for username/password prompting. */
543 typedef struct simple_prompt_provider_baton_t
544 {
545 svn_auth_simple_prompt_func_t prompt_func;
546 void *prompt_baton;
547
548 /* how many times to re-prompt after the first one fails */
549 int retry_limit;
550 } simple_prompt_provider_baton_t;
551
552
553 /* Iteration baton type for username/password prompting. */
554 typedef struct simple_prompt_iter_baton_t
555 {
556 /* how many times we've reprompted */
557 int retries;
558 } simple_prompt_iter_baton_t;
559
560
561
562 /*** Helper Functions ***/
563 static svn_error_t *
prompt_for_simple_creds(svn_auth_cred_simple_t ** cred_p,simple_prompt_provider_baton_t * pb,apr_hash_t * parameters,const char * realmstring,svn_boolean_t first_time,svn_boolean_t may_save,apr_pool_t * pool)564 prompt_for_simple_creds(svn_auth_cred_simple_t **cred_p,
565 simple_prompt_provider_baton_t *pb,
566 apr_hash_t *parameters,
567 const char *realmstring,
568 svn_boolean_t first_time,
569 svn_boolean_t may_save,
570 apr_pool_t *pool)
571 {
572 const char *default_username = NULL;
573 const char *default_password = NULL;
574
575 *cred_p = NULL;
576
577 /* If we're allowed to check for default usernames and passwords, do
578 so. */
579 if (first_time)
580 {
581 default_username = svn_hash_gets(parameters,
582 SVN_AUTH_PARAM_DEFAULT_USERNAME);
583
584 /* No default username? Try the auth cache. */
585 if (! default_username)
586 {
587 const char *config_dir = svn_hash_gets(parameters,
588 SVN_AUTH_PARAM_CONFIG_DIR);
589 apr_hash_t *creds_hash = NULL;
590 svn_string_t *str;
591 svn_error_t *err;
592
593 err = svn_config_read_auth_data(&creds_hash, SVN_AUTH_CRED_SIMPLE,
594 realmstring, config_dir, pool);
595 svn_error_clear(err);
596 if (! err && creds_hash)
597 {
598 str = svn_hash_gets(creds_hash, SVN_CONFIG_AUTHN_USERNAME_KEY);
599 if (str && str->data)
600 default_username = str->data;
601 }
602 }
603
604 /* Still no default username? Try the 'servers' file. */
605 if (! default_username)
606 {
607 svn_config_t *cfg = svn_hash_gets(parameters,
608 SVN_AUTH_PARAM_CONFIG_CATEGORY_SERVERS);
609 const char *server_group = svn_hash_gets(parameters,
610 SVN_AUTH_PARAM_SERVER_GROUP);
611 default_username =
612 svn_config_get_server_setting(cfg, server_group,
613 SVN_CONFIG_OPTION_USERNAME,
614 NULL);
615 }
616
617 /* Still no default username? Try the UID. */
618 if (! default_username)
619 default_username = svn_user_get_name(pool);
620
621 default_password = svn_hash_gets(parameters,
622 SVN_AUTH_PARAM_DEFAULT_PASSWORD);
623 }
624
625 /* If we have defaults, just build the cred here and return it.
626 *
627 * ### I do wonder why this is here instead of in a separate
628 * ### 'defaults' provider that would run before the prompt
629 * ### provider... Hmmm.
630 */
631 if (default_username && default_password)
632 {
633 *cred_p = apr_palloc(pool, sizeof(**cred_p));
634 (*cred_p)->username = apr_pstrdup(pool, default_username);
635 (*cred_p)->password = apr_pstrdup(pool, default_password);
636 (*cred_p)->may_save = TRUE;
637 }
638 else
639 {
640 SVN_ERR(pb->prompt_func(cred_p, pb->prompt_baton, realmstring,
641 default_username, may_save, pool));
642 }
643
644 return SVN_NO_ERROR;
645 }
646
647
648 /* Our first attempt will use any default username/password passed
649 in, and prompt for the remaining stuff. */
650 static svn_error_t *
simple_prompt_first_creds(void ** credentials_p,void ** iter_baton,void * provider_baton,apr_hash_t * parameters,const char * realmstring,apr_pool_t * pool)651 simple_prompt_first_creds(void **credentials_p,
652 void **iter_baton,
653 void *provider_baton,
654 apr_hash_t *parameters,
655 const char *realmstring,
656 apr_pool_t *pool)
657 {
658 simple_prompt_provider_baton_t *pb = provider_baton;
659 simple_prompt_iter_baton_t *ibaton = apr_pcalloc(pool, sizeof(*ibaton));
660 const char *no_auth_cache = svn_hash_gets(parameters,
661 SVN_AUTH_PARAM_NO_AUTH_CACHE);
662
663 SVN_ERR(prompt_for_simple_creds((svn_auth_cred_simple_t **) credentials_p,
664 pb, parameters, realmstring, TRUE,
665 ! no_auth_cache, pool));
666
667 ibaton->retries = 0;
668 *iter_baton = ibaton;
669
670 return SVN_NO_ERROR;
671 }
672
673
674 /* Subsequent attempts to fetch will ignore the default values, and
675 simply re-prompt for both, up to a maximum of ib->pb->retry_limit. */
676 static svn_error_t *
simple_prompt_next_creds(void ** credentials_p,void * iter_baton,void * provider_baton,apr_hash_t * parameters,const char * realmstring,apr_pool_t * pool)677 simple_prompt_next_creds(void **credentials_p,
678 void *iter_baton,
679 void *provider_baton,
680 apr_hash_t *parameters,
681 const char *realmstring,
682 apr_pool_t *pool)
683 {
684 simple_prompt_iter_baton_t *ib = iter_baton;
685 simple_prompt_provider_baton_t *pb = provider_baton;
686 const char *no_auth_cache = svn_hash_gets(parameters,
687 SVN_AUTH_PARAM_NO_AUTH_CACHE);
688
689 if ((pb->retry_limit >= 0) && (ib->retries >= pb->retry_limit))
690 {
691 /* give up, go on to next provider. */
692 *credentials_p = NULL;
693 return SVN_NO_ERROR;
694 }
695 ib->retries++;
696
697 return prompt_for_simple_creds((svn_auth_cred_simple_t **) credentials_p,
698 pb, parameters, realmstring, FALSE,
699 ! no_auth_cache, pool);
700 }
701
702 static const svn_auth_provider_t simple_prompt_provider = {
703 SVN_AUTH_CRED_SIMPLE,
704 simple_prompt_first_creds,
705 simple_prompt_next_creds,
706 NULL,
707 };
708
709
710 /* Public API */
711 void
svn_auth_get_simple_prompt_provider(svn_auth_provider_object_t ** provider,svn_auth_simple_prompt_func_t prompt_func,void * prompt_baton,int retry_limit,apr_pool_t * pool)712 svn_auth_get_simple_prompt_provider
713 (svn_auth_provider_object_t **provider,
714 svn_auth_simple_prompt_func_t prompt_func,
715 void *prompt_baton,
716 int retry_limit,
717 apr_pool_t *pool)
718 {
719 svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
720 simple_prompt_provider_baton_t *pb = apr_pcalloc(pool, sizeof(*pb));
721
722 pb->prompt_func = prompt_func;
723 pb->prompt_baton = prompt_baton;
724 pb->retry_limit = retry_limit;
725
726 po->vtable = &simple_prompt_provider;
727 po->provider_baton = pb;
728 *provider = po;
729 }
730