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 : 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. */
218 static const char *
make_cache_key(const char * cred_kind,const char * realmstring,apr_pool_t * pool)219 make_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
226 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)227 svn_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
334 svn_error_t *
svn_auth_next_credentials(void ** credentials,svn_auth_iterstate_t * state,apr_pool_t * pool)335 svn_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
388 svn_error_t *
svn_auth_save_credentials(svn_auth_iterstate_t * state,apr_pool_t * pool)389 svn_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
450 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)451 svn_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
475 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)476 svn_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
494 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)495 svn_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
608 svn_error_t *
svn_auth_get_platform_specific_client_providers(apr_array_header_t ** providers,svn_config_t * config,apr_pool_t * pool)609 svn_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
732 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)733 svn_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
887 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)888 dummy_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
900 void
svn_auth__get_dummmy_simple_provider(svn_auth_provider_object_t ** provider,apr_pool_t * pool)901 svn_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