~ubuntu-branches/debian/sid/subversion/sid

« back to all changes in this revision

Viewing changes to subversion/libsvn_ra_serf/get_lock.c

  • Committer: Package Import Robot
  • Author(s): James McCoy
  • Date: 2015-08-07 21:32:47 UTC
  • mfrom: (0.2.15) (4.1.7 experimental)
  • Revision ID: package-import@ubuntu.com-20150807213247-ozyewtmgsr6tkewl
Tags: 1.9.0-1
* Upload to unstable
* New upstream release.
  + Security fixes
    - CVE-2015-3184: Mixed anonymous/authenticated path-based authz with
      httpd 2.4
    - CVE-2015-3187: svn_repos_trace_node_locations() reveals paths hidden
      by authz
* Add >= 2.7 requirement for python-all-dev Build-Depends, needed to run
  tests.
* Remove Build-Conflicts against ruby-test-unit.  (Closes: #791844)
* Remove patches/apache_module_dependency in favor of expressing the
  dependencies in authz_svn.load/dav_svn.load.
* Build-Depend on apache2-dev (>= 2.4.16) to ensure ap_some_authn_required()
  is available when building mod_authz_svn and Depend on apache2-bin (>=
  2.4.16) for runtime support.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * get_lock.c :  obtain single lock information functions for ra_serf
 
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 <apr_uri.h>
 
27
#include <serf.h>
 
28
 
 
29
#include "svn_dav.h"
 
30
#include "svn_pools.h"
 
31
#include "svn_ra.h"
 
32
 
 
33
#include "../libsvn_ra/ra_loader.h"
 
34
#include "svn_config.h"
 
35
#include "svn_path.h"
 
36
#include "svn_time.h"
 
37
#include "svn_private_config.h"
 
38
 
 
39
#include "ra_serf.h"
 
40
 
 
41
 
 
42
/*
 
43
 * This enum represents the current state of our XML parsing for a REPORT.
 
44
 */
 
45
enum {
 
46
  INITIAL = 0,
 
47
  MULTISTATUS,
 
48
  RESPONSE,
 
49
  PROPSTAT,
 
50
  PROP,
 
51
  LOCK_DISCOVERY,
 
52
  ACTIVE_LOCK,
 
53
  LOCK_TYPE,
 
54
  LOCK_SCOPE,
 
55
  DEPTH,
 
56
  TIMEOUT,
 
57
  LOCK_TOKEN,
 
58
  OWNER,
 
59
  HREF
 
60
};
 
61
 
 
62
typedef struct lock_info_t {
 
63
  apr_pool_t *pool;
 
64
 
 
65
  const char *path;
 
66
 
 
67
  svn_lock_t *lock;
 
68
 
 
69
  svn_boolean_t read_headers;
 
70
 
 
71
  svn_ra_serf__handler_t *handler;
 
72
 
 
73
  /* The expat handler. We wrap this to do a bit more work.  */
 
74
  svn_ra_serf__response_handler_t inner_handler;
 
75
  void *inner_baton;
 
76
 
 
77
} lock_info_t;
 
78
 
 
79
#define D_ "DAV:"
 
80
#define S_ SVN_XML_NAMESPACE
 
81
static const svn_ra_serf__xml_transition_t locks_ttable[] = {
 
82
  /* The INITIAL state can transition into D:prop (LOCK) or
 
83
     to D:multistatus (PROPFIND)  */
 
84
  { INITIAL, D_, "multistatus", MULTISTATUS,
 
85
    FALSE, { NULL }, FALSE },
 
86
 
 
87
  { MULTISTATUS, D_, "response", RESPONSE,
 
88
    FALSE, { NULL }, FALSE },
 
89
 
 
90
  { RESPONSE, D_, "propstat", PROPSTAT,
 
91
    FALSE, { NULL }, FALSE },
 
92
 
 
93
  { PROPSTAT, D_, "prop", PROP,
 
94
    FALSE, { NULL }, FALSE },
 
95
 
 
96
  { PROP, D_, "lockdiscovery", LOCK_DISCOVERY,
 
97
    FALSE, { NULL }, FALSE },
 
98
 
 
99
  { LOCK_DISCOVERY, D_, "activelock", ACTIVE_LOCK,
 
100
    FALSE, { NULL }, FALSE },
 
101
 
 
102
#if 0
 
103
  /* ### we don't really need to parse locktype/lockscope. we know what
 
104
     ### the values are going to be. we *could* validate that the only
 
105
     ### possible children are D:write and D:exclusive. we'd need to
 
106
     ### modify the state transition to tell us about all children
 
107
     ### (ie. maybe support "*" for the name) and then validate. but it
 
108
     ### just isn't important to validate, so disable this for now... */
 
109
 
 
110
  { ACTIVE_LOCK, D_, "locktype", LOCK_TYPE,
 
111
    FALSE, { NULL }, FALSE },
 
112
 
 
113
  { LOCK_TYPE, D_, "write", WRITE,
 
114
    FALSE, { NULL }, TRUE },
 
115
 
 
116
  { ACTIVE_LOCK, D_, "lockscope", LOCK_SCOPE,
 
117
    FALSE, { NULL }, FALSE },
 
118
 
 
119
  { LOCK_SCOPE, D_, "exclusive", EXCLUSIVE,
 
120
    FALSE, { NULL }, TRUE },
 
121
#endif /* 0  */
 
122
 
 
123
  { ACTIVE_LOCK, D_, "timeout", TIMEOUT,
 
124
    TRUE, { NULL }, TRUE },
 
125
 
 
126
  { ACTIVE_LOCK, D_, "locktoken", LOCK_TOKEN,
 
127
    FALSE, { NULL }, FALSE },
 
128
 
 
129
  { LOCK_TOKEN, D_, "href", HREF,
 
130
    TRUE, { NULL }, TRUE },
 
131
 
 
132
  { ACTIVE_LOCK, D_, "owner", OWNER,
 
133
    TRUE, { NULL }, TRUE },
 
134
 
 
135
  /* ACTIVE_LOCK has a D:depth child, but we can ignore that.  */
 
136
 
 
137
  { 0 }
 
138
};
 
139
 
 
140
static const int locks_expected_status[] = {
 
141
  207,
 
142
  0
 
143
};
 
144
 
 
145
/* Conforms to svn_ra_serf__xml_closed_t  */
 
146
static svn_error_t *
 
147
locks_closed(svn_ra_serf__xml_estate_t *xes,
 
148
             void *baton,
 
149
             int leaving_state,
 
150
             const svn_string_t *cdata,
 
151
             apr_hash_t *attrs,
 
152
             apr_pool_t *scratch_pool)
 
153
{
 
154
  lock_info_t *lock_ctx = baton;
 
155
 
 
156
  if (leaving_state == TIMEOUT)
 
157
    {
 
158
      if (strcasecmp(cdata->data, "Infinite") == 0)
 
159
        lock_ctx->lock->expiration_date = 0;
 
160
      else if (strncasecmp(cdata->data, "Second-", 7) == 0)
 
161
        {
 
162
          unsigned n;
 
163
          SVN_ERR(svn_cstring_atoui(&n, cdata->data+7));
 
164
 
 
165
          lock_ctx->lock->expiration_date = apr_time_now() +
 
166
                                            apr_time_from_sec(n);
 
167
        }
 
168
      else
 
169
         return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
 
170
                                  _("Invalid LOCK timeout value '%s'"),
 
171
                                  cdata->data);
 
172
    }
 
173
  else if (leaving_state == HREF)
 
174
    {
 
175
      if (cdata->len)
 
176
        {
 
177
          char *buf = apr_pstrmemdup(lock_ctx->pool, cdata->data, cdata->len);
 
178
 
 
179
          apr_collapse_spaces(buf, buf);
 
180
          lock_ctx->lock->token = buf;
 
181
        }
 
182
    }
 
183
  else if (leaving_state == OWNER)
 
184
    {
 
185
      if (cdata->len)
 
186
        {
 
187
          lock_ctx->lock->comment = apr_pstrmemdup(lock_ctx->pool,
 
188
                                                   cdata->data, cdata->len);
 
189
        }
 
190
    }
 
191
 
 
192
  return SVN_NO_ERROR;
 
193
}
 
