authz_pool.c revision 299742
1/*
2 * authz_pool.c :  pool of authorization objects
3 *
4 * ====================================================================
5 *    Licensed to the Apache Software Foundation (ASF) under one
6 *    or more contributor license agreements.  See the NOTICE file
7 *    distributed with this work for additional information
8 *    regarding copyright ownership.  The ASF licenses this file
9 *    to you under the Apache License, Version 2.0 (the
10 *    "License"); you may not use this file except in compliance
11 *    with the License.  You may obtain a copy of the License at
12 *
13 *      http://www.apache.org/licenses/LICENSE-2.0
14 *
15 *    Unless required by applicable law or agreed to in writing,
16 *    software distributed under the License is distributed on an
17 *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 *    KIND, either express or implied.  See the License for the
19 *    specific language governing permissions and limitations
20 *    under the License.
21 * ====================================================================
22 */
23
24
25
26#include "svn_checksum.h"
27#include "svn_config.h"
28#include "svn_error.h"
29#include "svn_pools.h"
30
31#include "private/svn_dep_compat.h"
32#include "private/svn_mutex.h"
33#include "private/svn_object_pool.h"
34#include "private/svn_subr_private.h"
35#include "private/svn_repos_private.h"
36#include "private/svn_string_private.h"
37#include "private/svn_subr_private.h"
38
39#include "repos.h"
40
41/* Currently this structure is just a wrapper around a svn_config_t.
42 */
43struct svn_authz_t
44{
45  svn_config_t *cfg;
46};
47
48/* The wrapper object structure that we store in the object pool.  It
49 * combines the authz with the underlying config structures and their
50 * identifying keys.
51 */
52typedef struct authz_object_t
53{
54  /* key = concatenation of AUTHZ_KEY and GROUPS_KEY */
55  svn_membuf_t *key;
56
57  /* keys used to identify AUTHZ_CFG and GROUPS_CFG */
58  svn_membuf_t *authz_key;
59  svn_membuf_t *groups_key;
60
61  /* r/o references to configurations from the configuration pool.
62     GROUPS_CFG may be NULL. */
63  svn_config_t *authz_cfg;
64  svn_config_t *groups_cfg;
65
66  /* Case-sensitive config. */
67  svn_authz_t *authz;
68} authz_object_t;
69
70/* Root data structure simply adding the config_pool to the basic object pool.
71 */
72struct svn_repos__authz_pool_t
73{
74  /* authz_object_t object storage */
75  svn_object_pool__t *object_pool;
76
77  /* factory and storage of (shared) configuration objects */
78  svn_repos__config_pool_t *config_pool;
79};
80
81/* Return a combination of AUTHZ_KEY and GROUPS_KEY, allocated in POOL.
82 * GROUPS_KEY may be NULL.
83 */
84static svn_membuf_t *
85construct_key(svn_membuf_t *authz_key,
86              svn_membuf_t *groups_key,
87              apr_pool_t *pool)
88{
89  svn_membuf_t *result = apr_pcalloc(pool, sizeof(*result));
90  apr_size_t size;
91  if (groups_key)
92    {
93      size = authz_key->size + groups_key->size;
94      svn_membuf__create(result,size, pool);
95      memcpy(result->data, authz_key->data, authz_key->size);
96      memcpy((char *)result->data + authz_key->size,
97             groups_key->data, groups_key->size);
98    }
99  else
100    {
101      size = authz_key->size;
102      svn_membuf__create(result, size, pool);
103      memcpy(result->data, authz_key->data, authz_key->size);
104    }
105
106  result->size = size;
107  return result;
108}
109
110/* Implement svn_object_pool__getter_t on authz_object_t structures.
111 */
112static void *
113getter(void *object,
114       void *baton,
115       apr_pool_t *pool)
116{
117  return ((authz_object_t *)object)->authz;
118}
119
120/* API implementation */
121
122svn_error_t *
123svn_repos__authz_pool_create(svn_repos__authz_pool_t **authz_pool,
124                             svn_repos__config_pool_t *config_pool,
125                             svn_boolean_t thread_safe,
126                             apr_pool_t *pool)
127{
128  svn_repos__authz_pool_t *result;
129  svn_object_pool__t *object_pool;
130
131  /* there is no setter as we don't need to update existing authz */
132  SVN_ERR(svn_object_pool__create(&object_pool, getter, NULL, thread_safe,
133                                  pool));
134
135  result = apr_pcalloc(pool, sizeof(*result));
136  result->object_pool = object_pool;
137  result->config_pool = config_pool;
138
139  *authz_pool = result;
140  return SVN_NO_ERROR;
141}
142
143svn_error_t *
144svn_repos__authz_pool_get(svn_authz_t **authz_p,
145                          svn_repos__authz_pool_t *authz_pool,
146                          const char *path,
147                          const char *groups_path,
148                          svn_boolean_t must_exist,
149                          svn_repos_t *preferred_repos,
150                          apr_pool_t *pool)
151{
152  apr_pool_t *authz_ref_pool
153    = svn_object_pool__new_wrapper_pool(authz_pool->object_pool);
154  authz_object_t *authz_ref
155    = apr_pcalloc(authz_ref_pool, sizeof(*authz_ref));
156  svn_boolean_t have_all_keys;
157
158  /* read the configurations */
159  SVN_ERR(svn_repos__config_pool_get(&authz_ref->authz_cfg,
160                                     &authz_ref->authz_key,
161                                     authz_pool->config_pool,
162                                     path, must_exist, TRUE,
163                                     preferred_repos, authz_ref_pool));
164  have_all_keys = authz_ref->authz_key != NULL;
165
166  if (groups_path)
167    {
168      SVN_ERR(svn_repos__config_pool_get(&authz_ref->groups_cfg,
169                                         &authz_ref->groups_key,
170                                         authz_pool->config_pool,
171                                         groups_path, must_exist, TRUE,
172                                         preferred_repos, authz_ref_pool));
173      have_all_keys &= authz_ref->groups_key != NULL;
174    }
175
176  /* fall back to standard implementation in case we don't have all the
177   * facts (i.e. keys). */
178  if (!have_all_keys)
179    return svn_error_trace(svn_repos_authz_read2(authz_p, path, groups_path,
180                                                 must_exist, pool));
181
182  /* all keys are known and lookup is unambigious. */
183  authz_ref->key = construct_key(authz_ref->authz_key,
184                                 authz_ref->groups_key,
185                                 authz_ref_pool);
186
187  SVN_ERR(svn_object_pool__lookup((void **)authz_p, authz_pool->object_pool,
188                                  authz_ref->key, NULL, pool));
189  if (*authz_p)
190    {
191      svn_pool_destroy(authz_ref_pool);
192      return SVN_NO_ERROR;
193    }
194
195  authz_ref->authz = apr_palloc(authz_ref_pool, sizeof(*authz_ref->authz));
196  authz_ref->authz->cfg = authz_ref->authz_cfg;
197
198  if (groups_path)
199    {
200      /* Easy out: we prohibit local groups in the authz file when global
201         groups are being used. */
202      if (svn_config_has_section(authz_ref->authz->cfg,
203                                 SVN_CONFIG_SECTION_GROUPS))
204        return svn_error_createf(SVN_ERR_AUTHZ_INVALID_CONFIG, NULL,
205                                 "Error reading authz file '%s' with "
206                                 "groups file '%s':"
207                                 "Authz file cannot contain any groups "
208                                 "when global groups are being used.",
209                                 path, groups_path);
210
211      /* We simply need to add the [Groups] section to the authz config.
212       */
213      svn_config__shallow_replace_section(authz_ref->authz->cfg,
214                                          authz_ref->groups_cfg,
215                                          SVN_CONFIG_SECTION_GROUPS);
216    }
217
218  /* Make sure there are no errors in the configuration. */
219  SVN_ERR(svn_repos__authz_validate(authz_ref->authz, authz_ref_pool));
220
221  SVN_ERR(svn_object_pool__insert((void **)authz_p, authz_pool->object_pool,
222                                  authz_ref->key, authz_ref, NULL,
223                                  authz_ref_pool, pool));
224
225  return SVN_NO_ERROR;
226}
227