1251881Speter/*
2251881Speter * auth.c: authentication support functions for Subversion
3251881Speter *
4251881Speter * ====================================================================
5251881Speter *    Licensed to the Apache Software Foundation (ASF) under one
6251881Speter *    or more contributor license agreements.  See the NOTICE file
7251881Speter *    distributed with this work for additional information
8251881Speter *    regarding copyright ownership.  The ASF licenses this file
9251881Speter *    to you under the Apache License, Version 2.0 (the
10251881Speter *    "License"); you may not use this file except in compliance
11251881Speter *    with the License.  You may obtain a copy of the License at
12251881Speter *
13251881Speter *      http://www.apache.org/licenses/LICENSE-2.0
14251881Speter *
15251881Speter *    Unless required by applicable law or agreed to in writing,
16251881Speter *    software distributed under the License is distributed on an
17251881Speter *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18251881Speter *    KIND, either express or implied.  See the License for the
19251881Speter *    specific language governing permissions and limitations
20251881Speter *    under the License.
21251881Speter * ====================================================================
22251881Speter */
23251881Speter
24251881Speter
25251881Speter#include <apr_pools.h>
26251881Speter#include <apr_tables.h>
27251881Speter#include <apr_strings.h>
28251881Speter
29251881Speter#include "svn_hash.h"
30251881Speter#include "svn_types.h"
31251881Speter#include "svn_string.h"
32251881Speter#include "svn_error.h"
33251881Speter#include "svn_auth.h"
34251881Speter#include "svn_config.h"
35251881Speter#include "svn_private_config.h"
36251881Speter#include "svn_dso.h"
37251881Speter#include "svn_version.h"
38262250Speter#include "private/svn_auth_private.h"
39251881Speter#include "private/svn_dep_compat.h"
40251881Speter
41251881Speter#include "auth.h"
42251881Speter
43251881Speter/* AN OVERVIEW
44251881Speter   ===========
45251881Speter
46251881Speter   A good way to think of this machinery is as a set of tables.
47251881Speter
48251881Speter     - Each type of credentials selects a single table.
49251881Speter
50251881Speter     - In a given table, each row is a 'provider' capable of returning
51251881Speter       the same type of credentials.  Each column represents a
52251881Speter       provider's repeated attempts to provide credentials.
53251881Speter
54251881Speter
55251881Speter   Fetching Credentials from Providers
56251881Speter   -----------------------------------
57251881Speter
58251881Speter   When the caller asks for a particular type of credentials, the
59251881Speter   machinery in this file walks over the appropriate table.  It starts
60251881Speter   with the first provider (first row), and calls first_credentials()
61251881Speter   to get the first set of credentials (first column).  If the caller
62251881Speter   is unhappy with the credentials, then each subsequent call to
63251881Speter   next_credentials() traverses the row from left to right.  If the
64251881Speter   provider returns error at any point, then we go to the next provider
65251881Speter   (row).  We continue this way until every provider fails, or
66251881Speter   until the client is happy with the returned credentials.
67251881Speter
68251881Speter   Note that the caller cannot see the table traversal, and thus has
69251881Speter   no idea when we switch providers.
70251881Speter
71251881Speter
72251881Speter   Storing Credentials with Providers
73251881Speter   ----------------------------------
74251881Speter
75251881Speter   When the server has validated a set of credentials, and when
76251881Speter   credential caching is enabled, we have the chance to store those
77251881Speter   credentials for later use.  The provider which provided the working
78251881Speter   credentials is the first one given the opportunity to (re)cache
79251881Speter   those credentials.  Its save_credentials() function is invoked with
80251881Speter   the working credentials.  If that provider reports that it
81251881Speter   successfully stored the credentials, we're done.  Otherwise, we
82251881Speter   walk the providers (rows) for that type of credentials in order
83251881Speter   from the top of the table, allowing each in turn the opportunity to
84251881Speter   store the credentials.  When one reports that it has done so
85251881Speter   successfully -- or when we run out of providers (rows) to try --
86251881Speter   the table walk ends.
87251881Speter*/
88251881Speter
89251881Speter
90251881Speter
91251881Speter/* This effectively defines a single table.  Every provider in this
92251881Speter   array returns the same kind of credentials. */
93251881Spetertypedef struct provider_set_t
94251881Speter{
95251881Speter  /* ordered array of svn_auth_provider_object_t */
96251881Speter  apr_array_header_t *providers;
97251881Speter
98251881Speter} provider_set_t;
99251881Speter
100251881Speter
101251881Speter/* The main auth baton. */
102251881Speterstruct svn_auth_baton_t
103251881Speter{
104251881Speter  /* a collection of tables.  maps cred_kind -> provider_set */
105251881Speter  apr_hash_t *tables;
106251881Speter
107251881Speter  /* the pool I'm allocated in. */
108251881Speter  apr_pool_t *pool;
109251881Speter
110251881Speter  /* run-time parameters needed by providers. */
111251881Speter  apr_hash_t *parameters;
112289180Speter  apr_hash_t *slave_parameters;
113251881Speter
114251881Speter  /* run-time credentials cache. */
115251881Speter  apr_hash_t *creds_cache;
116251881Speter};
117251881Speter
118251881Speter/* Abstracted iteration baton */
119251881Speterstruct svn_auth_iterstate_t
120251881Speter{
121251881Speter  provider_set_t *table;        /* the table being searched */
122251881Speter  int provider_idx;             /* the current provider (row) */
123251881Speter  svn_boolean_t got_first;      /* did we get the provider's first creds? */
124251881Speter  void *provider_iter_baton;    /* the provider's own iteration context */
125251881Speter  const char *realmstring;      /* The original realmstring passed in */
126251881Speter  const char *cache_key;        /* key to use in auth_baton's creds_cache */
127251881Speter  svn_auth_baton_t *auth_baton; /* the original auth_baton. */
128289180Speter  apr_hash_t *parameters;
129251881Speter};
130251881Speter
131251881Speter
132251881Speter
133251881Spetervoid
134251881Spetersvn_auth_open(svn_auth_baton_t **auth_baton,
135251881Speter              const apr_array_header_t *providers,
136251881Speter              apr_pool_t *pool)
137251881Speter{
138251881Speter  svn_auth_baton_t *ab;
139251881Speter  svn_auth_provider_object_t *provider;
140251881Speter  int i;
141251881Speter
142251881Speter  /* Build the auth_baton. */
143251881Speter  ab = apr_pcalloc(pool, sizeof(*ab));
144251881Speter  ab->tables = apr_hash_make(pool);
145251881Speter  ab->parameters = apr_hash_make(pool);
146289180Speter  /* ab->slave_parameters = NULL; */
147251881Speter  ab->creds_cache = apr_hash_make(pool);
148251881Speter  ab->pool = pool;
149251881Speter
150251881Speter  /* Register each provider in order.  Providers of different
151251881Speter     credentials will be automatically sorted into different tables by
152251881Speter     register_provider(). */
153251881Speter  for (i = 0; i < providers->nelts; i++)
154251881Speter    {
155251881Speter      provider_set_t *table;
156251881Speter      provider = APR_ARRAY_IDX(providers, i, svn_auth_provider_object_t *);
157251881Speter
158251881Speter      /* Add it to the appropriate table in the auth_baton */
159251881Speter      table = svn_hash_gets(ab->tables, provider->vtable->cred_kind);
160251881Speter      if (! table)
161251881Speter        {
162251881Speter          table = apr_pcalloc(pool, sizeof(*table));
163251881Speter          table->providers
164251881Speter            = apr_array_make(pool, 1, sizeof(svn_auth_provider_object_t *));
165251881Speter
166251881Speter          svn_hash_sets(ab->tables, provider->vtable->cred_kind, table);
167251881Speter        }
168251881Speter      APR_ARRAY_PUSH(table->providers, svn_auth_provider_object_t *)
169251881Speter        = provider;
170251881Speter    }
171251881Speter
172251881Speter  *auth_baton = ab;
173251881Speter}
174251881Speter
175289180Speter/* Magic pointer value to allow storing 'NULL' in an apr_hash_t */
176289180Speterstatic const void *auth_NULL = NULL;
177251881Speter
178251881Spetervoid
179251881Spetersvn_auth_set_parameter(svn_auth_baton_t *auth_baton,
180251881Speter                       const char *name,
181251881Speter                       const void *value)
182251881Speter{
183289180Speter  if (auth_baton)
184289180Speter    {
185289180Speter      if (auth_baton->slave_parameters)
186289180Speter        {
187289180Speter          if (!value)
188289180Speter            value = &auth_NULL;
189289180Speter
190289180Speter          svn_hash_sets(auth_baton->slave_parameters, name, value);
191289180Speter        }
192289180Speter      else
193289180Speter        svn_hash_sets(auth_baton->parameters, name, value);
194289180Speter    }
195251881Speter}
196251881Speter
197251881Speterconst void *
198251881Spetersvn_auth_get_parameter(svn_auth_baton_t *auth_baton,
199251881Speter                       const char *name)
200251881Speter{
201289180Speter  const void *value;
202289180Speter  if (!auth_baton)
203289180Speter    return NULL;
204289180Speter  else if (!auth_baton->slave_parameters)
205289180Speter    return svn_hash_gets(auth_baton->parameters, name);
206289180Speter
207289180Speter  value = svn_hash_gets(auth_baton->slave_parameters, name);
208289180Speter
209289180Speter  if (value)
210362181Sdim    return (value == &auth_NULL ? NULL : value);
211289180Speter
212251881Speter  return svn_hash_gets(auth_baton->parameters, name);
213251881Speter}
214251881Speter
215251881Speter
216251881Speter/* Return the key used to address the in-memory cache of auth
217251881Speter   credentials of type CRED_KIND and associated with REALMSTRING. */
218251881Speterstatic const char *
219251881Spetermake_cache_key(const char *cred_kind,
220251881Speter               const char *realmstring,
221251881Speter               apr_pool_t *pool)
222251881Speter{
223289180Speter  return apr_pstrcat(pool, cred_kind, ":", realmstring, SVN_VA_NULL);
224251881Speter}
225251881Speter
226251881Spetersvn_error_t *
227251881Spetersvn_auth_first_credentials(void **credentials,
228251881Speter                           svn_auth_iterstate_t **state,
229251881Speter                           const char *cred_kind,
230251881Speter                           const char *realmstring,
231251881Speter                           svn_auth_baton_t *auth_baton,
232251881Speter                           apr_pool_t *pool)
233251881Speter{
234251881Speter  int i = 0;
235251881Speter  provider_set_t *table;
236251881Speter  svn_auth_provider_object_t *provider = NULL;
237251881Speter  void *creds = NULL;
238251881Speter  void *iter_baton = NULL;
239251881Speter  svn_boolean_t got_first = FALSE;
240251881Speter  svn_auth_iterstate_t *iterstate;
241251881Speter  const char *cache_key;
242289180Speter  apr_hash_t *parameters;
243251881Speter
244289180Speter  if (! auth_baton)
245289180Speter    return svn_error_create(SVN_ERR_AUTHN_NO_PROVIDER, NULL,
246289180Speter                            _("No authentication providers registered"));
247289180Speter
248251881Speter  /* Get the appropriate table of providers for CRED_KIND. */
249251881Speter  table = svn_hash_gets(auth_baton->tables, cred_kind);
250251881Speter  if (! table)
251251881Speter    return svn_error_createf(SVN_ERR_AUTHN_NO_PROVIDER, NULL,
252251881Speter                             _("No provider registered for '%s' credentials"),
253251881Speter                             cred_kind);
254251881Speter
255289180Speter  if (auth_baton->slave_parameters)
256289180Speter    {
257289180Speter      apr_hash_index_t *hi;
258289180Speter      parameters = apr_hash_copy(pool, auth_baton->parameters);
259289180Speter
260289180Speter      for (hi = apr_hash_first(pool, auth_baton->slave_parameters);
261289180Speter            hi;
262289180Speter            hi = apr_hash_next(hi))
263289180Speter        {
264289180Speter          const void *value = apr_hash_this_val(hi);
265289180Speter
266289180Speter          if (value == &auth_NULL)
267289180Speter            value = NULL;
268289180Speter
269289180Speter          svn_hash_sets(parameters, apr_hash_this_key(hi), value);
270289180Speter        }
271289180Speter    }
272289180Speter  else
273289180Speter    parameters = auth_baton->parameters;
274289180Speter
275251881Speter  /* First, see if we have cached creds in the auth_baton. */
276251881Speter  cache_key = make_cache_key(cred_kind, realmstring, pool);
277251881Speter  creds = svn_hash_gets(auth_baton->creds_cache, cache_key);
278251881Speter  if (creds)
279251881Speter    {
280251881Speter       got_first = FALSE;
281251881Speter    }
282251881Speter  else
283251881Speter    /* If not, find a provider that can give "first" credentials. */
284251881Speter    {
285251881Speter      /* Find a provider that can give "first" credentials. */
286251881Speter      for (i = 0; i < table->providers->nelts; i++)
287251881Speter        {
288251881Speter          provider = APR_ARRAY_IDX(table->providers, i,
289251881Speter                                   svn_auth_provider_object_t *);
290251881Speter          SVN_ERR(provider->vtable->first_credentials(&creds, &iter_baton,
291251881Speter                                                      provider->provider_baton,
292289180Speter                                                      parameters,
293251881Speter                                                      realmstring,
294251881Speter                                                      auth_baton->pool));
295251881Speter
296251881Speter          if (creds != NULL)
297251881Speter            {
298251881Speter              got_first = TRUE;
299251881Speter              break;
300251881Speter            }
301251881Speter        }
302251881Speter    }
303251881Speter
304251881Speter  if (! creds)
305289180Speter    {
306289180Speter      *state = NULL;
307289180Speter    }
308251881Speter  else
309251881Speter    {
310251881Speter      /* Build an abstract iteration state. */
311251881Speter      iterstate = apr_pcalloc(pool, sizeof(*iterstate));
312251881Speter      iterstate->table = table;
313251881Speter      iterstate->provider_idx = i;
314251881Speter      iterstate->got_first = got_first;
315251881Speter      iterstate->provider_iter_baton = iter_baton;
316251881Speter      iterstate->realmstring = apr_pstrdup(pool, realmstring);
317251881Speter      iterstate->cache_key = cache_key;
318251881Speter      iterstate->auth_baton = auth_baton;
319289180Speter      iterstate->parameters = parameters;
320251881Speter      *state = iterstate;
321251881Speter
322251881Speter      /* Put the creds in the cache */
323251881Speter      svn_hash_sets(auth_baton->creds_cache,
324251881Speter                    apr_pstrdup(auth_baton->pool, cache_key),
325251881Speter                    creds);
326251881Speter    }
327251881Speter
328251881Speter  *credentials = creds;
329251881Speter
330251881Speter  return SVN_NO_ERROR;
331251881Speter}
332251881Speter
333251881Speter
334251881Spetersvn_error_t *
335251881Spetersvn_auth_next_credentials(void **credentials,
336251881Speter                          svn_auth_iterstate_t *state,
337251881Speter                          apr_pool_t *pool)
338251881Speter{
339251881Speter  svn_auth_baton_t *auth_baton = state->auth_baton;
340251881Speter  svn_auth_provider_object_t *provider;
341251881Speter  provider_set_t *table = state->table;
342251881Speter  void *creds = NULL;
343251881Speter
344251881Speter  /* Continue traversing the table from where we left off. */
345251881Speter  for (/* no init */;
346251881Speter       state->provider_idx < table->providers->nelts;
347251881Speter       state->provider_idx++)
348251881Speter    {
349251881Speter      provider = APR_ARRAY_IDX(table->providers,
350251881Speter                               state->provider_idx,
351251881Speter                               svn_auth_provider_object_t *);
352251881Speter      if (! state->got_first)
353251881Speter        {
354251881Speter          SVN_ERR(provider->vtable->first_credentials(
355251881Speter                      &creds, &(state->provider_iter_baton),
356289180Speter                      provider->provider_baton, state->parameters,
357251881Speter                      state->realmstring, auth_baton->pool));
358251881Speter          state->got_first = TRUE;
359251881Speter        }
360251881Speter      else if (provider->vtable->next_credentials)
361251881Speter        {
362289180Speter          SVN_ERR(provider->vtable->next_credentials(&creds,
363289180Speter                                                     state->provider_iter_baton,
364289180Speter                                                     provider->provider_baton,
365289180Speter                                                     state->parameters,
366289180Speter                                                     state->realmstring,
367289180Speter                                                     auth_baton->pool));
368251881Speter        }
369251881Speter
370251881Speter      if (creds != NULL)
371251881Speter        {
372251881Speter          /* Put the creds in the cache */
373298845Sdim          svn_hash_sets(auth_baton->creds_cache,
374298845Sdim                        apr_pstrdup(auth_baton->pool, state->cache_key),
375298845Sdim                        creds);
376251881Speter          break;
377251881Speter        }
378251881Speter
379251881Speter      state->got_first = FALSE;
380251881Speter    }
381251881Speter
382251881Speter  *credentials = creds;
383251881Speter
384251881Speter  return SVN_NO_ERROR;
385251881Speter}
386251881Speter
387251881Speter
388251881Spetersvn_error_t *
389251881Spetersvn_auth_save_credentials(svn_auth_iterstate_t *state,
390251881Speter                          apr_pool_t *pool)
391251881Speter{
392251881Speter  int i;
393251881Speter  svn_auth_provider_object_t *provider;
394251881Speter  svn_boolean_t save_succeeded = FALSE;
395251881Speter  const char *no_auth_cache;
396251881Speter  void *creds;
397251881Speter
398251881Speter  if (! state || state->table->providers->nelts <= state->provider_idx)
399251881Speter    return SVN_NO_ERROR;
400251881Speter
401251881Speter  creds = svn_hash_gets(state->auth_baton->creds_cache, state->cache_key);
402251881Speter  if (! creds)
403251881Speter    return SVN_NO_ERROR;
404251881Speter
405251881Speter  /* Do not save the creds if SVN_AUTH_PARAM_NO_AUTH_CACHE is set */
406289180Speter  no_auth_cache = svn_hash_gets(state->parameters,
407251881Speter                                SVN_AUTH_PARAM_NO_AUTH_CACHE);
408251881Speter  if (no_auth_cache)
409251881Speter    return SVN_NO_ERROR;
410251881Speter
411251881Speter  /* First, try to save the creds using the provider that produced them. */
412251881Speter  provider = APR_ARRAY_IDX(state->table->providers,
413251881Speter                           state->provider_idx,
414251881Speter                           svn_auth_provider_object_t *);
415251881Speter  if (provider->vtable->save_credentials)
416251881Speter    SVN_ERR(provider->vtable->save_credentials(&save_succeeded,
417251881Speter                                               creds,
418251881Speter                                               provider->provider_baton,
419289180Speter                                               state->parameters,
420251881Speter                                               state->realmstring,
421251881Speter                                               pool));
422251881Speter  if (save_succeeded)
423251881Speter    return SVN_NO_ERROR;
424251881Speter
425251881Speter  /* Otherwise, loop from the top of the list, asking every provider
426251881Speter     to attempt a save.  ### todo: someday optimize so we don't
427251881Speter     necessarily start from the top of the list. */
428251881Speter  for (i = 0; i < state->table->providers->nelts; i++)
429251881Speter    {
430251881Speter      provider = APR_ARRAY_IDX(state->table->providers, i,
431251881Speter                               svn_auth_provider_object_t *);
432251881Speter      if (provider->vtable->save_credentials)
433289180Speter        SVN_ERR(provider->vtable->save_credentials(&save_succeeded, creds,
434289180Speter                                                   provider->provider_baton,
435289180Speter                                                   state->parameters,
436289180Speter                                                   state->realmstring,
437289180Speter                                                   pool));
438251881Speter
439251881Speter      if (save_succeeded)
440251881Speter        break;
441251881Speter    }
442251881Speter
443251881Speter  /* ### notice that at the moment, if no provider can save, there's
444251881Speter     no way the caller will know. */
445251881Speter
446251881Speter  return SVN_NO_ERROR;
447251881Speter}
448251881Speter
449251881Speter
450251881Spetersvn_error_t *
451251881Spetersvn_auth_forget_credentials(svn_auth_baton_t *auth_baton,
452251881Speter                            const char *cred_kind,
453251881Speter                            const char *realmstring,
454251881Speter                            apr_pool_t *scratch_pool)
455251881Speter{
456251881Speter  SVN_ERR_ASSERT((cred_kind && realmstring) || (!cred_kind && !realmstring));
457251881Speter
458251881Speter  /* If we have a CRED_KIND and REALMSTRING, we clear out just the
459251881Speter     cached item (if any).  Otherwise, empty the whole hash. */
460251881Speter  if (cred_kind)
461251881Speter    {
462251881Speter      svn_hash_sets(auth_baton->creds_cache,
463251881Speter                    make_cache_key(cred_kind, realmstring, scratch_pool),
464251881Speter                    NULL);
465251881Speter    }
466251881Speter  else
467251881Speter    {
468251881Speter      apr_hash_clear(auth_baton->creds_cache);
469251881Speter    }
470251881Speter
471251881Speter  return SVN_NO_ERROR;
472251881Speter}
473251881Speter
474251881Speter
475251881Spetersvn_auth_ssl_server_cert_info_t *
476251881Spetersvn_auth_ssl_server_cert_info_dup
477251881Speter  (const svn_auth_ssl_server_cert_info_t *info, apr_pool_t *pool)
478251881Speter{
479251881Speter  svn_auth_ssl_server_cert_info_t *new_info
480251881Speter    = apr_palloc(pool, sizeof(*new_info));
481251881Speter
482251881Speter  *new_info = *info;
483251881Speter
484251881Speter  new_info->hostname = apr_pstrdup(pool, new_info->hostname);
485251881Speter  new_info->fingerprint = apr_pstrdup(pool, new_info->fingerprint);
486251881Speter  new_info->valid_from = apr_pstrdup(pool, new_info->valid_from);
487251881Speter  new_info->valid_until = apr_pstrdup(pool, new_info->valid_until);
488251881Speter  new_info->issuer_dname = apr_pstrdup(pool, new_info->issuer_dname);
489251881Speter  new_info->ascii_cert = apr_pstrdup(pool, new_info->ascii_cert);
490251881Speter
491251881Speter  return new_info;
492251881Speter}
493251881Speter
494251881Spetersvn_error_t *
495251881Spetersvn_auth_get_platform_specific_provider(svn_auth_provider_object_t **provider,
496251881Speter                                        const char *provider_name,
497251881Speter                                        const char *provider_type,
498251881Speter                                        apr_pool_t *pool)
499251881Speter{
500251881Speter  *provider = NULL;
501251881Speter
502251881Speter  if (apr_strnatcmp(provider_name, "gnome_keyring") == 0 ||
503251881Speter      apr_strnatcmp(provider_name, "kwallet") == 0)
504251881Speter    {
505362181Sdim#if defined(SVN_HAVE_GNOME_KEYRING) || defined(SVN_HAVE_KWALLET) || defined (SVN_HAVE_LIBSECRET)
506251881Speter      apr_dso_handle_t *dso;
507251881Speter      apr_dso_handle_sym_t provider_function_symbol, version_function_symbol;
508251881Speter      const char *library_label, *library_name;
509251881Speter      const char *provider_function_name, *version_function_name;
510251881Speter      library_name = apr_psprintf(pool,
511251881Speter                                  "libsvn_auth_%s-%d.so.%d",
512251881Speter                                  provider_name,
513251881Speter                                  SVN_VER_MAJOR, SVN_SOVERSION);
514251881Speter      library_label = apr_psprintf(pool, "svn_%s", provider_name);
515251881Speter      provider_function_name = apr_psprintf(pool,
516251881Speter                                            "svn_auth_get_%s_%s_provider",
517251881Speter                                            provider_name, provider_type);
518251881Speter      version_function_name = apr_psprintf(pool,
519251881Speter                                           "svn_auth_%s_version",
520251881Speter                                           provider_name);
521251881Speter      SVN_ERR(svn_dso_load(&dso, library_name));
522251881Speter      if (dso)
523251881Speter        {
524251881Speter          if (apr_dso_sym(&version_function_symbol,
525251881Speter                          dso,
526251881Speter                          version_function_name) == 0)
527251881Speter            {
528251881Speter              svn_version_func_t version_function
529251881Speter                = version_function_symbol;
530251881Speter              svn_version_checklist_t check_list[2];
531251881Speter
532251881Speter              check_list[0].label = library_label;
533251881Speter              check_list[0].version_query = version_function;
534251881Speter              check_list[1].label = NULL;
535251881Speter              check_list[1].version_query = NULL;
536257936Speter              SVN_ERR(svn_ver_check_list2(svn_subr_version(), check_list,
537257936Speter                                          svn_ver_equal));
538251881Speter            }
539251881Speter          if (apr_dso_sym(&provider_function_symbol,
540251881Speter                          dso,
541251881Speter                          provider_function_name) == 0)
542251881Speter            {
543251881Speter              if (strcmp(provider_type, "simple") == 0)
544251881Speter                {
545251881Speter                  svn_auth_simple_provider_func_t provider_function
546251881Speter                    = provider_function_symbol;
547251881Speter                  provider_function(provider, pool);
548251881Speter                }
549251881Speter              else if (strcmp(provider_type, "ssl_client_cert_pw") == 0)
550251881Speter                {
551251881Speter                  svn_auth_ssl_client_cert_pw_provider_func_t provider_function
552251881Speter                    = provider_function_symbol;
553251881Speter                  provider_function(provider, pool);
554251881Speter                }
555251881Speter            }
556251881Speter        }
557251881Speter#endif
558251881Speter    }
559251881Speter  else
560251881Speter    {
561251881Speter#if defined(SVN_HAVE_GPG_AGENT)
562251881Speter      if (strcmp(provider_name, "gpg_agent") == 0 &&
563251881Speter          strcmp(provider_type, "simple") == 0)
564251881Speter        {
565289180Speter          svn_auth__get_gpg_agent_simple_provider(provider, pool);
566251881Speter        }
567251881Speter#endif
568251881Speter#ifdef SVN_HAVE_KEYCHAIN_SERVICES
569251881Speter      if (strcmp(provider_name, "keychain") == 0 &&
570251881Speter          strcmp(provider_type, "simple") == 0)
571251881Speter        {
572289180Speter          svn_auth__get_keychain_simple_provider(provider, pool);
573251881Speter        }
574251881Speter      else if (strcmp(provider_name, "keychain") == 0 &&
575251881Speter               strcmp(provider_type, "ssl_client_cert_pw") == 0)
576251881Speter        {
577289180Speter          svn_auth__get_keychain_ssl_client_cert_pw_provider(provider, pool);
578251881Speter        }
579251881Speter#endif
580251881Speter
581251881Speter#if defined(WIN32) && !defined(__MINGW32__)
582251881Speter      if (strcmp(provider_name, "windows") == 0 &&
583251881Speter          strcmp(provider_type, "simple") == 0)
584251881Speter        {
585289180Speter          svn_auth__get_windows_simple_provider(provider, pool);
586251881Speter        }
587251881Speter      else if (strcmp(provider_name, "windows") == 0 &&
588251881Speter               strcmp(provider_type, "ssl_client_cert_pw") == 0)
589251881Speter        {
590289180Speter          svn_auth__get_windows_ssl_client_cert_pw_provider(provider, pool);
591251881Speter        }
592251881Speter      else if (strcmp(provider_name, "windows") == 0 &&
593251881Speter               strcmp(provider_type, "ssl_server_trust") == 0)
594251881Speter        {
595289180Speter          svn_auth__get_windows_ssl_server_trust_provider(provider, pool);
596251881Speter        }
597262250Speter      else if (strcmp(provider_name, "windows") == 0 &&
598289180Speter               strcmp(provider_type, "ssl_server_authority") == 0)
599262250Speter        {
600262250Speter          svn_auth__get_windows_ssl_server_authority_provider(provider, pool);
601262250Speter        }
602251881Speter#endif
603251881Speter    }
604251881Speter
605251881Speter  return SVN_NO_ERROR;
606251881Speter}
607251881Speter
608251881Spetersvn_error_t *
609251881Spetersvn_auth_get_platform_specific_client_providers(apr_array_header_t **providers,
610251881Speter                                                svn_config_t *config,
611251881Speter                                                apr_pool_t *pool)
612251881Speter{
613251881Speter  svn_auth_provider_object_t *provider;
614251881Speter  const char *password_stores_config_option;
615251881Speter  apr_array_header_t *password_stores;
616251881Speter  int i;
617251881Speter
618251881Speter#define SVN__MAYBE_ADD_PROVIDER(list, p) \
619251881Speter  { if (p) APR_ARRAY_PUSH(list, svn_auth_provider_object_t *) = p; }
620251881Speter
621251881Speter#define SVN__DEFAULT_AUTH_PROVIDER_LIST \
622251881Speter         "gnome-keyring,kwallet,keychain,gpg-agent,windows-cryptoapi"
623251881Speter
624251881Speter  *providers = apr_array_make(pool, 12, sizeof(svn_auth_provider_object_t *));
625251881Speter
626251881Speter  /* Fetch the configured list of password stores, and split them into
627251881Speter     an array. */
628251881Speter  svn_config_get(config,
629251881Speter                 &password_stores_config_option,
630251881Speter                 SVN_CONFIG_SECTION_AUTH,
631251881Speter                 SVN_CONFIG_OPTION_PASSWORD_STORES,
632251881Speter                 SVN__DEFAULT_AUTH_PROVIDER_LIST);
633251881Speter  password_stores = svn_cstring_split(password_stores_config_option,
634251881Speter                                      " ,", TRUE, pool);
635251881Speter
636251881Speter  for (i = 0; i < password_stores->nelts; i++)
637251881Speter    {
638251881Speter      const char *password_store = APR_ARRAY_IDX(password_stores, i,
639251881Speter                                                 const char *);
640251881Speter
641251881Speter      /* GNOME Keyring */
642251881Speter      if (apr_strnatcmp(password_store, "gnome-keyring") == 0)
643251881Speter        {
644251881Speter          SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
645251881Speter                                                          "gnome_keyring",
646251881Speter                                                          "simple",
647251881Speter                                                          pool));
648251881Speter          SVN__MAYBE_ADD_PROVIDER(*providers, provider);
649251881Speter
650251881Speter          SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
651251881Speter                                                          "gnome_keyring",
652251881Speter                                                          "ssl_client_cert_pw",
653251881Speter                                                          pool));
654251881Speter          SVN__MAYBE_ADD_PROVIDER(*providers, provider);
655251881Speter        }
656251881Speter      /* GPG-AGENT */
657251881Speter      else if (apr_strnatcmp(password_store, "gpg-agent") == 0)
658251881Speter        {
659251881Speter          SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
660251881Speter                                                          "gpg_agent",
661251881Speter                                                          "simple",
662251881Speter                                                          pool));
663251881Speter          SVN__MAYBE_ADD_PROVIDER(*providers, provider);
664251881Speter        }
665251881Speter      /* KWallet */
666251881Speter      else if (apr_strnatcmp(password_store, "kwallet") == 0)
667251881Speter        {
668251881Speter          SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
669251881Speter                                                          "kwallet",
670251881Speter                                                          "simple",
671251881Speter                                                          pool));
672251881Speter          SVN__MAYBE_ADD_PROVIDER(*providers, provider);
673251881Speter
674251881Speter          SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
675251881Speter                                                          "kwallet",
676251881Speter                                                          "ssl_client_cert_pw",
677251881Speter                                                          pool));
678251881Speter          SVN__MAYBE_ADD_PROVIDER(*providers, provider);
679251881Speter        }
680251881Speter      /* Keychain */
681251881Speter      else if (apr_strnatcmp(password_store, "keychain") == 0)
682251881Speter        {
683251881Speter          SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
684251881Speter                                                          "keychain",
685251881Speter                                                          "simple",
686251881Speter                                                          pool));
687251881Speter          SVN__MAYBE_ADD_PROVIDER(*providers, provider);
688251881Speter
689251881Speter          SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
690251881Speter                                                          "keychain",
691251881Speter                                                          "ssl_client_cert_pw",
692251881Speter                                                          pool));
693251881Speter          SVN__MAYBE_ADD_PROVIDER(*providers, provider);
694251881Speter        }
695251881Speter      /* Windows */
696251881Speter      else if (apr_strnatcmp(password_store, "windows-cryptoapi") == 0)
697251881Speter        {
698251881Speter          SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
699251881Speter                                                          "windows",
700251881Speter                                                          "simple",
701251881Speter                                                          pool));
702251881Speter          SVN__MAYBE_ADD_PROVIDER(*providers, provider);
703251881Speter
704251881Speter          SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
705251881Speter                                                          "windows",
706251881Speter                                                          "ssl_client_cert_pw",
707251881Speter                                                          pool));
708251881Speter          SVN__MAYBE_ADD_PROVIDER(*providers, provider);
709251881Speter        }
710251881Speter    }
711251881Speter
712289180Speter  /* Windows has two providers without a store to allow easy access to
713289180Speter     SSL servers. We enable these unconditionally.
714289180Speter     (This behavior was moved here from svn_cmdline_create_auth_baton()) */
715289180Speter  SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
716289180Speter                                                  "windows",
717289180Speter                                                  "ssl_server_trust",
718289180Speter                                                  pool));
719289180Speter  SVN__MAYBE_ADD_PROVIDER(*providers, provider);
720289180Speter
721289180Speter  /* The windows ssl authority certificate CRYPTOAPI provider. */
722289180Speter  SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
723289180Speter                                                  "windows",
724289180Speter                                                  "ssl_server_authority",
725289180Speter                                                  pool));
726289180Speter
727289180Speter  SVN__MAYBE_ADD_PROVIDER(*providers, provider);
728289180Speter
729251881Speter  return SVN_NO_ERROR;
730251881Speter}
731289180Speter
732289180Spetersvn_error_t *
733289180Spetersvn_auth__make_session_auth(svn_auth_baton_t **session_auth_baton,
734289180Speter                            const svn_auth_baton_t *auth_baton,
735289180Speter                            apr_hash_t *config,
736289180Speter                            const char *server_name,
737289180Speter                            apr_pool_t *result_pool,
738289180Speter                            apr_pool_t *scratch_pool)
739289180Speter{
740289180Speter  svn_boolean_t store_passwords = SVN_CONFIG_DEFAULT_OPTION_STORE_PASSWORDS;
741289180Speter  svn_boolean_t store_auth_creds = SVN_CONFIG_DEFAULT_OPTION_STORE_AUTH_CREDS;
742289180Speter  const char *store_plaintext_passwords
743289180Speter    = SVN_CONFIG_DEFAULT_OPTION_STORE_PLAINTEXT_PASSWORDS;
744289180Speter  svn_boolean_t store_pp = SVN_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP;
745289180Speter  const char *store_pp_plaintext
746289180Speter    = SVN_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT;
747289180Speter  svn_config_t *servers = NULL;
748289180Speter  const char *server_group = NULL;
749289180Speter
750289180Speter  struct svn_auth_baton_t *ab;
751289180Speter
752289180Speter  ab = apr_pmemdup(result_pool, auth_baton, sizeof(*ab));
753289180Speter
754289180Speter  ab->slave_parameters = apr_hash_make(result_pool);
755289180Speter
756289180Speter  /* The 'store-passwords' and 'store-auth-creds' parameters used to
757289180Speter  * live in SVN_CONFIG_CATEGORY_CONFIG. For backward compatibility,
758289180Speter  * if values for these parameters have already been set by our
759289180Speter  * callers, we use those values as defaults.
760289180Speter  *
761289180Speter  * Note that we can only catch the case where users explicitly set
762289180Speter  * "store-passwords = no" or 'store-auth-creds = no".
763289180Speter  *
764289180Speter  * However, since the default value for both these options is
765289180Speter  * currently (and has always been) "yes", users won't know
766289180Speter  * the difference if they set "store-passwords = yes" or
767289180Speter  * "store-auth-creds = yes" -- they'll get the expected behaviour.
768289180Speter  */
769289180Speter
770362181Sdim  if (svn_auth_get_parameter(ab, SVN_AUTH_PARAM_DONT_STORE_PASSWORDS) != NULL)
771289180Speter    store_passwords = FALSE;
772289180Speter
773362181Sdim  if (svn_auth_get_parameter(ab, SVN_AUTH_PARAM_NO_AUTH_CACHE) != NULL)
774289180Speter    store_auth_creds = FALSE;
775289180Speter
776289180Speter  /* All the svn_auth_set_parameter() calls below this not only affect the
777289180Speter     to be created ra session, but also all the ra sessions that are already
778289180Speter     use this auth baton!
779289180Speter
780289180Speter     Please try to key things based on the realm string instead of this
781289180Speter     construct.
782289180Speter */
783289180Speter
784289180Speter  if (config)
785289180Speter    {
786289180Speter      /* Grab the 'servers' config. */
787289180Speter      servers = svn_hash_gets(config, SVN_CONFIG_CATEGORY_SERVERS);
788289180Speter      if (servers)
789289180Speter        {
790289180Speter          /* First, look in the global section. */
791289180Speter
792289180Speter          SVN_ERR(svn_config_get_bool
793289180Speter            (servers, &store_passwords, SVN_CONFIG_SECTION_GLOBAL,
794289180Speter             SVN_CONFIG_OPTION_STORE_PASSWORDS,
795289180Speter             store_passwords));
796289180Speter
797289180Speter          SVN_ERR(svn_config_get_yes_no_ask
798289180Speter            (servers, &store_plaintext_passwords, SVN_CONFIG_SECTION_GLOBAL,
799289180Speter             SVN_CONFIG_OPTION_STORE_PLAINTEXT_PASSWORDS,
800289180Speter             SVN_CONFIG_DEFAULT_OPTION_STORE_PLAINTEXT_PASSWORDS));
801289180Speter
802289180Speter          SVN_ERR(svn_config_get_bool
803289180Speter            (servers, &store_pp, SVN_CONFIG_SECTION_GLOBAL,
804289180Speter             SVN_CONFIG_OPTION_STORE_SSL_CLIENT_CERT_PP,
805289180Speter             store_pp));
806289180Speter
807289180Speter          SVN_ERR(svn_config_get_yes_no_ask
808289180Speter            (servers, &store_pp_plaintext,
809289180Speter             SVN_CONFIG_SECTION_GLOBAL,
810289180Speter             SVN_CONFIG_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT,
811289180Speter             SVN_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT));
812289180Speter
813289180Speter          SVN_ERR(svn_config_get_bool
814289180Speter            (servers, &store_auth_creds, SVN_CONFIG_SECTION_GLOBAL,
815289180Speter              SVN_CONFIG_OPTION_STORE_AUTH_CREDS,
816289180Speter              store_auth_creds));
817289180Speter
818289180Speter          /* Find out where we're about to connect to, and
819289180Speter           * try to pick a server group based on the destination. */
820289180Speter          server_group = svn_config_find_group(servers, server_name,
821289180Speter                                               SVN_CONFIG_SECTION_GROUPS,
822289180Speter                                               scratch_pool);
823289180Speter
824289180Speter          if (server_group)
825289180Speter            {
826289180Speter              /* Override global auth caching parameters with the ones
827289180Speter               * for the server group, if any. */
828289180Speter              SVN_ERR(svn_config_get_bool(servers, &store_auth_creds,
829289180Speter                                          server_group,
830289180Speter                                          SVN_CONFIG_OPTION_STORE_AUTH_CREDS,
831289180Speter                                          store_auth_creds));
832289180Speter
833289180Speter              SVN_ERR(svn_config_get_bool(servers, &store_passwords,
834289180Speter                                          server_group,
835289180Speter                                          SVN_CONFIG_OPTION_STORE_PASSWORDS,
836289180Speter                                          store_passwords));
837289180Speter
838289180Speter              SVN_ERR(svn_config_get_yes_no_ask
839289180Speter                (servers, &store_plaintext_passwords, server_group,
840289180Speter                 SVN_CONFIG_OPTION_STORE_PLAINTEXT_PASSWORDS,
841289180Speter                 store_plaintext_passwords));
842289180Speter
843289180Speter              SVN_ERR(svn_config_get_bool
844289180Speter                (servers, &store_pp,
845289180Speter                 server_group, SVN_CONFIG_OPTION_STORE_SSL_CLIENT_CERT_PP,
846289180Speter                 store_pp));
847289180Speter
848289180Speter              SVN_ERR(svn_config_get_yes_no_ask
849289180Speter                (servers, &store_pp_plaintext, server_group,
850289180Speter                 SVN_CONFIG_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT,
851289180Speter                 store_pp_plaintext));
852289180Speter            }
853289180Speter        }
854289180Speter    }
855289180Speter
856289180Speter  /* Save auth caching parameters in the auth parameter hash. */
857289180Speter  if (! store_passwords)
858362181Sdim    svn_auth_set_parameter(ab, SVN_AUTH_PARAM_DONT_STORE_PASSWORDS, "");
859289180Speter
860289180Speter  svn_auth_set_parameter(ab,
861289180Speter                         SVN_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS,
862289180Speter                         store_plaintext_passwords);
863289180Speter
864289180Speter  if (! store_pp)
865289180Speter    svn_auth_set_parameter(ab,
866289180Speter                           SVN_AUTH_PARAM_DONT_STORE_SSL_CLIENT_CERT_PP,
867289180Speter                           "");
868289180Speter
869289180Speter  svn_auth_set_parameter(ab,
870289180Speter                         SVN_AUTH_PARAM_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT,
871289180Speter                         store_pp_plaintext);
872289180Speter
873289180Speter  if (! store_auth_creds)
874362181Sdim    svn_auth_set_parameter(ab, SVN_AUTH_PARAM_NO_AUTH_CACHE, "");
875289180Speter
876289180Speter  if (server_group)
877289180Speter    svn_auth_set_parameter(ab,
878289180Speter                           SVN_AUTH_PARAM_SERVER_GROUP,
879289180Speter                           apr_pstrdup(ab->pool, server_group));
880289180Speter
881289180Speter  *session_auth_baton = ab;
882289180Speter
883289180Speter  return SVN_NO_ERROR;
884289180Speter}
885289180Speter
886289180Speter
887289180Speterstatic svn_error_t *
888289180Speterdummy_first_creds(void **credentials,
889289180Speter                  void **iter_baton,
890289180Speter                  void *provider_baton,
891289180Speter                  apr_hash_t *parameters,
892289180Speter                  const char *realmstring,
893289180Speter                  apr_pool_t *pool)
894289180Speter{
895289180Speter  *credentials = NULL;
896289180Speter  *iter_baton = NULL;
897289180Speter  return SVN_NO_ERROR;
898289180Speter}
899289180Speter
900289180Spetervoid
901289180Spetersvn_auth__get_dummmy_simple_provider(svn_auth_provider_object_t **provider,
902289180Speter                                     apr_pool_t *pool)
903289180Speter{
904289180Speter  static const svn_auth_provider_t vtable = {
905289180Speter    SVN_AUTH_CRED_SIMPLE,
906289180Speter    dummy_first_creds,
907289180Speter    NULL, NULL
908289180Speter  };
909289180Speter
910289180Speter  svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
911289180Speter
912289180Speter  po->vtable = &vtable;
913289180Speter  *provider = po;
914289180Speter}
915