194
 
 
195
/* Implements svn_ra_serf__response_handler_t */
 
196
static svn_error_t *
 
197
handle_lock(serf_request_t *request,
 
198
            serf_bucket_t *response,
 
199
            void *handler_baton,
 
200
            apr_pool_t *pool)
 
201
{
 
202
  lock_info_t *ctx = handler_baton;
 
203
 
 
204
  if (!ctx->read_headers)
 
205
    {
 
206
      serf_bucket_t *headers;
 
207
      const char *val;
 
208
 
 
209
      headers = serf_bucket_response_get_headers(response);
 
210
 
 
211
      val = serf_bucket_headers_get(headers, SVN_DAV_LOCK_OWNER_HEADER);
 
212
      if (val)
 
213
        {
 
214
          ctx->lock->owner = apr_pstrdup(ctx->pool, val);
 
215
        }
 
216
 
 
217
      val = serf_bucket_headers_get(headers, SVN_DAV_CREATIONDATE_HEADER);
 
218
      if (val)
 
219
        {
 
220
          SVN_ERR(svn_time_from_cstring(&ctx->lock->creation_date, val,
 
221
                                        ctx->pool));
 
222
        }
 
223
 
 
224
      ctx->read_headers = TRUE;
 
225
    }
 
226
 
 
227
  return ctx->inner_handler(request, response, ctx->inner_baton, pool);
 
228
}
 
229
 
 
230
/* Implements svn_ra_serf__request_body_delegate_t */
 
231
static svn_error_t *
 
232
create_getlock_body(serf_bucket_t **body_bkt,
 
233
                    void *baton,
 
234
                    serf_bucket_alloc_t *alloc,
 
235
                    apr_pool_t *pool /* request pool */,
 
236
                    apr_pool_t *scratch_pool)
 
