blob: fbc45edab0108a3e12469c2dbd246a827ff0d744 [file] [log] [blame]
/*
* auth.c: routines that drive "authenticator" objects received from RA.
*
* ====================================================================
* Copyright (c) 2000-2002 CollabNet. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://subversion.tigris.org/license-1.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
*
* This software consists of voluntary contributions made by many
* individuals. For exact contribution history, see the revision
* history and logs, available at http://subversion.tigris.org/.
* ====================================================================
*/
/* ==================================================================== */
/*** Includes. ***/
#define APR_WANT_STRFUNC
#include <apr_want.h>
#include <apr_strings.h>
#include <apr_pools.h>
#include "svn_client.h"
#include "svn_ra.h"
#include "svn_wc.h"
#include "svn_error.h"
#include "svn_io.h"
#include "svn_path.h"
#include "client.h"
/*-----------------------------------------------------------------------*/
/* Callback routines that RA libraries use to pull or store auth info. */
static svn_error_t *
get_username (char **username,
void *baton,
svn_boolean_t force_prompt,
apr_pool_t *pool)
{
svn_stringbuf_t *uname;
svn_client__callback_baton_t *cb = baton;
svn_client_auth_baton_t *ab = cb->auth_baton;
if (force_prompt)
{
char *prompt = apr_psprintf (pool, "username: ");
SVN_ERR (ab->prompt_callback (username, prompt,
FALSE, /* screen echo ok */
ab->prompt_baton, pool));
/* Since we got new totally new info, it's okay to overwrite
any cached info in the working copy (later on). */
ab->overwrite = TRUE;
/* Store a copy of the username in the auth_baton too. */
ab->username = apr_pstrdup (pool, *username);
return SVN_NO_ERROR;
}
/* Does auth_baton already have the value, received from
the application (probably from argv[])? */
if (ab->username)
{
*username = apr_pstrdup (pool, ab->username);
/* Since we got new totally new info, it's okay to overwrite
any cached info in the working copy (later on). */
ab->overwrite = TRUE;
}
/* Else, try to get it from file cached in working copy. */
else
{
/* If there is a base_dir, and we don't have any problems
getting the cached username from it, that's the result we'll
go with. */
if ((cb->base_dir)
&& (! svn_wc_get_auth_file (cb->base_dir,
SVN_CLIENT_AUTH_USERNAME,
&uname, pool)))
*username = uname->data;
else
{
/* No file cache? Then just use the process owner. */
char *un;
apr_uid_t uid;
apr_gid_t gid;
apr_status_t status;
status = apr_current_userid (&uid, &gid, pool);
if (status)
return
svn_error_create(status, 0, NULL, pool,
"Error getting UID of process.");
status = apr_get_username (&un, uid, pool);
if (status)
return svn_error_create(status, 0, NULL, pool,
"Error in UID->username.");
*username = un;
}
/* Store a copy of the username in the auth_baton too. */
ab->username = apr_pstrdup (pool, *username);
}
return SVN_NO_ERROR;
}
static svn_error_t *
get_password (char **password,
char *username,
void *baton,
svn_boolean_t force_prompt,
apr_pool_t *pool)
{
svn_stringbuf_t *pword;
char *prompt;
svn_client__callback_baton_t *cb = baton;
svn_client_auth_baton_t *ab = cb->auth_baton;
if (strlen(username) > 0)
prompt = apr_psprintf (pool, "%s's password: ", username);
else
prompt = apr_psprintf (pool, "password: ");
if (force_prompt)
{
SVN_ERR (ab->prompt_callback (password, prompt,
TRUE, /* don't echo to the screen */
ab->prompt_baton, pool));
/* Since we got new totally new info, it's okay to overwrite
any cached info in the working copy (later on). */
ab->overwrite = TRUE;
/* Store a copy of the password in the auth_baton too. */
ab->password = apr_pstrdup (pool, *password);
return SVN_NO_ERROR;
}
/* Does auth_baton already have the value, received from
the application (probably from argv[])? */
if (ab->password)
{
*password = apr_pstrdup (pool, ab->password);
/* Since we got new totally new info, it's okay to overwrite
any cached info in the working copy (later on). */
ab->overwrite = TRUE;
}
/* Else, try to get it from file cached in working copy. */
else
{
/* If there is a base_dir, and we don't have any problems
getting the cached password from it, that's the result we'll
go with. */
if ((cb->base_dir)
&& (! svn_wc_get_auth_file (cb->base_dir,
SVN_CLIENT_AUTH_PASSWORD,
&pword, pool)))
*password = pword->data;
else
{
/* No file cache? Then prompt the user. */
SVN_ERR (ab->prompt_callback (password, prompt,
TRUE, /* don't echo to the screen */
ab->prompt_baton, pool));
/* Since we got new totally new info, it's okay to overwrite
any cached info in the working copy (later on). */
ab->overwrite = TRUE;
}
/* Store a copy of the password in the auth_baton too. */
ab->password = apr_pstrdup (pool, *password);
}
return SVN_NO_ERROR;
}
static svn_error_t *
get_user_and_pass (char **username,
char **password,
void *baton,
svn_boolean_t force_prompt,
apr_pool_t *pool)
{
SVN_ERR (get_username (username, baton, force_prompt, pool));
SVN_ERR (get_password (password, *username, baton, force_prompt, pool));
return SVN_NO_ERROR;
}
static svn_error_t *
store_auth_info (const char *filename,
const char *data,
svn_stringbuf_t *wc_path,
apr_pool_t *pool)
{
enum svn_node_kind kind;
/* Sanity check -- store only in a directory. */
SVN_ERR (svn_io_check_path (wc_path->data, &kind, pool));
if (kind != svn_node_dir)
return SVN_NO_ERROR; /* ### is this really not an error? */
/* Do a recursive store. */
SVN_ERR (svn_wc_set_auth_file (wc_path, TRUE, filename,
svn_stringbuf_create (data, pool), pool));
return SVN_NO_ERROR;
}
static svn_error_t *
store_username (const char *username,
void *baton)
{
svn_client__callback_baton_t *cb = baton;
/* Sanity check: only store auth info if the `overwrite' flag is
set. This flag is set if the user was either prompted or
specified new info on the commandline. */
if (cb->auth_baton->overwrite)
return store_auth_info (SVN_CLIENT_AUTH_USERNAME, username,
cb->base_dir, cb->pool);
else
return SVN_NO_ERROR;
}
static svn_error_t *
store_password (const char *password,
void *baton)
{
svn_client__callback_baton_t *cb = baton;
/* Sanity check: only store auth info if the `overwrite' flag is
set. This flag is set if the user was either prompted or
specified new info on the commandline. */
if (cb->auth_baton->overwrite)
return store_auth_info (SVN_CLIENT_AUTH_PASSWORD, password,
cb->base_dir, cb->pool);
else
return SVN_NO_ERROR;
}
static svn_error_t *
store_user_and_pass (void *baton)
{
svn_client__callback_baton_t *cb = baton;
if (cb->auth_baton->username)
SVN_ERR (store_username (cb->auth_baton->username, baton));
if (cb->auth_baton->password)
SVN_ERR (store_password (cb->auth_baton->password, baton));
return SVN_NO_ERROR;
}
svn_error_t * svn_client__get_authenticator (void **authenticator,
void **auth_baton,
enum svn_ra_auth_method method,
void *callback_baton,
apr_pool_t *pool)
{
svn_client__callback_baton_t *cb = callback_baton;
/* At the moment, the callback_baton *is* the baton needed by the
authenticator objects. This may change. */
*auth_baton = callback_baton;
/* Return a specific authenticator vtable. */
switch (method)
{
case svn_ra_auth_username:
{
svn_ra_username_authenticator_t *ua = apr_pcalloc (pool, sizeof(*ua));
ua->get_username = get_username;
if (cb->do_store)
ua->store_username = store_username;
else
ua->store_username = NULL;
*authenticator = ua;
break;
}
case svn_ra_auth_simple_password:
{
svn_ra_simple_password_authenticator_t *ua
= apr_pcalloc (pool, sizeof(*ua));
ua->get_user_and_pass = get_user_and_pass;
if (cb->do_store)
ua->store_user_and_pass = store_user_and_pass;
else
ua->store_user_and_pass = NULL;
*authenticator = ua;
break;
}
default:
{
return svn_error_create (SVN_ERR_RA_UNKNOWN_AUTH, 0, NULL,
pool, "Unknown authenticator requested.");
}
}
return SVN_NO_ERROR;
}
/* --------------------------------------------------------------
* local variables:
* eval: (load-file "../../tools/dev/svn-dev.el")
* end: */