⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 serve.c

📁 subversion-1.4.5.tar.gz 配置svn的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * serve.c :  Functions for serving the Subversion protocol * * ==================================================================== * Copyright (c) 2000-2006 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/. * ==================================================================== */#include <limits.h> /* for UINT_MAX */#define APR_WANT_STRFUNC#include <apr_want.h>#include <apr_general.h>#include <apr_strings.h>#include <apr_md5.h>#include "svn_private_config.h"  /* For SVN_PATH_LOCAL_SEPARATOR */#include "svn_types.h"#include "svn_string.h"#include "svn_pools.h"#include "svn_error.h"#include "svn_ra_svn.h"#include "svn_repos.h"#include "svn_path.h"#include "svn_time.h"#include "svn_md5.h"#include "svn_config.h"#include "svn_props.h"#include "svn_user.h"#include "server.h"typedef struct {  svn_repos_t *repos;  svn_fs_t *fs;            /* For convenience; same as svn_repos_fs(repos) */  svn_config_t *cfg;       /* Parsed repository svnserve.conf */  svn_config_t *pwdb;      /* Parsed password database */  svn_authz_t *authzdb;    /* Parsed authz rules */  const char *authz_repos_name; /* The name of the repository */  const char *realm;       /* Authentication realm */  const char *repos_url;   /* URL to base of repository */  svn_stringbuf_t *fs_path;/* Decoded base path inside repository */  const char *user;  svn_boolean_t tunnel;    /* Tunneled through login agent */  const char *tunnel_user; /* Allow EXTERNAL to authenticate as this */  svn_boolean_t read_only; /* Disallow write access (global flag) */  int protocol_version;  apr_pool_t *pool;} server_baton_t;typedef struct {  apr_pool_t *pool;  svn_revnum_t *new_rev;  const char **date;  const char **author;  const char **post_commit_err;} commit_callback_baton_t;typedef struct {  server_baton_t *sb;  const char *repos_url;  /* Decoded repository URL. */  void *report_baton;  svn_error_t *err;} report_driver_baton_t;typedef struct {  const char *fs_path;  svn_ra_svn_conn_t *conn;} log_baton_t;typedef struct {  svn_ra_svn_conn_t *conn;  apr_pool_t *pool;  /* Pool provided in the handler call. */} file_revs_baton_t;enum authn_type { UNAUTHENTICATED, AUTHENTICATED };enum access_type { NO_ACCESS, READ_ACCESS, WRITE_ACCESS };/* Verify that URL is inside REPOS_URL and get its fs path. Assume that    REPOS_URL and URL are already URI-decoded. */static svn_error_t *get_fs_path(const char *repos_url, const char *url,                                const char **fs_path, apr_pool_t *pool){  apr_size_t len;  len = strlen(repos_url);  if (strncmp(url, repos_url, len) != 0)    return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,                             "'%s' is not the same repository as '%s'",                             url, repos_url);  *fs_path = url + len;  return SVN_NO_ERROR;}/* --- AUTHENTICATION AND AUTHORIZATION FUNCTIONS --- *//* Set *ALLOWED to TRUE if PATH is accessible in the REQUIRED mode to   the user described in BATON according to the authz rules in BATON.   Use POOL for temporary allocations only.  If no authz rules are   present in BATON, grant access by default. */static svn_error_t *authz_check_access(svn_boolean_t *allowed,                                       const char *path,                                       svn_repos_authz_access_t required,                                       server_baton_t *b,                                       apr_pool_t *pool){  /* If authz cannot be performed, grant access.  This is NOT the same     as the default policy when authz is performed on a path with no     rules.  In the latter case, the default is to deny access, and is     set by svn_repos_authz_check_access. */  if (!b->authzdb)    {      *allowed = TRUE;      return SVN_NO_ERROR;    }  /* If the authz request is for the empty path (ie. ""), replace it     with the root path.  This happens because of stripping done at     various levels in svnserve that remove the leading / on an     absolute path. Passing such a malformed path to the authz     routines throws them into an infinite loop and makes them miss     ACLs. */  if (path && *path != '/')    path = svn_path_join("/", path, pool);  return svn_repos_authz_check_access(b->authzdb, b->authz_repos_name,                                      path, b->user, required,                                      allowed, pool);}/* Set *ALLOWED to TRUE if PATH is readable by the user described in * BATON.  Use POOL for temporary allocations only.  ROOT is not used. * Implements the svn_repos_authz_func_t interface. */static svn_error_t *authz_check_access_cb(svn_boolean_t *allowed,                                          svn_fs_root_t *root,                                          const char *path,                                          void *baton,                                          apr_pool_t *pool){  server_baton_t *sb = baton;  return authz_check_access(allowed, path, svn_authz_read, sb, pool);}/* If authz is enabled in the specified BATON, return a read authorization   function. Otherwise, return NULL. */static svn_repos_authz_func_t authz_check_access_cb_func(server_baton_t *baton){  if (baton->authzdb)     return authz_check_access_cb;  return NULL;}/* Set *ALLOWED to TRUE if the REQUIRED access to PATH is granted, * according to the state in BATON.  Use POOL for temporary * allocations only.  ROOT is not used.  Implements the * svn_repos_authz_callback_t interface. */static svn_error_t *authz_commit_cb(svn_repos_authz_access_t required,                                    svn_boolean_t *allowed,                                    svn_fs_root_t *root,                                    const char *path,                                    void *baton,                                    apr_pool_t *pool){  server_baton_t *sb = baton;  return authz_check_access(allowed, path, required, sb, pool);}static enum access_type get_access(server_baton_t *b, enum authn_type auth){  const char *var = (auth == AUTHENTICATED) ? SVN_CONFIG_OPTION_AUTH_ACCESS :    SVN_CONFIG_OPTION_ANON_ACCESS;  const char *val, *def = (auth == AUTHENTICATED) ? "write" : "read";  enum access_type result;  svn_config_get(b->cfg, &val, SVN_CONFIG_SECTION_GENERAL, var, def);  result = (strcmp(val, "write") == 0 ? WRITE_ACCESS :            strcmp(val, "read") == 0 ? READ_ACCESS : NO_ACCESS);  return (result == WRITE_ACCESS && b->read_only) ? READ_ACCESS : result;}static enum access_type current_access(server_baton_t *b){  return get_access(b, (b->user) ? AUTHENTICATED : UNAUTHENTICATED);}/* Send authentication mechs for ACCESS_TYPE to the client.  If NEEDS_USERNAME   is true, don't send anonymous mech even if that would give the desired   access. */static svn_error_t *send_mechs(svn_ra_svn_conn_t *conn, apr_pool_t *pool,                               server_baton_t *b, enum access_type required,                               svn_boolean_t needs_username){  if (!needs_username && get_access(b, UNAUTHENTICATED) >= required)    SVN_ERR(svn_ra_svn_write_word(conn, pool, "ANONYMOUS"));  if (b->tunnel_user && get_access(b, AUTHENTICATED) >= required)    SVN_ERR(svn_ra_svn_write_word(conn, pool, "EXTERNAL"));  if (b->pwdb && get_access(b, AUTHENTICATED) >= required)    SVN_ERR(svn_ra_svn_write_word(conn, pool, "CRAM-MD5"));  return SVN_NO_ERROR;}/* Context for cleanup handler. */struct cleanup_fs_access_baton{  svn_fs_t *fs;  apr_pool_t *pool;};/* Pool cleanup handler.  Make sure fs's access_t points to NULL when   the command pool is destroyed. */static apr_status_t cleanup_fs_access(void *data){  svn_error_t *serr;  struct cleanup_fs_access_baton *baton = data;  serr = svn_fs_set_access(baton->fs, NULL);  if (serr)    {      apr_status_t apr_err = serr->apr_err;      svn_error_clear(serr);      return apr_err;    }  return APR_SUCCESS;}/* Create an svn_fs_access_t in POOL for USER and associate it with   B's filesystem.  Also, register a cleanup handler with POOL which   de-associates the svn_fs_access_t from B's filesystem. */static svn_error_t *create_fs_access(server_baton_t *b, apr_pool_t *pool){  svn_fs_access_t *fs_access;  struct cleanup_fs_access_baton *cleanup_baton;  if (!b->user)    return SVN_NO_ERROR;  SVN_ERR(svn_fs_create_access(&fs_access, b->user, pool));  SVN_ERR(svn_fs_set_access(b->fs, fs_access));  cleanup_baton = apr_pcalloc(pool, sizeof(*cleanup_baton));  cleanup_baton->pool = pool;  cleanup_baton->fs = b->fs;  apr_pool_cleanup_register(pool, cleanup_baton, cleanup_fs_access,                            apr_pool_cleanup_null);  return SVN_NO_ERROR;}/* Authenticate, once the client has chosen a mechanism and possibly * sent an initial mechanism token.  On success, set *success to true * and b->user to the authenticated username (or NULL for anonymous). * On authentication failure, report failure to the client and set * *success to FALSE.  On communications failure, return an error. * If NEEDS_USERNAME is TRUE, don't allow anonymous authentication. */static svn_error_t *auth(svn_ra_svn_conn_t *conn, apr_pool_t *pool,                         const char *mech, const char *mecharg,                         server_baton_t *b, enum access_type required,                         svn_boolean_t needs_username,                         svn_boolean_t *success){  const char *user;  *success = FALSE;  if (get_access(b, AUTHENTICATED) >= required      && b->tunnel_user && strcmp(mech, "EXTERNAL") == 0)    {      if (*mecharg && strcmp(mecharg, b->tunnel_user) != 0)        return svn_ra_svn_write_tuple(conn, pool, "w(c)", "failure",                                      "Requested username does not match");      b->user = b->tunnel_user;      SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "w()", "success"));      *success = TRUE;      return SVN_NO_ERROR;    }  if (get_access(b, UNAUTHENTICATED) >= required      && strcmp(mech, "ANONYMOUS") == 0 && ! needs_username)    {      SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "w()", "success"));      *success = TRUE;      return SVN_NO_ERROR;    }  if (get_access(b, AUTHENTICATED) >= required      && b->pwdb && strcmp(mech, "CRAM-MD5") == 0)    {      SVN_ERR(svn_ra_svn_cram_server(conn, pool, b->pwdb, &user, success));      b->user = apr_pstrdup(b->pool, user);      return SVN_NO_ERROR;    }  return svn_ra_svn_write_tuple(conn, pool, "w(c)", "failure",                                "Must authenticate with listed mechanism");}/* Perform an authentication request in order to get an access level of * REQUIRED or higher.  Since the client may escape the authentication * exchange, the caller should check current_access(b) to see if * authentication succeeded. */static svn_error_t *auth_request(svn_ra_svn_conn_t *conn, apr_pool_t *pool,                                 server_baton_t *b, enum access_type required,                                 svn_boolean_t needs_username){  svn_boolean_t success;  const char *mech, *mecharg;  SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "w((!", "success"));  SVN_ERR(send_mechs(conn, pool, b, required, needs_username));  SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "!)c)", b->realm));  do    {      SVN_ERR(svn_ra_svn_read_tuple(conn, pool, "w(?c)", &mech, &mecharg));      if (!*mech)        break;      SVN_ERR(auth(conn, pool, mech, mecharg, b, required, needs_username,                   &success));    }  while (!success);  return SVN_NO_ERROR;}/* Send a trivial auth request, listing no mechanisms. */static svn_error_t *trivial_auth_request(svn_ra_svn_conn_t *conn,                                         apr_pool_t *pool, server_baton_t *b){  if (b->protocol_version < 2)    return SVN_NO_ERROR;  return svn_ra_svn_write_cmd_response(conn, pool, "()c", "");}/* Ensure that the client has the REQUIRED access by checking the * access directives (both blanket and per-directory) in BATON.  If * PATH is NULL, then only the blanket access configuration will * impact the result. * * If NEEDS_USERNAME is TRUE, then a lookup is only successful if the * user described in BATON is authenticated and, well, has a username * assigned to him. * * Use POOL for temporary allocations only. */static svn_boolean_t lookup_access(apr_pool_t *pool,                                   server_baton_t *baton,                                   svn_repos_authz_access_t required,                                   const char *path,                                   svn_boolean_t needs_username)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -