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

📄 mod_authz_svn.c

📁 linux subdivision ying gai ke yi le ba
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * mod_authz_svn.c: an Apache mod_dav_svn sub-module to provide path
 *                  based authorization for a Subversion repository.
 *
 * ====================================================================
 * Copyright (c) 2003-2004 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 <httpd.h>
#include <http_config.h>
#include <http_core.h>
#include <http_request.h>
#include <http_protocol.h>
#include <http_log.h>
#include <ap_config.h>
#include <apr_uri.h>
#include <mod_dav.h>

#include "mod_dav_svn.h"
#include "svn_error.h"
#include "svn_path.h"
#include "svn_config.h"
#include "svn_string.h"


module AP_MODULE_DECLARE_DATA authz_svn_module;

enum {
    AUTHZ_SVN_NONE = 0,
    AUTHZ_SVN_READ = 1,
    AUTHZ_SVN_WRITE = 2,
    AUTHZ_SVN_RECURSIVE = 4
};

typedef struct {
    int authoritative;
    int anonymous;
    const char *base_path;
    const char *access_file;
} authz_svn_config_rec;

struct parse_authz_baton {
    apr_pool_t *pool;
    svn_config_t *config;
    const char *user;
    int allow;
    int deny;

    int required_access;
    const char *repos_path;
    const char *qualified_repos_path;

    int access;
};

/*
 * Configuration
 */

static void *create_authz_svn_dir_config(apr_pool_t *p, char *d)
{
    authz_svn_config_rec *conf = apr_pcalloc(p, sizeof(*conf));
    conf->base_path = d;

    /* By default keep the fortress secure */
    conf->authoritative = 1;
    conf->anonymous = 1;

    return conf;
}

static const command_rec authz_svn_cmds[] =
{
    AP_INIT_FLAG("AuthzSVNAuthoritative", ap_set_flag_slot,
                 (void *)APR_OFFSETOF(authz_svn_config_rec, authoritative),
                 OR_AUTHCFG,
                 "Set to 'Off' to allow access control to be passed along to "
                 "lower modules. (default is On.)"),
    AP_INIT_TAKE1("AuthzSVNAccessFile", ap_set_file_slot,
                  (void *)APR_OFFSETOF(authz_svn_config_rec, access_file),
                  OR_AUTHCFG,
                  "Text file containing permissions of repository paths."),
    AP_INIT_FLAG("AuthzSVNAnonymous", ap_set_flag_slot,
                 (void *)APR_OFFSETOF(authz_svn_config_rec, anonymous),
                 OR_AUTHCFG,
                 "Set to 'Off' to skip access control when no authenticated "
                 "user is required. (default is On.)"),
    { NULL }
};


/*
 * Access checking
 */

static int group_contains_user(svn_config_t *cfg,
    const char *group, const char *user, apr_pool_t *pool)
{
    const char *value;
    apr_array_header_t *list;
    int i;

    svn_config_get(cfg, &value, "groups", group, "");
    list = svn_cstring_split(value, ",", TRUE, pool);

    for (i = 0; i < list->nelts; i++) {
       const char *group_user = APR_ARRAY_IDX(list, i, char *);
       if (!strcmp(user, group_user))
           return 1;
    }

    return 0;
}

static svn_boolean_t parse_authz_line(const char *name, const char *value,
                                      void *baton)
{
    struct parse_authz_baton *b = baton;

    if (strcmp(name, "*")) {
        if (!b->user) {
            return TRUE;
        }

        if (*name == '@') {
            if (!group_contains_user(b->config, &name[1], b->user, b->pool))
                return TRUE;
        }
        else if (strcmp(name, b->user)) {
            return TRUE;
        }
    }

    if (ap_strchr_c(value, 'r')) {
        b->allow |= AUTHZ_SVN_READ;
    }
    else {
        b->deny |= AUTHZ_SVN_READ;
    }

    if (ap_strchr_c(value, 'w')) {
        b->allow |= AUTHZ_SVN_WRITE;
    }
    else {
        b->deny |= AUTHZ_SVN_WRITE;
    }

    ap_log_perror(APLOG_MARK, APLOG_DEBUG, 0, b->pool,
                  "%s = %s => allow = %i, deny = %i",
                  name, value, b->allow, b->deny);

    return TRUE;
}

/*
 * Return TRUE when ACCESS has been determined.
 */
