]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/subversion/subversion/libsvn_subr/username_providers.c
MFC r275385 (by bapt):
[FreeBSD/stable/10.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 /*** Username-only Provider ***/
44 static svn_error_t *
45 username_first_creds(void **credentials,
46                      void **iter_baton,
47                      void *provider_baton,
48                      apr_hash_t *parameters,
49                      const char *realmstring,
50                      apr_pool_t *pool)
51 {
52   const char *config_dir = svn_hash_gets(parameters,
53                                          SVN_AUTH_PARAM_CONFIG_DIR);
54   const char *username = svn_hash_gets(parameters,
55                                        SVN_AUTH_PARAM_DEFAULT_USERNAME);
56   svn_boolean_t may_save = !! username;
57   svn_error_t *err;
58
59   /* If we don't have a usename yet, try the auth cache */
60   if (! username)
61     {
62       apr_hash_t *creds_hash = NULL;
63
64       /* Try to load credentials from a file on disk, based on the
65          realmstring.  Don't throw an error, though: if something went
66          wrong reading the file, no big deal.  What really matters is that
67          we failed to get the creds, so allow the auth system to try the
68          next provider. */
69       err = svn_config_read_auth_data(&creds_hash, SVN_AUTH_CRED_USERNAME,
70                                       realmstring, config_dir, pool);
71       svn_error_clear(err);
72       if (! err && creds_hash)
73         {
74           svn_string_t *str = svn_hash_gets(creds_hash,
75                                             SVN_CONFIG_AUTHN_USERNAME_KEY);
76           if (str && str->data)
77             username = str->data;
78         }
79     }
80
81   /* If that failed, ask the OS for the username */
82   if (! username)
83     username = svn_user_get_name(pool);
84
85   if (username)
86     {
87       svn_auth_cred_simple_t *creds = apr_pcalloc(pool, sizeof(*creds));
88       creds->username = username;
89       creds->may_save = may_save;
90       *credentials = creds;
91     }
92   else
93     *credentials = NULL;
94
95   *iter_baton = NULL;
96
97   return SVN_NO_ERROR;
98 }
99
100
101 static svn_error_t *
102 username_save_creds(svn_boolean_t *saved,
103                     void *credentials,
104                     void *provider_baton,
105                     apr_hash_t *parameters,
106                     const char *realmstring,
107                     apr_pool_t *pool)
108 {
109   svn_auth_cred_simple_t *creds = credentials;
110   apr_hash_t *creds_hash = NULL;
111   const char *config_dir;
112   svn_error_t *err;
113
114   *saved = FALSE;
115
116   if (! creds->may_save)
117     return SVN_NO_ERROR;
118
119   config_dir = svn_hash_gets(parameters, SVN_AUTH_PARAM_CONFIG_DIR);
120
121   /* Put the credentials in a hash and save it to disk */
122   creds_hash = apr_hash_make(pool);
123   svn_hash_sets(creds_hash, SVN_CONFIG_AUTHN_USERNAME_KEY,
124                 svn_string_create(creds->username, pool));
125   err = svn_config_write_auth_data(creds_hash, SVN_AUTH_CRED_USERNAME,
126                                    realmstring, config_dir, pool);
127   svn_error_clear(err);
128   *saved = ! err;
129
130   return SVN_NO_ERROR;
131 }
132
133
134 static const svn_auth_provider_t username_provider = {
135   SVN_AUTH_CRED_USERNAME,
136   username_first_creds,
137   NULL,
138   username_save_creds
139 };
140
141
142 /* Public API */
143 void
144 svn_auth_get_username_provider(svn_auth_provider_object_t **provider,
145                                apr_pool_t *pool)
146 {
147   svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
148
149   po->vtable = &username_provider;
150   *provider = po;
151 }
152
153 \f
154 /*-----------------------------------------------------------------------*/
155 /* Prompt provider                                                       */
156 /*-----------------------------------------------------------------------*/
157
158 /* Baton type for username-only prompting. */
159 typedef struct username_prompt_provider_baton_t
160 {
161   svn_auth_username_prompt_func_t prompt_func;
162   void *prompt_baton;
163
164   /* how many times to re-prompt after the first one fails */
165   int retry_limit;
166 } username_prompt_provider_baton_t;
167
168
169 /* Iteration baton type for username-only prompting. */
170 typedef struct username_prompt_iter_baton_t
171 {
172   /* how many times we've reprompted */
173   int retries;
174
175 } username_prompt_iter_baton_t;
176
177 \f
178 /*** Helper Functions ***/
179 static svn_error_t *
180 prompt_for_username_creds(svn_auth_cred_username_t **cred_p,
181                           username_prompt_provider_baton_t *pb,
182                           apr_hash_t *parameters,
183                           const char *realmstring,
184                           svn_boolean_t first_time,
185                           svn_boolean_t may_save,
186                           apr_pool_t *pool)
187 {
188   const char *def_username = NULL;
189
190   *cred_p = NULL;
191
192   /* If we're allowed to check for default usernames, do so. */
193   if (first_time)
194     def_username = svn_hash_gets(parameters, SVN_AUTH_PARAM_DEFAULT_USERNAME);
195
196   /* If we have defaults, just build the cred here and return it.
197    *
198    * ### I do wonder why this is here instead of in a separate
199    * ### 'defaults' provider that would run before the prompt
200    * ### provider... Hmmm.
201    */
202   if (def_username)
203     {
204       *cred_p = apr_palloc(pool, sizeof(**cred_p));
205       (*cred_p)->username = apr_pstrdup(pool, def_username);
206       (*cred_p)->may_save = TRUE;
207     }
208   else
209     {
210       SVN_ERR(pb->prompt_func(cred_p, pb->prompt_baton, realmstring,
211                               may_save, pool));
212     }
213
214   return SVN_NO_ERROR;
215 }
216
217
218 /* Our first attempt will use any default username passed
219    in, and prompt for the remaining stuff. */
220 static svn_error_t *
221 username_prompt_first_creds(void **credentials_p,
222                             void **iter_baton,
223                             void *provider_baton,
224                             apr_hash_t *parameters,
225                             const char *realmstring,
226                             apr_pool_t *pool)
227 {
228   username_prompt_provider_baton_t *pb = provider_baton;
229   username_prompt_iter_baton_t *ibaton = apr_pcalloc(pool, sizeof(*ibaton));
230   const char *no_auth_cache = svn_hash_gets(parameters,
231                                             SVN_AUTH_PARAM_NO_AUTH_CACHE);
232
233   SVN_ERR(prompt_for_username_creds
234           ((svn_auth_cred_username_t **) credentials_p, pb,
235            parameters, realmstring, TRUE, ! no_auth_cache, pool));
236
237   ibaton->retries = 0;
238   *iter_baton = ibaton;
239
240   return SVN_NO_ERROR;
241 }
242
243
244 /* Subsequent attempts to fetch will ignore the default username
245    value, and simply re-prompt for the username, up to a maximum of
246    ib->pb->retry_limit. */
247 static svn_error_t *
248 username_prompt_next_creds(void **credentials_p,
249                            void *iter_baton,
250                            void *provider_baton,
251                            apr_hash_t *parameters,
252                            const char *realmstring,
253                            apr_pool_t *pool)
254 {
255   username_prompt_iter_baton_t *ib = iter_baton;
256   username_prompt_provider_baton_t *pb = provider_baton;
257   const char *no_auth_cache = svn_hash_gets(parameters,
258                                             SVN_AUTH_PARAM_NO_AUTH_CACHE);
259
260   if ((pb->retry_limit >= 0) && (ib->retries >= pb->retry_limit))
261     {
262       /* give up, go on to next provider. */
263       *credentials_p = NULL;
264       return SVN_NO_ERROR;
265     }
266   ib->retries++;
267
268   return prompt_for_username_creds
269          ((svn_auth_cred_username_t **) credentials_p, pb,
270           parameters, realmstring, FALSE, ! no_auth_cache, pool);
271 }
272
273
274 static const svn_auth_provider_t username_prompt_provider = {
275   SVN_AUTH_CRED_USERNAME,
276   username_prompt_first_creds,
277   username_prompt_next_creds,
278   NULL,
279 };
280
281
282 /* Public API */
283 void
284 svn_auth_get_username_prompt_provider
285   (svn_auth_provider_object_t **provider,
286    svn_auth_username_prompt_func_t prompt_func,
287    void *prompt_baton,
288    int retry_limit,
289    apr_pool_t *pool)
290 {
291   svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
292   username_prompt_provider_baton_t *pb = apr_pcalloc(pool, sizeof(*pb));
293
294   pb->prompt_func = prompt_func;
295   pb->prompt_baton = prompt_baton;
296   pb->retry_limit = retry_limit;
297
298   po->vtable = &username_prompt_provider;
299   po->provider_baton = pb;
300   *provider = po;
301 }