Home modules.gotpike.org
Username: Password: [Create Account]
[Forgot Password?]
Return to module

File Contents

Contents of /Subversion-0.112/auth.c:

/* ================================================================
 * Copyright (c) 2000-2004 CollabNet.  All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 * 
 * 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 
 * 2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 
 * 3. The end-user documentation included with the redistribution, if
 * any, must include the following acknowledgment: "This product includes
 * software developed by CollabNet (http://www.Collab.Net/)."
 * Alternately, this acknowledgment may appear in the software itself, if
 * and wherever such third-party acknowledgments normally appear.
 * 
 * 4. The hosted project names must not be used to endorse or promote
 * products derived from this software without prior written
 * permission. For written permission, please contact info@collab.net.
 * 
 * 5. Products derived from this software may not use the "Tigris" name
 * nor may "Tigris" appear in their names without prior written
 * permission of CollabNet.
 * 
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL COLLABNET OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ====================================================================
 * 
 * This software consists of voluntary contributions made by many
 * individuals on behalf of CollabNet.
 */


#include "svnmod.h"

#include <svn_auth.h>

/*! @module Subversion */

/*! @module Auth
 *!
 *!  The Auth submodule provides a set of classes for providing
 *!  authentication information to the various Subversion components.
 */


/*! @class AuthProvider
 *!
 *!  Base class for all authorization provider variants.
 */

/* Function indices for callbacks */
static int first_credentials_function, next_credentials_function, save_credentials_function;

struct program *svn_pike_auth_provider_program = NULL;

/* Internal object structure */
struct auth_provider_obj {
  svn_auth_provider_object_t ap;
  struct object *obj;
  int idlevel;
};

#define THIS ((struct auth_provider_obj *)(Pike_fp->current_storage))


enum auth_parameter_type {
  PARAMETER_TYPE_UNKNOWN = 0,
  PARAMETER_TYPE_BOOL,
  PARAMETER_TYPE_STRING,
  PARAMETER_TYPE_UINT32,
  PARAMETER_TYPE_CONFIG,
  PARAMETER_TYPE_SERVER_CERT,
};

/* Determine type of a parameter */
static enum auth_parameter_type check_auth_parameter_type (const char *name)
{
  if (!strcmp (name, SVN_AUTH_PARAM_DEFAULT_USERNAME) ||
      !strcmp (name, SVN_AUTH_PARAM_DEFAULT_PASSWORD) ||
      !strcmp (name, SVN_AUTH_PARAM_SERVER_GROUP) ||
      !strcmp (name, SVN_AUTH_PARAM_CONFIG_DIR))
    return PARAMETER_TYPE_STRING;
  else if(!strcmp (name, SVN_AUTH_PARAM_NON_INTERACTIVE) ||
#ifdef SVN_AUTH_PARAM_DONT_STORE_PASSWORDS
	  !strcmp (name, SVN_AUTH_PARAM_DONT_STORE_PASSWORDS) ||
#endif
	  !strcmp (name, SVN_AUTH_PARAM_NO_AUTH_CACHE))
    return PARAMETER_TYPE_BOOL;
  else if(!strcmp (name, SVN_AUTH_PARAM_SSL_SERVER_FAILURES))
    return PARAMETER_TYPE_UINT32;
  else if(!strcmp (name, SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO))
    return PARAMETER_TYPE_SERVER_CERT;
#if 0
  else if(!strcmp (name, SVN_AUTH_PARAM_CONFIG))
    return PARAMETER_TYPE_CONFIG;
#endif
  else
    return PARAMETER_TYPE_UNKNOWN;
}

