2 * username_providers.c: providers for SVN_AUTH_CRED_USERNAME
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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
21 * ====================================================================
24 /* ==================================================================== */
30 #include <apr_pools.h>
33 #include "svn_error.h"
35 #include "svn_config.h"
39 /*-----------------------------------------------------------------------*/
41 /*-----------------------------------------------------------------------*/
43 /* The key that will be stored on disk. Serves the same role as similar
44 constants in other providers. */
45 #define AUTHN_USERNAME_KEY "username"
49 /*** Username-only Provider ***/
51 username_first_creds(void **credentials,
54 apr_hash_t *parameters,
55 const char *realmstring,
58 const char *config_dir = svn_hash_gets(parameters,
59 SVN_AUTH_PARAM_CONFIG_DIR);
60 const char *username = svn_hash_gets(parameters,
61 SVN_AUTH_PARAM_DEFAULT_USERNAME);
62 svn_boolean_t may_save = !! username;
65 /* If we don't have a usename yet, try the auth cache */
68 apr_hash_t *creds_hash = NULL;
70 /* Try to load credentials from a file on disk, based on the
71 realmstring. Don't throw an error, though: if something went
72 wrong reading the file, no big deal. What really matters is that
73 we failed to get the creds, so allow the auth system to try the
75 err = svn_config_read_auth_data(&creds_hash, SVN_AUTH_CRED_USERNAME,
76 realmstring, config_dir, pool);
78 if (! err && creds_hash)
80 svn_string_t *str = svn_hash_gets(creds_hash, AUTHN_USERNAME_KEY);
86 /* If that failed, ask the OS for the username */
88 username = svn_user_get_name(pool);
92 svn_auth_cred_simple_t *creds = apr_pcalloc(pool, sizeof(*creds));
93 creds->username = username;
94 creds->may_save = may_save;
107 username_save_creds(svn_boolean_t *saved,
109 void *provider_baton,
110 apr_hash_t *parameters,
111 const char *realmstring,
114 svn_auth_cred_simple_t *creds = credentials;
115 apr_hash_t *creds_hash = NULL;
116 const char *config_dir;
121 if (! creds->may_save)
124 config_dir = svn_hash_gets(parameters, SVN_AUTH_PARAM_CONFIG_DIR);
126 /* Put the credentials in a hash and save it to disk */
127 creds_hash = apr_hash_make(pool);
128 svn_hash_sets(creds_hash, AUTHN_USERNAME_KEY,
129 svn_string_create(creds->username, pool));
130 err = svn_config_write_auth_data(creds_hash, SVN_AUTH_CRED_USERNAME,
131 realmstring, config_dir, pool);
132 svn_error_clear(err);
139 static const svn_auth_provider_t username_provider = {
140 SVN_AUTH_CRED_USERNAME,
141 username_first_creds,
149 svn_auth_get_username_provider(svn_auth_provider_object_t **provider,
152 svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
154 po->vtable = &username_provider;
159 /*-----------------------------------------------------------------------*/
160 /* Prompt provider */
161 /*-----------------------------------------------------------------------*/
163 /* Baton type for username-only prompting. */
164 typedef struct username_prompt_provider_baton_t
166 svn_auth_username_prompt_func_t prompt_func;
169 /* how many times to re-prompt after the first one fails */
171 } username_prompt_provider_baton_t;
174 /* Iteration baton type for username-only prompting. */
175 typedef struct username_prompt_iter_baton_t
177 /* how many times we've reprompted */
180 } username_prompt_iter_baton_t;
183 /*** Helper Functions ***/
185 prompt_for_username_creds(svn_auth_cred_username_t **cred_p,
186 username_prompt_provider_baton_t *pb,
187 apr_hash_t *parameters,
188 const char *realmstring,
189 svn_boolean_t first_time,
190 svn_boolean_t may_save,
193 const char *def_username = NULL;
197 /* If we're allowed to check for default usernames, do so. */
199 def_username = svn_hash_gets(parameters, SVN_AUTH_PARAM_DEFAULT_USERNAME);
201 /* If we have defaults, just build the cred here and return it.
203 * ### I do wonder why this is here instead of in a separate
204 * ### 'defaults' provider that would run before the prompt
205 * ### provider... Hmmm.
209 *cred_p = apr_palloc(pool, sizeof(**cred_p));
210 (*cred_p)->username = apr_pstrdup(pool, def_username);
211 (*cred_p)->may_save = TRUE;
215 SVN_ERR(pb->prompt_func(cred_p, pb->prompt_baton, realmstring,
223 /* Our first attempt will use any default username passed
224 in, and prompt for the remaining stuff. */
226 username_prompt_first_creds(void **credentials_p,
228 void *provider_baton,
229 apr_hash_t *parameters,
230 const char *realmstring,
233 username_prompt_provider_baton_t *pb = provider_baton;
234 username_prompt_iter_baton_t *ibaton = apr_pcalloc(pool, sizeof(*ibaton));
235 const char *no_auth_cache = svn_hash_gets(parameters,
236 SVN_AUTH_PARAM_NO_AUTH_CACHE);
238 SVN_ERR(prompt_for_username_creds
239 ((svn_auth_cred_username_t **) credentials_p, pb,
240 parameters, realmstring, TRUE, ! no_auth_cache, pool));
243 *iter_baton = ibaton;
249 /* Subsequent attempts to fetch will ignore the default username
250 value, and simply re-prompt for the username, up to a maximum of
251 ib->pb->retry_limit. */
253 username_prompt_next_creds(void **credentials_p,
255 void *provider_baton,
256 apr_hash_t *parameters,
257 const char *realmstring,
260 username_prompt_iter_baton_t *ib = iter_baton;
261 username_prompt_provider_baton_t *pb = provider_baton;
262 const char *no_auth_cache = svn_hash_gets(parameters,
263 SVN_AUTH_PARAM_NO_AUTH_CACHE);
265 if ((pb->retry_limit >= 0) && (ib->retries >= pb->retry_limit))
267 /* give up, go on to next provider. */
268 *credentials_p = NULL;
273 return prompt_for_username_creds
274 ((svn_auth_cred_username_t **) credentials_p, pb,
275 parameters, realmstring, FALSE, ! no_auth_cache, pool);
279 static const svn_auth_provider_t username_prompt_provider = {
280 SVN_AUTH_CRED_USERNAME,
281 username_prompt_first_creds,
282 username_prompt_next_creds,
289 svn_auth_get_username_prompt_provider
290 (svn_auth_provider_object_t **provider,
291 svn_auth_username_prompt_func_t prompt_func,
296 svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
297 username_prompt_provider_baton_t *pb = apr_pcalloc(pool, sizeof(*pb));
299 pb->prompt_func = prompt_func;
300 pb->prompt_baton = prompt_baton;
301 pb->retry_limit = retry_limit;
303 po->vtable = &username_prompt_provider;
304 po->provider_baton = pb;