]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/subversion/subversion/libsvn_subr/auth.c
MFC r275385 (by bapt):
[FreeBSD/stable/10.git] / contrib / subversion / subversion / libsvn_subr / auth.c
1 /*
2  * auth.c: authentication support functions for Subversion
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 #include <apr_pools.h>
26 #include <apr_tables.h>
27 #include <apr_strings.h>
28
29 #include "svn_hash.h"
30 #include "svn_types.h"
31 #include "svn_string.h"
32 #include "svn_error.h"
33 #include "svn_auth.h"
34 #include "svn_config.h"
35 #include "svn_private_config.h"
36 #include "svn_dso.h"
37 #include "svn_version.h"
38 #include "private/svn_auth_private.h"
39 #include "private/svn_dep_compat.h"
40
41 #include "auth.h"
42
43 /* AN OVERVIEW
44    ===========
45
46    A good way to think of this machinery is as a set of tables.
47
48      - Each type of credentials selects a single table.
49
50      - In a given table, each row is a 'provider' capable of returning
51        the same type of credentials.  Each column represents a
52        provider's repeated attempts to provide credentials.
53
54
55    Fetching Credentials from Providers
56    -----------------------------------
57
58    When the caller asks for a particular type of credentials, the
59    machinery in this file walks over the appropriate table.  It starts
60    with the first provider (first row), and calls first_credentials()
61    to get the first set of credentials (first column).  If the caller
62    is unhappy with the credentials, then each subsequent call to
63    next_credentials() traverses the row from left to right.  If the
64    provider returns error at any point, then we go to the next provider
65    (row).  We continue this way until every provider fails, or
66    until the client is happy with the returned credentials.
67
68    Note that the caller cannot see the table traversal, and thus has
69    no idea when we switch providers.
70
71
72    Storing Credentials with Providers
73    ----------------------------------
74
75    When the server has validated a set of credentials, and when
76    credential caching is enabled, we have the chance to store those
77    credentials for later use.  The provider which provided the working
78    credentials is the first one given the opportunity to (re)cache
79    those credentials.  Its save_credentials() function is invoked with
80    the working credentials.  If that provider reports that it
81    successfully stored the credentials, we're done.  Otherwise, we
82    walk the providers (rows) for that type of credentials in order
83    from the top of the table, allowing each in turn the opportunity to
84    store the credentials.  When one reports that it has done so
85    successfully -- or when we run out of providers (rows) to try --
86    the table walk ends.
87 */
88
89
90
91 /* This effectively defines a single table.  Every provider in this
92    array returns the same kind of credentials. */
93 typedef struct provider_set_t
94 {
95   /* ordered array of svn_auth_provider_object_t */
96   apr_array_header_t *providers;
97
98 } provider_set_t;
99
100
101 /* The main auth baton. */
102 struct svn_auth_baton_t
103 {
104   /* a collection of tables.  maps cred_kind -> provider_set */
105   apr_hash_t *tables;
106
107   /* the pool I'm allocated in. */
108   apr_pool_t *pool;
109
110   /* run-time parameters needed by providers. */
111   apr_hash_t *parameters;
112   apr_hash_t *slave_parameters;
113
114   /* run-time credentials cache. */
115   apr_hash_t *creds_cache;
116 };
117
118 /* Abstracted iteration baton */
119 struct svn_auth_iterstate_t
120 {
121   provider_set_t *table;        /* the table being searched */
122   int provider_idx;             /* the current provider (row) */
123   svn_boolean_t got_first;      /* did we get the provider's first creds? */
124   void *provider_iter_baton;    /* the provider's own iteration context */
125   const char *realmstring;      /* The original realmstring passed in */
126   const char *cache_key;        /* key to use in auth_baton's creds_cache */
127   svn_auth_baton_t *auth_baton; /* the original auth_baton. */
128   apr_hash_t *parameters;
129 };
130
131
132
133 void
134 svn_auth_open(svn_auth_baton_t **auth_baton,
135               const apr_array_header_t *providers,
136               apr_pool_t *pool)
137 {
138   svn_auth_baton_t *ab;
139   svn_auth_provider_object_t *provider;
140   int i;
141
142   /* Build the auth_baton. */
143   ab = apr_pcalloc(pool, sizeof(*ab));
144   ab->tables = apr_hash_make(pool);
145   ab->parameters = apr_hash_make(pool);
146   /* ab->slave_parameters = NULL; */
147   ab->creds_cache = apr_hash_make(pool);
148   ab->pool = pool;
149
150   /* Register each provider in order.  Providers of different
151      credentials will be automatically sorted into different tables by
152      register_provider(). */
153   for (i = 0; i < providers->nelts; i++)
154     {
155       provider_set_t *table;
156       provider = APR_ARRAY_IDX(providers, i, svn_auth_provider_object_t *);
157
158       /* Add it to the appropriate table in the auth_baton */
159       table = svn_hash_gets(ab->tables, provider->vtable->cred_kind);
160       if (! table)
161         {
162           table = apr_pcalloc(pool, sizeof(*table));
163           table->providers
164             = apr_array_make(pool, 1, sizeof(svn_auth_provider_object_t *));
165
166           svn_hash_sets(ab->tables, provider->vtable->cred_kind, table);
167         }
168       APR_ARRAY_PUSH(table->providers, svn_auth_provider_object_t *)
169         = provider;
170     }
171
172   *auth_baton = ab;
173 }
174
175 /* Magic pointer value to allow storing 'NULL' in an apr_hash_t */
176 static const void *auth_NULL = NULL;
177
178 void
179 svn_auth_set_parameter(svn_auth_baton_t *auth_baton,
180                        const char *name,
181                        const void *value)
182 {
183   if (auth_baton)
184     {
185       if (auth_baton->slave_parameters)
186         {
187           if (!value)
188             value = &auth_NULL;
189
190           svn_hash_sets(auth_baton->slave_parameters, name, value);
191         }
192       else
193         svn_hash_sets(auth_baton->parameters, name, value);
194     }
195 }
196
197 const void *
198 svn_auth_get_parameter(svn_auth_baton_t *auth_baton,
199                        const char *name)
200 {
201   const void *value;
202   if (!auth_baton)
203     return NULL;
204   else if (!auth_baton->slave_parameters)
205     return svn_hash_gets(auth_baton->parameters, name);
206
207   value = svn_hash_gets(auth_baton->slave_parameters, name);
208
209   if (value)
210     return (value == &auth_NULL) ? NULL
211                                 : value;
212
213   return svn_hash_gets(auth_baton->parameters, name);
214 }
215
216
217 /* Return the key used to address the in-memory cache of auth
218    credentials of type CRED_KIND and associated with REALMSTRING. */
219 static const char *
220 make_cache_key(const char *cred_kind,
221                const char *realmstring,
222                apr_pool_t *pool)
223 {
224   return apr_pstrcat(pool, cred_kind, ":", realmstring, SVN_VA_NULL);
225 }
226
227 svn_error_t *
228 svn_auth_first_credentials(void **credentials,
229                            svn_auth_iterstate_t **state,
230                            const char *cred_kind,
231                            const char *realmstring,
232                            svn_auth_baton_t *auth_baton,
233                            apr_pool_t *pool)
234 {
235   int i = 0;
236   provider_set_t *table;
237   svn_auth_provider_object_t *provider = NULL;
238   void *creds = NULL;
239   void *iter_baton = NULL;
240   svn_boolean_t got_first = FALSE;
241   svn_auth_iterstate_t *iterstate;
242   const char *cache_key;
243   apr_hash_t *parameters;
244
245   if (! auth_baton)
246     return svn_error_create(SVN_ERR_AUTHN_NO_PROVIDER, NULL,
247                             _("No authentication providers registered"));
248
249   /* Get the appropriate table of providers for CRED_KIND. */
250   table = svn_hash_gets(auth_baton->tables, cred_kind);
251   if (! table)
252     return svn_error_createf(SVN_ERR_AUTHN_NO_PROVIDER, NULL,
253                              _("No provider registered for '%s' credentials"),
254                              cred_kind);
255
256   if (auth_baton->slave_parameters)
257     {
258       apr_hash_index_t *hi;
259       parameters = apr_hash_copy(pool, auth_baton->parameters);
260
261       for (hi = apr_hash_first(pool, auth_baton->slave_parameters);
262             hi;
263             hi = apr_hash_next(hi))
264         {
265           const void *value = apr_hash_this_val(hi);
266
267           if (value == &auth_NULL)
268             value = NULL;
269
270           svn_hash_sets(parameters, apr_hash_this_key(hi), value);
271         }
272     }
273   else
274     parameters = auth_baton->parameters;
275
276   /* First, see if we have cached creds in the auth_baton. */
277   cache_key = make_cache_key(cred_kind, realmstring, pool);
278   creds = svn_hash_gets(auth_baton->creds_cache, cache_key);
279   if (creds)
280     {
281        got_first = FALSE;
282     }
283   else
284     /* If not, find a provider that can give "first" credentials. */
285     {
286       /* Find a provider that can give "first" credentials. */
287       for (i = 0; i < table->providers->nelts; i++)
288         {
289           provider = APR_ARRAY_IDX(table->providers, i,
290                                    svn_auth_provider_object_t *);
291           SVN_ERR(provider->vtable->first_credentials(&creds, &iter_baton,
292                                                       provider->provider_baton,
293                                                       parameters,
294                                                       realmstring,
295                                                       auth_baton->pool));
296
297           if (creds != NULL)
298             {
299               got_first = TRUE;
300               break;
301             }
302         }
303     }
304
305   if (! creds)
306     {
307       *state = NULL;
308     }
309   else
310     {
311       /* Build an abstract iteration state. */
312       iterstate = apr_pcalloc(pool, sizeof(*iterstate));
313       iterstate->table = table;
314       iterstate->provider_idx = i;
315       iterstate->got_first = got_first;
316       iterstate->provider_iter_baton = iter_baton;
317       iterstate->realmstring = apr_pstrdup(pool, realmstring);
318       iterstate->cache_key = cache_key;
319       iterstate->auth_baton = auth_baton;
320       iterstate->parameters = parameters;
321       *state = iterstate;
322
323       /* Put the creds in the cache */
324       svn_hash_sets(auth_baton->creds_cache,
325                     apr_pstrdup(auth_baton->pool, cache_key),
326                     creds);
327     }
328
329   *credentials = creds;
330
331   return SVN_NO_ERROR;
332 }
333
334
335 svn_error_t *
336 svn_auth_next_credentials(void **credentials,
337                           svn_auth_iterstate_t *state,
338                           apr_pool_t *pool)
339 {
340   svn_auth_baton_t *auth_baton = state->auth_baton;
341   svn_auth_provider_object_t *provider;
342   provider_set_t *table = state->table;
343   void *creds = NULL;
344
345   /* Continue traversing the table from where we left off. */
346   for (/* no init */;
347        state->provider_idx < table->providers->nelts;
348        state->provider_idx++)
349     {
350       provider = APR_ARRAY_IDX(table->providers,
351                                state->provider_idx,
352                                svn_auth_provider_object_t *);
353       if (! state->got_first)
354         {
355           SVN_ERR(provider->vtable->first_credentials(
356                       &creds, &(state->provider_iter_baton),
357                       provider->provider_baton, state->parameters,
358                       state->realmstring, auth_baton->pool));
359           state->got_first = TRUE;
360         }
361       else if (provider->vtable->next_credentials)
362         {
363           SVN_ERR(provider->vtable->next_credentials(&creds,
364                                                      state->provider_iter_baton,
365                                                      provider->provider_baton,
366                                                      state->parameters,
367                                                      state->realmstring,
368                                                      auth_baton->pool));
369         }
370
371       if (creds != NULL)
372         {
373           /* Put the creds in the cache */
374           svn_hash_sets(auth_baton->creds_cache,
375                         apr_pstrdup(auth_baton->pool, state->cache_key),
376                         creds);
377           break;
378         }
379
380       state->got_first = FALSE;
381     }
382
383   *credentials = creds;
384
385   return SVN_NO_ERROR;
386 }
387
388
389 svn_error_t *
390 svn_auth_save_credentials(svn_auth_iterstate_t *state,
391                           apr_pool_t *pool)
392 {
393   int i;
394   svn_auth_provider_object_t *provider;
395   svn_boolean_t save_succeeded = FALSE;
396   const char *no_auth_cache;
397   svn_auth_baton_t *auth_baton;
398   void *creds;
399
400   if (! state || state->table->providers->nelts <= state->provider_idx)
401     return SVN_NO_ERROR;
402
403   auth_baton = state->auth_baton;
404   creds = svn_hash_gets(state->auth_baton->creds_cache, state->cache_key);
405   if (! creds)
406     return SVN_NO_ERROR;
407
408   /* Do not save the creds if SVN_AUTH_PARAM_NO_AUTH_CACHE is set */
409   no_auth_cache = svn_hash_gets(state->parameters,
410                                 SVN_AUTH_PARAM_NO_AUTH_CACHE);
411   if (no_auth_cache)
412     return SVN_NO_ERROR;
413
414   /* First, try to save the creds using the provider that produced them. */
415   provider = APR_ARRAY_IDX(state->table->providers,
416                            state->provider_idx,
417                            svn_auth_provider_object_t *);
418   if (provider->vtable->save_credentials)
419     SVN_ERR(provider->vtable->save_credentials(&save_succeeded,
420                                                creds,
421                                                provider->provider_baton,
422                                                state->parameters,
423                                                state->realmstring,
424                                                pool));
425   if (save_succeeded)
426     return SVN_NO_ERROR;
427
428   /* Otherwise, loop from the top of the list, asking every provider
429      to attempt a save.  ### todo: someday optimize so we don't
430      necessarily start from the top of the list. */
431   for (i = 0; i < state->table->providers->nelts; i++)
432     {
433       provider = APR_ARRAY_IDX(state->table->providers, i,
434                                svn_auth_provider_object_t *);
435       if (provider->vtable->save_credentials)
436         SVN_ERR(provider->vtable->save_credentials(&save_succeeded, creds,
437                                                    provider->provider_baton,
438                                                    state->parameters,
439                                                    state->realmstring,
440                                                    pool));
441
442       if (save_succeeded)
443         break;
444     }
445
446   /* ### notice that at the moment, if no provider can save, there's
447      no way the caller will know. */
448
449   return SVN_NO_ERROR;
450 }
451
452
453 svn_error_t *
454 svn_auth_forget_credentials(svn_auth_baton_t *auth_baton,
455                             const char *cred_kind,
456                             const char *realmstring,
457                             apr_pool_t *scratch_pool)
458 {
459   SVN_ERR_ASSERT((cred_kind && realmstring) || (!cred_kind && !realmstring));
460
461   /* If we have a CRED_KIND and REALMSTRING, we clear out just the
462      cached item (if any).  Otherwise, empty the whole hash. */
463   if (cred_kind)
464     {
465       svn_hash_sets(auth_baton->creds_cache,
466                     make_cache_key(cred_kind, realmstring, scratch_pool),
467                     NULL);
468     }
469   else
470     {
471       apr_hash_clear(auth_baton->creds_cache);
472     }
473
474   return SVN_NO_ERROR;
475 }
476
477
478 svn_auth_ssl_server_cert_info_t *
479 svn_auth_ssl_server_cert_info_dup
480   (const svn_auth_ssl_server_cert_info_t *info, apr_pool_t *pool)
481 {
482   svn_auth_ssl_server_cert_info_t *new_info
483     = apr_palloc(pool, sizeof(*new_info));
484
485   *new_info = *info;
486
487   new_info->hostname = apr_pstrdup(pool, new_info->hostname);
488   new_info->fingerprint = apr_pstrdup(pool, new_info->fingerprint);
489   new_info->valid_from = apr_pstrdup(pool, new_info->valid_from);
490   new_info->valid_until = apr_pstrdup(pool, new_info->valid_until);
491   new_info->issuer_dname = apr_pstrdup(pool, new_info->issuer_dname);
492   new_info->ascii_cert = apr_pstrdup(pool, new_info->ascii_cert);
493
494   return new_info;
495 }
496
497 svn_error_t *
498 svn_auth_get_platform_specific_provider(svn_auth_provider_object_t **provider,
499                                         const char *provider_name,
500                                         const char *provider_type,
501                                         apr_pool_t *pool)
502 {
503   *provider = NULL;
504
505   if (apr_strnatcmp(provider_name, "gnome_keyring") == 0 ||
506       apr_strnatcmp(provider_name, "kwallet") == 0)
507     {
508 #if defined(SVN_HAVE_GNOME_KEYRING) || defined(SVN_HAVE_KWALLET)
509       apr_dso_handle_t *dso;
510       apr_dso_handle_sym_t provider_function_symbol, version_function_symbol;
511       const char *library_label, *library_name;
512       const char *provider_function_name, *version_function_name;
513       library_name = apr_psprintf(pool,
514                                   "libsvn_auth_%s-%d.so.%d",
515                                   provider_name,
516                                   SVN_VER_MAJOR, SVN_SOVERSION);
517       library_label = apr_psprintf(pool, "svn_%s", provider_name);
518       provider_function_name = apr_psprintf(pool,
519                                             "svn_auth_get_%s_%s_provider",
520                                             provider_name, provider_type);
521       version_function_name = apr_psprintf(pool,
522                                            "svn_auth_%s_version",
523                                            provider_name);
524       SVN_ERR(svn_dso_load(&dso, library_name));
525       if (dso)
526         {
527           if (apr_dso_sym(&version_function_symbol,
528                           dso,
529                           version_function_name) == 0)
530             {
531               svn_version_func_t version_function
532                 = version_function_symbol;
533               svn_version_checklist_t check_list[2];
534
535               check_list[0].label = library_label;
536               check_list[0].version_query = version_function;
537               check_list[1].label = NULL;
538               check_list[1].version_query = NULL;
539               SVN_ERR(svn_ver_check_list2(svn_subr_version(), check_list,
540                                           svn_ver_equal));
541             }
542           if (apr_dso_sym(&provider_function_symbol,
543                           dso,
544                           provider_function_name) == 0)
545             {
546               if (strcmp(provider_type, "simple") == 0)
547                 {
548                   svn_auth_simple_provider_func_t provider_function
549                     = provider_function_symbol;
550                   provider_function(provider, pool);
551                 }
552               else if (strcmp(provider_type, "ssl_client_cert_pw") == 0)
553                 {
554                   svn_auth_ssl_client_cert_pw_provider_func_t provider_function
555                     = provider_function_symbol;
556                   provider_function(provider, pool);
557                 }
558             }
559         }
560 #endif
561     }
562   else
563     {
564 #if defined(SVN_HAVE_GPG_AGENT)
565       if (strcmp(provider_name, "gpg_agent") == 0 &&
566           strcmp(provider_type, "simple") == 0)
567         {
568           svn_auth__get_gpg_agent_simple_provider(provider, pool);
569         }
570 #endif
571 #ifdef SVN_HAVE_KEYCHAIN_SERVICES
572       if (strcmp(provider_name, "keychain") == 0 &&
573           strcmp(provider_type, "simple") == 0)
574         {
575           svn_auth__get_keychain_simple_provider(provider, pool);
576         }
577       else if (strcmp(provider_name, "keychain") == 0 &&
578                strcmp(provider_type, "ssl_client_cert_pw") == 0)
579         {
580           svn_auth__get_keychain_ssl_client_cert_pw_provider(provider, pool);
581         }
582 #endif
583
584 #if defined(WIN32) && !defined(__MINGW32__)
585       if (strcmp(provider_name, "windows") == 0 &&
586           strcmp(provider_type, "simple") == 0)
587         {
588           svn_auth__get_windows_simple_provider(provider, pool);
589         }
590       else if (strcmp(provider_name, "windows") == 0 &&
591                strcmp(provider_type, "ssl_client_cert_pw") == 0)
592         {
593           svn_auth__get_windows_ssl_client_cert_pw_provider(provider, pool);
594         }
595       else if (strcmp(provider_name, "windows") == 0 &&
596                strcmp(provider_type, "ssl_server_trust") == 0)
597         {
598           svn_auth__get_windows_ssl_server_trust_provider(provider, pool);
599         }
600       else if (strcmp(provider_name, "windows") == 0 &&
601                strcmp(provider_type, "ssl_server_authority") == 0)
602         {
603           svn_auth__get_windows_ssl_server_authority_provider(provider, pool);
604         }
605 #endif
606     }
607
608   return SVN_NO_ERROR;
609 }
610
611 svn_error_t *
612 svn_auth_get_platform_specific_client_providers(apr_array_header_t **providers,
613                                                 svn_config_t *config,
614                                                 apr_pool_t *pool)
615 {
616   svn_auth_provider_object_t *provider;
617   const char *password_stores_config_option;
618   apr_array_header_t *password_stores;
619   int i;
620
621 #define SVN__MAYBE_ADD_PROVIDER(list, p) \
622   { if (p) APR_ARRAY_PUSH(list, svn_auth_provider_object_t *) = p; }
623
624 #define SVN__DEFAULT_AUTH_PROVIDER_LIST \
625          "gnome-keyring,kwallet,keychain,gpg-agent,windows-cryptoapi"
626
627   *providers = apr_array_make(pool, 12, sizeof(svn_auth_provider_object_t *));
628
629   /* Fetch the configured list of password stores, and split them into
630      an array. */
631   svn_config_get(config,
632                  &password_stores_config_option,
633                  SVN_CONFIG_SECTION_AUTH,
634                  SVN_CONFIG_OPTION_PASSWORD_STORES,
635                  SVN__DEFAULT_AUTH_PROVIDER_LIST);
636   password_stores = svn_cstring_split(password_stores_config_option,
637                                       " ,", TRUE, pool);
638
639   for (i = 0; i < password_stores->nelts; i++)
640     {
641       const char *password_store = APR_ARRAY_IDX(password_stores, i,
642                                                  const char *);
643
644       /* GNOME Keyring */
645       if (apr_strnatcmp(password_store, "gnome-keyring") == 0)
646         {
647           SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
648                                                           "gnome_keyring",
649                                                           "simple",
650                                                           pool));
651           SVN__MAYBE_ADD_PROVIDER(*providers, provider);
652
653           SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
654                                                           "gnome_keyring",
655                                                           "ssl_client_cert_pw",
656                                                           pool));
657           SVN__MAYBE_ADD_PROVIDER(*providers, provider);
658         }
659       /* GPG-AGENT */
660       else if (apr_strnatcmp(password_store, "gpg-agent") == 0)
661         {
662           SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
663                                                           "gpg_agent",
664                                                           "simple",
665                                                           pool));
666           SVN__MAYBE_ADD_PROVIDER(*providers, provider);
667         }
668       /* KWallet */
669       else if (apr_strnatcmp(password_store, "kwallet") == 0)
670         {
671           SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
672                                                           "kwallet",
673                                                           "simple",
674                                                           pool));
675           SVN__MAYBE_ADD_PROVIDER(*providers, provider);
676
677           SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
678                                                           "kwallet",
679                                                           "ssl_client_cert_pw",
680                                                           pool));
681           SVN__MAYBE_ADD_PROVIDER(*providers, provider);
682         }
683       /* Keychain */
684       else if (apr_strnatcmp(password_store, "keychain") == 0)
685         {
686           SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
687                                                           "keychain",
688                                                           "simple",
689                                                           pool));
690           SVN__MAYBE_ADD_PROVIDER(*providers, provider);
691
692           SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
693                                                           "keychain",
694                                                           "ssl_client_cert_pw",
695                                                           pool));
696           SVN__MAYBE_ADD_PROVIDER(*providers, provider);
697         }
698       /* Windows */
699       else if (apr_strnatcmp(password_store, "windows-cryptoapi") == 0)
700         {
701           SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
702                                                           "windows",
703                                                           "simple",
704                                                           pool));
705           SVN__MAYBE_ADD_PROVIDER(*providers, provider);
706
707           SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
708                                                           "windows",
709                                                           "ssl_client_cert_pw",
710                                                           pool));
711           SVN__MAYBE_ADD_PROVIDER(*providers, provider);
712         }
713     }
714
715   /* Windows has two providers without a store to allow easy access to
716      SSL servers. We enable these unconditionally.
717      (This behavior was moved here from svn_cmdline_create_auth_baton()) */
718   SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
719                                                   "windows",
720                                                   "ssl_server_trust",
721                                                   pool));
722   SVN__MAYBE_ADD_PROVIDER(*providers, provider);
723
724   /* The windows ssl authority certificate CRYPTOAPI provider. */
725   SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
726                                                   "windows",
727                                                   "ssl_server_authority",
728                                                   pool));
729
730   SVN__MAYBE_ADD_PROVIDER(*providers, provider);
731
732   return SVN_NO_ERROR;
733 }
734
735 svn_error_t *
736 svn_auth__make_session_auth(svn_auth_baton_t **session_auth_baton,
737                             const svn_auth_baton_t *auth_baton,
738                             apr_hash_t *config,
739                             const char *server_name,
740                             apr_pool_t *result_pool,
741                             apr_pool_t *scratch_pool)
742 {
743   svn_boolean_t store_passwords = SVN_CONFIG_DEFAULT_OPTION_STORE_PASSWORDS;
744   svn_boolean_t store_auth_creds = SVN_CONFIG_DEFAULT_OPTION_STORE_AUTH_CREDS;
745   const char *store_plaintext_passwords
746     = SVN_CONFIG_DEFAULT_OPTION_STORE_PLAINTEXT_PASSWORDS;
747   svn_boolean_t store_pp = SVN_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP;
748   const char *store_pp_plaintext
749     = SVN_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT;
750   svn_config_t *servers = NULL;
751   const char *server_group = NULL;
752
753   struct svn_auth_baton_t *ab;
754
755   ab = apr_pmemdup(result_pool, auth_baton, sizeof(*ab));
756
757   ab->slave_parameters = apr_hash_make(result_pool);
758
759   /* The 'store-passwords' and 'store-auth-creds' parameters used to
760   * live in SVN_CONFIG_CATEGORY_CONFIG. For backward compatibility,
761   * if values for these parameters have already been set by our
762   * callers, we use those values as defaults.
763   *
764   * Note that we can only catch the case where users explicitly set
765   * "store-passwords = no" or 'store-auth-creds = no".
766   *
767   * However, since the default value for both these options is
768   * currently (and has always been) "yes", users won't know
769   * the difference if they set "store-passwords = yes" or
770   * "store-auth-creds = yes" -- they'll get the expected behaviour.
771   */
772
773   if (svn_auth_get_parameter(ab,
774                               SVN_AUTH_PARAM_DONT_STORE_PASSWORDS) != NULL)
775     store_passwords = FALSE;
776
777   if (svn_auth_get_parameter(ab,
778                               SVN_AUTH_PARAM_NO_AUTH_CACHE) != NULL)
779     store_auth_creds = FALSE;
780
781   /* All the svn_auth_set_parameter() calls below this not only affect the
782      to be created ra session, but also all the ra sessions that are already
783      use this auth baton!
784
785      Please try to key things based on the realm string instead of this
786      construct.
787  */
788
789   if (config)
790     {
791       /* Grab the 'servers' config. */
792       servers = svn_hash_gets(config, SVN_CONFIG_CATEGORY_SERVERS);
793       if (servers)
794         {
795           /* First, look in the global section. */
796
797           SVN_ERR(svn_config_get_bool
798             (servers, &store_passwords, SVN_CONFIG_SECTION_GLOBAL,
799              SVN_CONFIG_OPTION_STORE_PASSWORDS,
800              store_passwords));
801
802           SVN_ERR(svn_config_get_yes_no_ask
803             (servers, &store_plaintext_passwords, SVN_CONFIG_SECTION_GLOBAL,
804              SVN_CONFIG_OPTION_STORE_PLAINTEXT_PASSWORDS,
805              SVN_CONFIG_DEFAULT_OPTION_STORE_PLAINTEXT_PASSWORDS));
806
807           SVN_ERR(svn_config_get_bool
808             (servers, &store_pp, SVN_CONFIG_SECTION_GLOBAL,
809              SVN_CONFIG_OPTION_STORE_SSL_CLIENT_CERT_PP,
810              store_pp));
811
812           SVN_ERR(svn_config_get_yes_no_ask
813             (servers, &store_pp_plaintext,
814              SVN_CONFIG_SECTION_GLOBAL,
815              SVN_CONFIG_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT,
816              SVN_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT));
817
818           SVN_ERR(svn_config_get_bool
819             (servers, &store_auth_creds, SVN_CONFIG_SECTION_GLOBAL,
820               SVN_CONFIG_OPTION_STORE_AUTH_CREDS,
821               store_auth_creds));
822
823           /* Find out where we're about to connect to, and
824            * try to pick a server group based on the destination. */
825           server_group = svn_config_find_group(servers, server_name,
826                                                SVN_CONFIG_SECTION_GROUPS,
827                                                scratch_pool);
828
829           if (server_group)
830             {
831               /* Override global auth caching parameters with the ones
832                * for the server group, if any. */
833               SVN_ERR(svn_config_get_bool(servers, &store_auth_creds,
834                                           server_group,
835                                           SVN_CONFIG_OPTION_STORE_AUTH_CREDS,
836                                           store_auth_creds));
837
838               SVN_ERR(svn_config_get_bool(servers, &store_passwords,
839                                           server_group,
840                                           SVN_CONFIG_OPTION_STORE_PASSWORDS,
841                                           store_passwords));
842
843               SVN_ERR(svn_config_get_yes_no_ask
844                 (servers, &store_plaintext_passwords, server_group,
845                  SVN_CONFIG_OPTION_STORE_PLAINTEXT_PASSWORDS,
846                  store_plaintext_passwords));
847
848               SVN_ERR(svn_config_get_bool
849                 (servers, &store_pp,
850                  server_group, SVN_CONFIG_OPTION_STORE_SSL_CLIENT_CERT_PP,
851                  store_pp));
852
853               SVN_ERR(svn_config_get_yes_no_ask
854                 (servers, &store_pp_plaintext, server_group,
855                  SVN_CONFIG_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT,
856                  store_pp_plaintext));
857             }
858         }
859     }
860
861   /* Save auth caching parameters in the auth parameter hash. */
862   if (! store_passwords)
863     svn_auth_set_parameter(ab,
864                            SVN_AUTH_PARAM_DONT_STORE_PASSWORDS, "");
865
866   svn_auth_set_parameter(ab,
867                          SVN_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS,
868                          store_plaintext_passwords);
869
870   if (! store_pp)
871     svn_auth_set_parameter(ab,
872                            SVN_AUTH_PARAM_DONT_STORE_SSL_CLIENT_CERT_PP,
873                            "");
874
875   svn_auth_set_parameter(ab,
876                          SVN_AUTH_PARAM_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT,
877                          store_pp_plaintext);
878
879   if (! store_auth_creds)
880     svn_auth_set_parameter(ab,
881                            SVN_AUTH_PARAM_NO_AUTH_CACHE, "");
882
883   if (server_group)
884     svn_auth_set_parameter(ab,
885                            SVN_AUTH_PARAM_SERVER_GROUP,
886                            apr_pstrdup(ab->pool, server_group));
887
888   *session_auth_baton = ab;
889
890   return SVN_NO_ERROR;
891 }
892
893
894 static svn_error_t *
895 dummy_first_creds(void **credentials,
896                   void **iter_baton,
897                   void *provider_baton,
898                   apr_hash_t *parameters,
899                   const char *realmstring,
900                   apr_pool_t *pool)
901 {
902   *credentials = NULL;
903   *iter_baton = NULL;
904   return SVN_NO_ERROR;
905 }
906
907 void
908 svn_auth__get_dummmy_simple_provider(svn_auth_provider_object_t **provider,
909                                      apr_pool_t *pool)
910 {
911   static const svn_auth_provider_t vtable = {
912     SVN_AUTH_CRED_SIMPLE,
913     dummy_first_creds,
914     NULL, NULL
915   };
916
917   svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
918
919   po->vtable = &vtable;
920   *provider = po;
921 }