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