xref: /NextBSD/contrib/subversion/subversion/libsvn_subr/auth.c (revision 84d351007654069f9643c8e4b4802a7f5f08ee42)
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
svn_auth_open(svn_auth_baton_t ** auth_baton,const apr_array_header_t * providers,apr_pool_t * pool)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
svn_auth_set_parameter(svn_auth_baton_t * auth_baton,const char * name,const void * value)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 *
svn_auth_get_parameter(svn_auth_baton_t * auth_baton,const char * name)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 *
make_cache_key(const char * cred_kind,const char * realmstring,apr_pool_t * pool)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 *
svn_auth_first_credentials(void ** credentials,svn_auth_iterstate_t ** state,const char * cred_kind,const char * realmstring,svn_auth_baton_t * auth_baton,apr_pool_t * pool)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 *
svn_auth_next_credentials(void ** credentials,svn_auth_iterstate_t * state,apr_pool_t * pool)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, state->cache_key, creds);
375           break;
376         }
377 
378       state->got_first = FALSE;
379     }
380 
381   *credentials = creds;
382 
383   return SVN_NO_ERROR;
384 }
385 
386 
387 svn_error_t *
svn_auth_save_credentials(svn_auth_iterstate_t * state,apr_pool_t * pool)388 svn_auth_save_credentials(svn_auth_iterstate_t *state,
389                           apr_pool_t *pool)
390 {
391   int i;
392   svn_auth_provider_object_t *provider;
393   svn_boolean_t save_succeeded = FALSE;
394   const char *no_auth_cache;
395   svn_auth_baton_t *auth_baton;
396   void *creds;
397 
398   if (! state || state->table->providers->nelts <= state->provider_idx)
399     return SVN_NO_ERROR;
400 
401   auth_baton = state->auth_baton;
402   creds = svn_hash_gets(state->auth_baton->creds_cache, state->cache_key);
403   if (! creds)
404     return SVN_NO_ERROR;
405 
406   /* Do not save the creds if SVN_AUTH_PARAM_NO_AUTH_CACHE is set */
407   no_auth_cache = svn_hash_gets(state->parameters,
408                                 SVN_AUTH_PARAM_NO_AUTH_CACHE);
409   if (no_auth_cache)
410     return SVN_NO_ERROR;
411 
412   /* First, try to save the creds using the provider that produced them. */
413   provider = APR_ARRAY_IDX(state->table->providers,
414                            state->provider_idx,
415                            svn_auth_provider_object_t *);
416   if (provider->vtable->save_credentials)
417     SVN_ERR(provider->vtable->save_credentials(&save_succeeded,
418                                                creds,
419                                                provider->provider_baton,
420                                                state->parameters,
421                                                state->realmstring,
422                                                pool));
423   if (save_succeeded)
424     return SVN_NO_ERROR;
425 
426   /* Otherwise, loop from the top of the list, asking every provider
427      to attempt a save.  ### todo: someday optimize so we don't
428      necessarily start from the top of the list. */
429   for (i = 0; i < state->table->providers->nelts; i++)
430     {
431       provider = APR_ARRAY_IDX(state->table->providers, i,
432                                svn_auth_provider_object_t *);
433       if (provider->vtable->save_credentials)
434         SVN_ERR(provider->vtable->save_credentials(&save_succeeded, creds,
435                                                    provider->provider_baton,
436                                                    state->parameters,
437                                                    state->realmstring,
438                                                    pool));
439 
440       if (save_succeeded)
441         break;
442     }
443 
444   /* ### notice that at the moment, if no provider can save, there's
445      no way the caller will know. */
446 
447   return SVN_NO_ERROR;
448 }
449 
450 
451 svn_error_t *
svn_auth_forget_credentials(svn_auth_baton_t * auth_baton,const char * cred_kind,const char * realmstring,apr_pool_t * scratch_pool)452 svn_auth_forget_credentials(svn_auth_baton_t *auth_baton,
453                             const char *cred_kind,
454                             const char *realmstring,
455                             apr_pool_t *scratch_pool)
456 {
457   SVN_ERR_ASSERT((cred_kind && realmstring) || (!cred_kind && !realmstring));
458 
459   /* If we have a CRED_KIND and REALMSTRING, we clear out just the
460      cached item (if any).  Otherwise, empty the whole hash. */
461   if (cred_kind)
462     {
463       svn_hash_sets(auth_baton->creds_cache,
464                     make_cache_key(cred_kind, realmstring, scratch_pool),
465                     NULL);
466     }
467   else
468     {
469       apr_hash_clear(auth_baton->creds_cache);
470     }
471 
472   return SVN_NO_ERROR;
473 }
474 
475 
476 svn_auth_ssl_server_cert_info_t *
svn_auth_ssl_server_cert_info_dup(const svn_auth_ssl_server_cert_info_t * info,apr_pool_t * pool)477 svn_auth_ssl_server_cert_info_dup
478   (const svn_auth_ssl_server_cert_info_t *info, apr_pool_t *pool)
479 {
480   svn_auth_ssl_server_cert_info_t *new_info
481     = apr_palloc(pool, sizeof(*new_info));
482 
483   *new_info = *info;
484 
485   new_info->hostname = apr_pstrdup(pool, new_info->hostname);
486   new_info->fingerprint = apr_pstrdup(pool, new_info->fingerprint);
487   new_info->valid_from = apr_pstrdup(pool, new_info->valid_from);
488   new_info->valid_until = apr_pstrdup(pool, new_info->valid_until);
489   new_info->issuer_dname = apr_pstrdup(pool, new_info->issuer_dname);
490   new_info->ascii_cert = apr_pstrdup(pool, new_info->ascii_cert);
491 
492   return new_info;
493 }
494 
495 svn_error_t *
svn_auth_get_platform_specific_provider(svn_auth_provider_object_t ** provider,const char * provider_name,const char * provider_type,apr_pool_t * pool)496 svn_auth_get_platform_specific_provider(svn_auth_provider_object_t **provider,
497                                         const char *provider_name,
498                                         const char *provider_type,
499                                         apr_pool_t *pool)
500 {
501   *provider = NULL;
502 
503   if (apr_strnatcmp(provider_name, "gnome_keyring") == 0 ||
504       apr_strnatcmp(provider_name, "kwallet") == 0)
505     {
506 #if defined(SVN_HAVE_GNOME_KEYRING) || defined(SVN_HAVE_KWALLET)
507       apr_dso_handle_t *dso;
508       apr_dso_handle_sym_t provider_function_symbol, version_function_symbol;
509       const char *library_label, *library_name;
510       const char *provider_function_name, *version_function_name;
511       library_name = apr_psprintf(pool,
512                                   "libsvn_auth_%s-%d.so.%d",
513                                   provider_name,
514                                   SVN_VER_MAJOR, SVN_SOVERSION);
515       library_label = apr_psprintf(pool, "svn_%s", provider_name);
516       provider_function_name = apr_psprintf(pool,
517                                             "svn_auth_get_%s_%s_provider",
518                                             provider_name, provider_type);
519       version_function_name = apr_psprintf(pool,
520                                            "svn_auth_%s_version",
521                                            provider_name);
522       SVN_ERR(svn_dso_load(&dso, library_name));
523       if (dso)
524         {
525           if (apr_dso_sym(&version_function_symbol,
526                           dso,
527                           version_function_name) == 0)
528             {
529               svn_version_func_t version_function
530                 = version_function_symbol;
531               svn_version_checklist_t check_list[2];
532 
533               check_list[0].label = library_label;
534               check_list[0].version_query = version_function;
535               check_list[1].label = NULL;
536               check_list[1].version_query = NULL;
537               SVN_ERR(svn_ver_check_list2(svn_subr_version(), check_list,
538                                           svn_ver_equal));
539             }
540           if (apr_dso_sym(&provider_function_symbol,
541                           dso,
542                           provider_function_name) == 0)
543             {
544               if (strcmp(provider_type, "simple") == 0)
545                 {
546                   svn_auth_simple_provider_func_t provider_function
547                     = provider_function_symbol;
548                   provider_function(provider, pool);
549                 }
550               else if (strcmp(provider_type, "ssl_client_cert_pw") == 0)
551                 {
552                   svn_auth_ssl_client_cert_pw_provider_func_t provider_function
553                     = provider_function_symbol;
554                   provider_function(provider, pool);
555                 }
556             }
557         }
558 #endif
559     }
560   else
561     {
562 #if defined(SVN_HAVE_GPG_AGENT)
563       if (strcmp(provider_name, "gpg_agent") == 0 &&
564           strcmp(provider_type, "simple") == 0)
565         {
566           svn_auth__get_gpg_agent_simple_provider(provider, pool);
567         }
568 #endif
569 #ifdef SVN_HAVE_KEYCHAIN_SERVICES
570       if (strcmp(provider_name, "keychain") == 0 &&
571           strcmp(provider_type, "simple") == 0)
572         {
573           svn_auth__get_keychain_simple_provider(provider, pool);
574         }
575       else if (strcmp(provider_name, "keychain") == 0 &&
576                strcmp(provider_type, "ssl_client_cert_pw") == 0)
577         {
578           svn_auth__get_keychain_ssl_client_cert_pw_provider(provider, pool);
579         }
580 #endif
581 
582 #if defined(WIN32) && !defined(__MINGW32__)
583       if (strcmp(provider_name, "windows") == 0 &&
584           strcmp(provider_type, "simple") == 0)
585         {
586           svn_auth__get_windows_simple_provider(provider, pool);
587         }
588       else if (strcmp(provider_name, "windows") == 0 &&
589                strcmp(provider_type, "ssl_client_cert_pw") == 0)
590         {
591           svn_auth__get_windows_ssl_client_cert_pw_provider(provider, pool);
592         }
593       else if (strcmp(provider_name, "windows") == 0 &&
594                strcmp(provider_type, "ssl_server_trust") == 0)
595         {
596           svn_auth__get_windows_ssl_server_trust_provider(provider, pool);
597         }
598       else if (strcmp(provider_name, "windows") == 0 &&
599                strcmp(provider_type, "ssl_server_authority") == 0)
600         {
601           svn_auth__get_windows_ssl_server_authority_provider(provider, pool);
602         }
603 #endif
604     }
605 
606   return SVN_NO_ERROR;
607 }
608 
609 svn_error_t *
svn_auth_get_platform_specific_client_providers(apr_array_header_t ** providers,svn_config_t * config,apr_pool_t * pool)610 svn_auth_get_platform_specific_client_providers(apr_array_header_t **providers,
611                                                 svn_config_t *config,
612                                                 apr_pool_t *pool)
613 {
614   svn_auth_provider_object_t *provider;
615   const char *password_stores_config_option;
616   apr_array_header_t *password_stores;
617   int i;
618 
619 #define SVN__MAYBE_ADD_PROVIDER(list, p) \
620   { if (p) APR_ARRAY_PUSH(list, svn_auth_provider_object_t *) = p; }
621 
622 #define SVN__DEFAULT_AUTH_PROVIDER_LIST \
623          "gnome-keyring,kwallet,keychain,gpg-agent,windows-cryptoapi"
624 
625   *providers = apr_array_make(pool, 12, sizeof(svn_auth_provider_object_t *));
626 
627   /* Fetch the configured list of password stores, and split them into
628      an array. */
629   svn_config_get(config,
630                  &password_stores_config_option,
631                  SVN_CONFIG_SECTION_AUTH,
632                  SVN_CONFIG_OPTION_PASSWORD_STORES,
633                  SVN__DEFAULT_AUTH_PROVIDER_LIST);
634   password_stores = svn_cstring_split(password_stores_config_option,
635                                       " ,", TRUE, pool);
636 
637   for (i = 0; i < password_stores->nelts; i++)
638     {
639       const char *password_store = APR_ARRAY_IDX(password_stores, i,
640                                                  const char *);
641 
642       /* GNOME Keyring */
643       if (apr_strnatcmp(password_store, "gnome-keyring") == 0)
644         {
645           SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
646                                                           "gnome_keyring",
647                                                           "simple",
648                                                           pool));
649           SVN__MAYBE_ADD_PROVIDER(*providers, provider);
650 
651           SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
652                                                           "gnome_keyring",
653                                                           "ssl_client_cert_pw",
654                                                           pool));
655           SVN__MAYBE_ADD_PROVIDER(*providers, provider);
656         }
657       /* GPG-AGENT */
658       else if (apr_strnatcmp(password_store, "gpg-agent") == 0)
659         {
660           SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
661                                                           "gpg_agent",
662                                                           "simple",
663                                                           pool));
664           SVN__MAYBE_ADD_PROVIDER(*providers, provider);
665         }
666       /* KWallet */
667       else if (apr_strnatcmp(password_store, "kwallet") == 0)
668         {
669           SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
670                                                           "kwallet",
671                                                           "simple",
672                                                           pool));
673           SVN__MAYBE_ADD_PROVIDER(*providers, provider);
674 
675           SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
676                                                           "kwallet",
677                                                           "ssl_client_cert_pw",
678                                                           pool));
679           SVN__MAYBE_ADD_PROVIDER(*providers, provider);
680         }
681       /* Keychain */
682       else if (apr_strnatcmp(password_store, "keychain") == 0)
683         {
684           SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
685                                                           "keychain",
686                                                           "simple",
687                                                           pool));
688           SVN__MAYBE_ADD_PROVIDER(*providers, provider);
689 
690           SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
691                                                           "keychain",
692                                                           "ssl_client_cert_pw",
693                                                           pool));
694           SVN__MAYBE_ADD_PROVIDER(*providers, provider);
695         }
696       /* Windows */
697       else if (apr_strnatcmp(password_store, "windows-cryptoapi") == 0)
698         {
699           SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
700                                                           "windows",
701                                                           "simple",
702                                                           pool));
703           SVN__MAYBE_ADD_PROVIDER(*providers, provider);
704 
705           SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
706                                                           "windows",
707                                                           "ssl_client_cert_pw",
708                                                           pool));
709           SVN__MAYBE_ADD_PROVIDER(*providers, provider);
710         }
711     }
712 
713   /* Windows has two providers without a store to allow easy access to
714      SSL servers. We enable these unconditionally.
715      (This behavior was moved here from svn_cmdline_create_auth_baton()) */
716   SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
717                                                   "windows",
718                                                   "ssl_server_trust",
719                                                   pool));
720   SVN__MAYBE_ADD_PROVIDER(*providers, provider);
721 
722   /* The windows ssl authority certificate CRYPTOAPI provider. */
723   SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
724                                                   "windows",
725                                                   "ssl_server_authority",
726                                                   pool));
727 
728   SVN__MAYBE_ADD_PROVIDER(*providers, provider);
729 
730   return SVN_NO_ERROR;
731 }
732 
733 svn_error_t *
svn_auth__make_session_auth(svn_auth_baton_t ** session_auth_baton,const svn_auth_baton_t * auth_baton,apr_hash_t * config,const char * server_name,apr_pool_t * result_pool,apr_pool_t * scratch_pool)734 svn_auth__make_session_auth(svn_auth_baton_t **session_auth_baton,
735                             const svn_auth_baton_t *auth_baton,
736                             apr_hash_t *config,
737                             const char *server_name,
738                             apr_pool_t *result_pool,
739                             apr_pool_t *scratch_pool)
740 {
741   svn_boolean_t store_passwords = SVN_CONFIG_DEFAULT_OPTION_STORE_PASSWORDS;
742   svn_boolean_t store_auth_creds = SVN_CONFIG_DEFAULT_OPTION_STORE_AUTH_CREDS;
743   const char *store_plaintext_passwords
744     = SVN_CONFIG_DEFAULT_OPTION_STORE_PLAINTEXT_PASSWORDS;
745   svn_boolean_t store_pp = SVN_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP;
746   const char *store_pp_plaintext
747     = SVN_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT;
748   svn_config_t *servers = NULL;
749   const char *server_group = NULL;
750 
751   struct svn_auth_baton_t *ab;
752 
753   ab = apr_pmemdup(result_pool, auth_baton, sizeof(*ab));
754 
755   ab->slave_parameters = apr_hash_make(result_pool);
756 
757   /* The 'store-passwords' and 'store-auth-creds' parameters used to
758   * live in SVN_CONFIG_CATEGORY_CONFIG. For backward compatibility,
759   * if values for these parameters have already been set by our
760   * callers, we use those values as defaults.
761   *
762   * Note that we can only catch the case where users explicitly set
763   * "store-passwords = no" or 'store-auth-creds = no".
764   *
765   * However, since the default value for both these options is
766   * currently (and has always been) "yes", users won't know
767   * the difference if they set "store-passwords = yes" or
768   * "store-auth-creds = yes" -- they'll get the expected behaviour.
769   */
770 
771   if (svn_auth_get_parameter(ab,
772                               SVN_AUTH_PARAM_DONT_STORE_PASSWORDS) != NULL)
773     store_passwords = FALSE;
774 
775   if (svn_auth_get_parameter(ab,
776                               SVN_AUTH_PARAM_NO_AUTH_CACHE) != NULL)
777     store_auth_creds = FALSE;
778 
779   /* All the svn_auth_set_parameter() calls below this not only affect the
780      to be created ra session, but also all the ra sessions that are already
781      use this auth baton!
782 
783      Please try to key things based on the realm string instead of this
784      construct.
785  */
786 
787   if (config)
788     {
789       /* Grab the 'servers' config. */
790       servers = svn_hash_gets(config, SVN_CONFIG_CATEGORY_SERVERS);
791       if (servers)
792         {
793           /* First, look in the global section. */
794 
795           SVN_ERR(svn_config_get_bool
796             (servers, &store_passwords, SVN_CONFIG_SECTION_GLOBAL,
797              SVN_CONFIG_OPTION_STORE_PASSWORDS,
798              store_passwords));
799 
800           SVN_ERR(svn_config_get_yes_no_ask
801             (servers, &store_plaintext_passwords, SVN_CONFIG_SECTION_GLOBAL,
802              SVN_CONFIG_OPTION_STORE_PLAINTEXT_PASSWORDS,
803              SVN_CONFIG_DEFAULT_OPTION_STORE_PLAINTEXT_PASSWORDS));
804 
805           SVN_ERR(svn_config_get_bool
806             (servers, &store_pp, SVN_CONFIG_SECTION_GLOBAL,
807              SVN_CONFIG_OPTION_STORE_SSL_CLIENT_CERT_PP,
808              store_pp));
809 
810           SVN_ERR(svn_config_get_yes_no_ask
811             (servers, &store_pp_plaintext,
812              SVN_CONFIG_SECTION_GLOBAL,
813              SVN_CONFIG_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT,
814              SVN_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT));
815 
816           SVN_ERR(svn_config_get_bool
817             (servers, &store_auth_creds, SVN_CONFIG_SECTION_GLOBAL,
818               SVN_CONFIG_OPTION_STORE_AUTH_CREDS,
819               store_auth_creds));
820 
821           /* Find out where we're about to connect to, and
822            * try to pick a server group based on the destination. */
823           server_group = svn_config_find_group(servers, server_name,
824                                                SVN_CONFIG_SECTION_GROUPS,
825                                                scratch_pool);
826 
827           if (server_group)
828             {
829               /* Override global auth caching parameters with the ones
830                * for the server group, if any. */
831               SVN_ERR(svn_config_get_bool(servers, &store_auth_creds,
832                                           server_group,
833                                           SVN_CONFIG_OPTION_STORE_AUTH_CREDS,
834                                           store_auth_creds));
835 
836               SVN_ERR(svn_config_get_bool(servers, &store_passwords,
837                                           server_group,
838                                           SVN_CONFIG_OPTION_STORE_PASSWORDS,
839                                           store_passwords));
840 
841               SVN_ERR(svn_config_get_yes_no_ask
842                 (servers, &store_plaintext_passwords, server_group,
843                  SVN_CONFIG_OPTION_STORE_PLAINTEXT_PASSWORDS,
844                  store_plaintext_passwords));
845 
846               SVN_ERR(svn_config_get_bool
847                 (servers, &store_pp,
848                  server_group, SVN_CONFIG_OPTION_STORE_SSL_CLIENT_CERT_PP,
849                  store_pp));
850 
851               SVN_ERR(svn_config_get_yes_no_ask
852                 (servers, &store_pp_plaintext, server_group,
853                  SVN_CONFIG_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT,
854                  store_pp_plaintext));
855             }
856         }
857     }
858 
859   /* Save auth caching parameters in the auth parameter hash. */
860   if (! store_passwords)
861     svn_auth_set_parameter(ab,
862                            SVN_AUTH_PARAM_DONT_STORE_PASSWORDS, "");
863 
864   svn_auth_set_parameter(ab,
865                          SVN_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS,
866                          store_plaintext_passwords);
867 
868   if (! store_pp)
869     svn_auth_set_parameter(ab,
870                            SVN_AUTH_PARAM_DONT_STORE_SSL_CLIENT_CERT_PP,
871                            "");
872 
873   svn_auth_set_parameter(ab,
874                          SVN_AUTH_PARAM_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT,
875                          store_pp_plaintext);
876 
877   if (! store_auth_creds)
878     svn_auth_set_parameter(ab,
879                            SVN_AUTH_PARAM_NO_AUTH_CACHE, "");
880 
881   if (server_group)
882     svn_auth_set_parameter(ab,
883                            SVN_AUTH_PARAM_SERVER_GROUP,
884                            apr_pstrdup(ab->pool, server_group));
885 
886   *session_auth_baton = ab;
887 
888   return SVN_NO_ERROR;
889 }
890 
891 
892 static svn_error_t *
dummy_first_creds(void ** credentials,void ** iter_baton,void * provider_baton,apr_hash_t * parameters,const char * realmstring,apr_pool_t * pool)893 dummy_first_creds(void **credentials,
894                   void **iter_baton,
895                   void *provider_baton,
896                   apr_hash_t *parameters,
897                   const char *realmstring,
898                   apr_pool_t *pool)
899 {
900   *credentials = NULL;
901   *iter_baton = NULL;
902   return SVN_NO_ERROR;
903 }
904 
905 void
svn_auth__get_dummmy_simple_provider(svn_auth_provider_object_t ** provider,apr_pool_t * pool)906 svn_auth__get_dummmy_simple_provider(svn_auth_provider_object_t **provider,
907                                      apr_pool_t *pool)
908 {
909   static const svn_auth_provider_t vtable = {
910     SVN_AUTH_CRED_SIMPLE,
911     dummy_first_creds,
912     NULL, NULL
913   };
914 
915   svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
916 
917   po->vtable = &vtable;
918   *provider = po;
919 }
920