/* Convert an apr_hash_t of authentication parameters to a mapping */
static void push_auth_parameters (apr_hash_t *parameters, apr_pool_t *pool)
{
  apr_hash_index_t *hi;
  INT32 n_items = 0;
  for (hi = apr_hash_first (pool, parameters);
       hi;
       hi = apr_hash_next (hi)) {
    const void *name;
    void *val;
    enum auth_parameter_type pt;

    apr_hash_this (hi, &name, NULL, &val);

    if ((pt = check_auth_parameter_type ((const char *)name))
	!= PARAMETER_TYPE_UNKNOWN) {
      svn_pike_push_utf8 ((const char *)name);
      switch(pt) {
      case PARAMETER_TYPE_BOOL:
	push_int (1);
	break;
      case PARAMETER_TYPE_STRING:
	svn_pike_push_utf8 ((char *)val);
	break;
      case PARAMETER_TYPE_UINT32:
	push_int (*(apr_uint32_t *)val);
	break;
#if 0
      case PARAMETER_TYPE_CONFIG:
	push_config ((svn_config_t *)val);
	break;
#endif
      case PARAMETER_TYPE_SERVER_CERT:
	{
	  svn_auth_ssl_server_cert_info_t *sci =
	    (svn_auth_ssl_server_cert_info_t *)val;

	  svn_pike_push_utf8 (sci->hostname);
	  svn_pike_push_utf8 (sci->fingerprint);
	  svn_pike_push_utf8 (sci->valid_from);
	  svn_pike_push_utf8 (sci->valid_until);
	  svn_pike_push_utf8 (sci->issuer_dname);
	  svn_pike_push_utf8 (sci->ascii_cert);
	  f_aggregate (6);
	}
	break;
      }
      n_items ++;
    }
  }
  f_aggregate_mapping (2*n_items);
}

/*! @decl mixed first_credentials( mapping(string:mixed) parameters,	@
 *!				   string realm )
 *!
 *!  Return a set of valid credentials within @[realm], or 0 if no
 *!  credentials are avaialble.  The type of a credentials value differs
 *!  with the different subclasses of @[AuthProvider].
 *!
 *!  This function should be overridden by the user class to provide
 *!  actual credentials.  The default implementation always returns 0.
 *!
 *! @param parameters
 *!   Any run-time data that the provider may need.  Currently supported
 *!   parameters are:
 *!   @mapping
 *!     @member string "svn:auth:username"
 *!       Default username.
 *!     @member string "svn:auth:password"
 *!       Default password.
 *!     @member int(1..1) "svn:auth:non-interactive"
 *!       The application doesn't want any providers to prompt users.
 *!     @member int(1..1) "svn:auth:dont-store-passwords"
 *!       The application doesn't want any providers to save passwords to disk.
 *!     @member int(1..1) "svn:auth:no-auth-cache"
 *!       The application doesn't want any providers to save credentials to disk.
 *!     @member int "svn:auth:ssl:failures"
 *!       Bitmask of failures detected by the SSL certificate validator.
 *!     @member array(string) "svn:auth:ssl:cert-info"
 *!       Certificate info for the SSL server.  The elements in the array are:
 *!       @array
 *!         @elem string hostname
 *!           Primary CN
 *!         @elem string fingerprint
 *!           ASCII fingerprint
 *!         @elem string valid_from
 *!           ASCII date from which the certificate is valid
 *!         @elem string valid_until
 *!           ASCII date until which the certificate is valid
 *!         @elem string issuer_dname
 *!           DN of the certificate issuer
 *!         @elem string ascii_cert
 *!           Base-64 encoded DER certificate representation
 *!       @endarray
 *!     @member string "svn:auth:server-group"
 *!       The current server group.
 *!     @member string "svn:auth:config-dir"
 *!       A configuration directory that overrides the default
 *!       @tt{~/.subversion@}.
 *!   @endmapping
 *! @param realm
 *!   The realm to aquire credentials for.
 *!
 *! @returns
 *!   A credentials set, or 0 if no credentials are available.
 */
static void f_first_credentials (INT32 args)
{
  pop_n_elems (args);
  push_int (0);
}

static svn_error_t *first_credentials_null (void **credentials,
					    void **iter_baton,
					    void *provider_baton,
					    apr_hash_t *parameters,
					    const char *realmstring,
					    apr_pool_t *pool)
{
  *credentials = NULL;
  *iter_baton = NULL;
  return SVN_NO_ERROR;
}

