auth.c revision 302408
1/* 2 * auth.c: authentication support functions for Subversion 3 * 4 * ==================================================================== 5 * Licensed to the Apache Software Foundation (ASF) under one 6 * or more contributor license agreements. See the NOTICE file 7 * distributed with this work for additional information 8 * regarding copyright ownership. The ASF licenses this file 9 * to you under the Apache License, Version 2.0 (the 10 * "License"); you may not use this file except in compliance 11 * with the License. You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, 16 * software distributed under the License is distributed on an 17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18 * KIND, either express or implied. See the License for the 19 * specific language governing permissions and limitations 20 * under the License. 21 * ==================================================================== 22 */ 23 24 25#include <apr_pools.h> 26#include <apr_tables.h> 27#include <apr_strings.h> 28 29#include "svn_hash.h" 30#include "svn_types.h" 31#include "svn_string.h" 32#include "svn_error.h" 33#include "svn_auth.h" 34#include "svn_config.h" 35#include "svn_private_config.h" 36#include "svn_dso.h" 37#include "svn_version.h" 38#include "private/svn_auth_private.h" 39#include "private/svn_dep_compat.h" 40 41#include "auth.h" 42 43/* AN OVERVIEW 44 =========== 45 46 A good way to think of this machinery is as a set of tables. 47 48 - Each type of credentials selects a single table. 49 50 - In a given table, each row is a 'provider' capable of returning 51 the same type of credentials. Each column represents a 52 provider's repeated attempts to provide credentials. 53 54 55 Fetching Credentials from Providers 56 ----------------------------------- 57 58 When the caller asks for a particular type of credentials, the 59 machinery in this file walks over the appropriate table. It starts 60 with the first provider (first row), and calls first_credentials() 61 to get the first set of credentials (first column). If the caller 62 is unhappy with the credentials, then each subsequent call to 63 next_credentials() traverses the row from left to right. If the 64 provider returns error at any point, then we go to the next provider 65 (row). We continue this way until every provider fails, or 66 until the client is happy with the returned credentials. 67 68 Note that the caller cannot see the table traversal, and thus has 69 no idea when we switch providers. 70 71 72 Storing Credentials with Providers 73 ---------------------------------- 74 75 When the server has validated a set of credentials, and when 76 credential caching is enabled, we have the chance to store those 77 credentials for later use. The provider which provided the working 78 credentials is the first one given the opportunity to (re)cache 79 those credentials. Its save_credentials() function is invoked with 80 the working credentials. If that provider reports that it 81 successfully stored the credentials, we're done. Otherwise, we 82 walk the providers (rows) for that type of credentials in order 83 from the top of the table, allowing each in turn the opportunity to 84 store the credentials. When one reports that it has done so 85 successfully -- or when we run out of providers (rows) to try -- 86 the table walk ends. 87*/ 88 89 90 91/* This effectively defines a single table. Every provider in this 92 array returns the same kind of credentials. */ 93typedef struct provider_set_t 94{ 95 /* ordered array of svn_auth_provider_object_t */ 96 apr_array_header_t *providers; 97 98} provider_set_t; 99 100 101/* The main auth baton. */ 102struct svn_auth_baton_t 103{ 104 /* a collection of tables. maps cred_kind -> provider_set */ 105 apr_hash_t *tables; 106 107 /* the pool I'm allocated in. */ 108 apr_pool_t *pool; 109 110 /* run-time parameters needed by providers. */ 111 apr_hash_t *parameters; 112 apr_hash_t *slave_parameters; 113 114 /* run-time credentials cache. */ 115 apr_hash_t *creds_cache; 116}; 117 118/* Abstracted iteration baton */ 119struct svn_auth_iterstate_t 120{ 121 provider_set_t *table; /* the table being searched */ 122 int provider_idx; /* the current provider (row) */ 123 svn_boolean_t got_first; /* did we get the provider's first creds? */ 124 void *provider_iter_baton; /* the provider's own iteration context */ 125 const char *realmstring; /* The original realmstring passed in */ 126 const char *cache_key; /* key to use in auth_baton's creds_cache */ 127 svn_auth_baton_t *auth_baton; /* the original auth_baton. */ 128 apr_hash_t *parameters; 129}; 130 131 132 133void 134svn_auth_open(svn_auth_baton_t **auth_baton, 135 const apr_array_header_t *providers, 136 apr_pool_t *pool) 137{ 138 svn_auth_baton_t *ab; 139 svn_auth_provider_object_t *provider; 140 int i; 141 142 /* Build the auth_baton. */ 143 ab = apr_pcalloc(pool, sizeof(*ab)); 144 ab->tables = apr_hash_make(pool); 145 ab->parameters = apr_hash_make(pool); 146 /* ab->slave_parameters = NULL; */ 147 ab->creds_cache = apr_hash_make(pool); 148 ab->pool = pool; 149 150 /* Register each provider in order. Providers of different 151 credentials will be automatically sorted into different tables by 152 register_provider(). */ 153 for (i = 0; i < providers->nelts; i++) 154 { 155 provider_set_t *table; 156 provider = APR_ARRAY_IDX(providers, i, svn_auth_provider_object_t *); 157 158 /* Add it to the appropriate table in the auth_baton */ 159 table = svn_hash_gets(ab->tables, provider->vtable->cred_kind); 160 if (! table) 161 { 162 table = apr_pcalloc(pool, sizeof(*table)); 163 table->providers 164 = apr_array_make(pool, 1, sizeof(svn_auth_provider_object_t *)); 165 166 svn_hash_sets(ab->tables, provider->vtable->cred_kind, table); 167 } 168 APR_ARRAY_PUSH(table->providers, svn_auth_provider_object_t *) 169 = provider; 170 } 171 172 *auth_baton = ab; 173} 174 175/* Magic pointer value to allow storing 'NULL' in an apr_hash_t */ 176static const void *auth_NULL = NULL; 177 178void 179svn_auth_set_parameter(svn_auth_baton_t *auth_baton, 180 const char *name, 181 const void *value) 182{ 183 if (auth_baton) 184 { 185 if (auth_baton->slave_parameters) 186 { 187 if (!value) 188 value = &auth_NULL; 189 190 svn_hash_sets(auth_baton->slave_parameters, name, value); 191 } 192 else 193 svn_hash_sets(auth_baton->parameters, name, value); 194 } 195} 196 197const void * 198svn_auth_get_parameter(svn_auth_baton_t *auth_baton, 199 const char *name) 200{ 201 const void *value; 202 if (!auth_baton) 203 return NULL; 204 else if (!auth_baton->slave_parameters) 205 return svn_hash_gets(auth_baton->parameters, name); 206 207 value = svn_hash_gets(auth_baton->slave_parameters, name); 208 209 if (value) 210 return (value == &auth_NULL) ? NULL 211 : value; 212 213 return svn_hash_gets(auth_baton->parameters, name); 214} 215 216 217/* Return the key used to address the in-memory cache of auth 218 credentials of type CRED_KIND and associated with REALMSTRING. */ 219static const char * 220make_cache_key(const char *cred_kind, 221 const char *realmstring, 222 apr_pool_t *pool) 223{ 224 return apr_pstrcat(pool, cred_kind, ":", realmstring, SVN_VA_NULL); 225} 226 227svn_error_t * 228svn_auth_first_credentials(void **credentials, 229 svn_auth_iterstate_t **state, 230 const char *cred_kind, 231 const char *realmstring, 232 svn_auth_baton_t *auth_baton, 233 apr_pool_t *pool) 234{ 235 int i = 0; 236 provider_set_t *table; 237 svn_auth_provider_object_t *provider = NULL; 238 void *creds = NULL; 239 void *iter_baton = NULL; 240 svn_boolean_t got_first = FALSE; 241 svn_auth_iterstate_t *iterstate; 242 const char *cache_key; 243 apr_hash_t *parameters; 244 245 if (! auth_baton) 246 return svn_error_create(SVN_ERR_AUTHN_NO_PROVIDER, NULL, 247 _("No authentication providers registered")); 248 249 /* Get the appropriate table of providers for CRED_KIND. */ 250 table = svn_hash_gets(auth_baton->tables, cred_kind); 251 if (! table) 252 return svn_error_createf(SVN_ERR_AUTHN_NO_PROVIDER, NULL, 253 _("No provider registered for '%s' credentials"), 254 cred_kind); 255 256 if (auth_baton->slave_parameters) 257 { 258 apr_hash_index_t *hi; 259 parameters = apr_hash_copy(pool, auth_baton->parameters); 260 261 for (hi = apr_hash_first(pool, auth_baton->slave_parameters); 262 hi; 263 hi = apr_hash_next(hi)) 264 { 265 const void *value = apr_hash_this_val(hi); 266 267 if (value == &auth_NULL) 268 value = NULL; 269 270 svn_hash_sets(parameters, apr_hash_this_key(hi), value); 271 } 272 } 273 else 274 parameters = auth_baton->parameters; 275 276 /* First, see if we have cached creds in the auth_baton. */ 277 cache_key = make_cache_key(cred_kind, realmstring, pool); 278 creds = svn_hash_gets(auth_baton->creds_cache, cache_key); 279 if (creds) 280 { 281 got_first = FALSE; 282 } 283 else 284 /* If not, find a provider that can give "first" credentials. */ 285 { 286 /* Find a provider that can give "first" credentials. */ 287 for (i = 0; i < table->providers->nelts; i++) 288 { 289 provider = APR_ARRAY_IDX(table->providers, i, 290 svn_auth_provider_object_t *); 291 SVN_ERR(provider->vtable->first_credentials(&creds, &iter_baton, 292 provider->provider_baton, 293 parameters, 294 realmstring, 295 auth_baton->pool)); 296 297 if (creds != NULL) 298 { 299 got_first = TRUE; 300 break; 301 } 302 } 303 } 304 305 if (! creds) 306 { 307 *state = NULL; 308 } 309 else 310 { 311 /* Build an abstract iteration state. */ 312 iterstate = apr_pcalloc(pool, sizeof(*iterstate)); 313 iterstate->table = table; 314 iterstate->provider_idx = i; 315 iterstate->got_first = got_first; 316 iterstate->provider_iter_baton = iter_baton; 317 iterstate->realmstring = apr_pstrdup(pool, realmstring); 318 iterstate->cache_key = cache_key; 319 iterstate->auth_baton = auth_baton; 320 iterstate->parameters = parameters; 321 *state = iterstate; 322 323 /* Put the creds in the cache */ 324 svn_hash_sets(auth_baton->creds_cache, 325 apr_pstrdup(auth_baton->pool, cache_key), 326 creds); 327 } 328 329 *credentials = creds; 330 331 return SVN_NO_ERROR; 332} 333 334 335svn_error_t * 336svn_auth_next_credentials(void **credentials, 337 svn_auth_iterstate_t *state, 338 apr_pool_t *pool) 339{ 340 svn_auth_baton_t *auth_baton = state->auth_baton; 341 svn_auth_provider_object_t *provider; 342 provider_set_t *table = state->table; 343 void *creds = NULL; 344 345 /* Continue traversing the table from where we left off. */ 346 for (/* no init */; 347 state->provider_idx < table->providers->nelts; 348 state->provider_idx++) 349 { 350 provider = APR_ARRAY_IDX(table->providers, 351 state->provider_idx, 352 svn_auth_provider_object_t *); 353 if (! state->got_first) 354 { 355 SVN_ERR(provider->vtable->first_credentials( 356 &creds, &(state->provider_iter_baton), 357 provider->provider_baton, state->parameters, 358 state->realmstring, auth_baton->pool)); 359 state->got_first = TRUE; 360 } 361 else if (provider->vtable->next_credentials) 362 { 363 SVN_ERR(provider->vtable->next_credentials(&creds, 364 state->provider_iter_baton, 365 provider->provider_baton, 366 state->parameters, 367 state->realmstring, 368 auth_baton->pool)); 369 } 370 371 if (creds != NULL) 372 { 373 /* Put the creds in the cache */ 374 svn_hash_sets(auth_baton->creds_cache, 375 apr_pstrdup(auth_baton->pool, state->cache_key), 376 creds); 377 break; 378 } 379 380 state->got_first = FALSE; 381 } 382 383 *credentials = creds; 384 385 return SVN_NO_ERROR; 386} 387 388 389svn_error_t * 390svn_auth_save_credentials(svn_auth_iterstate_t *state, 391 apr_pool_t *pool) 392{ 393 int i; 394 svn_auth_provider_object_t *provider; 395 svn_boolean_t save_succeeded = FALSE; 396 const char *no_auth_cache; 397 svn_auth_baton_t *auth_baton; 398 void *creds; 399 400 if (! state || state->table->providers->nelts <= state->provider_idx) 401 return SVN_NO_ERROR; 402 403 auth_baton = state->auth_baton; 404 creds = svn_hash_gets(state->auth_baton->creds_cache, state->cache_key); 405 if (! creds) 406 return SVN_NO_ERROR; 407 408 /* Do not save the creds if SVN_AUTH_PARAM_NO_AUTH_CACHE is set */ 409 no_auth_cache = svn_hash_gets(state->parameters, 410 SVN_AUTH_PARAM_NO_AUTH_CACHE); 411 if (no_auth_cache) 412 return SVN_NO_ERROR; 413 414 /* First, try to save the creds using the provider that produced them. */ 415 provider = APR_ARRAY_IDX(state->table->providers, 416 state->provider_idx, 417 svn_auth_provider_object_t *); 418 if (provider->vtable->save_credentials) 419 SVN_ERR(provider->vtable->save_credentials(&save_succeeded, 420 creds, 421 provider->provider_baton, 422 state->parameters, 423 state->realmstring, 424 pool)); 425 if (save_succeeded) 426 return SVN_NO_ERROR; 427 428 /* Otherwise, loop from the top of the list, asking every provider 429 to attempt a save. ### todo: someday optimize so we don't 430 necessarily start from the top of the list. */ 431 for (i = 0; i < state->table->providers->nelts; i++) 432 { 433 provider = APR_ARRAY_IDX(state->table->providers, i, 434 svn_auth_provider_object_t *); 435 if (provider->vtable->save_credentials) 436 SVN_ERR(provider->vtable->save_credentials(&save_succeeded, creds, 437 provider->provider_baton, 438 state->parameters, 439 state->realmstring, 440 pool)); 441 442 if (save_succeeded) 443 break; 444 } 445 446 /* ### notice that at the moment, if no provider can save, there's 447 no way the caller will know. */ 448 449 return SVN_NO_ERROR; 450} 451 452 453svn_error_t * 454svn_auth_forget_credentials(svn_auth_baton_t *auth_baton, 455 const char *cred_kind, 456 const char *realmstring, 457 apr_pool_t *scratch_pool) 458{ 459 SVN_ERR_ASSERT((cred_kind && realmstring) || (!cred_kind && !realmstring)); 460 461 /* If we have a CRED_KIND and REALMSTRING, we clear out just the 462 cached item (if any). Otherwise, empty the whole hash. */ 463 if (cred_kind) 464 { 465 svn_hash_sets(auth_baton->creds_cache, 466 make_cache_key(cred_kind, realmstring, scratch_pool), 467 NULL); 468 } 469 else 470 { 471 apr_hash_clear(auth_baton->creds_cache); 472 } 473 474 return SVN_NO_ERROR; 475} 476 477 478svn_auth_ssl_server_cert_info_t * 479svn_auth_ssl_server_cert_info_dup 480 (const svn_auth_ssl_server_cert_info_t *info, apr_pool_t *pool) 481{ 482 svn_auth_ssl_server_cert_info_t *new_info 483 = apr_palloc(pool, sizeof(*new_info)); 484 485 *new_info = *info; 486 487 new_info->hostname = apr_pstrdup(pool, new_info->hostname); 488 new_info->fingerprint = apr_pstrdup(pool, new_info->fingerprint); 489 new_info->valid_from = apr_pstrdup(pool, new_info->valid_from); 490 new_info->valid_until = apr_pstrdup(pool, new_info->valid_until); 491 new_info->issuer_dname = apr_pstrdup(pool, new_info->issuer_dname); 492 new_info->ascii_cert = apr_pstrdup(pool, new_info->ascii_cert); 493 494 return new_info; 495} 496 497svn_error_t * 498svn_auth_get_platform_specific_provider(svn_auth_provider_object_t **provider, 499 const char *provider_name, 500 const char *provider_type, 501 apr_pool_t *pool) 502{ 503 *provider = NULL; 504 505 if (apr_strnatcmp(provider_name, "gnome_keyring") == 0 || 506 apr_strnatcmp(provider_name, "kwallet") == 0) 507 { 508#if defined(SVN_HAVE_GNOME_KEYRING) || defined(SVN_HAVE_KWALLET) 509 apr_dso_handle_t *dso; 510 apr_dso_handle_sym_t provider_function_symbol, version_function_symbol; 511 const char *library_label, *library_name; 512 const char *provider_function_name, *version_function_name; 513 library_name = apr_psprintf(pool, 514 "libsvn_auth_%s-%d.so.%d", 515 provider_name, 516 SVN_VER_MAJOR, SVN_SOVERSION); 517 library_label = apr_psprintf(pool, "svn_%s", provider_name); 518 provider_function_name = apr_psprintf(pool, 519 "svn_auth_get_%s_%s_provider", 520 provider_name, provider_type); 521 version_function_name = apr_psprintf(pool, 522 "svn_auth_%s_version", 523 provider_name); 524 SVN_ERR(svn_dso_load(&dso, library_name)); 525 if (dso) 526 { 527 if (apr_dso_sym(&version_function_symbol, 528 dso, 529 version_function_name) == 0) 530 { 531 svn_version_func_t version_function 532 = version_function_symbol; 533 svn_version_checklist_t check_list[2]; 534 535 check_list[0].label = library_label; 536 check_list[0].version_query = version_function; 537 check_list[1].label = NULL; 538 check_list[1].version_query = NULL; 539 SVN_ERR(svn_ver_check_list2(svn_subr_version(), check_list, 540 svn_ver_equal)); 541 } 542 if (apr_dso_sym(&provider_function_symbol, 543 dso, 544 provider_function_name) == 0) 545 { 546 if (strcmp(provider_type, "simple") == 0) 547 { 548 svn_auth_simple_provider_func_t provider_function 549 = provider_function_symbol; 550 provider_function(provider, pool); 551 } 552 else if (strcmp(provider_type, "ssl_client_cert_pw") == 0) 553 { 554 svn_auth_ssl_client_cert_pw_provider_func_t provider_function 555 = provider_function_symbol; 556 provider_function(provider, pool); 557 } 558 } 559 } 560#endif 561 } 562 else 563 { 564#if defined(SVN_HAVE_GPG_AGENT) 565 if (strcmp(provider_name, "gpg_agent") == 0 && 566 strcmp(provider_type, "simple") == 0) 567 { 568 svn_auth__get_gpg_agent_simple_provider(provider, pool); 569 } 570#endif 571#ifdef SVN_HAVE_KEYCHAIN_SERVICES 572 if (strcmp(provider_name, "keychain") == 0 && 573 strcmp(provider_type, "simple") == 0) 574 { 575 svn_auth__get_keychain_simple_provider(provider, pool); 576 } 577 else if (strcmp(provider_name, "keychain") == 0 && 578 strcmp(provider_type, "ssl_client_cert_pw") == 0) 579 { 580 svn_auth__get_keychain_ssl_client_cert_pw_provider(provider, pool); 581 } 582#endif 583 584#if defined(WIN32) && !defined(__MINGW32__) 585 if (strcmp(provider_name, "windows") == 0 && 586 strcmp(provider_type, "simple") == 0) 587 { 588 svn_auth__get_windows_simple_provider(provider, pool); 589 } 590 else if (strcmp(provider_name, "windows") == 0 && 591 strcmp(provider_type, "ssl_client_cert_pw") == 0) 592 { 593 svn_auth__get_windows_ssl_client_cert_pw_provider(provider, pool); 594 } 595 else if (strcmp(provider_name, "windows") == 0 && 596 strcmp(provider_type, "ssl_server_trust") == 0) 597 { 598 svn_auth__get_windows_ssl_server_trust_provider(provider, pool); 599 } 600 else if (strcmp(provider_name, "windows") == 0 && 601 strcmp(provider_type, "ssl_server_authority") == 0) 602 { 603 svn_auth__get_windows_ssl_server_authority_provider(provider, pool); 604 } 605#endif 606 } 607 608 return SVN_NO_ERROR; 609} 610 611svn_error_t * 612svn_auth_get_platform_specific_client_providers(apr_array_header_t **providers, 613 svn_config_t *config, 614 apr_pool_t *pool) 615{ 616 svn_auth_provider_object_t *provider; 617 const char *password_stores_config_option; 618 apr_array_header_t *password_stores; 619 int i; 620 621#define SVN__MAYBE_ADD_PROVIDER(list, p) \ 622 { if (p) APR_ARRAY_PUSH(list, svn_auth_provider_object_t *) = p; } 623 624#define SVN__DEFAULT_AUTH_PROVIDER_LIST \ 625 "gnome-keyring,kwallet,keychain,gpg-agent,windows-cryptoapi" 626 627 *providers = apr_array_make(pool, 12, sizeof(svn_auth_provider_object_t *)); 628 629 /* Fetch the configured list of password stores, and split them into 630 an array. */ 631 svn_config_get(config, 632 &password_stores_config_option, 633 SVN_CONFIG_SECTION_AUTH, 634 SVN_CONFIG_OPTION_PASSWORD_STORES, 635 SVN__DEFAULT_AUTH_PROVIDER_LIST); 636 password_stores = svn_cstring_split(password_stores_config_option, 637 " ,", TRUE, pool); 638 639 for (i = 0; i < password_stores->nelts; i++) 640 { 641 const char *password_store = APR_ARRAY_IDX(password_stores, i, 642 const char *); 643 644 /* GNOME Keyring */ 645 if (apr_strnatcmp(password_store, "gnome-keyring") == 0) 646 { 647 SVN_ERR(svn_auth_get_platform_specific_provider(&provider, 648 "gnome_keyring", 649 "simple", 650 pool)); 651 SVN__MAYBE_ADD_PROVIDER(*providers, provider); 652 653 SVN_ERR(svn_auth_get_platform_specific_provider(&provider, 654 "gnome_keyring", 655 "ssl_client_cert_pw", 656 pool)); 657 SVN__MAYBE_ADD_PROVIDER(*providers, provider); 658 } 659 /* GPG-AGENT */ 660 else if (apr_strnatcmp(password_store, "gpg-agent") == 0) 661 { 662 SVN_ERR(svn_auth_get_platform_specific_provider(&provider, 663 "gpg_agent", 664 "simple", 665 pool)); 666 SVN__MAYBE_ADD_PROVIDER(*providers, provider); 667 } 668 /* KWallet */ 669 else if (apr_strnatcmp(password_store, "kwallet") == 0) 670 { 671 SVN_ERR(svn_auth_get_platform_specific_provider(&provider, 672 "kwallet", 673 "simple", 674 pool)); 675 SVN__MAYBE_ADD_PROVIDER(*providers, provider); 676 677 SVN_ERR(svn_auth_get_platform_specific_provider(&provider, 678 "kwallet", 679 "ssl_client_cert_pw", 680 pool)); 681 SVN__MAYBE_ADD_PROVIDER(*providers, provider); 682 } 683 /* Keychain */ 684 else if (apr_strnatcmp(password_store, "keychain") == 0) 685 { 686 SVN_ERR(svn_auth_get_platform_specific_provider(&provider, 687 "keychain", 688 "simple", 689 pool)); 690 SVN__MAYBE_ADD_PROVIDER(*providers, provider); 691 692 SVN_ERR(svn_auth_get_platform_specific_provider(&provider, 693 "keychain", 694 "ssl_client_cert_pw", 695 pool)); 696 SVN__MAYBE_ADD_PROVIDER(*providers, provider); 697 } 698 /* Windows */ 699 else if (apr_strnatcmp(password_store, "windows-cryptoapi") == 0) 700 { 701 SVN_ERR(svn_auth_get_platform_specific_provider(&provider, 702 "windows", 703 "simple", 704 pool)); 705 SVN__MAYBE_ADD_PROVIDER(*providers, provider); 706 707 SVN_ERR(svn_auth_get_platform_specific_provider(&provider, 708 "windows", 709 "ssl_client_cert_pw", 710 pool)); 711 SVN__MAYBE_ADD_PROVIDER(*providers, provider); 712 } 713 } 714 715 /* Windows has two providers without a store to allow easy access to 716 SSL servers. We enable these unconditionally. 717 (This behavior was moved here from svn_cmdline_create_auth_baton()) */ 718 SVN_ERR(svn_auth_get_platform_specific_provider(&provider, 719 "windows", 720 "ssl_server_trust", 721 pool)); 722 SVN__MAYBE_ADD_PROVIDER(*providers, provider); 723 724 /* The windows ssl authority certificate CRYPTOAPI provider. */ 725 SVN_ERR(svn_auth_get_platform_specific_provider(&provider, 726 "windows", 727 "ssl_server_authority", 728 pool)); 729 730 SVN__MAYBE_ADD_PROVIDER(*providers, provider); 731 732 return SVN_NO_ERROR; 733} 734 735svn_error_t * 736svn_auth__make_session_auth(svn_auth_baton_t **session_auth_baton, 737 const svn_auth_baton_t *auth_baton, 738 apr_hash_t *config, 739 const char *server_name, 740 apr_pool_t *result_pool, 741 apr_pool_t *scratch_pool) 742{ 743 svn_boolean_t store_passwords = SVN_CONFIG_DEFAULT_OPTION_STORE_PASSWORDS; 744 svn_boolean_t store_auth_creds = SVN_CONFIG_DEFAULT_OPTION_STORE_AUTH_CREDS; 745 const char *store_plaintext_passwords 746 = SVN_CONFIG_DEFAULT_OPTION_STORE_PLAINTEXT_PASSWORDS; 747 svn_boolean_t store_pp = SVN_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP; 748 const char *store_pp_plaintext 749 = SVN_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT; 750 svn_config_t *servers = NULL; 751 const char *server_group = NULL; 752 753 struct svn_auth_baton_t *ab; 754 755 ab = apr_pmemdup(result_pool, auth_baton, sizeof(*ab)); 756 757 ab->slave_parameters = apr_hash_make(result_pool); 758 759 /* The 'store-passwords' and 'store-auth-creds' parameters used to 760 * live in SVN_CONFIG_CATEGORY_CONFIG. For backward compatibility, 761 * if values for these parameters have already been set by our 762 * callers, we use those values as defaults. 763 * 764 * Note that we can only catch the case where users explicitly set 765 * "store-passwords = no" or 'store-auth-creds = no". 766 * 767 * However, since the default value for both these options is 768 * currently (and has always been) "yes", users won't know 769 * the difference if they set "store-passwords = yes" or 770 * "store-auth-creds = yes" -- they'll get the expected behaviour. 771 */ 772 773 if (svn_auth_get_parameter(ab, 774 SVN_AUTH_PARAM_DONT_STORE_PASSWORDS) != NULL) 775 store_passwords = FALSE; 776 777 if (svn_auth_get_parameter(ab, 778 SVN_AUTH_PARAM_NO_AUTH_CACHE) != NULL) 779 store_auth_creds = FALSE; 780 781 /* All the svn_auth_set_parameter() calls below this not only affect the 782 to be created ra session, but also all the ra sessions that are already 783 use this auth baton! 784 785 Please try to key things based on the realm string instead of this 786 construct. 787 */ 788 789 if (config) 790 { 791 /* Grab the 'servers' config. */ 792 servers = svn_hash_gets(config, SVN_CONFIG_CATEGORY_SERVERS); 793 if (servers) 794 { 795 /* First, look in the global section. */ 796 797 SVN_ERR(svn_config_get_bool 798 (servers, &store_passwords, SVN_CONFIG_SECTION_GLOBAL, 799 SVN_CONFIG_OPTION_STORE_PASSWORDS, 800 store_passwords)); 801 802 SVN_ERR(svn_config_get_yes_no_ask 803 (servers, &store_plaintext_passwords, SVN_CONFIG_SECTION_GLOBAL, 804 SVN_CONFIG_OPTION_STORE_PLAINTEXT_PASSWORDS, 805 SVN_CONFIG_DEFAULT_OPTION_STORE_PLAINTEXT_PASSWORDS)); 806 807 SVN_ERR(svn_config_get_bool 808 (servers, &store_pp, SVN_CONFIG_SECTION_GLOBAL, 809 SVN_CONFIG_OPTION_STORE_SSL_CLIENT_CERT_PP, 810 store_pp)); 811 812 SVN_ERR(svn_config_get_yes_no_ask 813 (servers, &store_pp_plaintext, 814 SVN_CONFIG_SECTION_GLOBAL, 815 SVN_CONFIG_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT, 816 SVN_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT)); 817 818 SVN_ERR(svn_config_get_bool 819 (servers, &store_auth_creds, SVN_CONFIG_SECTION_GLOBAL, 820 SVN_CONFIG_OPTION_STORE_AUTH_CREDS, 821 store_auth_creds)); 822 823 /* Find out where we're about to connect to, and 824 * try to pick a server group based on the destination. */ 825 server_group = svn_config_find_group(servers, server_name, 826 SVN_CONFIG_SECTION_GROUPS, 827 scratch_pool); 828 829 if (server_group) 830 { 831 /* Override global auth caching parameters with the ones 832 * for the server group, if any. */ 833 SVN_ERR(svn_config_get_bool(servers, &store_auth_creds, 834 server_group, 835 SVN_CONFIG_OPTION_STORE_AUTH_CREDS, 836 store_auth_creds)); 837 838 SVN_ERR(svn_config_get_bool(servers, &store_passwords, 839 server_group, 840 SVN_CONFIG_OPTION_STORE_PASSWORDS, 841 store_passwords)); 842 843 SVN_ERR(svn_config_get_yes_no_ask 844 (servers, &store_plaintext_passwords, server_group, 845 SVN_CONFIG_OPTION_STORE_PLAINTEXT_PASSWORDS, 846 store_plaintext_passwords)); 847 848 SVN_ERR(svn_config_get_bool 849 (servers, &store_pp, 850 server_group, SVN_CONFIG_OPTION_STORE_SSL_CLIENT_CERT_PP, 851 store_pp)); 852 853 SVN_ERR(svn_config_get_yes_no_ask 854 (servers, &store_pp_plaintext, server_group, 855 SVN_CONFIG_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT, 856 store_pp_plaintext)); 857 } 858 } 859 } 860 861 /* Save auth caching parameters in the auth parameter hash. */ 862 if (! store_passwords) 863 svn_auth_set_parameter(ab, 864 SVN_AUTH_PARAM_DONT_STORE_PASSWORDS, ""); 865 866 svn_auth_set_parameter(ab, 867 SVN_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS, 868 store_plaintext_passwords); 869 870 if (! store_pp) 871 svn_auth_set_parameter(ab, 872 SVN_AUTH_PARAM_DONT_STORE_SSL_CLIENT_CERT_PP, 873 ""); 874 875 svn_auth_set_parameter(ab, 876 SVN_AUTH_PARAM_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT, 877 store_pp_plaintext); 878 879 if (! store_auth_creds) 880 svn_auth_set_parameter(ab, 881 SVN_AUTH_PARAM_NO_AUTH_CACHE, ""); 882 883 if (server_group) 884 svn_auth_set_parameter(ab, 885 SVN_AUTH_PARAM_SERVER_GROUP, 886 apr_pstrdup(ab->pool, server_group)); 887 888 *session_auth_baton = ab; 889 890 return SVN_NO_ERROR; 891} 892 893 894static svn_error_t * 895dummy_first_creds(void **credentials, 896 void **iter_baton, 897 void *provider_baton, 898 apr_hash_t *parameters, 899 const char *realmstring, 900 apr_pool_t *pool) 901{ 902 *credentials = NULL; 903 *iter_baton = NULL; 904 return SVN_NO_ERROR; 905} 906 907void 908svn_auth__get_dummmy_simple_provider(svn_auth_provider_object_t **provider, 909 apr_pool_t *pool) 910{ 911 static const svn_auth_provider_t vtable = { 912 SVN_AUTH_CRED_SIMPLE, 913 dummy_first_creds, 914 NULL, NULL 915 }; 916 917 svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po)); 918 919 po->vtable = &vtable; 920 *provider = po; 921} 922