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