static svn_error_t *first_credentials_x (void **credentials,
					 void **iter_baton,
					 void *provider_baton,
					 apr_hash_t *parameters,
					 const char *realmstring,
					 apr_pool_t *pool,
					 void *(*make_cred)(struct svalue *,
							    apr_pool_t *))
{
  JMP_BUF recovery;
  svn_error_t *err = SVN_NO_ERROR;
  struct auth_provider_obj *apo = provider_baton;

  *credentials = NULL;
  *iter_baton = NULL;

  do {
    struct thread_state *_tmp=thread_state_for_id (th_self ());
    HIDE_GLOBAL_VARIABLES ();
    THREADS_DISALLOW ();

    if (SETJMP (recovery))
      err = svn_pike_make_svn_error (&throw_value);
    else {
      struct svalue f;

      low_object_index_no_free(&f, apo->obj, apo->idlevel + 
			       first_credentials_function);

      push_auth_parameters (parameters, pool);
      svn_pike_push_utf8 (realmstring);
      apply_svalue (&f, 2);
      *credentials = make_cred(Pike_sp-1, pool);
      pop_stack ();
    }
    UNSETJMP (recovery);

    THREADS_ALLOW ();
  } while (0);

  return err;
}


/*! @decl mixed next_credentials( mapping(string:mixed) parameters,	@
 *!				   string realm )
 *!
 *!  If the provider can provide multiple sets of credentials, this
 *!  function should return the next one available.  The iteration is
 *!  started with the call to @[first_credentials()].  When no more
 *!  credentials are available, 0 should be returned.  The type of a
 *!  credentials value differs with the different subclasses of
 *!  @[AuthProvider].
 *!
 *!  This function may be overridden by the user class to provide
 *!  actual credentials.  The default implementation always returns 0.
 *!
 *! @param parameters
 *!   Any run-time data that the provider may need.  See @[first_credentials()].
 *! @param realm
 *!   The realm to aquire credentials for.
 *!
 *! @returns
 *!   A credentials set, or 0 if no more credentials are available.
 */
static void f_next_credentials (INT32 args)
{
  pop_n_elems (args);
  push_int (0);
}

static svn_error_t *next_credentials_null (void **credentials,
					   void *iter_baton,
					   void *provider_baton,
					   apr_hash_t *parameters,
					   const char *realmstring,
					   apr_pool_t *pool)
{
  *credentials = NULL;
  return SVN_NO_ERROR;
}

static svn_error_t *next_credentials_x (void **credentials,
					void *iter_baton,
					void *provider_baton,
					apr_hash_t *parameters,
					const char *realmstring,
					apr_pool_t *pool,
					void *(*make_cred)(struct svalue *,
							   apr_pool_t *))
{
  JMP_BUF recovery;
  svn_error_t *err = SVN_NO_ERROR;
  struct auth_provider_obj *apo = provider_baton;

  *credentials = NULL;

  do {
    struct thread_state *_tmp=thread_state_for_id (th_self ());
    HIDE_GLOBAL_VARIABLES ();
    THREADS_DISALLOW ();

    if (SETJMP (recovery))
      err = svn_pike_make_svn_error (&throw_value);
    else {
      struct svalue f;

      low_object_index_no_free(&f, apo->obj, apo->idlevel + 
			       next_credentials_function);

      push_auth_parameters (parameters, pool);
      svn_pike_push_utf8 (realmstring);
      apply_svalue (&f, 2);
      *credentials = make_cred(Pike_sp-1, pool);
      pop_stack ();
    }
    UNSETJMP (recovery);

    THREADS_ALLOW ();
  } while (0);

  return err;
}


/*! @decl int(0..1) save_credentials( mixed credentials,		@
 *!				      mapping(string:mixed) parameters,	@
 *!				      string realm )
 *!
 *!  Store @[credentials] for future use.  The provider is not required
 *!  to save; if it refuses or is unable to save for non-fatal reasons,
 *!  it should return 0.  The type of a credentials value differs with
 *!  the different subclasses of @[AuthProvider].
 *!
 *!  This function may be overridden by the user class to actually
 *!  store credentials.  The default implementation always returns 0.
 *!
 *! @param credentials
 *!   The credentials to save.
 *! @param parameters
 *!   Any run-time data that the provider may need.  See @[first_credentials()].
 *! @param realm
 *!   The realm to save credentials for.
 *!
 *! @returns
 *!   1 if the credentials were saved, 0 if the credentials were not saved.
 */
