Remove no-longer-used svn_*_get_mergeinfo_for_tree APIs.
[svn.git] / subversion / libsvn_subr / auth.c
blobcc062ba522f49b7b4fb909f84f1a7b91b8cde86c
1 /*
2 * auth.c: authentication support functions for Subversion
4 * ====================================================================
5 * Copyright (c) 2000-2007 CollabNet. All rights reserved.
7 * This software is licensed as described in the file COPYING, which
8 * you should have received as part of this distribution. The terms
9 * are also available at http://subversion.tigris.org/license-1.html.
10 * If newer versions of this license are posted there, you may use a
11 * newer version instead, at your option.
13 * This software consists of voluntary contributions made by many
14 * individuals. For exact contribution history, see the revision
15 * history and logs, available at http://subversion.tigris.org/.
16 * ====================================================================
20 #include <apr_pools.h>
21 #include <apr_tables.h>
22 #include <apr_strings.h>
24 #include "svn_types.h"
25 #include "svn_error.h"
26 #include "svn_auth.h"
28 /* The good way to think of this machinery is as a set of tables.
30 - Each type of credentials selects a single table.
32 - In a given table, each row is a 'provider' capable of returning
33 the same type of credentials. Each column represents a
34 provider's repeated attempts to provide credentials.
36 When the caller asks for a particular type of credentials, the
37 machinery in this file walks over the appropriate table. It starts
38 with the first provider (first row), and calls first_credentials()
39 to get the first set of credentials (first column). If the caller
40 is unhappy with the credentials, then each subsequent call to
41 next_credentials() traverses the row from left to right. If the
42 provider returns error at any point, then we go to the next provider
43 (row). We continue this way until every provider fails, or
44 until the client is happy with the returned credentials.
46 Note that the caller cannot see the table traversal, and thus has
47 no idea when we switch providers.
52 /* This effectively defines a single table. Every provider in this
53 array returns the same kind of credentials. */
54 typedef struct
56 /* ordered array of svn_auth_provider_object_t */
57 apr_array_header_t *providers;
59 } provider_set_t;
62 /* The main auth baton. */
63 struct svn_auth_baton_t
65 /* a collection of tables. maps cred_kind -> provider_set */
66 apr_hash_t *tables;
68 /* the pool I'm allocated in. */
69 apr_pool_t *pool;
71 /* run-time parameters needed by providers. */
72 apr_hash_t *parameters;
74 /* run-time credentials cache. */
75 apr_hash_t *creds_cache;
79 /* Abstracted iteration baton */
80 struct svn_auth_iterstate_t
82 provider_set_t *table; /* the table being searched */
83 int provider_idx; /* the current provider (row) */
84 svn_boolean_t got_first; /* did we get the provider's first creds? */
85 void *provider_iter_baton; /* the provider's own iteration context */
86 const char *realmstring; /* The original realmstring passed in */
87 const char *cache_key; /* key to use in auth_baton's creds_cache */
88 svn_auth_baton_t *auth_baton; /* the original auth_baton. */
93 void
94 svn_auth_open(svn_auth_baton_t **auth_baton,
95 apr_array_header_t *providers,
96 apr_pool_t *pool)
98 svn_auth_baton_t *ab;
99 svn_auth_provider_object_t *provider;
100 int i;
102 /* Build the auth_baton. */
103 ab = apr_pcalloc(pool, sizeof(*ab));
104 ab->tables = apr_hash_make(pool);
105 ab->parameters = apr_hash_make(pool);
106 ab->creds_cache = apr_hash_make(pool);
107 ab->pool = pool;
109 /* Register each provider in order. Providers of different
110 credentials will be automatically sorted into different tables by
111 register_provider(). */
112 for (i = 0; i < providers->nelts; i++)
114 provider_set_t *table;
115 provider = APR_ARRAY_IDX(providers, i, svn_auth_provider_object_t *);
117 /* Add it to the appropriate table in the auth_baton */
118 table = apr_hash_get(ab->tables,
119 provider->vtable->cred_kind, APR_HASH_KEY_STRING);
120 if (! table)
122 table = apr_pcalloc(pool, sizeof(*table));
123 table->providers
124 = apr_array_make(pool, 1, sizeof(svn_auth_provider_object_t *));
126 apr_hash_set(ab->tables,
127 provider->vtable->cred_kind, APR_HASH_KEY_STRING,
128 table);
130 APR_ARRAY_PUSH(table->providers, svn_auth_provider_object_t *)
131 = provider;
134 *auth_baton = ab;
139 void
140 svn_auth_set_parameter(svn_auth_baton_t *auth_baton,
141 const char *name,
142 const void *value)
144 apr_hash_set(auth_baton->parameters, name, APR_HASH_KEY_STRING, value);
147 const void *
148 svn_auth_get_parameter(svn_auth_baton_t *auth_baton,
149 const char *name)
151 return apr_hash_get(auth_baton->parameters, name, APR_HASH_KEY_STRING);
156 svn_error_t *
157 svn_auth_first_credentials(void **credentials,
158 svn_auth_iterstate_t **state,
159 const char *cred_kind,
160 const char *realmstring,
161 svn_auth_baton_t *auth_baton,
162 apr_pool_t *pool)
164 int i = 0;
165 provider_set_t *table;
166 svn_auth_provider_object_t *provider = NULL;
167 void *creds = NULL;
168 void *iter_baton = NULL;
169 svn_boolean_t got_first = FALSE;
170 svn_auth_iterstate_t *iterstate;
171 const char *cache_key;
173 /* Get the appropriate table of providers for CRED_KIND. */
174 table = apr_hash_get(auth_baton->tables, cred_kind, APR_HASH_KEY_STRING);
175 if (! table)
176 return svn_error_createf(SVN_ERR_AUTHN_NO_PROVIDER, NULL,
177 "No provider registered for '%s' credentials",
178 cred_kind);
180 /* First, see if we have cached creds in the auth_baton. */
181 cache_key = apr_pstrcat(pool, cred_kind, ":", realmstring, NULL);
182 creds = apr_hash_get(auth_baton->creds_cache,
183 cache_key, APR_HASH_KEY_STRING);
184 if (creds)
186 got_first = FALSE;
188 else
189 /* If not, find a provider that can give "first" credentials. */
191 /* Find a provider that can give "first" credentials. */
192 for (i = 0; i < table->providers->nelts; i++)
194 provider = APR_ARRAY_IDX(table->providers, i,
195 svn_auth_provider_object_t *);
196 SVN_ERR(provider->vtable->first_credentials
197 (&creds, &iter_baton, provider->provider_baton,
198 auth_baton->parameters, realmstring, auth_baton->pool));
200 if (creds != NULL)
202 got_first = TRUE;
203 break;
208 if (! creds)
209 *state = NULL;
210 else
212 /* Build an abstract iteration state. */
213 iterstate = apr_pcalloc(pool, sizeof(*iterstate));
214 iterstate->table = table;
215 iterstate->provider_idx = i;
216 iterstate->got_first = got_first;
217 iterstate->provider_iter_baton = iter_baton;
218 iterstate->realmstring = apr_pstrdup(pool, realmstring);
219 iterstate->cache_key = cache_key;
220 iterstate->auth_baton = auth_baton;
221 *state = iterstate;
223 /* Put the creds in the cache */
224 apr_hash_set(auth_baton->creds_cache,
225 apr_pstrdup(auth_baton->pool, cache_key),
226 APR_HASH_KEY_STRING,
227 creds);
230 *credentials = creds;
232 return SVN_NO_ERROR;
236 svn_error_t *
237 svn_auth_next_credentials(void **credentials,
238 svn_auth_iterstate_t *state,
239 apr_pool_t *pool)
241 svn_auth_baton_t *auth_baton = state->auth_baton;
242 svn_auth_provider_object_t *provider;
243 provider_set_t *table = state->table;
244 void *creds = NULL;
246 /* Continue traversing the table from where we left off. */
247 for (/* no init */;
248 state->provider_idx < table->providers->nelts;
249 state->provider_idx++)
251 provider = APR_ARRAY_IDX(table->providers,
252 state->provider_idx,
253 svn_auth_provider_object_t *);
254 if (! state->got_first)
256 SVN_ERR(provider->vtable->first_credentials
257 (&creds, &(state->provider_iter_baton),
258 provider->provider_baton, auth_baton->parameters,
259 state->realmstring, auth_baton->pool));
260 state->got_first = TRUE;
262 else
264 if (provider->vtable->next_credentials)
265 SVN_ERR(provider->vtable->next_credentials
266 (&creds, state->provider_iter_baton,
267 provider->provider_baton, auth_baton->parameters,
268 state->realmstring, auth_baton->pool));
271 if (creds != NULL)
273 /* Put the creds in the cache */
274 apr_hash_set(auth_baton->creds_cache,
275 state->cache_key, APR_HASH_KEY_STRING,
276 creds);
277 break;
280 state->got_first = FALSE;
283 *credentials = creds;
285 return SVN_NO_ERROR;
289 svn_error_t *
290 svn_auth_save_credentials(svn_auth_iterstate_t *state,
291 apr_pool_t *pool)
293 int i;
294 svn_auth_provider_object_t *provider;
295 svn_boolean_t save_succeeded = FALSE;
296 const char *no_auth_cache;
297 svn_auth_baton_t *auth_baton;
298 void *creds;
300 if (! state || state->table->providers->nelts <= state->provider_idx)
301 return SVN_NO_ERROR;
303 auth_baton = state->auth_baton;
304 creds = apr_hash_get(state->auth_baton->creds_cache,
305 state->cache_key, APR_HASH_KEY_STRING);
306 if (! creds)
307 return SVN_NO_ERROR;
309 /* Do not save the creds if SVN_AUTH_PARAM_NO_AUTH_CACHE is set */
310 no_auth_cache = apr_hash_get(auth_baton->parameters,
311 SVN_AUTH_PARAM_NO_AUTH_CACHE,
312 APR_HASH_KEY_STRING);
313 if (no_auth_cache)
314 return SVN_NO_ERROR;
316 /* First, try to save the creds using the provider that produced them. */
317 provider = APR_ARRAY_IDX(state->table->providers,
318 state->provider_idx,
319 svn_auth_provider_object_t *);
320 if (provider->vtable->save_credentials)
321 SVN_ERR(provider->vtable->save_credentials(&save_succeeded,
322 creds,
323 provider->provider_baton,
324 auth_baton->parameters,
325 state->realmstring,
326 pool));
327 if (save_succeeded)
328 return SVN_NO_ERROR;
330 /* Otherwise, loop from the top of the list, asking every provider
331 to attempt a save. ### todo: someday optimize so we don't
332 necessarily start from the top of the list. */
333 for (i = 0; i < state->table->providers->nelts; i++)
335 provider = APR_ARRAY_IDX(state->table->providers, i,
336 svn_auth_provider_object_t *);
337 if (provider->vtable->save_credentials)
338 SVN_ERR(provider->vtable->save_credentials
339 (&save_succeeded, creds,
340 provider->provider_baton, auth_baton->parameters,
341 state->realmstring, pool));
343 if (save_succeeded)
344 break;
347 /* ### notice that at the moment, if no provider can save, there's
348 no way the caller will know. */
350 return SVN_NO_ERROR;
353 svn_auth_ssl_server_cert_info_t *
354 svn_auth_ssl_server_cert_info_dup
355 (const svn_auth_ssl_server_cert_info_t *info, apr_pool_t *pool)
357 svn_auth_ssl_server_cert_info_t *new_info
358 = apr_palloc(pool, sizeof(*new_info));
360 *new_info = *info;
362 new_info->hostname = apr_pstrdup(pool, new_info->hostname);
363 new_info->fingerprint = apr_pstrdup(pool, new_info->fingerprint);
364 new_info->valid_from = apr_pstrdup(pool, new_info->valid_from);
365 new_info->valid_until = apr_pstrdup(pool, new_info->valid_until);
366 new_info->issuer_dname = apr_pstrdup(pool, new_info->issuer_dname);
367 new_info->ascii_cert = apr_pstrdup(pool, new_info->ascii_cert);
369 return new_info;