237
{
 
238
  serf_bucket_t *buckets;
 
239
 
 
240
  buckets = serf_bucket_aggregate_create(alloc);
 
241
 
 
242
  svn_ra_serf__add_xml_header_buckets(buckets, alloc);
 
243
  svn_ra_serf__add_open_tag_buckets(buckets, alloc, "propfind",
 
244
                                    "xmlns", "DAV:",
 
245
                                    SVN_VA_NULL);
 
246
  svn_ra_serf__add_open_tag_buckets(buckets, alloc, "prop", SVN_VA_NULL);
 
247
  svn_ra_serf__add_empty_tag_buckets(buckets, alloc,
 
248
                                     "lockdiscovery", SVN_VA_NULL);
 
249
  svn_ra_serf__add_close_tag_buckets(buckets, alloc, "prop");
 
250
  svn_ra_serf__add_close_tag_buckets(buckets, alloc, "propfind");
 
251
 
 
252
  *body_bkt = buckets;
 
253
  return SVN_NO_ERROR;
 
254
}
 
255
 
 
256
static svn_error_t*
 
257
setup_getlock_headers(serf_bucket_t *headers,
 
258
                      void *baton,
 
259
                      apr_pool_t *pool /* request pool */,
 
260
                      apr_pool_t *scratch_pool)
 
261
{
 
262
  serf_bucket_headers_setn(headers, "Depth", "0");
 
263
 
 
264
  return SVN_NO_ERROR;
 
265
}
 
266
 
 
267
svn_error_t *
 
268
svn_ra_serf__get_lock(svn_ra_session_t *ra_session,
 
269
                      svn_lock_t **lock,
 
270
                      const char *path,
 
271
                      apr_pool_t *result_pool)
 
272
{
 
273
  svn_ra_serf__session_t *session = ra_session->priv;
 
274
  svn_ra_serf__handler_t *handler;
 
275
  svn_ra_serf__xml_context_t *xmlctx;
 
276
  apr_pool_t *scratch_pool = svn_pool_create(result_pool);
 
277
  lock_info_t *lock_ctx;
 
278
  const char *req_url;
 
279
  svn_error_t *err;
 
280
 
 
281
  req_url = svn_path_url_add_component2(session->session_url.path, path,
 
282
                                        scratch_pool);
 
283
 
 
284
  lock_ctx = apr_pcalloc(scratch_pool, sizeof(*lock_ctx));
 
285
  lock_ctx->pool = result_pool;
 
286
  lock_ctx->path = req_url;
 
287
  lock_ctx->lock = svn_lock_create(result_pool);
 
288
  lock_ctx->lock->path = apr_pstrdup(result_pool, path);
 
289
 
 
290
  xmlctx = svn_ra_serf__xml_context_create(locks_ttable,
 
291
                                           NULL, locks_closed, NULL,
 
292
                                           lock_ctx,
 
293
                                           scratch_pool);
 
294
  handler = svn_ra_serf__create_expat_handler(session, xmlctx,
 
295
                                              locks_expected_status,
 
296
                                              scratch_pool);
 
297
 
 
298
  handler->method = "PROPFIND";
 
299
  handler->path = req_url;
 
300
  handler->body_type = "text/xml";
 
301
 
 
302
  handler->body_delegate = create_getlock_body;
 
303
  handler->body_delegate_baton = lock_ctx;
 
304
 
 
305
  handler->header_delegate = setup_getlock_headers;
 
306
  handler->header_delegate_baton = lock_ctx;
 
307
 
 
308
  handler->no_dav_headers = TRUE;
 
309
 
 
310
  lock_ctx->inner_handler = handler->response_handler;
 
311
  lock_ctx->inner_baton = handler->response_baton;
 
312
  handler->response_handler = handle_lock;
 
313
  handler->response_baton = lock_ctx;
 
314
 
 
315
  lock_ctx->handler = handler;
 
316
 
 
317
  err = svn_ra_serf__context_run_one(handler, scratch_pool);
 
318
 
 
319
  if ((err && (handler->sline.code == 500 || handler->sline.code == 501))
 
320
      || svn_error_find_cause(err, SVN_ERR_UNSUPPORTED_FEATURE))
 
321
    return svn_error_trace(
 
322
             svn_error_create(SVN_ERR_RA_NOT_IMPLEMENTED, err,
 
323
                              _("Server does not support locking features")));
 
324
  else if (svn_error_find_cause(err, SVN_ERR_FS_NOT_FOUND))
 
325
    svn_error_clear(err); /* Behave like the other RA layers */
 
326
  else if (handler->sline.code != 207)
 
327
    return svn_error_trace(svn_ra_serf__unexpected_status(handler));
 
328
 
 
329
  if (lock_ctx->lock && lock_ctx->lock->token)
 
330
    *lock = lock_ctx->lock;
 
331
  else
 
332
    *lock = NULL;
 
333
 
 
334
  svn_pool_destroy(scratch_pool);
 
335
 
 
336
  return SVN_NO_ERROR;
 
337
}