static void f_save_credentials (INT32 args)
{
  pop_n_elems (args);
  push_int (0);
}

static svn_error_t *save_credentials_null (svn_boolean_t *saved,
					   void *credentials,
					   void *provider_baton,
					   apr_hash_t *parameters,
					   const char *realmstring,
					   apr_pool_t *pool)
{
  *saved = FALSE;
  return SVN_NO_ERROR;
}

static svn_error_t *save_credentials_x (svn_boolean_t *saved,
					void *credentials,
					void *provider_baton,
					apr_hash_t *parameters,
					const char *realmstring,
					apr_pool_t *pool,
					void (*push_cred)(void *))
{
  JMP_BUF recovery;
  svn_error_t *err = SVN_NO_ERROR;
  struct auth_provider_obj *apo = provider_baton;

  *saved = FALSE;

  do {
    struct thread_state *_tmp=thread_state_for_id (th_self ());
    HIDE_GLOBAL_VARIABLES ();
    THREADS_DISALLOW ();

    if (SETJMP (recovery))
      err = svn_pike_make_svn_error (&throw_value);
    else {
      struct svalue f;

      low_object_index_no_free(&f, apo->obj, apo->idlevel + 
			       save_credentials_function);

      push_cred (credentials);
      push_auth_parameters (parameters, pool);
      svn_pike_push_utf8 (realmstring);
      apply_svalue (&f, 3);
      *saved = !UNSAFE_IS_ZERO (Pike_sp-1);
      pop_stack ();
    }
    UNSETJMP (recovery);

    THREADS_ALLOW ();
  } while (0);

  return err;
}


static const svn_auth_provider_t null_auth_provider_vtable = {
  "(null)",
  first_credentials_null,
  next_credentials_null,
  save_credentials_null
};

static void init_auth_provider (struct object *o)
{
  struct auth_provider_obj *apo = THIS;

  apo->ap.provider_baton = apo;
  apo->ap.vtable = &null_auth_provider_vtable;
  apo->obj = o;
  apo->idlevel = Pike_fp->context.identifier_level;
}

/*! @endclass */


/*! @class SimpleProvider
 *!
 *!   Simple username/password pair authentication provider
 *!
 *!   The credentials value is an array with the following contents:
 *!   @array
 *!     @elem string username
 *!       Username.
 *!     @elem string password
 *!       Password.
 *!     @elem int(0..1) may_save
 *!       Indicates if the credentials may be saved (to disk).
 *!   @endarray
 */

/*! @decl inherit AuthProvider */

void *make_simple_cred (struct svalue *credentials, apr_pool_t *pool)
{
  svn_auth_cred_simple_t *acs;
  struct pike_string *username, *password;

  if (credentials->type != PIKE_T_ARRAY ||
      credentials->u.array->size != 3 ||
      ITEM(credentials->u.array)[0].type != PIKE_T_STRING ||
      ITEM(credentials->u.array)[1].type != PIKE_T_STRING ||
      ITEM(credentials->u.array)[2].type != PIKE_T_INT)
    Pike_error ("Invalid credentials type.\n");

  username = svn_pike_to_utf8 (ITEM(credentials->u.array)[0].u.string);
  password = svn_pike_to_utf8 (ITEM(credentials->u.array)[1].u.string);

  acs = apr_pcalloc (pool, sizeof (*acs));
  acs->username = apr_pstrdup (pool, APR_STR0 (username));
  acs->password = apr_pstrdup (pool, APR_STR0 (password));
  acs->may_save = !!ITEM(credentials->u.array)[2].u.integer;

  do_free_string (username);
  do_free_string (password);

  return acs;
}

static void push_simple_cred (void *credentials)
{
  svn_auth_cred_simple_t *acs = credentials;

  svn_pike_push_utf8 (acs->username);
  svn_pike_push_utf8 (acs->password);
  push_int (acs->may_save);
  f_aggregate (3);
}

static svn_error_t *first_credentials_simple (void **credentials,
					      void **iter_baton,
					      void *provider_baton,
					      apr_hash_t *parameters,
					      const char *realmstring,
					      apr_pool_t *pool)
{
  return first_credentials_x (credentials, iter_baton, provider_baton,
			      parameters, realmstring, pool,
			      make_simple_cred);
}

