]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/subversion/subversion/libsvn_subr/simple_providers.c
MFC r275385 (by bapt):
[FreeBSD/stable/10.git] / contrib / subversion / subversion / libsvn_subr / simple_providers.c
1 /*
2  * simple_providers.c: providers for SVN_AUTH_CRED_SIMPLE
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_auth.h"
32 #include "svn_dirent_uri.h"
33 #include "svn_hash.h"
34 #include "svn_pools.h"
35 #include "svn_error.h"
36 #include "svn_utf.h"
37 #include "svn_config.h"
38 #include "svn_user.h"
39
40 #include "private/svn_auth_private.h"
41
42 #include "svn_private_config.h"
43
44 #include "auth.h"
45 \f
46 /*-----------------------------------------------------------------------*/
47 /* File provider                                                         */
48 /*-----------------------------------------------------------------------*/
49
50 /* Baton type for the simple provider. */
51 typedef struct simple_provider_baton_t
52 {
53   svn_auth_plaintext_prompt_func_t plaintext_prompt_func;
54   void *prompt_baton;
55   /* We cache the user's answer to the plaintext prompt, keyed
56    * by realm, in case we'll be called multiple times for the
57    * same realm. */
58   apr_hash_t *plaintext_answers;
59 } simple_provider_baton_t;
60
61 \f
62 /* Implementation of svn_auth__password_get_t that retrieves
63    the plaintext password from CREDS. */
64 svn_error_t *
65 svn_auth__simple_password_get(svn_boolean_t *done,
66                               const char **password,
67                               apr_hash_t *creds,
68                               const char *realmstring,
69                               const char *username,
70                               apr_hash_t *parameters,
71                               svn_boolean_t non_interactive,
72                               apr_pool_t *pool)
73 {
74   svn_string_t *str;
75
76   *done = FALSE;
77
78   str = svn_hash_gets(creds, SVN_CONFIG_AUTHN_USERNAME_KEY);
79   if (str && username && strcmp(str->data, username) == 0)
80     {
81       str = svn_hash_gets(creds, SVN_CONFIG_AUTHN_PASSWORD_KEY);
82       if (str && str->data)
83         {
84           *password = str->data;
85           *done = TRUE;
86         }
87     }
88
89   return SVN_NO_ERROR;
90 }
91
92 /* Implementation of svn_auth__password_set_t that stores
93    the plaintext password in CREDS. */
94 svn_error_t *
95 svn_auth__simple_password_set(svn_boolean_t *done,
96                               apr_hash_t *creds,
97                               const char *realmstring,
98                               const char *username,
99                               const char *password,
100                               apr_hash_t *parameters,
101                               svn_boolean_t non_interactive,
102                               apr_pool_t *pool)
103 {
104   svn_hash_sets(creds, SVN_CONFIG_AUTHN_PASSWORD_KEY,
105                 svn_string_create(password, pool));
106   *done = TRUE;
107
108   return SVN_NO_ERROR;
109 }
110
111 /* Set **USERNAME to the username retrieved from CREDS; ignore
112    other parameters. *USERNAME will have the same lifetime as CREDS. */
113 static svn_boolean_t
114 simple_username_get(const char **username,
115                     apr_hash_t *creds,
116                     const char *realmstring,
117                     svn_boolean_t non_interactive)
118 {
119   svn_string_t *str;
120   str = svn_hash_gets(creds, SVN_CONFIG_AUTHN_USERNAME_KEY);
121   if (str && str->data)
122     {
123       *username = str->data;
124       return TRUE;
125     }
126   return FALSE;
127 }
128
129
130 svn_error_t *
131 svn_auth__simple_creds_cache_get(void **credentials,
132                                  void **iter_baton,
133                                  void *provider_baton,
134                                  apr_hash_t *parameters,
135                                  const char *realmstring,
136                                  svn_auth__password_get_t password_get,
137                                  const char *passtype,
138                                  apr_pool_t *pool)
139 {
140   const char *config_dir = svn_hash_gets(parameters, SVN_AUTH_PARAM_CONFIG_DIR);
141   svn_config_t *cfg = svn_hash_gets(parameters,
142                                     SVN_AUTH_PARAM_CONFIG_CATEGORY_SERVERS);
143   const char *server_group = svn_hash_gets(parameters,
144                                            SVN_AUTH_PARAM_SERVER_GROUP);
145   const char *username = svn_hash_gets(parameters,
146                                        SVN_AUTH_PARAM_DEFAULT_USERNAME);
147   const char *password = svn_hash_gets(parameters,
148                                        SVN_AUTH_PARAM_DEFAULT_PASSWORD);
149   svn_boolean_t non_interactive = svn_hash_gets(parameters,
150                                                 SVN_AUTH_PARAM_NON_INTERACTIVE)
151       != NULL;
152   const char *default_username = NULL; /* Default username from cache. */
153   const char *default_password = NULL; /* Default password from cache. */
154
155   /* This checks if we should save the CREDS, iff saving the credentials is
156      allowed by the run-time configuration. */
157   svn_boolean_t need_to_save = FALSE;
158   apr_hash_t *creds_hash = NULL;
159   svn_error_t *err;
160   svn_string_t *str;
161
162   /* Try to load credentials from a file on disk, based on the
163      realmstring.  Don't throw an error, though: if something went
164      wrong reading the file, no big deal.  What really matters is that
165      we failed to get the creds, so allow the auth system to try the
166      next provider. */
167   err = svn_config_read_auth_data(&creds_hash, SVN_AUTH_CRED_SIMPLE,
168                                   realmstring, config_dir, pool);
169   if (err)
170     {
171       svn_error_clear(err);
172       err = NULL;
173     }
174   else if (creds_hash)
175     {
176       /* We have something in the auth cache for this realm. */
177       svn_boolean_t have_passtype = FALSE;
178
179       /* The password type in the auth data must match the
180          mangler's type, otherwise the password must be
181          interpreted by another provider. */
182       str = svn_hash_gets(creds_hash, SVN_CONFIG_AUTHN_PASSTYPE_KEY);
183       if (str && str->data)
184         if (passtype && (0 == strcmp(str->data, passtype)))
185           have_passtype = TRUE;
186
187       /* See if we need to save this username if it is not present in
188          auth cache. */
189       if (username)
190         {
191           if (!simple_username_get(&default_username, creds_hash, realmstring,
192                                    non_interactive))
193             {
194               need_to_save = TRUE;
195             }
196           else
197             {
198               if (strcmp(default_username, username) != 0)
199                 need_to_save = TRUE;
200             }
201         }
202
203       /* See if we need to save this password if it is not present in
204          auth cache. */
205       if (password)
206         {
207           if (have_passtype)
208             {
209               svn_boolean_t done;
210
211               SVN_ERR(password_get(&done, &default_password, creds_hash,
212                                    realmstring, username, parameters,
213                                    non_interactive, pool));
214               if (!done)
215                 {
216                   need_to_save = TRUE;
217                 }
218               else
219                 {
220                   if (strcmp(default_password, password) != 0)
221                     need_to_save = TRUE;
222                 }
223             }
224         }
225
226       /* If we don't have a username and a password yet, we try the
227          auth cache */
228       if (! (username && password))
229         {
230           if (! username)
231             if (!simple_username_get(&username, creds_hash, realmstring,
232                                      non_interactive))
233               username = NULL;
234
235           if (username && ! password)
236             {
237               if (! have_passtype)
238                 password = NULL;
239               else
240                 {
241                   svn_boolean_t done;
242
243                   SVN_ERR(password_get(&done, &password, creds_hash,
244                                        realmstring, username, parameters,
245                                        non_interactive, pool));
246                   if (!done)
247                     password = NULL;
248
249                   /* If the auth data didn't contain a password type,
250                      force a write to upgrade the format of the auth
251                      data file. */
252                   if (password && ! have_passtype)
253                     need_to_save = TRUE;
254                 }
255             }
256         }
257     }
258   else
259     {
260       /* Nothing was present in the auth cache, so indicate that these
261          credentials should be saved. */
262       need_to_save = TRUE;
263     }
264
265   /* If we don't have a username yet, check the 'servers' file */
266   if (! username)
267     {
268       username = svn_config_get_server_setting(cfg, server_group,
269                                                SVN_CONFIG_OPTION_USERNAME,
270                                                NULL);
271     }
272
273   /* Ask the OS for the username if we have a password but no
274      username. */
275   if (password && ! username)
276     username = svn_user_get_name(pool);
277
278   if (username && password)
279     {
280       svn_auth_cred_simple_t *creds = apr_pcalloc(pool, sizeof(*creds));
281       creds->username = username;
282       creds->password = password;
283       creds->may_save = need_to_save;
284       *credentials = creds;
285     }
286   else
287     *credentials = NULL;
288
289   *iter_baton = NULL;
290
291   return SVN_NO_ERROR;
292 }
293
294
295 svn_error_t *
296 svn_auth__simple_creds_cache_set(svn_boolean_t *saved,
297                                  void *credentials,
298                                  void *provider_baton,
299                                  apr_hash_t *parameters,
300                                  const char *realmstring,
301                                  svn_auth__password_set_t password_set,
302                                  const char *passtype,
303                                  apr_pool_t *pool)
304 {
305   svn_auth_cred_simple_t *creds = credentials;
306   apr_hash_t *creds_hash = NULL;
307   const char *config_dir;
308   svn_error_t *err;
309   svn_boolean_t dont_store_passwords =
310     svn_hash_gets(parameters, SVN_AUTH_PARAM_DONT_STORE_PASSWORDS) != NULL;
311   svn_boolean_t non_interactive = svn_hash_gets(parameters,
312                                                 SVN_AUTH_PARAM_NON_INTERACTIVE)
313       != NULL;
314   svn_boolean_t no_auth_cache =
315     (! creds->may_save) || (svn_hash_gets(parameters,
316                                           SVN_AUTH_PARAM_NO_AUTH_CACHE)
317                             != NULL);
318
319   /* Make sure we've been passed a passtype. */
320   SVN_ERR_ASSERT(passtype != NULL);
321
322   *saved = FALSE;
323
324   if (no_auth_cache)
325     return SVN_NO_ERROR;
326
327   config_dir = svn_hash_gets(parameters, SVN_AUTH_PARAM_CONFIG_DIR);
328
329   /* Put the username into the credentials hash. */
330   creds_hash = apr_hash_make(pool);
331   svn_hash_sets(creds_hash, SVN_CONFIG_AUTHN_USERNAME_KEY,
332                 svn_string_create(creds->username, pool));
333
334   /* Don't store passwords in any form if the user has told
335    * us not to do so. */
336   if (! dont_store_passwords)
337     {
338       svn_boolean_t may_save_password = FALSE;
339
340       /* If the password is going to be stored encrypted, go right
341        * ahead and store it to disk. Else determine whether saving
342        * in plaintext is OK. */
343       if (passtype &&
344            (strcmp(passtype, SVN_AUTH__WINCRYPT_PASSWORD_TYPE) == 0
345             || strcmp(passtype, SVN_AUTH__KEYCHAIN_PASSWORD_TYPE) == 0
346             || strcmp(passtype, SVN_AUTH__KWALLET_PASSWORD_TYPE) == 0
347             || strcmp(passtype, SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE) == 0
348             || strcmp(passtype, SVN_AUTH__GPG_AGENT_PASSWORD_TYPE) == 0))
349         {
350           may_save_password = TRUE;
351         }
352       else
353         {
354 #ifdef SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE
355           may_save_password = FALSE;
356 #else
357           const char *store_plaintext_passwords =
358             svn_hash_gets(parameters, SVN_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS);
359           simple_provider_baton_t *b =
360             (simple_provider_baton_t *)provider_baton;
361
362           if (store_plaintext_passwords
363               && svn_cstring_casecmp(store_plaintext_passwords,
364                                      SVN_CONFIG_ASK) == 0)
365             {
366               if (non_interactive)
367                 /* In non-interactive mode, the default behaviour is
368                  * to not store the password, because it is usually
369                  * passed on the command line. */
370                 may_save_password = FALSE;
371               else if (b->plaintext_prompt_func)
372                 {
373                   /* We're interactive, and the client provided a
374                    * prompt callback. So we can ask the user.
375                    *
376                    * Check for a cached answer before prompting. */
377                   svn_boolean_t *cached_answer;
378                   cached_answer = svn_hash_gets(b->plaintext_answers,
379                                                 realmstring);
380                   if (cached_answer != NULL)
381                     may_save_password = *cached_answer;
382                   else
383                     {
384                       apr_pool_t *cached_answer_pool;
385
386                       /* Nothing cached for this realm, prompt the user. */
387                       SVN_ERR((*b->plaintext_prompt_func)(&may_save_password,
388                                                           realmstring,
389                                                           b->prompt_baton,
390                                                           pool));
391
392                       /* Cache the user's answer in case we're called again
393                        * for the same realm.
394                        *
395                        * We allocate the answer cache in the hash table's pool
396                        * to make sure that is has the same life time as the
397                        * hash table itself. This means that the answer will
398                        * survive across RA sessions -- which is important,
399                        * because otherwise we'd prompt users once per RA session.
400                        */
401                       cached_answer_pool = apr_hash_pool_get(b->plaintext_answers);
402                       cached_answer = apr_palloc(cached_answer_pool,
403                                                  sizeof(svn_boolean_t));
404                       *cached_answer = may_save_password;
405                       svn_hash_sets(b->plaintext_answers, realmstring,
406                                     cached_answer);
407                     }
408                 }
409               else
410                 {
411                   /* TODO: We might want to default to not storing if the
412                    * prompt callback is NULL, i.e. have may_save_password
413                    * default to FALSE here, in order to force clients to
414                    * implement the callback.
415                    *
416                    * This would change the semantics of old API though.
417                    *
418                    * So for now, clients that don't implement the callback
419                    * and provide no explicit value for
420                    * SVN_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS
421                    * cause unencrypted passwords to be stored by default.
422                    * Needless to say, our own client is sane, but who knows
423                    * what other clients are doing.
424                    */
425                   may_save_password = TRUE;
426                 }
427             }
428           else if (store_plaintext_passwords
429                    && svn_cstring_casecmp(store_plaintext_passwords,
430                                           SVN_CONFIG_FALSE) == 0)
431             {
432               may_save_password = FALSE;
433             }
434           else if (!store_plaintext_passwords
435                    || svn_cstring_casecmp(store_plaintext_passwords,
436                                           SVN_CONFIG_TRUE) == 0)
437             {
438               may_save_password = TRUE;
439             }
440           else
441             {
442               return svn_error_createf
443                 (SVN_ERR_BAD_CONFIG_VALUE, NULL,
444                  _("Config error: invalid value '%s' for option '%s'"),
445                 store_plaintext_passwords,
446                 SVN_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS);
447             }
448 #endif
449         }
450
451       if (may_save_password)
452         {
453           SVN_ERR(password_set(saved, creds_hash, realmstring,
454                                creds->username, creds->password,
455                                parameters, non_interactive, pool));
456           if (*saved && passtype)
457             /* Store the password type with the auth data, so that we
458                know which provider owns the password. */
459             svn_hash_sets(creds_hash, SVN_CONFIG_AUTHN_PASSTYPE_KEY,
460                           svn_string_create(passtype, pool));
461         }
462     }
463
464   /* Save credentials to disk. */
465   err = svn_config_write_auth_data(creds_hash, SVN_AUTH_CRED_SIMPLE,
466                                    realmstring, config_dir, pool);
467   if (err)
468     *saved = FALSE;
469
470   /* ### return error? */
471   svn_error_clear(err);
472
473   return SVN_NO_ERROR;
474 }
475
476 /* Get cached (unencrypted) credentials from the simple provider's cache. */
477 static svn_error_t *
478 simple_first_creds(void **credentials,
479                    void **iter_baton,
480                    void *provider_baton,
481                    apr_hash_t *parameters,
482                    const char *realmstring,
483                    apr_pool_t *pool)
484 {
485   return svn_auth__simple_creds_cache_get(credentials, iter_baton,
486                                           provider_baton, parameters,
487                                           realmstring,
488                                           svn_auth__simple_password_get,
489                                           SVN_AUTH__SIMPLE_PASSWORD_TYPE,
490                                           pool);
491 }
492
493 /* Save (unencrypted) credentials to the simple provider's cache. */
494 static svn_error_t *
495 simple_save_creds(svn_boolean_t *saved,
496                   void *credentials,
497                   void *provider_baton,
498                   apr_hash_t *parameters,
499                   const char *realmstring,
500                   apr_pool_t *pool)
501 {
502   return svn_auth__simple_creds_cache_set(saved, credentials, provider_baton,
503                                           parameters, realmstring,
504                                           svn_auth__simple_password_set,
505                                           SVN_AUTH__SIMPLE_PASSWORD_TYPE,
506                                           pool);
507 }
508
509 static const svn_auth_provider_t simple_provider = {
510   SVN_AUTH_CRED_SIMPLE,
511   simple_first_creds,
512   NULL,
513   simple_save_creds
514 };
515
516
517 /* Public API */
518 void
519 svn_auth_get_simple_provider2
520   (svn_auth_provider_object_t **provider,
521    svn_auth_plaintext_prompt_func_t plaintext_prompt_func,
522    void* prompt_baton,
523    apr_pool_t *pool)
524 {
525   svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
526   simple_provider_baton_t *pb = apr_pcalloc(pool, sizeof(*pb));
527
528   pb->plaintext_prompt_func = plaintext_prompt_func;
529   pb->prompt_baton = prompt_baton;
530   pb->plaintext_answers = apr_hash_make(pool);
531
532   po->vtable = &simple_provider;
533   po->provider_baton = pb;
534   *provider = po;
535 }
536
537 \f
538 /*-----------------------------------------------------------------------*/
539 /* Prompt provider                                                       */
540 /*-----------------------------------------------------------------------*/
541
542 /* Baton type for username/password prompting. */
543 typedef struct simple_prompt_provider_baton_t
544 {
545   svn_auth_simple_prompt_func_t prompt_func;
546   void *prompt_baton;
547
548   /* how many times to re-prompt after the first one fails */
549   int retry_limit;
550 } simple_prompt_provider_baton_t;
551
552
553 /* Iteration baton type for username/password prompting. */
554 typedef struct simple_prompt_iter_baton_t
555 {
556   /* how many times we've reprompted */
557   int retries;
558 } simple_prompt_iter_baton_t;
559
560
561 \f
562 /*** Helper Functions ***/
563 static svn_error_t *
564 prompt_for_simple_creds(svn_auth_cred_simple_t **cred_p,
565                         simple_prompt_provider_baton_t *pb,
566                         apr_hash_t *parameters,
567                         const char *realmstring,
568                         svn_boolean_t first_time,
569                         svn_boolean_t may_save,
570                         apr_pool_t *pool)
571 {
572   const char *default_username = NULL;
573   const char *default_password = NULL;
574
575   *cred_p = NULL;
576
577   /* If we're allowed to check for default usernames and passwords, do
578      so. */
579   if (first_time)
580     {
581       default_username = svn_hash_gets(parameters,
582                                        SVN_AUTH_PARAM_DEFAULT_USERNAME);
583
584       /* No default username?  Try the auth cache. */
585       if (! default_username)
586         {
587           const char *config_dir = svn_hash_gets(parameters,
588                                                  SVN_AUTH_PARAM_CONFIG_DIR);
589           apr_hash_t *creds_hash = NULL;
590           svn_string_t *str;
591           svn_error_t *err;
592
593           err = svn_config_read_auth_data(&creds_hash, SVN_AUTH_CRED_SIMPLE,
594                                           realmstring, config_dir, pool);
595           svn_error_clear(err);
596           if (! err && creds_hash)
597             {
598               str = svn_hash_gets(creds_hash, SVN_CONFIG_AUTHN_USERNAME_KEY);
599               if (str && str->data)
600                 default_username = str->data;
601             }
602         }
603
604       /* Still no default username?  Try the 'servers' file. */
605       if (! default_username)
606         {
607           svn_config_t *cfg = svn_hash_gets(parameters,
608                                             SVN_AUTH_PARAM_CONFIG_CATEGORY_SERVERS);
609           const char *server_group = svn_hash_gets(parameters,
610                                                    SVN_AUTH_PARAM_SERVER_GROUP);
611           default_username =
612             svn_config_get_server_setting(cfg, server_group,
613                                           SVN_CONFIG_OPTION_USERNAME,
614                                           NULL);
615         }
616
617       /* Still no default username?  Try the UID. */
618       if (! default_username)
619         default_username = svn_user_get_name(pool);
620
621       default_password = svn_hash_gets(parameters,
622                                        SVN_AUTH_PARAM_DEFAULT_PASSWORD);
623     }
624
625   /* If we have defaults, just build the cred here and return it.
626    *
627    * ### I do wonder why this is here instead of in a separate
628    * ### 'defaults' provider that would run before the prompt
629    * ### provider... Hmmm.
630    */
631   if (default_username && default_password)
632     {
633       *cred_p = apr_palloc(pool, sizeof(**cred_p));
634       (*cred_p)->username = apr_pstrdup(pool, default_username);
635       (*cred_p)->password = apr_pstrdup(pool, default_password);
636       (*cred_p)->may_save = TRUE;
637     }
638   else
639     {
640       SVN_ERR(pb->prompt_func(cred_p, pb->prompt_baton, realmstring,
641                               default_username, may_save, pool));
642     }
643
644   return SVN_NO_ERROR;
645 }
646
647
648 /* Our first attempt will use any default username/password passed
649    in, and prompt for the remaining stuff. */
650 static svn_error_t *
651 simple_prompt_first_creds(void **credentials_p,
652                           void **iter_baton,
653                           void *provider_baton,
654                           apr_hash_t *parameters,
655                           const char *realmstring,
656                           apr_pool_t *pool)
657 {
658   simple_prompt_provider_baton_t *pb = provider_baton;
659   simple_prompt_iter_baton_t *ibaton = apr_pcalloc(pool, sizeof(*ibaton));
660   const char *no_auth_cache = svn_hash_gets(parameters,
661                                             SVN_AUTH_PARAM_NO_AUTH_CACHE);
662
663   SVN_ERR(prompt_for_simple_creds((svn_auth_cred_simple_t **) credentials_p,
664                                   pb, parameters, realmstring, TRUE,
665                                   ! no_auth_cache, pool));
666
667   ibaton->retries = 0;
668   *iter_baton = ibaton;
669
670   return SVN_NO_ERROR;
671 }
672
673
674 /* Subsequent attempts to fetch will ignore the default values, and
675    simply re-prompt for both, up to a maximum of ib->pb->retry_limit. */
676 static svn_error_t *
677 simple_prompt_next_creds(void **credentials_p,
678                          void *iter_baton,
679                          void *provider_baton,
680                          apr_hash_t *parameters,
681                          const char *realmstring,
682                          apr_pool_t *pool)
683 {
684   simple_prompt_iter_baton_t *ib = iter_baton;
685   simple_prompt_provider_baton_t *pb = provider_baton;
686   const char *no_auth_cache = svn_hash_gets(parameters,
687                                             SVN_AUTH_PARAM_NO_AUTH_CACHE);
688
689   if ((pb->retry_limit >= 0) && (ib->retries >= pb->retry_limit))
690     {
691       /* give up, go on to next provider. */
692       *credentials_p = NULL;
693       return SVN_NO_ERROR;
694     }
695   ib->retries++;
696
697   return prompt_for_simple_creds((svn_auth_cred_simple_t **) credentials_p,
698                                  pb, parameters, realmstring, FALSE,
699                                  ! no_auth_cache, pool);
700 }
701
702 static const svn_auth_provider_t simple_prompt_provider = {
703   SVN_AUTH_CRED_SIMPLE,
704   simple_prompt_first_creds,
705   simple_prompt_next_creds,
706   NULL,
707 };
708
709
710 /* Public API */
711 void
712 svn_auth_get_simple_prompt_provider
713   (svn_auth_provider_object_t **provider,
714    svn_auth_simple_prompt_func_t prompt_func,
715    void *prompt_baton,
716    int retry_limit,
717    apr_pool_t *pool)
718 {
719   svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
720   simple_prompt_provider_baton_t *pb = apr_pcalloc(pool, sizeof(*pb));
721
722   pb->prompt_func = prompt_func;
723   pb->prompt_baton = prompt_baton;
724   pb->retry_limit = retry_limit;
725
726   po->vtable = &simple_prompt_provider;
727   po->provider_baton = pb;
728   *provider = po;
729 }