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