static svn_error_t *next_credentials_simple (void **credentials,
					     void *iter_baton,
					     void *provider_baton,
					     apr_hash_t *parameters,
					     const char *realmstring,
					     apr_pool_t *pool)
{
  return next_credentials_x (credentials, iter_baton, provider_baton,
			     parameters, realmstring, pool,
			     make_simple_cred);
}

static svn_error_t *save_credentials_simple (svn_boolean_t *saved,
					     void *credentials,
					     void *provider_baton,
					     apr_hash_t *parameters,
					     const char *realmstring,
					     apr_pool_t *pool)
{
  return save_credentials_x (saved, credentials, provider_baton,
			     parameters, realmstring, pool,
			     push_simple_cred);
}

static const svn_auth_provider_t simple_auth_provider_vtable = {
  SVN_AUTH_CRED_SIMPLE,
  first_credentials_simple,
  next_credentials_simple,
  save_credentials_simple
};

static void init_simple_provider (struct object *o)
{
  struct auth_provider_obj *apo = THIS;
  apo->ap.vtable = &simple_auth_provider_vtable;
}

/*! @endclass */


/*! @class UsernameProvider
 *!
 *!   Username provider
 *!
 *!   The credentials value is an array with the following contents:
 *!   @array
 *!     @elem string username
 *!       Username.
 *!     @elem int(0..1) may_save
 *!       Indicates if the credentials may be saved (to disk).
 *!   @endarray
 */

/*! @decl inherit AuthProvider */

void *make_username_cred (struct svalue *credentials, apr_pool_t *pool)
{
  svn_auth_cred_username_t *acu;
  struct pike_string *username;

  if (credentials->type != PIKE_T_ARRAY ||
      credentials->u.array->size != 2 ||
      ITEM(credentials->u.array)[0].type != PIKE_T_STRING ||
      ITEM(credentials->u.array)[1].type != PIKE_T_INT)
    Pike_error ("Invalid credentials type.\n");

  username = svn_pike_to_utf8 (ITEM(credentials->u.array)[0].u.string);

  acu = apr_pcalloc (pool, sizeof (*acu));
  acu->username = apr_pstrdup (pool, APR_STR0 (username));
  acu->may_save = !!ITEM(credentials->u.array)[1].u.integer;

  do_free_string (username);

  return acu;
}

static void push_username_cred (void *credentials)
{
  svn_auth_cred_username_t *acu = credentials;

  svn_pike_push_utf8 (acu->username);
  push_int (acu->may_save);
  f_aggregate (2);
}

static svn_error_t *first_credentials_username (void **credentials,
						void **iter_baton,
						void *provider_baton,
						apr_hash_t *parameters,
						const char *realmstring,
						apr_pool_t *pool)
{
  return first_credentials_x (credentials, iter_baton, provider_baton,
			      parameters, realmstring, pool,
			      make_username_cred);
}

static svn_error_t *next_credentials_username (void **credentials,
					       void *iter_baton,
					       void *provider_baton,
					       apr_hash_t *parameters,
					       const char *realmstring,
					       apr_pool_t *pool)
{
  return next_credentials_x (credentials, iter_baton, provider_baton,
			     parameters, realmstring, pool,
			     make_username_cred);
}

static svn_error_t *save_credentials_username (svn_boolean_t *saved,
					       void *credentials,
					       void *provider_baton,
					       apr_hash_t *parameters,
					       const char *realmstring,
					       apr_pool_t *pool)
{
  return save_credentials_x (saved, credentials, provider_baton,
			     parameters, realmstring, pool,
			     push_username_cred);
}

static const svn_auth_provider_t username_auth_provider_vtable = {
  SVN_AUTH_CRED_USERNAME,
  first_credentials_username,
  next_credentials_username,
  save_credentials_username
};

static void init_username_provider (struct object *o)
{
  struct auth_provider_obj *apo = THIS;
  apo->ap.vtable = &username_auth_provider_vtable;
}

/*! @endclass */


