34
35
#include "svn_private_config.h"
35
36
#include "svn_dso.h"
36
37
#include "svn_version.h"
38
/* The good way to think of this machinery is as a set of tables.
40
- Each type of credentials selects a single table.
42
- In a given table, each row is a 'provider' capable of returning
43
the same type of credentials. Each column represents a
44
provider's repeated attempts to provide credentials.
38
#include "private/svn_dep_compat.h"
39
#include "private/svn_subr_private.h"
46
A good way to think of this machinery is as a set of tables.
48
- Each type of credentials selects a single table.
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.
55
Fetching Credentials from Providers
56
-----------------------------------
46
58
When the caller asks for a particular type of credentials, the
47
59
machinery in this file walks over the appropriate table. It starts
56
68
Note that the caller cannot see the table traversal, and thus has
57
69
no idea when we switch providers.
72
Storing Credentials with Providers
73
----------------------------------
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 --
125
154
provider = APR_ARRAY_IDX(providers, i, svn_auth_provider_object_t *);
127
156
/* Add it to the appropriate table in the auth_baton */
128
table = apr_hash_get(ab->tables,
129
provider->vtable->cred_kind, APR_HASH_KEY_STRING);
157
table = svn_hash_gets(ab->tables, provider->vtable->cred_kind);
132
160
table = apr_pcalloc(pool, sizeof(*table));
134
162
= apr_array_make(pool, 1, sizeof(svn_auth_provider_object_t *));
136
apr_hash_set(ab->tables,
137
provider->vtable->cred_kind, APR_HASH_KEY_STRING,
164
svn_hash_sets(ab->tables, provider->vtable->cred_kind, table);
140
166
APR_ARRAY_PUSH(table->providers, svn_auth_provider_object_t *)
151
177
const char *name,
152
178
const void *value)
154
apr_hash_set(auth_baton->parameters, name, APR_HASH_KEY_STRING, value);
180
svn_hash_sets(auth_baton->parameters, name, value);
158
184
svn_auth_get_parameter(svn_auth_baton_t *auth_baton,
159
185
const char *name)
161
return apr_hash_get(auth_baton->parameters, name, APR_HASH_KEY_STRING);
187
return svn_hash_gets(auth_baton->parameters, name);
191
/* Return the key used to address the in-memory cache of auth
192
credentials of type CRED_KIND and associated with REALMSTRING. */
194
make_cache_key(const char *cred_kind,
195
const char *realmstring,
198
return apr_pstrcat(pool, cred_kind, ":", realmstring, (char *)NULL);
167
202
svn_auth_first_credentials(void **credentials,
181
216
const char *cache_key;
183
218
/* Get the appropriate table of providers for CRED_KIND. */
184
table = apr_hash_get(auth_baton->tables, cred_kind, APR_HASH_KEY_STRING);
219
table = svn_hash_gets(auth_baton->tables, cred_kind);
186
221
return svn_error_createf(SVN_ERR_AUTHN_NO_PROVIDER, NULL,
187
222
_("No provider registered for '%s' credentials"),
190
225
/* First, see if we have cached creds in the auth_baton. */
191
cache_key = apr_pstrcat(pool, cred_kind, ":", realmstring, (char *)NULL);
192
creds = apr_hash_get(auth_baton->creds_cache,
193
cache_key, APR_HASH_KEY_STRING);
226
cache_key = make_cache_key(cred_kind, realmstring, pool);
227
creds = svn_hash_gets(auth_baton->creds_cache, cache_key);
196
230
got_first = FALSE;
204
238
provider = APR_ARRAY_IDX(table->providers, i,
205
239
svn_auth_provider_object_t *);
206
SVN_ERR(provider->vtable->first_credentials
207
(&creds, &iter_baton, provider->provider_baton,
208
auth_baton->parameters, realmstring, auth_baton->pool));
240
SVN_ERR(provider->vtable->first_credentials(&creds, &iter_baton,
241
provider->provider_baton,
242
auth_baton->parameters,
210
246
if (creds != NULL)
231
267
*state = iterstate;
233
269
/* Put the creds in the cache */
234
apr_hash_set(auth_baton->creds_cache,
235
apr_pstrdup(auth_baton->pool, cache_key),
270
svn_hash_sets(auth_baton->creds_cache,
271
apr_pstrdup(auth_baton->pool, cache_key),
240
275
*credentials = creds;
263
298
svn_auth_provider_object_t *);
264
299
if (! state->got_first)
266
SVN_ERR(provider->vtable->first_credentials
267
(&creds, &(state->provider_iter_baton),
268
provider->provider_baton, auth_baton->parameters,
269
state->realmstring, auth_baton->pool));
301
SVN_ERR(provider->vtable->first_credentials(
302
&creds, &(state->provider_iter_baton),
303
provider->provider_baton, auth_baton->parameters,
304
state->realmstring, auth_baton->pool));
270
305
state->got_first = TRUE;
307
else if (provider->vtable->next_credentials)
274
if (provider->vtable->next_credentials)
275
SVN_ERR(provider->vtable->next_credentials
276
(&creds, state->provider_iter_baton,
277
provider->provider_baton, auth_baton->parameters,
278
state->realmstring, auth_baton->pool));
309
SVN_ERR(provider->vtable->next_credentials(
310
&creds, state->provider_iter_baton,
311
provider->provider_baton, auth_baton->parameters,
312
state->realmstring, auth_baton->pool));
281
315
if (creds != NULL)
283
317
/* Put the creds in the cache */
284
apr_hash_set(auth_baton->creds_cache,
285
state->cache_key, APR_HASH_KEY_STRING,
318
svn_hash_sets(auth_baton->creds_cache, state->cache_key, creds);
311
343
return SVN_NO_ERROR;
313
345
auth_baton = state->auth_baton;
314
creds = apr_hash_get(state->auth_baton->creds_cache,
315
state->cache_key, APR_HASH_KEY_STRING);
346
creds = svn_hash_gets(state->auth_baton->creds_cache, state->cache_key);
317
348
return SVN_NO_ERROR;
319
350
/* Do not save the creds if SVN_AUTH_PARAM_NO_AUTH_CACHE is set */
320
no_auth_cache = apr_hash_get(auth_baton->parameters,
321
SVN_AUTH_PARAM_NO_AUTH_CACHE,
322
APR_HASH_KEY_STRING);
351
no_auth_cache = svn_hash_gets(auth_baton->parameters,
352
SVN_AUTH_PARAM_NO_AUTH_CACHE);
323
353
if (no_auth_cache)
324
354
return SVN_NO_ERROR;
362
392
return SVN_NO_ERROR;
397
svn_auth_forget_credentials(svn_auth_baton_t *auth_baton,
398
const char *cred_kind,
399
const char *realmstring,
400
apr_pool_t *scratch_pool)
402
SVN_ERR_ASSERT((cred_kind && realmstring) || (!cred_kind && !realmstring));
404
/* If we have a CRED_KIND and REALMSTRING, we clear out just the
405
cached item (if any). Otherwise, empty the whole hash. */
408
svn_hash_sets(auth_baton->creds_cache,
409
make_cache_key(cred_kind, realmstring, scratch_pool),
414
apr_hash_clear(auth_baton->creds_cache);
365
421
svn_auth_ssl_server_cert_info_t *
366
422
svn_auth_ssl_server_cert_info_dup
367
423
(const svn_auth_ssl_server_cert_info_t *info, apr_pool_t *pool)
385
svn_auth_get_platform_specific_provider
386
(svn_auth_provider_object_t **provider,
387
const char *provider_name,
388
const char *provider_type,
441
svn_auth_get_platform_specific_provider(svn_auth_provider_object_t **provider,
442
const char *provider_name,
443
const char *provider_type,
391
446
*provider = NULL;
399
454
const char *library_label, *library_name;
400
455
const char *provider_function_name, *version_function_name;
401
456
library_name = apr_psprintf(pool,
402
"libsvn_auth_%s-%d.so.0",
457
"libsvn_auth_%s-%d.so.%d",
459
SVN_VER_MAJOR, SVN_SOVERSION);
405
460
library_label = apr_psprintf(pool, "svn_%s", provider_name);
406
461
provider_function_name = apr_psprintf(pool,
407
462
"svn_auth_get_%s_%s_provider",
424
479
check_list[0].version_query = version_function;
425
480
check_list[1].label = NULL;
426
481
check_list[1].version_query = NULL;
427
SVN_ERR(svn_ver_check_list(svn_subr_version(), check_list));
482
SVN_ERR(svn_ver_check_list2(svn_subr_version(), check_list,
429
485
if (apr_dso_sym(&provider_function_symbol,
507
#if defined(SVN_HAVE_GPG_AGENT)
508
if (strcmp(provider_name, "gpg_agent") == 0 &&
509
strcmp(provider_type, "simple") == 0)
511
svn_auth_get_gpg_agent_simple_provider(provider, pool);
451
514
#ifdef SVN_HAVE_KEYCHAIN_SERVICES
452
515
if (strcmp(provider_name, "keychain") == 0 &&
453
516
strcmp(provider_type, "simple") == 0)
487
svn_auth_get_platform_specific_client_providers
488
(apr_array_header_t **providers,
489
svn_config_t *config,
550
svn_auth_get_platform_specific_client_providers(apr_array_header_t **providers,
551
svn_config_t *config,
492
554
svn_auth_provider_object_t *provider;
493
555
const char *password_stores_config_option;
497
559
#define SVN__MAYBE_ADD_PROVIDER(list, p) \
498
560
{ if (p) APR_ARRAY_PUSH(list, svn_auth_provider_object_t *) = p; }
562
#define SVN__DEFAULT_AUTH_PROVIDER_LIST \
563
"gnome-keyring,kwallet,keychain,gpg-agent,windows-cryptoapi"
500
565
*providers = apr_array_make(pool, 12, sizeof(svn_auth_provider_object_t *));
502
567
/* Fetch the configured list of password stores, and split them into
505
570
&password_stores_config_option,
506
571
SVN_CONFIG_SECTION_AUTH,
507
572
SVN_CONFIG_OPTION_PASSWORD_STORES,
508
"gnome-keyring,kwallet,keychain,windows-cryptoapi");
573
SVN__DEFAULT_AUTH_PROVIDER_LIST);
509
574
password_stores = svn_cstring_split(password_stores_config_option,
510
575
" ,", TRUE, pool);
530
595
SVN__MAYBE_ADD_PROVIDER(*providers, provider);
598
else if (apr_strnatcmp(password_store, "gpg-agent") == 0)
600
SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
604
SVN__MAYBE_ADD_PROVIDER(*providers, provider);
533
607
else if (apr_strnatcmp(password_store, "kwallet") == 0)