static int parse_authz_lines(svn_config_t *cfg,
                             const char *repos_name, const char *repos_path,
                             const char *user,
                             int required_access, int *access,
                             apr_pool_t *pool)
{
    const char *qualified_repos_path;
    struct parse_authz_baton baton = { 0 };

    baton.pool = pool;
    baton.config = cfg;
    baton.user = user;

    /* First try repos specific */
    qualified_repos_path = apr_pstrcat(pool, repos_name, ":", repos_path,
                                       NULL);
    svn_config_enumerate(cfg, qualified_repos_path,
                         parse_authz_line, &baton);
    *access = !(baton.deny & required_access)
              || (baton.allow & required_access);

    if ((baton.deny & required_access)
        || (baton.allow & required_access))
        return TRUE;

    svn_config_enumerate(cfg, repos_path,
                         parse_authz_line, &baton);
    *access = !(baton.deny & required_access)
              || (baton.allow & required_access);

    return (baton.deny & required_access)
           || (baton.allow & required_access);
}

static svn_boolean_t parse_authz_section(const char *section_name,
                                         void *baton)
{
  struct parse_authz_baton *b = baton;
  int conclusive;

  if (strncmp(section_name, b->qualified_repos_path,
              strlen(b->qualified_repos_path))
      && strncmp(section_name, b->repos_path,
                 strlen(b->repos_path))) {
      /* No match, move on to the next section. */
      return TRUE;
  }

  b->allow = b->deny = 0;
  svn_config_enumerate(b->config, section_name,
                       parse_authz_line, b);

  conclusive = (b->deny & b->required_access)
               || (b->allow & b->required_access);

  b->access = !(b->deny & b->required_access)
              || (b->allow & b->required_access)
              || !conclusive;
  
  /* If access isn't denied, move on to check the next section. */
  return b->access;
}

static int parse_authz_sections(svn_config_t *cfg,
                                const char *repos_name, const char *repos_path,
                                const char *user,
                                int required_access,
                                apr_pool_t *pool)
{
    struct parse_authz_baton baton = { 0 };

    baton.pool = pool;
    baton.config = cfg;
    baton.user = user;
    baton.required_access = required_access;
    baton.repos_path = repos_path;
    baton.qualified_repos_path = apr_pstrcat(pool, repos_name, ":",
                                             repos_path, NULL);
    
    baton.access = 1; /* Allow by default */
    svn_config_enumerate_sections(cfg, parse_authz_section, &baton);

    return baton.access;
}

static int check_access(svn_config_t *cfg, const char *repos_name,
                        const char *repos_path, const char *user,
                        int required_access, apr_pool_t *pool)
{
    const char *base_name;
    const char *original_repos_path = repos_path;
    int access;

    if (!repos_path) {
        /* XXX: Check if the user has 'required_access' _anywhere_ in the
         * XXX: repository.  For now, make this always succeed, until
         * XXX: we come up with a good way of figuring this out.
         */
        return 1;
    }

    base_name = repos_path;
    while (!parse_authz_lines(cfg, repos_name, repos_path,
                              user, required_access, &access,
                              pool)) {
        if (base_name[0] == '/' && base_name[1] == '\0') {
            /* By default, deny access */
            return 0;
        }

        svn_path_split(repos_path, &repos_path, &base_name, pool);
    }

    if (access && (required_access & AUTHZ_SVN_RECURSIVE) != 0) {
        /* Check access on entries below the current repos path */
        access = parse_authz_sections(cfg,
                                      repos_name, original_repos_path,
                                      user, required_access,
                                      pool);
    }

    return access;
}

/* Check if the current request R is allowed.  Upon exit *REPOS_PATH_REF
 * will contain the path and repository name that an operation was requested
 * on in the form 'name:path'.  *DEST_REPOS_PATH_REF will contain the
 * destination path if the requested operation was a MOVE or a COPY.
 * Returns OK when access is allowed, DECLINED when it isn't, or an HTTP_
 * error code when an error occurred.
 */
static int req_check_access(request_rec *r,
                            authz_svn_config_rec *conf,
                            const char **repos_path_ref,
                            const char **dest_repos_path_ref)
{
    const char *dest_uri;
    apr_uri_t parsed_dest_uri;
    const char *cleaned_uri;
    int trailing_slash;
    const char *repos_name;
    const char *dest_repos_name;
    const char *relative_path;
    const char *repos_path;
    const char *dest_repos_path = NULL;
    dav_error *dav_err;
    int authz_svn_type = 0;
    svn_config_t *access_conf = NULL;

⌨️ 快捷键说明

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