auth.c revision 302408
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. */
93typedef 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. */
102struct 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 */
119struct 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
133void
134svn_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 */
176static const void *auth_NULL = NULL;
177
178void
179svn_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
197const void *
198svn_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. */
219static const char *
220make_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
227svn_error_t *
228svn_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
335svn_error_t *
336svn_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
389svn_error_t *
390svn_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
453svn_error_t *
454svn_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
478svn_auth_ssl_server_cert_info_t *
479svn_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
497svn_error_t *
498svn_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
611svn_error_t *
612svn_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
735svn_error_t *
736svn_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
894static svn_error_t *
895dummy_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
907void
908svn_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}
922