]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/subversion/subversion/libsvn_subr/username_providers.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / subversion / subversion / libsvn_subr / username_providers.c
1 /*
2  * username_providers.c: providers for SVN_AUTH_CRED_USERNAME
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
26
27 \f
28 /*** Includes. ***/
29
30 #include <apr_pools.h>
31 #include "svn_hash.h"
32 #include "svn_auth.h"
33 #include "svn_error.h"
34 #include "svn_utf.h"
35 #include "svn_config.h"
36 #include "svn_user.h"
37
38 \f
39 /*-----------------------------------------------------------------------*/
40 /* File provider                                                         */
41 /*-----------------------------------------------------------------------*/
42
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"
46
47
48 \f
49 /*** Username-only Provider ***/
50 static svn_error_t *
51 username_first_creds(void **credentials,
52                      void **iter_baton,
53                      void *provider_baton,
54                      apr_hash_t *parameters,
55                      const char *realmstring,
56                      apr_pool_t *pool)
57 {
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;
63   svn_error_t *err;
64
65   /* If we don't have a usename yet, try the auth cache */
66   if (! username)
67     {
68       apr_hash_t *creds_hash = NULL;
69
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
74          next provider. */
75       err = svn_config_read_auth_data(&creds_hash, SVN_AUTH_CRED_USERNAME,
76                                       realmstring, config_dir, pool);
77       svn_error_clear(err);
78       if (! err && creds_hash)
79         {
80           svn_string_t *str = svn_hash_gets(creds_hash, AUTHN_USERNAME_KEY);
81           if (str && str->data)
82             username = str->data;
83         }
84     }
85
86   /* If that failed, ask the OS for the username */
87   if (! username)
88     username = svn_user_get_name(pool);
89
90   if (username)
91     {
92       svn_auth_cred_simple_t *creds = apr_pcalloc(pool, sizeof(*creds));
93       creds->username = username;
94       creds->may_save = may_save;
95       *credentials = creds;
96     }
97   else
98     *credentials = NULL;
99
100   *iter_baton = NULL;
101
102   return SVN_NO_ERROR;
103 }
104
105
106 static svn_error_t *
107 username_save_creds(svn_boolean_t *saved,
108                     void *credentials,
109                     void *provider_baton,
110                     apr_hash_t *parameters,
111                     const char *realmstring,
112                     apr_pool_t *pool)
113 {
114   svn_auth_cred_simple_t *creds = credentials;
115   apr_hash_t *creds_hash = NULL;
116   const char *config_dir;
117   svn_error_t *err;
118
119   *saved = FALSE;
120
121   if (! creds->may_save)
122     return SVN_NO_ERROR;
123
124   config_dir = svn_hash_gets(parameters, SVN_AUTH_PARAM_CONFIG_DIR);
125
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);
133   *saved = ! err;
134
135   return SVN_NO_ERROR;
136 }
137
138
139 static const svn_auth_provider_t username_provider = {
140   SVN_AUTH_CRED_USERNAME,
141   username_first_creds,
142   NULL,
143   username_save_creds
144 };
145
146
147 /* Public API */
148 void
149 svn_auth_get_username_provider(svn_auth_provider_object_t **provider,
150                                apr_pool_t *pool)
151 {
152   svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
153
154   po->vtable = &username_provider;
155   *provider = po;
156 }
157
158 \f
159 /*-----------------------------------------------------------------------*/
160 /* Prompt provider                                                       */
161 /*-----------------------------------------------------------------------*/
162
163 /* Baton type for username-only prompting. */
164 typedef struct username_prompt_provider_baton_t
165 {
166   svn_auth_username_prompt_func_t prompt_func;
167   void *prompt_baton;
168
169   /* how many times to re-prompt after the first one fails */
170   int retry_limit;
171 } username_prompt_provider_baton_t;
172
173
174 /* Iteration baton type for username-only prompting. */
175 typedef struct username_prompt_iter_baton_t
176 {
177   /* how many times we've reprompted */
178   int retries;
179
180 } username_prompt_iter_baton_t;
181
182 \f
183 /*** Helper Functions ***/
184 static svn_error_t *
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,
191                           apr_pool_t *pool)
192 {
193   const char *def_username = NULL;
194
195   *cred_p = NULL;
196
197   /* If we're allowed to check for default usernames, do so. */
198   if (first_time)
199     def_username = svn_hash_gets(parameters, SVN_AUTH_PARAM_DEFAULT_USERNAME);
200
201   /* If we have defaults, just build the cred here and return it.
202    *
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.
206    */
207   if (def_username)
208     {
209       *cred_p = apr_palloc(pool, sizeof(**cred_p));
210       (*cred_p)->username = apr_pstrdup(pool, def_username);
211       (*cred_p)->may_save = TRUE;
212     }
213   else
214     {
215       SVN_ERR(pb->prompt_func(cred_p, pb->prompt_baton, realmstring,
216                               may_save, pool));
217     }
218
219   return SVN_NO_ERROR;
220 }
221
222
223 /* Our first attempt will use any default username passed
224    in, and prompt for the remaining stuff. */
225 static svn_error_t *
226 username_prompt_first_creds(void **credentials_p,
227                             void **iter_baton,
228                             void *provider_baton,
229                             apr_hash_t *parameters,
230                             const char *realmstring,
231                             apr_pool_t *pool)
232 {
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);
237
238   SVN_ERR(prompt_for_username_creds
239           ((svn_auth_cred_username_t **) credentials_p, pb,
240            parameters, realmstring, TRUE, ! no_auth_cache, pool));
241
242   ibaton->retries = 0;
243   *iter_baton = ibaton;
244
245   return SVN_NO_ERROR;
246 }
247
248
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. */
252 static svn_error_t *
253 username_prompt_next_creds(void **credentials_p,
254                            void *iter_baton,
255                            void *provider_baton,
256                            apr_hash_t *parameters,
257                            const char *realmstring,
258                            apr_pool_t *pool)
259 {
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);
264
265   if ((pb->retry_limit >= 0) && (ib->retries >= pb->retry_limit))
266     {
267       /* give up, go on to next provider. */
268       *credentials_p = NULL;
269       return SVN_NO_ERROR;
270     }
271   ib->retries++;
272
273   return prompt_for_username_creds
274          ((svn_auth_cred_username_t **) credentials_p, pb,
275           parameters, realmstring, FALSE, ! no_auth_cache, pool);
276 }
277
278
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,
283   NULL,
284 };
285
286
287 /* Public API */
288 void
289 svn_auth_get_username_prompt_provider
290   (svn_auth_provider_object_t **provider,
291    svn_auth_username_prompt_func_t prompt_func,
292    void *prompt_baton,
293    int retry_limit,
294    apr_pool_t *pool)
295 {
296   svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
297   username_prompt_provider_baton_t *pb = apr_pcalloc(pool, sizeof(*pb));
298
299   pb->prompt_func = prompt_func;
300   pb->prompt_baton = prompt_baton;
301   pb->retry_limit = retry_limit;
302
303   po->vtable = &username_prompt_provider;
304   po->provider_baton = pb;
305   *provider = po;
306 }