Blame src/lib/uriparser.c

Packit Service 779887
/*
Packit Service 779887
    Copyright (C) 2015  ABRT team
Packit Service 779887
    Copyright (C) 2015  RedHat Inc
Packit Service 779887
Packit Service 779887
    This program is free software; you can redistribute it and/or modify
Packit Service 779887
    it under the terms of the GNU General Public License as published by
Packit Service 779887
    the Free Software Foundation; either version 2 of the License, or
Packit Service 779887
    (at your option) any later version.
Packit Service 779887
Packit Service 779887
    This program is distributed in the hope that it will be useful,
Packit Service 779887
    but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 779887
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 779887
    GNU General Public License for more details.
Packit Service 779887
Packit Service 779887
    You should have received a copy of the GNU General Public License along
Packit Service 779887
    with this program; if not, write to the Free Software Foundation, Inc.,
Packit Service 779887
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Packit Service 779887
*/
Packit Service 779887
Packit Service 779887
#include "internal_libreport.h"
Packit Service 779887
Packit Service 779887
#include <regex.h>
Packit Service 779887
Packit Service 779887
int uri_userinfo_remove(const char *uri, char **result, char **scheme, char **hostname, char **username, char **password, char **location)
Packit Service 779887
{
Packit Service 779887
    /* https://www.ietf.org/rfc/rfc3986.txt
Packit Service 779887
     * Appendix B.  Parsing a URI Reference with a Regular Expression
Packit Service 779887
     *
Packit Service 779887
     * scheme    = $2
Packit Service 779887
     * authority = $4
Packit Service 779887
     * location  = $5 <- introduced by jfilak
Packit Service 779887
     * path      = $6
Packit Service 779887
     * query     = $8
Packit Service 779887
     * fragment  = $10
Packit Service 779887
     *                         12            3  4          56       7   8        9 10 */
Packit Service 779887
    const char *rfc3986_rx = "^(([^:/?#]+):)?(//([^/?#]*))?(([^?#]*)(\\?([^#]*))?(#(.*))?)$";
Packit Service 779887
    regex_t re;
Packit Service 779887
    int r = regcomp(&re, rfc3986_rx, REG_EXTENDED);
Packit Service 779887
    assert(r == 0 || !"BUG: invalid regular expression");
Packit Service 779887
Packit Service 779887
    regmatch_t matchptr[10];
Packit Service 779887
    r = regexec(&re, uri, ARRAY_SIZE(matchptr), matchptr, 0);
Packit Service 779887
    if (r != 0)
Packit Service 779887
    {
Packit Service 779887
        log_debug("URI does not match RFC3986 regular expression.");
Packit Service 779887
        return -EINVAL;
Packit Service 779887
    }
Packit Service 779887
Packit Service 779887
    char *ptr = xzalloc((strlen(uri) + 1) * sizeof(char));
Packit Service 779887
    *result = ptr;
Packit Service 779887
    if (scheme != NULL)
Packit Service 779887
        *scheme = NULL;
Packit Service 779887
    if (hostname != NULL)
Packit Service 779887
        *hostname = NULL;
Packit Service 779887
    if (username != NULL)
Packit Service 779887
        *username = NULL;
Packit Service 779887
    if (password != NULL)
Packit Service 779887
        *password = NULL;
Packit Service 779887
    if (location != NULL)
Packit Service 779887
        *location= NULL;
Packit Service 779887
Packit Service 779887
    /* https://www.ietf.org/rfc/rfc3986.txt
Packit Service 779887
     * 5.3.  Component Recomposition
Packit Service 779887
     *
Packit Service 779887
      result = ""
Packit Service 779887
Packit Service 779887
      if defined(scheme) then
Packit Service 779887
         append scheme to result;
Packit Service 779887
         append ":" to result;
Packit Service 779887
      endif;
Packit Service 779887
Packit Service 779887
      if defined(authority) then
Packit Service 779887
         append "//" to result;
Packit Service 779887
         append authority to result;
Packit Service 779887
      endif;
Packit Service 779887
Packit Service 779887
      append path to result;
Packit Service 779887
Packit Service 779887
      if defined(query) then
Packit Service 779887
         append "?" to result;
Packit Service 779887
         append query to result;
Packit Service 779887
      endif;
Packit Service 779887
Packit Service 779887
      if defined(fragment) then
Packit Service 779887
         append "#" to result;
Packit Service 779887
         append fragment to result;
Packit Service 779887
      endif;
Packit Service 779887
Packit Service 779887
      return result;
Packit Service 779887
    */
Packit Service 779887
Packit Service 779887
#define APPEND_MATCH(i, output) \
Packit Service 779887
    if (matchptr[(i)].rm_so != -1) \
Packit Service 779887
    { \
Packit Service 779887
        size_t len = 0; \
Packit Service 779887
        len = matchptr[(i)].rm_eo - matchptr[(i)].rm_so; \
Packit Service 779887
        if (output) *output = xstrndup(uri + matchptr[(i)].rm_so, len); \
Packit Service 779887
        strncpy(ptr, uri + matchptr[(i)].rm_so, len); \
Packit Service 779887
        ptr += len; \
Packit Service 779887
    }
Packit Service 779887
Packit Service 779887
    /* Append "scheme:" if defined */
Packit Service 779887
    APPEND_MATCH(1, scheme);
Packit Service 779887
Packit Service 779887
    /* If authority is defined, append "//" */
Packit Service 779887
    regmatch_t *match_authority = matchptr + 3;
Packit Service 779887
    if (match_authority->rm_so != -1)
Packit Service 779887
    {
Packit Service 779887
        strcat(ptr, "//");
Packit Service 779887
        ptr += 2;
Packit Service 779887
    }
Packit Service 779887
Packit Service 779887
    ++match_authority;
Packit Service 779887
    /* If authority has address part, remove userinfo and add the address */
Packit Service 779887
    if (match_authority->rm_so != -1)
Packit Service 779887
    {
Packit Service 779887
        size_t len = match_authority->rm_eo - match_authority->rm_so;
Packit Service 779887
        const char *authority = uri + match_authority->rm_so;
Packit Service 779887
Packit Service 779887
        /* Find the last '@'. Just for the case some used @ in username or
Packit Service 779887
         * password */
Packit Service 779887
        size_t at = len;
Packit Service 779887
        while (at != 0)
Packit Service 779887
        {
Packit Service 779887
            if (authority[--at] != '@')
Packit Service 779887
                continue;
Packit Service 779887
Packit Service 779887
            /* Find the first ':' before @. There should not be more ':' but this
Packit Service 779887
             * is the most secure way -> avoid leaking an excerpt of a password
Packit Service 779887
             * containing ':'.*/
Packit Service 779887
            size_t colon = 0;
Packit Service 779887
            while (colon < at)
Packit Service 779887
            {
Packit Service 779887
                if (authority[colon] != ':')
Packit Service 779887
                {
Packit Service 779887
                    ++colon;
Packit Service 779887
                    continue;
Packit Service 779887
                }
Packit Service 779887
Packit Service 779887
                if (password != NULL)
Packit Service 779887
                    *password = xstrndup(authority + colon + 1, at - colon - 1);
Packit Service 779887
Packit Service 779887
                break;
Packit Service 779887
            }
Packit Service 779887
Packit Service 779887
            if (username != NULL)
Packit Service 779887
                *username = xstrndup(authority, colon);
Packit Service 779887
Packit Service 779887
            ++at;
Packit Service 779887
            break;
Packit Service 779887
        }
Packit Service 779887
Packit Service 779887
        len -= at;
Packit Service 779887
Packit Service 779887
        if (hostname != NULL)
Packit Service 779887
            *hostname = xstrndup(authority + at, len);
Packit Service 779887
Packit Service 779887
        strncpy(ptr, authority + at, len);
Packit Service 779887
        ptr += len;
Packit Service 779887
    }
Packit Service 779887
Packit Service 779887
    /* Append path, query and fragment or "" */
Packit Service 779887
    APPEND_MATCH(5, location);
Packit Service 779887
Packit Service 779887
    return 0;
Packit Service 779887
}