1251881Speter/* 2251881Speter * simple_providers.c: providers for SVN_AUTH_CRED_SIMPLE 3251881Speter * 4251881Speter * ==================================================================== 5251881Speter * Licensed to the Apache Software Foundation (ASF) under one 6251881Speter * or more contributor license agreements. See the NOTICE file 7251881Speter * distributed with this work for additional information 8251881Speter * regarding copyright ownership. The ASF licenses this file 9251881Speter * to you under the Apache License, Version 2.0 (the 10251881Speter * "License"); you may not use this file except in compliance 11251881Speter * with the License. You may obtain a copy of the License at 12251881Speter * 13251881Speter * http://www.apache.org/licenses/LICENSE-2.0 14251881Speter * 15251881Speter * Unless required by applicable law or agreed to in writing, 16251881Speter * software distributed under the License is distributed on an 17251881Speter * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18251881Speter * KIND, either express or implied. See the License for the 19251881Speter * specific language governing permissions and limitations 20251881Speter * under the License. 21251881Speter * ==================================================================== 22251881Speter */ 23251881Speter 24251881Speter/* ==================================================================== */ 25251881Speter 26251881Speter 27251881Speter 28251881Speter/*** Includes. ***/ 29251881Speter 30251881Speter#include <apr_pools.h> 31251881Speter#include "svn_auth.h" 32251881Speter#include "svn_dirent_uri.h" 33251881Speter#include "svn_hash.h" 34251881Speter#include "svn_pools.h" 35251881Speter#include "svn_error.h" 36251881Speter#include "svn_utf.h" 37251881Speter#include "svn_config.h" 38251881Speter#include "svn_user.h" 39251881Speter 40251881Speter#include "private/svn_auth_private.h" 41251881Speter 42251881Speter#include "svn_private_config.h" 43251881Speter 44251881Speter#include "auth.h" 45251881Speter 46251881Speter/*-----------------------------------------------------------------------*/ 47251881Speter/* File provider */ 48251881Speter/*-----------------------------------------------------------------------*/ 49251881Speter 50251881Speter/* The keys that will be stored on disk. These serve the same role as 51251881Speter similar constants in other providers. */ 52251881Speter#define AUTHN_USERNAME_KEY "username" 53251881Speter#define AUTHN_PASSWORD_KEY "password" 54251881Speter#define AUTHN_PASSTYPE_KEY "passtype" 55251881Speter 56251881Speter/* Baton type for the simple provider. */ 57251881Spetertypedef struct simple_provider_baton_t 58251881Speter{ 59251881Speter svn_auth_plaintext_prompt_func_t plaintext_prompt_func; 60251881Speter void *prompt_baton; 61251881Speter /* We cache the user's answer to the plaintext prompt, keyed 62251881Speter * by realm, in case we'll be called multiple times for the 63251881Speter * same realm. */ 64251881Speter apr_hash_t *plaintext_answers; 65251881Speter} simple_provider_baton_t; 66251881Speter 67251881Speter 68251881Speter/* Implementation of svn_auth__password_get_t that retrieves 69251881Speter the plaintext password from CREDS. */ 70251881Spetersvn_error_t * 71251881Spetersvn_auth__simple_password_get(svn_boolean_t *done, 72251881Speter const char **password, 73251881Speter apr_hash_t *creds, 74251881Speter const char *realmstring, 75251881Speter const char *username, 76251881Speter apr_hash_t *parameters, 77251881Speter svn_boolean_t non_interactive, 78251881Speter apr_pool_t *pool) 79251881Speter{ 80251881Speter svn_string_t *str; 81251881Speter 82251881Speter *done = FALSE; 83251881Speter 84251881Speter str = svn_hash_gets(creds, AUTHN_USERNAME_KEY); 85251881Speter if (str && username && strcmp(str->data, username) == 0) 86251881Speter { 87251881Speter str = svn_hash_gets(creds, AUTHN_PASSWORD_KEY); 88251881Speter if (str && str->data) 89251881Speter { 90251881Speter *password = str->data; 91251881Speter *done = TRUE; 92251881Speter } 93251881Speter } 94251881Speter 95251881Speter return SVN_NO_ERROR; 96251881Speter} 97251881Speter 98251881Speter/* Implementation of svn_auth__password_set_t that stores 99251881Speter the plaintext password in CREDS. */ 100251881Spetersvn_error_t * 101251881Spetersvn_auth__simple_password_set(svn_boolean_t *done, 102251881Speter apr_hash_t *creds, 103251881Speter const char *realmstring, 104251881Speter const char *username, 105251881Speter const char *password, 106251881Speter apr_hash_t *parameters, 107251881Speter svn_boolean_t non_interactive, 108251881Speter apr_pool_t *pool) 109251881Speter{ 110251881Speter svn_hash_sets(creds, AUTHN_PASSWORD_KEY, svn_string_create(password, pool)); 111251881Speter *done = TRUE; 112251881Speter 113251881Speter return SVN_NO_ERROR; 114251881Speter} 115251881Speter 116251881Speter/* Set **USERNAME to the username retrieved from CREDS; ignore 117251881Speter other parameters. *USERNAME will have the same lifetime as CREDS. */ 118251881Speterstatic svn_boolean_t 119251881Spetersimple_username_get(const char **username, 120251881Speter apr_hash_t *creds, 121251881Speter const char *realmstring, 122251881Speter svn_boolean_t non_interactive) 123251881Speter{ 124251881Speter svn_string_t *str; 125251881Speter str = svn_hash_gets(creds, AUTHN_USERNAME_KEY); 126251881Speter if (str && str->data) 127251881Speter { 128251881Speter *username = str->data; 129251881Speter return TRUE; 130251881Speter } 131251881Speter return FALSE; 132251881Speter} 133251881Speter 134251881Speter 135251881Spetersvn_error_t * 136251881Spetersvn_auth__simple_creds_cache_get(void **credentials, 137251881Speter void **iter_baton, 138251881Speter void *provider_baton, 139251881Speter apr_hash_t *parameters, 140251881Speter const char *realmstring, 141251881Speter svn_auth__password_get_t password_get, 142251881Speter const char *passtype, 143251881Speter apr_pool_t *pool) 144251881Speter{ 145251881Speter const char *config_dir = svn_hash_gets(parameters, SVN_AUTH_PARAM_CONFIG_DIR); 146251881Speter svn_config_t *cfg = svn_hash_gets(parameters, 147251881Speter SVN_AUTH_PARAM_CONFIG_CATEGORY_SERVERS); 148251881Speter const char *server_group = svn_hash_gets(parameters, 149251881Speter SVN_AUTH_PARAM_SERVER_GROUP); 150251881Speter const char *username = svn_hash_gets(parameters, 151251881Speter SVN_AUTH_PARAM_DEFAULT_USERNAME); 152251881Speter const char *password = svn_hash_gets(parameters, 153251881Speter SVN_AUTH_PARAM_DEFAULT_PASSWORD); 154251881Speter svn_boolean_t non_interactive = svn_hash_gets(parameters, 155251881Speter SVN_AUTH_PARAM_NON_INTERACTIVE) 156251881Speter != NULL; 157251881Speter const char *default_username = NULL; /* Default username from cache. */ 158251881Speter const char *default_password = NULL; /* Default password from cache. */ 159251881Speter 160251881Speter /* This checks if we should save the CREDS, iff saving the credentials is 161251881Speter allowed by the run-time configuration. */ 162251881Speter svn_boolean_t need_to_save = FALSE; 163251881Speter apr_hash_t *creds_hash = NULL; 164251881Speter svn_error_t *err; 165251881Speter svn_string_t *str; 166251881Speter 167251881Speter /* Try to load credentials from a file on disk, based on the 168251881Speter realmstring. Don't throw an error, though: if something went 169251881Speter wrong reading the file, no big deal. What really matters is that 170251881Speter we failed to get the creds, so allow the auth system to try the 171251881Speter next provider. */ 172251881Speter err = svn_config_read_auth_data(&creds_hash, SVN_AUTH_CRED_SIMPLE, 173251881Speter realmstring, config_dir, pool); 174251881Speter if (err) 175251881Speter { 176251881Speter svn_error_clear(err); 177251881Speter err = NULL; 178251881Speter } 179251881Speter else if (creds_hash) 180251881Speter { 181251881Speter /* We have something in the auth cache for this realm. */ 182251881Speter svn_boolean_t have_passtype = FALSE; 183251881Speter 184251881Speter /* The password type in the auth data must match the 185251881Speter mangler's type, otherwise the password must be 186251881Speter interpreted by another provider. */ 187251881Speter str = svn_hash_gets(creds_hash, AUTHN_PASSTYPE_KEY); 188251881Speter if (str && str->data) 189251881Speter if (passtype && (0 == strcmp(str->data, passtype))) 190251881Speter have_passtype = TRUE; 191251881Speter 192251881Speter /* See if we need to save this username if it is not present in 193251881Speter auth cache. */ 194251881Speter if (username) 195251881Speter { 196251881Speter if (!simple_username_get(&default_username, creds_hash, realmstring, 197251881Speter non_interactive)) 198251881Speter { 199251881Speter need_to_save = TRUE; 200251881Speter } 201251881Speter else 202251881Speter { 203251881Speter if (strcmp(default_username, username) != 0) 204251881Speter need_to_save = TRUE; 205251881Speter } 206251881Speter } 207251881Speter 208251881Speter /* See if we need to save this password if it is not present in 209251881Speter auth cache. */ 210251881Speter if (password) 211251881Speter { 212251881Speter if (have_passtype) 213251881Speter { 214251881Speter svn_boolean_t done; 215251881Speter 216251881Speter SVN_ERR(password_get(&done, &default_password, creds_hash, 217251881Speter realmstring, username, parameters, 218251881Speter non_interactive, pool)); 219251881Speter if (!done) 220251881Speter { 221251881Speter need_to_save = TRUE; 222251881Speter } 223251881Speter else 224251881Speter { 225251881Speter if (strcmp(default_password, password) != 0) 226251881Speter need_to_save = TRUE; 227251881Speter } 228251881Speter } 229251881Speter } 230251881Speter 231251881Speter /* If we don't have a username and a password yet, we try the 232251881Speter auth cache */ 233251881Speter if (! (username && password)) 234251881Speter { 235251881Speter if (! username) 236251881Speter if (!simple_username_get(&username, creds_hash, realmstring, 237251881Speter non_interactive)) 238251881Speter username = NULL; 239251881Speter 240251881Speter if (username && ! password) 241251881Speter { 242251881Speter if (! have_passtype) 243251881Speter password = NULL; 244251881Speter else 245251881Speter { 246251881Speter svn_boolean_t done; 247251881Speter 248251881Speter SVN_ERR(password_get(&done, &password, creds_hash, 249251881Speter realmstring, username, parameters, 250251881Speter non_interactive, pool)); 251251881Speter if (!done) 252251881Speter password = NULL; 253251881Speter 254251881Speter /* If the auth data didn't contain a password type, 255251881Speter force a write to upgrade the format of the auth 256251881Speter data file. */ 257251881Speter if (password && ! have_passtype) 258251881Speter need_to_save = TRUE; 259251881Speter } 260251881Speter } 261251881Speter } 262251881Speter } 263251881Speter else 264251881Speter { 265251881Speter /* Nothing was present in the auth cache, so indicate that these 266251881Speter credentials should be saved. */ 267251881Speter need_to_save = TRUE; 268251881Speter } 269251881Speter 270251881Speter /* If we don't have a username yet, check the 'servers' file */ 271251881Speter if (! username) 272251881Speter { 273251881Speter username = svn_config_get_server_setting(cfg, server_group, 274251881Speter SVN_CONFIG_OPTION_USERNAME, 275251881Speter NULL); 276251881Speter } 277251881Speter 278251881Speter /* Ask the OS for the username if we have a password but no 279251881Speter username. */ 280251881Speter if (password && ! username) 281251881Speter username = svn_user_get_name(pool); 282251881Speter 283251881Speter if (username && password) 284251881Speter { 285251881Speter svn_auth_cred_simple_t *creds = apr_pcalloc(pool, sizeof(*creds)); 286251881Speter creds->username = username; 287251881Speter creds->password = password; 288251881Speter creds->may_save = need_to_save; 289251881Speter *credentials = creds; 290251881Speter } 291251881Speter else 292251881Speter *credentials = NULL; 293251881Speter 294251881Speter *iter_baton = NULL; 295251881Speter 296251881Speter return SVN_NO_ERROR; 297251881Speter} 298251881Speter 299251881Speter 300251881Spetersvn_error_t * 301251881Spetersvn_auth__simple_creds_cache_set(svn_boolean_t *saved, 302251881Speter void *credentials, 303251881Speter void *provider_baton, 304251881Speter apr_hash_t *parameters, 305251881Speter const char *realmstring, 306251881Speter svn_auth__password_set_t password_set, 307251881Speter const char *passtype, 308251881Speter apr_pool_t *pool) 309251881Speter{ 310251881Speter svn_auth_cred_simple_t *creds = credentials; 311251881Speter apr_hash_t *creds_hash = NULL; 312251881Speter const char *config_dir; 313251881Speter svn_error_t *err; 314251881Speter svn_boolean_t dont_store_passwords = 315251881Speter svn_hash_gets(parameters, SVN_AUTH_PARAM_DONT_STORE_PASSWORDS) != NULL; 316251881Speter svn_boolean_t non_interactive = svn_hash_gets(parameters, 317251881Speter SVN_AUTH_PARAM_NON_INTERACTIVE) 318251881Speter != NULL; 319251881Speter svn_boolean_t no_auth_cache = 320251881Speter (! creds->may_save) || (svn_hash_gets(parameters, 321251881Speter SVN_AUTH_PARAM_NO_AUTH_CACHE) 322251881Speter != NULL); 323251881Speter 324251881Speter /* Make sure we've been passed a passtype. */ 325251881Speter SVN_ERR_ASSERT(passtype != NULL); 326251881Speter 327251881Speter *saved = FALSE; 328251881Speter 329251881Speter if (no_auth_cache) 330251881Speter return SVN_NO_ERROR; 331251881Speter 332251881Speter config_dir = svn_hash_gets(parameters, SVN_AUTH_PARAM_CONFIG_DIR); 333251881Speter 334251881Speter /* Put the username into the credentials hash. */ 335251881Speter creds_hash = apr_hash_make(pool); 336251881Speter svn_hash_sets(creds_hash, AUTHN_USERNAME_KEY, 337251881Speter svn_string_create(creds->username, pool)); 338251881Speter 339251881Speter /* Don't store passwords in any form if the user has told 340251881Speter * us not to do so. */ 341251881Speter if (! dont_store_passwords) 342251881Speter { 343251881Speter svn_boolean_t may_save_password = FALSE; 344251881Speter 345251881Speter /* If the password is going to be stored encrypted, go right 346251881Speter * ahead and store it to disk. Else determine whether saving 347251881Speter * in plaintext is OK. */ 348251881Speter if (passtype && 349251881Speter (strcmp(passtype, SVN_AUTH__WINCRYPT_PASSWORD_TYPE) == 0 350251881Speter || strcmp(passtype, SVN_AUTH__KEYCHAIN_PASSWORD_TYPE) == 0 351251881Speter || strcmp(passtype, SVN_AUTH__KWALLET_PASSWORD_TYPE) == 0 352251881Speter || strcmp(passtype, SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE) == 0 353251881Speter || strcmp(passtype, SVN_AUTH__GPG_AGENT_PASSWORD_TYPE) == 0)) 354251881Speter { 355251881Speter may_save_password = TRUE; 356251881Speter } 357251881Speter else 358251881Speter { 359251881Speter#ifdef SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE 360251881Speter may_save_password = FALSE; 361251881Speter#else 362251881Speter const char *store_plaintext_passwords = 363251881Speter svn_hash_gets(parameters, SVN_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS); 364251881Speter simple_provider_baton_t *b = 365251881Speter (simple_provider_baton_t *)provider_baton; 366251881Speter 367251881Speter if (store_plaintext_passwords 368251881Speter && svn_cstring_casecmp(store_plaintext_passwords, 369251881Speter SVN_CONFIG_ASK) == 0) 370251881Speter { 371251881Speter if (non_interactive) 372251881Speter /* In non-interactive mode, the default behaviour is 373251881Speter * to not store the password, because it is usually 374251881Speter * passed on the command line. */ 375251881Speter may_save_password = FALSE; 376251881Speter else if (b->plaintext_prompt_func) 377251881Speter { 378251881Speter /* We're interactive, and the client provided a 379251881Speter * prompt callback. So we can ask the user. 380251881Speter * 381251881Speter * Check for a cached answer before prompting. */ 382251881Speter svn_boolean_t *cached_answer; 383251881Speter cached_answer = svn_hash_gets(b->plaintext_answers, 384251881Speter realmstring); 385251881Speter if (cached_answer != NULL) 386251881Speter may_save_password = *cached_answer; 387251881Speter else 388251881Speter { 389251881Speter apr_pool_t *cached_answer_pool; 390251881Speter 391251881Speter /* Nothing cached for this realm, prompt the user. */ 392251881Speter SVN_ERR((*b->plaintext_prompt_func)(&may_save_password, 393251881Speter realmstring, 394251881Speter b->prompt_baton, 395251881Speter pool)); 396251881Speter 397251881Speter /* Cache the user's answer in case we're called again 398251881Speter * for the same realm. 399251881Speter * 400251881Speter * We allocate the answer cache in the hash table's pool 401251881Speter * to make sure that is has the same life time as the 402251881Speter * hash table itself. This means that the answer will 403251881Speter * survive across RA sessions -- which is important, 404251881Speter * because otherwise we'd prompt users once per RA session. 405251881Speter */ 406251881Speter cached_answer_pool = apr_hash_pool_get(b->plaintext_answers); 407251881Speter cached_answer = apr_palloc(cached_answer_pool, 408251881Speter sizeof(svn_boolean_t)); 409251881Speter *cached_answer = may_save_password; 410251881Speter svn_hash_sets(b->plaintext_answers, realmstring, 411251881Speter cached_answer); 412251881Speter } 413251881Speter } 414251881Speter else 415251881Speter { 416251881Speter /* TODO: We might want to default to not storing if the 417251881Speter * prompt callback is NULL, i.e. have may_save_password 418251881Speter * default to FALSE here, in order to force clients to 419251881Speter * implement the callback. 420251881Speter * 421251881Speter * This would change the semantics of old API though. 422251881Speter * 423251881Speter * So for now, clients that don't implement the callback 424251881Speter * and provide no explicit value for 425251881Speter * SVN_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS 426251881Speter * cause unencrypted passwords to be stored by default. 427251881Speter * Needless to say, our own client is sane, but who knows 428251881Speter * what other clients are doing. 429251881Speter */ 430251881Speter may_save_password = TRUE; 431251881Speter } 432251881Speter } 433251881Speter else if (store_plaintext_passwords 434251881Speter && svn_cstring_casecmp(store_plaintext_passwords, 435251881Speter SVN_CONFIG_FALSE) == 0) 436251881Speter { 437251881Speter may_save_password = FALSE; 438251881Speter } 439251881Speter else if (!store_plaintext_passwords 440251881Speter || svn_cstring_casecmp(store_plaintext_passwords, 441251881Speter SVN_CONFIG_TRUE) == 0) 442251881Speter { 443251881Speter may_save_password = TRUE; 444251881Speter } 445251881Speter else 446251881Speter { 447251881Speter return svn_error_createf 448251881Speter (SVN_ERR_BAD_CONFIG_VALUE, NULL, 449251881Speter _("Config error: invalid value '%s' for option '%s'"), 450251881Speter store_plaintext_passwords, 451251881Speter SVN_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS); 452251881Speter } 453251881Speter#endif 454251881Speter } 455251881Speter 456251881Speter if (may_save_password) 457251881Speter { 458251881Speter SVN_ERR(password_set(saved, creds_hash, realmstring, 459251881Speter creds->username, creds->password, 460251881Speter parameters, non_interactive, pool)); 461251881Speter if (*saved && passtype) 462251881Speter /* Store the password type with the auth data, so that we 463251881Speter know which provider owns the password. */ 464251881Speter svn_hash_sets(creds_hash, AUTHN_PASSTYPE_KEY, 465251881Speter svn_string_create(passtype, pool)); 466251881Speter } 467251881Speter } 468251881Speter 469251881Speter /* Save credentials to disk. */ 470251881Speter err = svn_config_write_auth_data(creds_hash, SVN_AUTH_CRED_SIMPLE, 471251881Speter realmstring, config_dir, pool); 472251881Speter if (err) 473251881Speter *saved = FALSE; 474251881Speter 475251881Speter /* ### return error? */ 476251881Speter svn_error_clear(err); 477251881Speter 478251881Speter return SVN_NO_ERROR; 479251881Speter} 480251881Speter 481251881Speter/* Get cached (unencrypted) credentials from the simple provider's cache. */ 482251881Speterstatic svn_error_t * 483251881Spetersimple_first_creds(void **credentials, 484251881Speter void **iter_baton, 485251881Speter void *provider_baton, 486251881Speter apr_hash_t *parameters, 487251881Speter const char *realmstring, 488251881Speter apr_pool_t *pool) 489251881Speter{ 490251881Speter return svn_auth__simple_creds_cache_get(credentials, iter_baton, 491251881Speter provider_baton, parameters, 492251881Speter realmstring, 493251881Speter svn_auth__simple_password_get, 494251881Speter SVN_AUTH__SIMPLE_PASSWORD_TYPE, 495251881Speter pool); 496251881Speter} 497251881Speter 498251881Speter/* Save (unencrypted) credentials to the simple provider's cache. */ 499251881Speterstatic svn_error_t * 500251881Spetersimple_save_creds(svn_boolean_t *saved, 501251881Speter void *credentials, 502251881Speter void *provider_baton, 503251881Speter apr_hash_t *parameters, 504251881Speter const char *realmstring, 505251881Speter apr_pool_t *pool) 506251881Speter{ 507251881Speter return svn_auth__simple_creds_cache_set(saved, credentials, provider_baton, 508251881Speter parameters, realmstring, 509251881Speter svn_auth__simple_password_set, 510251881Speter SVN_AUTH__SIMPLE_PASSWORD_TYPE, 511251881Speter pool); 512251881Speter} 513251881Speter 514251881Speterstatic const svn_auth_provider_t simple_provider = { 515251881Speter SVN_AUTH_CRED_SIMPLE, 516251881Speter simple_first_creds, 517251881Speter NULL, 518251881Speter simple_save_creds 519251881Speter}; 520251881Speter 521251881Speter 522251881Speter/* Public API */ 523251881Spetervoid 524251881Spetersvn_auth_get_simple_provider2 525251881Speter (svn_auth_provider_object_t **provider, 526251881Speter svn_auth_plaintext_prompt_func_t plaintext_prompt_func, 527251881Speter void* prompt_baton, 528251881Speter apr_pool_t *pool) 529251881Speter{ 530251881Speter svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po)); 531251881Speter simple_provider_baton_t *pb = apr_pcalloc(pool, sizeof(*pb)); 532251881Speter 533251881Speter pb->plaintext_prompt_func = plaintext_prompt_func; 534251881Speter pb->prompt_baton = prompt_baton; 535251881Speter pb->plaintext_answers = apr_hash_make(pool); 536251881Speter 537251881Speter po->vtable = &simple_provider; 538251881Speter po->provider_baton = pb; 539251881Speter *provider = po; 540251881Speter} 541251881Speter 542251881Speter 543251881Speter/*-----------------------------------------------------------------------*/ 544251881Speter/* Prompt provider */ 545251881Speter/*-----------------------------------------------------------------------*/ 546251881Speter 547251881Speter/* Baton type for username/password prompting. */ 548251881Spetertypedef struct simple_prompt_provider_baton_t 549251881Speter{ 550251881Speter svn_auth_simple_prompt_func_t prompt_func; 551251881Speter void *prompt_baton; 552251881Speter 553251881Speter /* how many times to re-prompt after the first one fails */ 554251881Speter int retry_limit; 555251881Speter} simple_prompt_provider_baton_t; 556251881Speter 557251881Speter 558251881Speter/* Iteration baton type for username/password prompting. */ 559251881Spetertypedef struct simple_prompt_iter_baton_t 560251881Speter{ 561251881Speter /* how many times we've reprompted */ 562251881Speter int retries; 563251881Speter} simple_prompt_iter_baton_t; 564251881Speter 565251881Speter 566251881Speter 567251881Speter/*** Helper Functions ***/ 568251881Speterstatic svn_error_t * 569251881Speterprompt_for_simple_creds(svn_auth_cred_simple_t **cred_p, 570251881Speter simple_prompt_provider_baton_t *pb, 571251881Speter apr_hash_t *parameters, 572251881Speter const char *realmstring, 573251881Speter svn_boolean_t first_time, 574251881Speter svn_boolean_t may_save, 575251881Speter apr_pool_t *pool) 576251881Speter{ 577251881Speter const char *default_username = NULL; 578251881Speter const char *default_password = NULL; 579251881Speter 580251881Speter *cred_p = NULL; 581251881Speter 582251881Speter /* If we're allowed to check for default usernames and passwords, do 583251881Speter so. */ 584251881Speter if (first_time) 585251881Speter { 586251881Speter default_username = svn_hash_gets(parameters, 587251881Speter SVN_AUTH_PARAM_DEFAULT_USERNAME); 588251881Speter 589251881Speter /* No default username? Try the auth cache. */ 590251881Speter if (! default_username) 591251881Speter { 592251881Speter const char *config_dir = svn_hash_gets(parameters, 593251881Speter SVN_AUTH_PARAM_CONFIG_DIR); 594251881Speter apr_hash_t *creds_hash = NULL; 595251881Speter svn_string_t *str; 596251881Speter svn_error_t *err; 597251881Speter 598251881Speter err = svn_config_read_auth_data(&creds_hash, SVN_AUTH_CRED_SIMPLE, 599251881Speter realmstring, config_dir, pool); 600251881Speter svn_error_clear(err); 601251881Speter if (! err && creds_hash) 602251881Speter { 603251881Speter str = svn_hash_gets(creds_hash, AUTHN_USERNAME_KEY); 604251881Speter if (str && str->data) 605251881Speter default_username = str->data; 606251881Speter } 607251881Speter } 608251881Speter 609251881Speter /* Still no default username? Try the 'servers' file. */ 610251881Speter if (! default_username) 611251881Speter { 612251881Speter svn_config_t *cfg = svn_hash_gets(parameters, 613251881Speter SVN_AUTH_PARAM_CONFIG_CATEGORY_SERVERS); 614251881Speter const char *server_group = svn_hash_gets(parameters, 615251881Speter SVN_AUTH_PARAM_SERVER_GROUP); 616251881Speter default_username = 617251881Speter svn_config_get_server_setting(cfg, server_group, 618251881Speter SVN_CONFIG_OPTION_USERNAME, 619251881Speter NULL); 620251881Speter } 621251881Speter 622251881Speter /* Still no default username? Try the UID. */ 623251881Speter if (! default_username) 624251881Speter default_username = svn_user_get_name(pool); 625251881Speter 626251881Speter default_password = svn_hash_gets(parameters, 627251881Speter SVN_AUTH_PARAM_DEFAULT_PASSWORD); 628251881Speter } 629251881Speter 630251881Speter /* If we have defaults, just build the cred here and return it. 631251881Speter * 632251881Speter * ### I do wonder why this is here instead of in a separate 633251881Speter * ### 'defaults' provider that would run before the prompt 634251881Speter * ### provider... Hmmm. 635251881Speter */ 636251881Speter if (default_username && default_password) 637251881Speter { 638251881Speter *cred_p = apr_palloc(pool, sizeof(**cred_p)); 639251881Speter (*cred_p)->username = apr_pstrdup(pool, default_username); 640251881Speter (*cred_p)->password = apr_pstrdup(pool, default_password); 641251881Speter (*cred_p)->may_save = TRUE; 642251881Speter } 643251881Speter else 644251881Speter { 645251881Speter SVN_ERR(pb->prompt_func(cred_p, pb->prompt_baton, realmstring, 646251881Speter default_username, may_save, pool)); 647251881Speter } 648251881Speter 649251881Speter return SVN_NO_ERROR; 650251881Speter} 651251881Speter 652251881Speter 653251881Speter/* Our first attempt will use any default username/password passed 654251881Speter in, and prompt for the remaining stuff. */ 655251881Speterstatic svn_error_t * 656251881Spetersimple_prompt_first_creds(void **credentials_p, 657251881Speter void **iter_baton, 658251881Speter void *provider_baton, 659251881Speter apr_hash_t *parameters, 660251881Speter const char *realmstring, 661251881Speter apr_pool_t *pool) 662251881Speter{ 663251881Speter simple_prompt_provider_baton_t *pb = provider_baton; 664251881Speter simple_prompt_iter_baton_t *ibaton = apr_pcalloc(pool, sizeof(*ibaton)); 665251881Speter const char *no_auth_cache = svn_hash_gets(parameters, 666251881Speter SVN_AUTH_PARAM_NO_AUTH_CACHE); 667251881Speter 668251881Speter SVN_ERR(prompt_for_simple_creds((svn_auth_cred_simple_t **) credentials_p, 669251881Speter pb, parameters, realmstring, TRUE, 670251881Speter ! no_auth_cache, pool)); 671251881Speter 672251881Speter ibaton->retries = 0; 673251881Speter *iter_baton = ibaton; 674251881Speter 675251881Speter return SVN_NO_ERROR; 676251881Speter} 677251881Speter 678251881Speter 679251881Speter/* Subsequent attempts to fetch will ignore the default values, and 680251881Speter simply re-prompt for both, up to a maximum of ib->pb->retry_limit. */ 681251881Speterstatic svn_error_t * 682251881Spetersimple_prompt_next_creds(void **credentials_p, 683251881Speter void *iter_baton, 684251881Speter void *provider_baton, 685251881Speter apr_hash_t *parameters, 686251881Speter const char *realmstring, 687251881Speter apr_pool_t *pool) 688251881Speter{ 689251881Speter simple_prompt_iter_baton_t *ib = iter_baton; 690251881Speter simple_prompt_provider_baton_t *pb = provider_baton; 691251881Speter const char *no_auth_cache = svn_hash_gets(parameters, 692251881Speter SVN_AUTH_PARAM_NO_AUTH_CACHE); 693251881Speter 694251881Speter if ((pb->retry_limit >= 0) && (ib->retries >= pb->retry_limit)) 695251881Speter { 696251881Speter /* give up, go on to next provider. */ 697251881Speter *credentials_p = NULL; 698251881Speter return SVN_NO_ERROR; 699251881Speter } 700251881Speter ib->retries++; 701251881Speter 702251881Speter return prompt_for_simple_creds((svn_auth_cred_simple_t **) credentials_p, 703251881Speter pb, parameters, realmstring, FALSE, 704251881Speter ! no_auth_cache, pool); 705251881Speter} 706251881Speter 707251881Speterstatic const svn_auth_provider_t simple_prompt_provider = { 708251881Speter SVN_AUTH_CRED_SIMPLE, 709251881Speter simple_prompt_first_creds, 710251881Speter simple_prompt_next_creds, 711251881Speter NULL, 712251881Speter}; 713251881Speter 714251881Speter 715251881Speter/* Public API */ 716251881Spetervoid 717251881Spetersvn_auth_get_simple_prompt_provider 718251881Speter (svn_auth_provider_object_t **provider, 719251881Speter svn_auth_simple_prompt_func_t prompt_func, 720251881Speter void *prompt_baton, 721251881Speter int retry_limit, 722251881Speter apr_pool_t *pool) 723251881Speter{ 724251881Speter svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po)); 725251881Speter simple_prompt_provider_baton_t *pb = apr_pcalloc(pool, sizeof(*pb)); 726251881Speter 727251881Speter pb->prompt_func = prompt_func; 728251881Speter pb->prompt_baton = prompt_baton; 729251881Speter pb->retry_limit = retry_limit; 730251881Speter 731251881Speter po->vtable = &simple_prompt_provider; 732251881Speter po->provider_baton = pb; 733251881Speter *provider = po; 734251881Speter} 735