/*! @class ClientCertProvider
 *!
 *!   SSL client certificate provider
 *!
 *!   The credentials value is an array with the following contents:
 *!   @array
 *!     @elem string cert_file
 *!       Full path to the certificate file.
 *!     @elem int(0..1) may_save
 *!       Indicates if the credentials may be saved (to disk).
 *!   @endarray
 */

/*! @decl inherit AuthProvider */

void *make_clientcert_cred (struct svalue *credentials, apr_pool_t *pool)
{
  svn_auth_cred_ssl_client_cert_t *acscc;
  struct pike_string *cert_file;

  if (credentials->type != PIKE_T_ARRAY ||
      credentials->u.array->size != 2 ||
      ITEM(credentials->u.array)[0].type != PIKE_T_STRING ||
      ITEM(credentials->u.array)[1].type != PIKE_T_INT)
    Pike_error ("Invalid credentials type.\n");

  cert_file = svn_pike_to_utf8 (ITEM(credentials->u.array)[0].u.string);

  acscc = apr_pcalloc (pool, sizeof (*acscc));
  acscc->cert_file = apr_pstrdup (pool, APR_STR0 (cert_file));
  acscc->may_save = !!ITEM(credentials->u.array)[1].u.integer;

  do_free_string (cert_file);

  return acscc;
}

static void push_clientcert_cred (void *credentials)
{
  svn_auth_cred_ssl_client_cert_t *acscc = credentials;

  svn_pike_push_utf8 (acscc->cert_file);
  push_int (acscc->may_save);
  f_aggregate (2);
}

static svn_error_t *first_credentials_clientcert (void **credentials,
						  void **iter_baton,
						  void *provider_baton,
						  apr_hash_t *parameters,
						  const char *realmstring,
						  apr_pool_t *pool)
{
  return first_credentials_x (credentials, iter_baton, provider_baton,
			      parameters, realmstring, pool,
			      make_clientcert_cred);
}

static svn_error_t *next_credentials_clientcert (void **credentials,
						 void *iter_baton,
						 void *provider_baton,
						 apr_hash_t *parameters,
						 const char *realmstring,
						 apr_pool_t *pool)
{
  return next_credentials_x (credentials, iter_baton, provider_baton,
			     parameters, realmstring, pool,
			     make_clientcert_cred);
}

static svn_error_t *save_credentials_clientcert (svn_boolean_t *saved,
						 void *credentials,
						 void *provider_baton,
						 apr_hash_t *parameters,
						 const char *realmstring,
						 apr_pool_t *pool)
{
  return save_credentials_x (saved, credentials, provider_baton,
			     parameters, realmstring, pool,
			     push_clientcert_cred);
}

static const svn_auth_provider_t clientcert_auth_provider_vtable = {
  SVN_AUTH_CRED_SSL_CLIENT_CERT,
  first_credentials_clientcert,
  next_credentials_clientcert,
  save_credentials_clientcert
};

static void init_clientcert_provider (struct object *o)
{
  struct auth_provider_obj *apo = THIS;
  apo->ap.vtable = &clientcert_auth_provider_vtable;
}

/*! @endclass */


/*! @class ClientCertPWProvider
 *!
 *!   Provides passphrases for SSL client certificates
 *!
 *!   The credentials value is an array with the following contents:
 *!   @array
 *!     @elem string password
 *!       Certificate password.
 *!     @elem int(0..1) may_save
 *!       Indicates if the credentials may be saved (to disk).
 *!   @endarray
 */

/*! @decl inherit AuthProvider */

void *make_clientcertpw_cred (struct svalue *credentials, apr_pool_t *pool)
{
  svn_auth_cred_ssl_client_cert_pw_t *acsccp;
  struct pike_string *password;

  if (credentials->type != PIKE_T_ARRAY ||
      credentials->u.array->size != 2 ||
      ITEM(credentials->u.array)[0].type != PIKE_T_STRING ||
      ITEM(credentials->u.array)[1].type != PIKE_T_INT)
    Pike_error ("Invalid credentials type.\n");

  password = svn_pike_to_utf8 (ITEM(credentials->u.array)[0].u.string);

  acsccp = apr_pcalloc (pool, sizeof (*acsccp));
  acsccp->password = apr_pstrdup (pool, APR_STR0 (password));
  acsccp->may_save = !!ITEM(credentials->u.array)[1].u.integer;

  do_free_string (password);

  return acsccp;
}

