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