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