static void push_clientcertpw_cred (void *credentials)
{
  svn_auth_cred_ssl_client_cert_pw_t *acsccp = credentials;

  svn_pike_push_utf8 (acsccp->password);
  push_int (acsccp->may_save);
  f_aggregate (2);
}

static svn_error_t *first_credentials_clientcertpw (void **credentials,
						    void **iter_baton,
						    void *provider_baton,
						    apr_hash_t *parameters,
						    const char *realmstring,
						    apr_pool_t *pool)
{
  return first_credentials_x (credentials, iter_baton, provider_baton,
			      parameters, realmstring, pool,
			      make_clientcertpw_cred);
}

static svn_error_t *next_credentials_clientcertpw (void **credentials,
						   void *iter_baton,
						   void *provider_baton,
						   apr_hash_t *parameters,
						   const char *realmstring,
						   apr_pool_t *pool)
{
  return next_credentials_x (credentials, iter_baton, provider_baton,
			     parameters, realmstring, pool,
			     make_clientcertpw_cred);
}

static svn_error_t *save_credentials_clientcertpw (svn_boolean_t *saved,
						   void *credentials,
						   void *provider_baton,
						   apr_hash_t *parameters,
						   const char *realmstring,
						   apr_pool_t *pool)
{
  return save_credentials_x (saved, credentials, provider_baton,
			     parameters, realmstring, pool,
			     push_clientcertpw_cred);
}

static const svn_auth_provider_t clientcertpw_auth_provider_vtable = {
  SVN_AUTH_CRED_SSL_CLIENT_CERT_PW,
  first_credentials_clientcertpw,
  next_credentials_clientcertpw,
  save_credentials_clientcertpw
};

static void init_clientcertpw_provider (struct object *o)
{
  struct auth_provider_obj *apo = THIS;
  apo->ap.vtable = &clientcertpw_auth_provider_vtable;
}

/*! @endclass */


/*! @class ServerTrustProvider
 *!
 *!   Server verification provider
 *!
 *!   The credentials value is an array with the following contents:
 *!   @array
 *!     @elem int(0..1) may_save
 *!       Indicates if the credentials may be saved (to disk).
 *!     @elem int accepted_failures
 *!       Bit mask of accepted failures.
 *!   @endarray
 */

/*! @decl inherit AuthProvider */

void *make_servertrust_cred (struct svalue *credentials, apr_pool_t *pool)
{
  svn_auth_cred_ssl_server_trust_t *acsst;

  if (credentials->type != PIKE_T_ARRAY ||
      credentials->u.array->size != 2 ||
      ITEM(credentials->u.array)[0].type != PIKE_T_INT ||
      ITEM(credentials->u.array)[1].type != PIKE_T_INT)
    Pike_error ("Invalid credentials type.\n");

  acsst = apr_pcalloc (pool, sizeof (*acsst));
  acsst->may_save = !!ITEM(credentials->u.array)[0].u.integer;
  acsst->accepted_failures = ITEM(credentials->u.array)[1].u.integer;

  return acsst;
}

static void push_servertrust_cred (void *credentials)
{
  svn_auth_cred_ssl_server_trust_t *acsst = credentials;

  push_int (acsst->may_save);
  push_int (acsst->accepted_failures);
  f_aggregate (2);
}

static svn_error_t *first_credentials_servertrust (void **credentials,
						   void **iter_baton,
						   void *provider_baton,
						   apr_hash_t *parameters,
						   const char *realmstring,
						   apr_pool_t *pool)
{
  return first_credentials_x (credentials, iter_baton, provider_baton,
			      parameters, realmstring, pool,
			      make_servertrust_cred);
}

static svn_error_t *next_credentials_servertrust (void **credentials,
						  void *iter_baton,
						  void *provider_baton,
						  apr_hash_t *parameters,
						  const char *realmstring,
						  apr_pool_t *pool)
{
  return next_credentials_x (credentials, iter_baton, provider_baton,
			     parameters, realmstring, pool,
			     make_servertrust_cred);
}

