/* Implementation of svn_auth__password_get_t that decrypts the incoming password using the Windows CryptoAPI and verifies its validity. */ static svn_error_t * windows_ssl_client_cert_pw_decrypter(svn_boolean_t *done, const char **out, apr_hash_t *creds, const char *realmstring, const char *username, apr_hash_t *parameters, svn_boolean_t non_interactive, apr_pool_t *pool) { const svn_string_t *orig; const char *in; SVN_ERR(svn_auth__ssl_client_cert_pw_get(done, &in, creds, realmstring, username, parameters, non_interactive, pool)); if (!*done) return SVN_NO_ERROR; orig = svn_base64_decode_string(svn_string_create(in, pool), pool); orig = decrypt_data(orig, pool); if (orig) { *out = orig->data; *done = TRUE; } else { *done = FALSE; } return SVN_NO_ERROR; }
/* Store CDATA into REVPROPS, associated with PROPNAME. If ENCODING is not NULL, then it must base "base64" and CDATA will be decoded first. NOTE: PROPNAME must live longer than REVPROPS. */ static svn_error_t * collect_revprop(apr_hash_t *revprops, const char *propname, const svn_string_t *cdata, const char *encoding) { apr_pool_t *result_pool = apr_hash_pool_get(revprops); const svn_string_t *decoded; if (encoding) { /* Check for a known encoding type. This is easy -- there's only one. */ if (strcmp(encoding, "base64") != 0) { return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL, _("Unsupported encoding '%s'"), encoding); } decoded = svn_base64_decode_string(cdata, result_pool); } else { decoded = svn_string_dup(cdata, result_pool); } /* Caller has ensured PROPNAME has sufficient lifetime. */ apr_hash_set(revprops, propname, APR_HASH_KEY_STRING, decoded); return SVN_NO_ERROR; }
static dav_error * decode_property_value(const svn_string_t **out_propval_p, svn_boolean_t *absent, const svn_string_t *maybe_encoded_propval, const apr_xml_elem *elem, apr_pool_t *pool) { apr_xml_attr *attr = elem->attr; /* Default: no "encoding" attribute. */ *absent = FALSE; *out_propval_p = maybe_encoded_propval; /* Check for special encodings of the property value. */ while (attr) { if (strcmp(attr->name, "encoding") == 0) /* ### namespace check? */ { const char *enc_type = attr->value; /* Handle known encodings here. */ if (enc_type && (strcmp(enc_type, "base64") == 0)) *out_propval_p = svn_base64_decode_string(maybe_encoded_propval, pool); else return dav_svn__new_error(pool, HTTP_INTERNAL_SERVER_ERROR, 0, "Unknown property encoding"); break; } if (strcmp(attr->name, SVN_DAV__OLD_VALUE__ABSENT) == 0) { /* ### parse attr->value */ *absent = TRUE; *out_propval_p = NULL; } /* Next attribute, please. */ attr = attr->next; } return NULL; }
const svn_string_t * SVNAuthData::decrypt_data(const svn_string_t *crypted, apr_pool_t *pool) { crypted = svn_base64_decode_string(crypted, pool); DATA_BLOB blobin; DATA_BLOB blobout; LPWSTR descr; const svn_string_t * orig = NULL; blobin.cbData = (DWORD)crypted->len; blobin.pbData = (BYTE *)crypted->data; if (CryptUnprotectData(&blobin, &descr, NULL, NULL, NULL, CRYPTPROTECT_UI_FORBIDDEN, &blobout)) { if (0 == lstrcmpW(descr, description)) orig = svn_string_ncreate((const char *)blobout.pbData, blobout.cbData, pool); LocalFree(blobout.pbData); LocalFree(descr); } return orig; }
svn_error_t * SVNAuthData::cleanup_callback(svn_boolean_t *delete_cred, void *cleanup_baton, const char *cred_kind, const char *realmstring, apr_hash_t * hash, apr_pool_t * scratch_pool) { std::tuple<std::vector<std::tuple<CString, CString, SVNAuthDataInfo>>*, std::vector<std::tuple<CString, CString, SVNAuthDataInfo>>> * tupleBaton = (std::tuple<std::vector<std::tuple<CString, CString, SVNAuthDataInfo>>*, std::vector<std::tuple<CString, CString, SVNAuthDataInfo>>>*)cleanup_baton; auto authList = std::get<0>(*tupleBaton); auto delList = std::get<1>(*tupleBaton); CString s1, s2; if (cred_kind) s1 = CUnicodeUtils::GetUnicode(cred_kind); if (realmstring) s2 = CUnicodeUtils::GetUnicode(realmstring); SVNAuthDataInfo authinfodata; for (apr_hash_index_t *hi = apr_hash_first(scratch_pool, hash); hi; hi = apr_hash_next(hi)) { const void *vkey; void *val; apr_hash_this(hi, &vkey, NULL, &val); const char * key = (const char*)vkey; svn_string_t *value = (svn_string_t *)val; if (strcmp(key, SVN_CONFIG_AUTHN_PASSWORD_KEY) == 0) { CStringA data(value->data, (int)value->len); authinfodata.password = CUnicodeUtils::GetUnicode(data); } else if (strcmp(key, SVN_CONFIG_AUTHN_PASSPHRASE_KEY) == 0) { CStringA data(value->data, (int)value->len); authinfodata.passphrase = CUnicodeUtils::GetUnicode(data); } else if (strcmp(key, SVN_CONFIG_AUTHN_PASSTYPE_KEY) == 0) { CStringA data(value->data, (int)value->len); authinfodata.passtype = CUnicodeUtils::GetUnicode(data); } else if (strcmp(key, SVN_CONFIG_AUTHN_USERNAME_KEY) == 0) { CStringA data(value->data, (int)value->len); authinfodata.username = CUnicodeUtils::GetUnicode(data); } else if (strcmp(key, SVN_CONFIG_AUTHN_ASCII_CERT_KEY) == 0) { const svn_string_t * der_cert = nullptr; svn_x509_certinfo_t * certinfo = nullptr; const apr_array_header_t * hostnames = nullptr; svn_error_t *err; /* Convert header-less PEM to DER by undoing base64 encoding. */ der_cert = svn_base64_decode_string(value, scratch_pool); err = svn_x509_parse_cert(&certinfo, der_cert->data, der_cert->len, scratch_pool, scratch_pool); if (err) continue; authinfodata.subject = svn_x509_certinfo_get_subject(certinfo, scratch_pool); authinfodata.validfrom = svn_time_to_human_cstring(svn_x509_certinfo_get_valid_from(certinfo), scratch_pool); authinfodata.validuntil = svn_time_to_human_cstring(svn_x509_certinfo_get_valid_to(certinfo), scratch_pool); authinfodata.issuer = svn_x509_certinfo_get_issuer(certinfo, scratch_pool); authinfodata.fingerprint = svn_checksum_to_cstring_display(svn_x509_certinfo_get_digest(certinfo), scratch_pool); hostnames = svn_x509_certinfo_get_hostnames(certinfo); if (hostnames && !apr_is_empty_array(hostnames)) { int i; svn_stringbuf_t *buf = svn_stringbuf_create_empty(scratch_pool); for (i = 0; i < hostnames->nelts; ++i) { const char *hostname = APR_ARRAY_IDX(hostnames, i, const char*); if (i > 0) svn_stringbuf_appendbytes(buf, ", ", 2); svn_stringbuf_appendbytes(buf, hostname, strlen(hostname)); } authinfodata.hostname = buf->data; } } else if (strcmp(key, SVN_CONFIG_AUTHN_FAILURES_KEY) == 0)
/* Conforms to svn_ra_serf__xml_closed_t */ static svn_error_t * propfind_closed(svn_ra_serf__xml_estate_t *xes, void *baton, int leaving_state, const svn_string_t *cdata, apr_hash_t *attrs, apr_pool_t *scratch_pool) { propfind_context_t *ctx = baton; if (leaving_state == MULTISTATUS) { /* We've gathered all the data from the reponse. Add this item onto the "done list". External callers will then know this request has been completed (tho stray response bytes may still arrive). */ } else if (leaving_state == HREF) { const char *path; if (strcmp(ctx->depth, "1") == 0) path = svn_urlpath__canonicalize(cdata->data, scratch_pool); else path = ctx->path; svn_ra_serf__xml_note(xes, RESPONSE, "path", path); SVN_ERR(ctx->prop_func(ctx->prop_func_baton, path, D_, "href", cdata, scratch_pool)); } else if (leaving_state == COLLECTION) { svn_ra_serf__xml_note(xes, PROPVAL, "altvalue", "collection"); } else if (leaving_state == HREF_VALUE) { svn_ra_serf__xml_note(xes, PROPVAL, "altvalue", cdata->data); } else if (leaving_state == STATUS) { /* Parse the status field, and remember if this is a property that we wish to ignore. (Typically, if it's not a 200, the status will be 404 to indicate that a property we specifically requested from the server doesn't exist.) */ apr_int64_t status = parse_status_code(cdata->data); if (status != 200) svn_ra_serf__xml_note(xes, PROPSTAT, "ignore-prop", "*"); } else if (leaving_state == PROPVAL) { const char *encoding; const svn_string_t *val_str; const char *ns; const char *name; const char *altvalue; if ((altvalue = svn_hash_gets(attrs, "altvalue")) != NULL) { val_str = svn_string_create(altvalue, scratch_pool); } else if ((encoding = svn_hash_gets(attrs, "V:encoding")) != NULL) { if (strcmp(encoding, "base64") != 0) return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL, _("Got unrecognized encoding '%s'"), encoding); /* Decode into the right pool. */ val_str = svn_base64_decode_string(cdata, scratch_pool); } else { /* Copy into the right pool. */ val_str = cdata; } /* The current path sits on the RESPONSE state. Now, it would be nice if we could, at this point, know that the status code for this property indicated a problem -- then we could simply bail out here and ignore the property. Sadly, though, we might get the status code *after* we get the property value. So we'll carry on with our processing here, setting the property and value as expected. Once we know for sure the status code associate with the property, we'll decide its fate. */ ns = svn_hash_gets(attrs, "ns"); name = svn_hash_gets(attrs, "name"); set_ns_prop(ctx->ps_props, ns, name, val_str, apr_hash_pool_get(ctx->ps_props)); } else { apr_hash_t *gathered; SVN_ERR_ASSERT(leaving_state == PROPSTAT); gathered = svn_ra_serf__xml_gather_since(xes, RESPONSE); /* If we've squirreled away a note that says we want to ignore these properties, we'll do so. Otherwise, we need to copy them from the temporary hash into the ctx->ret_props hash. */ if (! svn_hash_gets(gathered, "ignore-prop")) { apr_hash_index_t *hi_ns; const char *path; apr_pool_t *iterpool = svn_pool_create(scratch_pool); path = svn_hash_gets(gathered, "path"); if (!path) path = ctx->path; for (hi_ns = apr_hash_first(scratch_pool, ctx->ps_props); hi_ns; hi_ns = apr_hash_next(hi_ns)) { const char *ns = apr_hash_this_key(hi_ns); apr_hash_t *props = apr_hash_this_val(hi_ns); apr_hash_index_t *hi_prop; svn_pool_clear(iterpool); for (hi_prop = apr_hash_first(iterpool, props); hi_prop; hi_prop = apr_hash_next(hi_prop)) { const char *name = apr_hash_this_key(hi_prop); const svn_string_t *value = apr_hash_this_val(hi_prop); SVN_ERR(ctx->prop_func(ctx->prop_func_baton, path, ns, name, value, iterpool)); } } svn_pool_destroy(iterpool); } ctx->ps_props = NULL; /* Allocated in PROPSTAT state pool */ } return SVN_NO_ERROR; }
static svn_error_t *try_auth(svn_ra_svn_conn_t *conn, sasl_conn_t *sasl_ctx, apr_pool_t *pool, server_baton_t *b, svn_boolean_t *success) { const char *out, *mech; const svn_string_t *arg = NULL, *in; unsigned int outlen; int result; svn_boolean_t use_base64; *success = FALSE; /* Read the client's chosen mech and the initial token. */ SVN_ERR(svn_ra_svn_read_tuple(conn, pool, "w(?s)", &mech, &in)); if (strcmp(mech, "EXTERNAL") == 0 && !in) in = svn_string_create(b->tunnel_user, pool); else if (in) in = svn_base64_decode_string(in, pool); /* For CRAM-MD5, we don't base64-encode stuff. */ use_base64 = (strcmp(mech, "CRAM-MD5") != 0); result = sasl_server_start(sasl_ctx, mech, in ? in->data : NULL, in ? in->len : 0, &out, &outlen); if (result != SASL_OK && result != SASL_CONTINUE) return fail_auth(conn, pool, sasl_ctx); while (result == SASL_CONTINUE) { svn_ra_svn_item_t *item; arg = svn_string_ncreate(out, outlen, pool); /* Encode what we send to the client. */ if (use_base64) arg = svn_base64_encode_string2(arg, TRUE, pool); SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "w(s)", "step", arg)); /* Read and decode the client response. */ SVN_ERR(svn_ra_svn_read_item(conn, pool, &item)); if (item->kind != SVN_RA_SVN_STRING) return SVN_NO_ERROR; in = item->u.string; if (use_base64) in = svn_base64_decode_string(in, pool); result = sasl_server_step(sasl_ctx, in->data, in->len, &out, &outlen); } if (result != SASL_OK) return fail_auth(conn, pool, sasl_ctx); /* Send our last response, if necessary. */ if (outlen) arg = svn_base64_encode_string2(svn_string_ncreate(out, outlen, pool), TRUE, pool); else arg = NULL; *success = TRUE; SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "w(?s)", "success", arg)); return SVN_NO_ERROR; }
static svn_error_t * end_element(svn_ra_serf__xml_parser_t *parser, svn_ra_serf__dav_props_t name, apr_pool_t *scratch_pool) { iprops_context_t *iprops_ctx = parser->user_data; iprops_state_e state; state = parser->state->current_state; if (state == IPROPS_REPORT && strcmp(name.name, SVN_DAV__INHERITED_PROPS_REPORT) == 0) { svn_ra_serf__xml_pop_state(parser); } else if (state == IPROPS_PATH && strcmp(name.name, SVN_DAV__IPROP_PATH) == 0) { iprops_ctx->curr_iprop = apr_palloc( iprops_ctx->pool, sizeof(svn_prop_inherited_item_t)); iprops_ctx->curr_iprop->path_or_url = svn_path_url_add_component2(iprops_ctx->repos_root_url, iprops_ctx->curr_path->data, iprops_ctx->pool); iprops_ctx->curr_iprop->prop_hash = apr_hash_make(iprops_ctx->pool); svn_ra_serf__xml_pop_state(parser); } else if (state == IPROPS_PROPVAL && strcmp(name.name, SVN_DAV__IPROP_PROPVAL) == 0) { const svn_string_t *prop_val; if (iprops_ctx->curr_prop_val_encoding) { svn_string_t encoded_prop_val; if (strcmp(iprops_ctx->curr_prop_val_encoding, "base64") != 0) return svn_error_create(SVN_ERR_XML_MALFORMED, NULL, NULL); encoded_prop_val.data = iprops_ctx->curr_propval->data; encoded_prop_val.len = iprops_ctx->curr_propval->len; prop_val = svn_base64_decode_string(&encoded_prop_val, iprops_ctx->pool); } else { prop_val = svn_string_create_from_buf(iprops_ctx->curr_propval, iprops_ctx->pool); } svn_hash_sets(iprops_ctx->curr_iprop->prop_hash, apr_pstrdup(iprops_ctx->pool, iprops_ctx->curr_propname->data), prop_val); /* Clear current propname and propval in the event there are multiple properties on the current path. */ svn_stringbuf_setempty(iprops_ctx->curr_propname); svn_stringbuf_setempty(iprops_ctx->curr_propval); svn_ra_serf__xml_pop_state(parser); } else if (state == IPROPS_PROPNAME && strcmp(name.name, SVN_DAV__IPROP_PROPNAME) == 0) { svn_ra_serf__xml_pop_state(parser); } else if (state == IPROPS_ITEM && strcmp(name.name, SVN_DAV__IPROP_ITEM) == 0) { APR_ARRAY_PUSH(iprops_ctx->iprops, svn_prop_inherited_item_t *) = iprops_ctx->curr_iprop; svn_ra_serf__xml_pop_state(parser); }
/* Conforms to svn_ra_serf__xml_closed_t */ static svn_error_t * blame_closed(svn_ra_serf__xml_estate_t *xes, void *baton, int leaving_state, const svn_string_t *cdata, apr_hash_t *attrs, apr_pool_t *scratch_pool) { blame_context_t *blame_ctx = baton; if (leaving_state == FILE_REV) { /* Note that we test STREAM, but any pointer is currently invalid. It was closed when left the TXDELTA state. */ if (blame_ctx->stream == NULL) { const char *path; const char *rev; path = svn_hash_gets(attrs, "path"); rev = svn_hash_gets(attrs, "rev"); /* Send a "no content" notification. */ SVN_ERR(blame_ctx->file_rev(blame_ctx->file_rev_baton, path, SVN_STR_TO_REV(rev), blame_ctx->rev_props, FALSE /* result_of_merge */, NULL, NULL, /* txdelta / baton */ blame_ctx->prop_diffs, scratch_pool)); } } else if (leaving_state == MERGED_REVISION) { svn_ra_serf__xml_note(xes, FILE_REV, "merged-revision", "*"); } else if (leaving_state == TXDELTA) { SVN_ERR(svn_stream_close(blame_ctx->stream)); } else { const char *name; const svn_string_t *value; SVN_ERR_ASSERT(leaving_state == REV_PROP || leaving_state == SET_PROP || leaving_state == REMOVE_PROP); name = apr_pstrdup(blame_ctx->state_pool, svn_hash_gets(attrs, "name")); if (leaving_state == REMOVE_PROP) { value = NULL; } else { const char *encoding = svn_hash_gets(attrs, "encoding"); if (encoding && strcmp(encoding, "base64") == 0) value = svn_base64_decode_string(cdata, blame_ctx->state_pool); else value = svn_string_dup(cdata, blame_ctx->state_pool); } if (leaving_state == REV_PROP) { svn_hash_sets(blame_ctx->rev_props, name, value); } else { svn_prop_t *prop = apr_array_push(blame_ctx->prop_diffs); prop->name = name; prop->value = value; } } return SVN_NO_ERROR; }
static svn_error_t * end_element(void *baton, int state, const char *nspace, const char *elt_name) { replay_baton_t *rb = baton; const svn_ra_neon__xml_elm_t *elm = svn_ra_neon__lookup_xml_elem(editor_report_elements, nspace, elt_name); if (! elm) return SVN_NO_ERROR; switch (elm->id) { case ELEM_editor_report: if (rb->dirs->nelts) svn_pool_destroy(APR_ARRAY_IDX(rb->dirs, 0, dir_item_t).pool); return SVN_NO_ERROR; break; case ELEM_apply_textdelta: SVN_ERR(svn_stream_close(rb->base64_decoder)); rb->whandler = NULL; rb->whandler_baton = NULL; rb->svndiff_decoder = NULL; rb->base64_decoder = NULL; break; case ELEM_change_file_prop: case ELEM_change_dir_prop: { const svn_string_t *decoded_value; if (rb->prop_accum) { const svn_string_t *prop; prop = svn_stringbuf__morph_into_string(rb->prop_accum); decoded_value = svn_base64_decode_string(prop, rb->prop_pool); } else decoded_value = NULL; /* It's a delete */ if (elm->id == ELEM_change_dir_prop) SVN_ERR(rb->editor->change_dir_prop(TOP_DIR(rb).baton, rb->prop_name, decoded_value, TOP_DIR(rb).pool)); else SVN_ERR(rb->editor->change_file_prop(rb->file_baton, rb->prop_name, decoded_value, TOP_DIR(rb).file_pool)); } break; default: break; } return SVN_NO_ERROR; }
static svn_error_t *try_auth(svn_ra_svn_conn_t *conn, sasl_conn_t *sasl_ctx, apr_pool_t *pool, server_baton_t *b, svn_boolean_t *success) { const char *out, *mech; const svn_string_t *arg = NULL, *in; unsigned int outlen; int result; svn_boolean_t use_base64; *success = FALSE; /* Read the client's chosen mech and the initial token. */ SVN_ERR(svn_ra_svn__read_tuple(conn, pool, "w(?s)", &mech, &in)); if (strcmp(mech, "EXTERNAL") == 0 && !in) in = svn_string_create(b->client_info->tunnel_user, pool); else if (in) in = svn_base64_decode_string(in, pool); /* For CRAM-MD5, we don't base64-encode stuff. */ use_base64 = (strcmp(mech, "CRAM-MD5") != 0); /* sasl uses unsigned int for the length of strings, we use apr_size_t * which may not be the same size. Deal with potential integer overflow */ if (in && in->len > UINT_MAX) return svn_error_createf(SVN_ERR_RA_NOT_AUTHORIZED, NULL, _("Initial token is too long")); result = svn_sasl__server_start(sasl_ctx, mech, in ? in->data : NULL, in ? (unsigned int) in->len : 0, &out, &outlen); if (result != SASL_OK && result != SASL_CONTINUE) return fail_auth(conn, pool, sasl_ctx); while (result == SASL_CONTINUE) { svn_ra_svn__item_t *item; arg = svn_string_ncreate(out, outlen, pool); /* Encode what we send to the client. */ if (use_base64) arg = svn_base64_encode_string2(arg, TRUE, pool); SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "w(s)", "step", arg)); /* Read and decode the client response. */ SVN_ERR(svn_ra_svn__read_item(conn, pool, &item)); if (item->kind != SVN_RA_SVN_STRING) return SVN_NO_ERROR; in = &item->u.string; if (use_base64) in = svn_base64_decode_string(in, pool); if (in->len > UINT_MAX) return svn_error_createf(SVN_ERR_RA_NOT_AUTHORIZED, NULL, _("Step response is too long")); result = svn_sasl__server_step(sasl_ctx, in->data, (unsigned int) in->len, &out, &outlen); } if (result != SASL_OK) return fail_auth(conn, pool, sasl_ctx); /* Send our last response, if necessary. */ if (outlen) arg = svn_base64_encode_string2(svn_string_ncreate(out, outlen, pool), TRUE, pool); else arg = NULL; *success = TRUE; SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "w(?s)", "success", arg)); return SVN_NO_ERROR; }
/* This implements the `svn_ra_neon__endelm_cb_t' prototype. */ static svn_error_t * getlocks_end_element(void *userdata, int state, const char *ns, const char *ln) { get_locks_baton_t *baton = userdata; const svn_ra_neon__xml_elm_t *elm; elm = svn_ra_neon__lookup_xml_elem(getlocks_report_elements, ns, ln); /* Just skip unknown elements. */ if (elm == NULL) return SVN_NO_ERROR; switch (elm->id) { case ELEM_lock: /* is the final svn_lock_t valid? all fields must be present except for 'comment' and 'expiration_date'. */ if ((! baton->current_lock->path) || (! baton->current_lock->token) || (! baton->current_lock->owner) || (! baton->current_lock->creation_date)) SVN_ERR(svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL, _("Incomplete lock data returned"))); /* Filter out unwanted paths. Since Subversion only allows locks on files, we can treat depth=immediates the same as depth=files for filtering purposes. Meaning, we'll keep this lock if: a) its path is the very path we queried, or b) we've asked for a fully recursive answer, or c) we've asked for depth=files or depth=immediates, and this lock is on an immediate child of our query path. */ if ((strcmp(baton->path, baton->current_lock->path) == 0) || (baton->requested_depth == svn_depth_infinity)) { apr_hash_set(baton->lock_hash, baton->current_lock->path, APR_HASH_KEY_STRING, baton->current_lock); } else if ((baton->requested_depth == svn_depth_files) || (baton->requested_depth == svn_depth_immediates)) { const char *rel_uri = svn_fspath__is_child(baton->path, baton->current_lock->path, baton->scratchpool); if (rel_uri && (svn_path_component_count(rel_uri) == 1)) apr_hash_set(baton->lock_hash, baton->current_lock->path, APR_HASH_KEY_STRING, baton->current_lock); svn_pool_clear(baton->scratchpool); } break; case ELEM_lock_path: /* neon has already xml-unescaped the cdata for us. */ baton->current_lock->path = svn_fspath__canonicalize(apr_pstrmemdup(baton->scratchpool, baton->cdata_accum->data, baton->cdata_accum->len), baton->pool); /* clean up the accumulator. */ svn_stringbuf_setempty(baton->cdata_accum); svn_pool_clear(baton->scratchpool); break; case ELEM_lock_token: /* neon has already xml-unescaped the cdata for us. */ baton->current_lock->token = apr_pstrmemdup(baton->pool, baton->cdata_accum->data, baton->cdata_accum->len); /* clean up the accumulator. */ svn_stringbuf_setempty(baton->cdata_accum); svn_pool_clear(baton->scratchpool); break; case ELEM_lock_creationdate: SVN_ERR(svn_time_from_cstring(&(baton->current_lock->creation_date), baton->cdata_accum->data, baton->scratchpool)); /* clean up the accumulator. */ svn_stringbuf_setempty(baton->cdata_accum); svn_pool_clear(baton->scratchpool); break; case ELEM_lock_expirationdate: SVN_ERR(svn_time_from_cstring(&(baton->current_lock->expiration_date), baton->cdata_accum->data, baton->scratchpool)); /* clean up the accumulator. */ svn_stringbuf_setempty(baton->cdata_accum); svn_pool_clear(baton->scratchpool); break; case ELEM_lock_owner: case ELEM_lock_comment: { const char *final_val; if (baton->encoding) { /* Possibly recognize other encodings someday. */ if (strcmp(baton->encoding, "base64") == 0) { svn_string_t *encoded_val; const svn_string_t *decoded_val; encoded_val = svn_string_create_from_buf(baton->cdata_accum, baton->scratchpool); decoded_val = svn_base64_decode_string(encoded_val, baton->scratchpool); final_val = decoded_val->data; } else return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL, _("Got unrecognized encoding '%s'"), baton->encoding); baton->encoding = NULL; } else { /* neon has already xml-unescaped the cdata for us. */ final_val = baton->cdata_accum->data; } if (elm->id == ELEM_lock_owner) baton->current_lock->owner = apr_pstrdup(baton->pool, final_val); if (elm->id == ELEM_lock_comment) baton->current_lock->comment = apr_pstrdup(baton->pool, final_val); /* clean up the accumulator. */ svn_stringbuf_setempty(baton->cdata_accum); svn_pool_clear(baton->scratchpool); break; } default: break; } return SVN_NO_ERROR; }
/* Conforms to svn_ra_serf__xml_closed_t */ static svn_error_t * item_closed(svn_ra_serf__xml_estate_t *xes, void *baton, int leaving_state, const svn_string_t *cdata, apr_hash_t *attrs, apr_pool_t *scratch_pool) { list_context_t *list_ctx = baton; if (leaving_state == AUTHOR) { /* For compatibility with liveprops, current servers will not use * base64-encoding for "binary" user names bu simply drop the * offending control chars. * * We might want to switch to revprop-style encoding, though, * and this is the code to do that. */ const char *encoding = svn_hash_gets(attrs, "encoding"); if (encoding) { /* Check for a known encoding type. This is easy -- there's only one. */ if (strcmp(encoding, "base64") != 0) { return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL, _("Unsupported encoding '%s'"), encoding); } cdata = svn_base64_decode_string(cdata, scratch_pool); } /* Remember until the next ITEM closing tag. */ svn_stringbuf_set(list_ctx->author_buf, cdata->data); list_ctx->author = list_ctx->author_buf->data; } else if (leaving_state == ITEM) { const char *dirent_path = cdata->data; const char *kind_word, *date, *crev, *size; svn_dirent_t dirent = { 0 }; kind_word = svn_hash_gets(attrs, "node-kind"); size = svn_hash_gets(attrs, "size"); dirent.has_props = svn_hash__get_bool(attrs, "has-props", FALSE); crev = svn_hash_gets(attrs, "created-rev"); date = svn_hash_gets(attrs, "date"); /* Convert data. */ dirent.kind = svn_node_kind_from_word(kind_word); if (size) SVN_ERR(svn_cstring_atoi64(&dirent.size, size)); else dirent.size = SVN_INVALID_FILESIZE; if (crev) SVN_ERR(svn_revnum_parse(&dirent.created_rev, crev, NULL)); else dirent.created_rev = SVN_INVALID_REVNUM; if (date) SVN_ERR(svn_time_from_cstring(&dirent.time, date, scratch_pool)); if (list_ctx->author) dirent.last_author = list_ctx->author; /* Invoke RECEIVER */ SVN_ERR(list_ctx->receiver(dirent_path, &dirent, list_ctx->receiver_baton, scratch_pool)); /* Reset buffered info. */ list_ctx->author = NULL; } return SVN_NO_ERROR; }
static svn_error_t * end_element(void *baton, int state, const char *nspace, const char *name) { propfind_ctx_t *pc = baton; svn_ra_neon__resource_t *rsrc = pc->rsrc; const svn_string_t *value = NULL; const elem_defn *parent_defn; const elem_defn *defn; ne_status status; const char *cdata = pc->cdata->data; switch (state) { case ELEM_response: /* Verify that we've received a URL for this resource. */ if (!pc->rsrc->url) return svn_error_create(SVN_ERR_XML_MALFORMED, NULL, NULL); /* Store the resource in the top-level hash table. */ apr_hash_set(pc->props, pc->rsrc->url, APR_HASH_KEY_STRING, pc->rsrc); pc->rsrc = NULL; return SVN_NO_ERROR; case ELEM_propstat: /* We're at the end of a set of properties. Do the right thing status-wise. */ if (pc->status) { /* We have a status. Loop over the buffered properties, and if the status is a good one (200), copy them into the resources's property hash. Regardless of the status, we'll be removing these from the temporary buffer as we go along. */ apr_hash_index_t *hi = apr_hash_first(pc->pool, pc->propbuffer); for (; hi; hi = apr_hash_next(hi)) { const void *key; apr_ssize_t klen; void *val; apr_hash_this(hi, &key, &klen, &val); if (pc->status == 200) apr_hash_set(rsrc->propset, key, klen, val); apr_hash_set(pc->propbuffer, key, klen, NULL); } } else if (! pc->status) { /* No status at all? Bogosity. */ return svn_error_create(SVN_ERR_XML_MALFORMED, NULL, NULL); } return SVN_NO_ERROR; case ELEM_status: /* Parse the <status> tag's CDATA for a status code. */ if (ne_parse_statusline(cdata, &status)) return svn_error_create(SVN_ERR_XML_MALFORMED, NULL, NULL); free(status.reason_phrase); pc->status = status.code; return SVN_NO_ERROR; case ELEM_href: /* Special handling for <href> that belongs to the <response> tag. */ if (rsrc->href_parent == ELEM_response) return assign_rsrc_url(pc->rsrc, cdata, pc->pool); /* Use the parent element's name, not the href. */ parent_defn = defn_from_id(rsrc->href_parent); /* No known parent? Get outta here. */ if (!parent_defn) return SVN_NO_ERROR; /* All other href's we'll treat as property values. */ name = parent_defn->name; value = svn_string_create(cdata, pc->pool); break; default: /*** This case is, as usual, for everything not covered by other cases. ELM->id should be either ELEM_unknown, or one of the ids in the elem_definitions[] structure. In this case, we seek to handle properties. Since ELEM_unknown should only occur for properties, we will handle that id. All other ids will be searched for in the elem_definitions[] structure to determine if they are properties. Properties, we handle; all else hits the road. ***/ if (state == ELEM_unknown) { name = apr_pstrcat(pc->pool, nspace, name, NULL); } else { defn = defn_from_id(state); if (! (defn && defn->is_property)) return SVN_NO_ERROR; name = defn->name; } /* Check for encoding attribute. */ if (pc->encoding == NULL) { /* Handle the property value by converting it to string. */ value = svn_string_create(cdata, pc->pool); break; } /* Check for known encoding type */ if (strcmp(pc->encoding, "base64") != 0) return svn_error_create(SVN_ERR_XML_MALFORMED, NULL, NULL); /* There is an encoding on this property, handle it. * the braces are needed to allocate "in" on the stack. */ { svn_string_t in; in.data = cdata; in.len = strlen(cdata); value = svn_base64_decode_string(&in, pc->pool); } pc->encoding = NULL; /* Reset encoding for future attribute(s). */ } /*** Handling resource properties from here out. ***/ /* Add properties to the temporary propbuffer. At the end of the <propstat>, we'll either dump the props as invalid or move them into the resource's property hash. */ apr_hash_set(pc->propbuffer, name, APR_HASH_KEY_STRING, value); return SVN_NO_ERROR; }