1251881Speter/* 2251881Speter * username_providers.c: providers for SVN_AUTH_CRED_USERNAME 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_hash.h" 32251881Speter#include "svn_auth.h" 33251881Speter#include "svn_error.h" 34251881Speter#include "svn_utf.h" 35251881Speter#include "svn_config.h" 36251881Speter#include "svn_user.h" 37251881Speter 38251881Speter 39251881Speter/*-----------------------------------------------------------------------*/ 40251881Speter/* File provider */ 41251881Speter/*-----------------------------------------------------------------------*/ 42251881Speter 43251881Speter/* The key that will be stored on disk. Serves the same role as similar 44251881Speter constants in other providers. */ 45251881Speter#define AUTHN_USERNAME_KEY "username" 46251881Speter 47251881Speter 48251881Speter 49251881Speter/*** Username-only Provider ***/ 50251881Speterstatic svn_error_t * 51251881Speterusername_first_creds(void **credentials, 52251881Speter void **iter_baton, 53251881Speter void *provider_baton, 54251881Speter apr_hash_t *parameters, 55251881Speter const char *realmstring, 56251881Speter apr_pool_t *pool) 57251881Speter{ 58251881Speter const char *config_dir = svn_hash_gets(parameters, 59251881Speter SVN_AUTH_PARAM_CONFIG_DIR); 60251881Speter const char *username = svn_hash_gets(parameters, 61251881Speter SVN_AUTH_PARAM_DEFAULT_USERNAME); 62251881Speter svn_boolean_t may_save = !! username; 63251881Speter svn_error_t *err; 64251881Speter 65251881Speter /* If we don't have a usename yet, try the auth cache */ 66251881Speter if (! username) 67251881Speter { 68251881Speter apr_hash_t *creds_hash = NULL; 69251881Speter 70251881Speter /* Try to load credentials from a file on disk, based on the 71251881Speter realmstring. Don't throw an error, though: if something went 72251881Speter wrong reading the file, no big deal. What really matters is that 73251881Speter we failed to get the creds, so allow the auth system to try the 74251881Speter next provider. */ 75251881Speter err = svn_config_read_auth_data(&creds_hash, SVN_AUTH_CRED_USERNAME, 76251881Speter realmstring, config_dir, pool); 77251881Speter svn_error_clear(err); 78251881Speter if (! err && creds_hash) 79251881Speter { 80251881Speter svn_string_t *str = svn_hash_gets(creds_hash, AUTHN_USERNAME_KEY); 81251881Speter if (str && str->data) 82251881Speter username = str->data; 83251881Speter } 84251881Speter } 85251881Speter 86251881Speter /* If that failed, ask the OS for the username */ 87251881Speter if (! username) 88251881Speter username = svn_user_get_name(pool); 89251881Speter 90251881Speter if (username) 91251881Speter { 92251881Speter svn_auth_cred_simple_t *creds = apr_pcalloc(pool, sizeof(*creds)); 93251881Speter creds->username = username; 94251881Speter creds->may_save = may_save; 95251881Speter *credentials = creds; 96251881Speter } 97251881Speter else 98251881Speter *credentials = NULL; 99251881Speter 100251881Speter *iter_baton = NULL; 101251881Speter 102251881Speter return SVN_NO_ERROR; 103251881Speter} 104251881Speter 105251881Speter 106251881Speterstatic svn_error_t * 107251881Speterusername_save_creds(svn_boolean_t *saved, 108251881Speter void *credentials, 109251881Speter void *provider_baton, 110251881Speter apr_hash_t *parameters, 111251881Speter const char *realmstring, 112251881Speter apr_pool_t *pool) 113251881Speter{ 114251881Speter svn_auth_cred_simple_t *creds = credentials; 115251881Speter apr_hash_t *creds_hash = NULL; 116251881Speter const char *config_dir; 117251881Speter svn_error_t *err; 118251881Speter 119251881Speter *saved = FALSE; 120251881Speter 121251881Speter if (! creds->may_save) 122251881Speter return SVN_NO_ERROR; 123251881Speter 124251881Speter config_dir = svn_hash_gets(parameters, SVN_AUTH_PARAM_CONFIG_DIR); 125251881Speter 126251881Speter /* Put the credentials in a hash and save it to disk */ 127251881Speter creds_hash = apr_hash_make(pool); 128251881Speter svn_hash_sets(creds_hash, AUTHN_USERNAME_KEY, 129251881Speter svn_string_create(creds->username, pool)); 130251881Speter err = svn_config_write_auth_data(creds_hash, SVN_AUTH_CRED_USERNAME, 131251881Speter realmstring, config_dir, pool); 132251881Speter svn_error_clear(err); 133251881Speter *saved = ! err; 134251881Speter 135251881Speter return SVN_NO_ERROR; 136251881Speter} 137251881Speter 138251881Speter 139251881Speterstatic const svn_auth_provider_t username_provider = { 140251881Speter SVN_AUTH_CRED_USERNAME, 141251881Speter username_first_creds, 142251881Speter NULL, 143251881Speter username_save_creds 144251881Speter}; 145251881Speter 146251881Speter 147251881Speter/* Public API */ 148251881Spetervoid 149251881Spetersvn_auth_get_username_provider(svn_auth_provider_object_t **provider, 150251881Speter apr_pool_t *pool) 151251881Speter{ 152251881Speter svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po)); 153251881Speter 154251881Speter po->vtable = &username_provider; 155251881Speter *provider = po; 156251881Speter} 157251881Speter 158251881Speter 159251881Speter/*-----------------------------------------------------------------------*/ 160251881Speter/* Prompt provider */ 161251881Speter/*-----------------------------------------------------------------------*/ 162251881Speter 163251881Speter/* Baton type for username-only prompting. */ 164251881Spetertypedef struct username_prompt_provider_baton_t 165251881Speter{ 166251881Speter svn_auth_username_prompt_func_t prompt_func; 167251881Speter void *prompt_baton; 168251881Speter 169251881Speter /* how many times to re-prompt after the first one fails */ 170251881Speter int retry_limit; 171251881Speter} username_prompt_provider_baton_t; 172251881Speter 173251881Speter 174251881Speter/* Iteration baton type for username-only prompting. */ 175251881Spetertypedef struct username_prompt_iter_baton_t 176251881Speter{ 177251881Speter /* how many times we've reprompted */ 178251881Speter int retries; 179251881Speter 180251881Speter} username_prompt_iter_baton_t; 181251881Speter 182251881Speter 183251881Speter/*** Helper Functions ***/ 184251881Speterstatic svn_error_t * 185251881Speterprompt_for_username_creds(svn_auth_cred_username_t **cred_p, 186251881Speter username_prompt_provider_baton_t *pb, 187251881Speter apr_hash_t *parameters, 188251881Speter const char *realmstring, 189251881Speter svn_boolean_t first_time, 190251881Speter svn_boolean_t may_save, 191251881Speter apr_pool_t *pool) 192251881Speter{ 193251881Speter const char *def_username = NULL; 194251881Speter 195251881Speter *cred_p = NULL; 196251881Speter 197251881Speter /* If we're allowed to check for default usernames, do so. */ 198251881Speter if (first_time) 199251881Speter def_username = svn_hash_gets(parameters, SVN_AUTH_PARAM_DEFAULT_USERNAME); 200251881Speter 201251881Speter /* If we have defaults, just build the cred here and return it. 202251881Speter * 203251881Speter * ### I do wonder why this is here instead of in a separate 204251881Speter * ### 'defaults' provider that would run before the prompt 205251881Speter * ### provider... Hmmm. 206251881Speter */ 207251881Speter if (def_username) 208251881Speter { 209251881Speter *cred_p = apr_palloc(pool, sizeof(**cred_p)); 210251881Speter (*cred_p)->username = apr_pstrdup(pool, def_username); 211251881Speter (*cred_p)->may_save = TRUE; 212251881Speter } 213251881Speter else 214251881Speter { 215251881Speter SVN_ERR(pb->prompt_func(cred_p, pb->prompt_baton, realmstring, 216251881Speter may_save, pool)); 217251881Speter } 218251881Speter 219251881Speter return SVN_NO_ERROR; 220251881Speter} 221251881Speter 222251881Speter 223251881Speter/* Our first attempt will use any default username passed 224251881Speter in, and prompt for the remaining stuff. */ 225251881Speterstatic svn_error_t * 226251881Speterusername_prompt_first_creds(void **credentials_p, 227251881Speter void **iter_baton, 228251881Speter void *provider_baton, 229251881Speter apr_hash_t *parameters, 230251881Speter const char *realmstring, 231251881Speter apr_pool_t *pool) 232251881Speter{ 233251881Speter username_prompt_provider_baton_t *pb = provider_baton; 234251881Speter username_prompt_iter_baton_t *ibaton = apr_pcalloc(pool, sizeof(*ibaton)); 235251881Speter const char *no_auth_cache = svn_hash_gets(parameters, 236251881Speter SVN_AUTH_PARAM_NO_AUTH_CACHE); 237251881Speter 238251881Speter SVN_ERR(prompt_for_username_creds 239251881Speter ((svn_auth_cred_username_t **) credentials_p, pb, 240251881Speter parameters, realmstring, TRUE, ! no_auth_cache, pool)); 241251881Speter 242251881Speter ibaton->retries = 0; 243251881Speter *iter_baton = ibaton; 244251881Speter 245251881Speter return SVN_NO_ERROR; 246251881Speter} 247251881Speter 248251881Speter 249251881Speter/* Subsequent attempts to fetch will ignore the default username 250251881Speter value, and simply re-prompt for the username, up to a maximum of 251251881Speter ib->pb->retry_limit. */ 252251881Speterstatic svn_error_t * 253251881Speterusername_prompt_next_creds(void **credentials_p, 254251881Speter void *iter_baton, 255251881Speter void *provider_baton, 256251881Speter apr_hash_t *parameters, 257251881Speter const char *realmstring, 258251881Speter apr_pool_t *pool) 259251881Speter{ 260251881Speter username_prompt_iter_baton_t *ib = iter_baton; 261251881Speter username_prompt_provider_baton_t *pb = provider_baton; 262251881Speter const char *no_auth_cache = svn_hash_gets(parameters, 263251881Speter SVN_AUTH_PARAM_NO_AUTH_CACHE); 264251881Speter 265251881Speter if ((pb->retry_limit >= 0) && (ib->retries >= pb->retry_limit)) 266251881Speter { 267251881Speter /* give up, go on to next provider. */ 268251881Speter *credentials_p = NULL; 269251881Speter return SVN_NO_ERROR; 270251881Speter } 271251881Speter ib->retries++; 272251881Speter 273251881Speter return prompt_for_username_creds 274251881Speter ((svn_auth_cred_username_t **) credentials_p, pb, 275251881Speter parameters, realmstring, FALSE, ! no_auth_cache, pool); 276251881Speter} 277251881Speter 278251881Speter 279251881Speterstatic const svn_auth_provider_t username_prompt_provider = { 280251881Speter SVN_AUTH_CRED_USERNAME, 281251881Speter username_prompt_first_creds, 282251881Speter username_prompt_next_creds, 283251881Speter NULL, 284251881Speter}; 285251881Speter 286251881Speter 287251881Speter/* Public API */ 288251881Spetervoid 289251881Spetersvn_auth_get_username_prompt_provider 290251881Speter (svn_auth_provider_object_t **provider, 291251881Speter svn_auth_username_prompt_func_t prompt_func, 292251881Speter void *prompt_baton, 293251881Speter int retry_limit, 294251881Speter apr_pool_t *pool) 295251881Speter{ 296251881Speter svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po)); 297251881Speter username_prompt_provider_baton_t *pb = apr_pcalloc(pool, sizeof(*pb)); 298251881Speter 299251881Speter pb->prompt_func = prompt_func; 300251881Speter pb->prompt_baton = prompt_baton; 301251881Speter pb->retry_limit = retry_limit; 302251881Speter 303251881Speter po->vtable = &username_prompt_provider; 304251881Speter po->provider_baton = pb; 305251881Speter *provider = po; 306251881Speter} 307