static svn_error_t *save_credentials_servertrust (svn_boolean_t *saved,
						  void *credentials,
						  void *provider_baton,
						  apr_hash_t *parameters,
						  const char *realmstring,
						  apr_pool_t *pool)
{
  return save_credentials_x (saved, credentials, provider_baton,
			     parameters, realmstring, pool,
			     push_servertrust_cred);
}

static const svn_auth_provider_t servertrust_auth_provider_vtable = {
  SVN_AUTH_CRED_SSL_SERVER_TRUST,
  first_credentials_servertrust,
  next_credentials_servertrust,
  save_credentials_servertrust
};

static void init_servertrust_provider (struct object *o)
{
  struct auth_provider_obj *apo = THIS;
  apo->ap.vtable = &servertrust_auth_provider_vtable;
}

/*! @endclass */


/* Initialize Auth submodule */

void svn_pike_init_auth (void)
{
  struct program *auth_program;
  struct svalue prog;
  prog.type = PIKE_T_PROGRAM;
  prog.subtype = 0;

  start_new_program ();

  /*! @class AuthProvider */

  start_new_program ();

  ADD_STORAGE (struct auth_provider_obj);
  set_init_callback(init_auth_provider);

  first_credentials_function = ADD_FUNCTION ("first_credentials",
					     f_first_credentials,
					     tFunc (tMap (tStr, tMixed) tStr,
						    tMixed), 0);

  next_credentials_function = ADD_FUNCTION ("next_credentials",
					    f_next_credentials,
					    tFunc (tMap (tStr, tMixed) tStr,
						   tMixed), 0);

  save_credentials_function = ADD_FUNCTION ("save_credentials",
					    f_save_credentials,
					    tFunc (tMixed tMap (tStr, tMixed)
						   tStr, tInt01), 0);


  /*! @decl constant SSL_NOTYETVALID
   *! @decl constant SSL_EXPIRED
   *! @decl constant SSL_CNMISMATCH
   *! @decl constant SSL_UNKNOWNCA
   *! @decl constant SSL_OTHER
   *!
   *! Bits that can be set in the "svn:auth:ssl:failures" parameter to
   *! indicate various certificate validation failures.
   *!
   *! @seealso
   *!   @[ServerTrustProvider]
   */
  ADD_INT_CONSTANT ("SSL_NOTYETVALID", SVN_AUTH_SSL_NOTYETVALID, 0);
  ADD_INT_CONSTANT ("SSL_EXPIRED", SVN_AUTH_SSL_EXPIRED, 0);
  ADD_INT_CONSTANT ("SSL_CNMISMATCH", SVN_AUTH_SSL_CNMISMATCH, 0);
  ADD_INT_CONSTANT ("SSL_UNKNOWNCA", SVN_AUTH_SSL_UNKNOWNCA, 0);
  ADD_INT_CONSTANT ("SSL_OTHER", SVN_AUTH_SSL_OTHER, 0);

  svn_pike_auth_provider_program = end_program ();
  prog.u.program = svn_pike_auth_provider_program;
  add_program_constant ("AuthProvider", svn_pike_auth_provider_program, 0);

  /*! @endclass */

  start_new_program ();
  do_inherit(&prog, 0, NULL);
  set_init_callback(init_simple_provider);
  end_class ("SimpleProvider", 0);

  start_new_program ();
  do_inherit(&prog, 0, NULL);
  set_init_callback(init_username_provider);
  end_class ("UsernameProvider", 0);

  start_new_program ();
  do_inherit(&prog, 0, NULL);
  set_init_callback(init_clientcert_provider);
  end_class ("ClientCertProvider", 0);

  start_new_program ();
  do_inherit(&prog, 0, NULL);
  set_init_callback(init_clientcertpw_provider);
  end_class ("ClientCertPWProvider", 0);

  start_new_program ();
  do_inherit(&prog, 0, NULL);
  set_init_callback(init_servertrust_provider);
  end_class ("ServerTrustProvider", 0);

  auth_program = end_program ();
  add_object_constant ("Auth", clone_object (auth_program, 0), 0);
  free_program (auth_program);
}

/*! @endmodule */
/*! @endmodule */

gotpike.org | Copyright © 2004 - 2011 | Pike is a trademark of Department of Computer and Information Science, Linköping University