Example #1
0
File: ldap.c Project: AndyUI/curl
/*
 * Break apart the pieces of an LDAP URL.
 * Syntax:
 *   ldap://<hostname>:<port>/<base_dn>?<attributes>?<scope>?<filter>?<ext>
 *
 * <hostname> already known from 'conn->host.name'.
 * <port>     already known from 'conn->remote_port'.
 * extract the rest from 'conn->data->state.path+1'. All fields are optional.
 * e.g.
 *   ldap://<hostname>:<port>/?<attributes>?<scope>?<filter>
 * yields ludp->lud_dn = "".
 *
 * Defined in RFC4516 section 2.
 */
static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp)
{
  int rc = LDAP_SUCCESS;
  char *path;
  char *p;
  char *q;
  size_t i;

  if(!conn->data ||
      !conn->data->state.path ||
      conn->data->state.path[0] != '/' ||
      !checkprefix("LDAP", conn->data->change.url))
    return LDAP_INVALID_SYNTAX;

  ludp->lud_scope = LDAP_SCOPE_BASE;
  ludp->lud_port  = conn->remote_port;
  ludp->lud_host  = conn->host.name;

  /* Duplicate the path */
  p = path = strdup(conn->data->state.path + 1);
  if(!path)
    return LDAP_NO_MEMORY;

  /* Parse the DN (Distinguished Name) */
  q = strchr(p, '?');
  if(q)
    *q++ = '\0';

  if(*p) {
    char *dn = p;
    char *unescaped;

    LDAP_TRACE (("DN '%s'\n", dn));

    /* Unescape the DN */
    unescaped = curl_easy_unescape(conn->data, dn, 0, NULL);
    if(!unescaped) {
      rc = LDAP_NO_MEMORY;

      goto quit;
    }

#if defined(USE_WIN32_LDAP)
    /* Convert the unescaped string to a tchar */
    ludp->lud_dn = Curl_convert_UTF8_to_tchar(unescaped);

    /* Free the unescaped string as we are done with it */
    Curl_unicodefree(unescaped);

    if(!ludp->lud_dn) {
      rc = LDAP_NO_MEMORY;

      goto quit;
    }
#else
    ludp->lud_dn = unescaped;
#endif
  }

  p = q;
  if(!p)
    goto quit;

  /* Parse the attributes. skip "??" */
  q = strchr(p, '?');
  if(q)
    *q++ = '\0';

  if(*p) {
    char **attributes;
    size_t count = 0;

    /* Split the string into an array of attributes */
    if(!split_str(p, &attributes, &count)) {
      rc = LDAP_NO_MEMORY;

      goto quit;
    }

    /* Allocate our array (+1 for the NULL entry) */
#if defined(USE_WIN32_LDAP)
    ludp->lud_attrs = calloc(count + 1, sizeof(TCHAR *));
#else
    ludp->lud_attrs = calloc(count + 1, sizeof(char *));
#endif
    if(!ludp->lud_attrs) {
      free(attributes);

      rc = LDAP_NO_MEMORY;

      goto quit;
    }

    for(i = 0; i < count; i++) {
      char *unescaped;

      LDAP_TRACE (("attr[%d] '%s'\n", i, attributes[i]));

      /* Unescape the attribute */
      unescaped = curl_easy_unescape(conn->data, attributes[i], 0, NULL);
      if(!unescaped) {
        free(attributes);

        rc = LDAP_NO_MEMORY;

        goto quit;
      }

#if defined(USE_WIN32_LDAP)
      /* Convert the unescaped string to a tchar */
      ludp->lud_attrs[i] = Curl_convert_UTF8_to_tchar(unescaped);

      /* Free the unescaped string as we are done with it */
      Curl_unicodefree(unescaped);

      if(!ludp->lud_attrs[i]) {
        free(attributes);

        rc = LDAP_NO_MEMORY;

        goto quit;
      }
#else
      ludp->lud_attrs[i] = unescaped;
#endif

      ludp->lud_attrs_dups++;
    }

    free(attributes);
  }

  p = q;
  if(!p)
    goto quit;

  /* Parse the scope. skip "??" */
  q = strchr(p, '?');
  if(q)
    *q++ = '\0';

  if(*p) {
    ludp->lud_scope = str2scope(p);
    if(ludp->lud_scope == -1) {
      rc = LDAP_INVALID_SYNTAX;

      goto quit;
    }
    LDAP_TRACE (("scope %d\n", ludp->lud_scope));
  }

  p = q;
  if(!p)
    goto quit;

  /* Parse the filter */
  q = strchr(p, '?');
  if(q)
    *q++ = '\0';

  if(*p) {
    char *filter = p;
    char *unescaped;

    LDAP_TRACE (("filter '%s'\n", filter));

    /* Unescape the filter */
    unescaped = curl_easy_unescape(conn->data, filter, 0, NULL);
    if(!unescaped) {
      rc = LDAP_NO_MEMORY;

      goto quit;
    }

#if defined(USE_WIN32_LDAP)
    /* Convert the unescaped string to a tchar */
    ludp->lud_filter = Curl_convert_UTF8_to_tchar(unescaped);

    /* Free the unescaped string as we are done with it */
    Curl_unicodefree(unescaped);

    if(!ludp->lud_filter) {
      rc = LDAP_NO_MEMORY;

      goto quit;
    }
#else
    ludp->lud_filter = unescaped;
#endif
  }

  p = q;
  if(p && !*p) {
    rc = LDAP_INVALID_SYNTAX;

    goto quit;
  }

quit:
  free(path);

  return rc;
}
Example #2
0
/*
 * Break apart the pieces of an LDAP URL.
 * Syntax:
 *   ldap://<hostname>:<port>/<base_dn>?<attributes>?<scope>?<filter>?<ext>
 *
 * <hostname> already known from 'conn->host.name'.
 * <port>     already known from 'conn->remote_port'.
 * extract the rest from 'conn->data->state.path+1'. All fields are optional.
 * e.g.
 *   ldap://<hostname>:<port>/?<attributes>?<scope>?<filter>
 * yields ludp->lud_dn = "".
 *
 * Defined in RFC4516 section 2.
 */
static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp)
{
  char *p, *q;
  int i;

  if(!conn->data ||
      !conn->data->state.path ||
      conn->data->state.path[0] != '/' ||
      !checkprefix("LDAP", conn->data->change.url))
    return LDAP_INVALID_SYNTAX;

  ludp->lud_scope = LDAP_SCOPE_BASE;
  ludp->lud_port  = conn->remote_port;
  ludp->lud_host  = conn->host.name;

  /* parse DN (Distinguished Name).
   */
  ludp->lud_dn = strdup(conn->data->state.path+1);
  if(!ludp->lud_dn)
    return LDAP_NO_MEMORY;

  p = strchr(ludp->lud_dn, '?');
  LDAP_TRACE (("DN '%.*s'\n", p ? (size_t)(p-ludp->lud_dn) :
               strlen(ludp->lud_dn), ludp->lud_dn));

  if(!p)
    goto success;

  *p++ = '\0';

  /* parse attributes. skip "??".
   */
  q = strchr(p, '?');
  if(q)
    *q++ = '\0';

  if(*p && *p != '?') {
    ludp->lud_attrs = split_str(p);
    if(!ludp->lud_attrs)
      return LDAP_NO_MEMORY;

    for(i = 0; ludp->lud_attrs[i]; i++)
      LDAP_TRACE (("attr[%d] '%s'\n", i, ludp->lud_attrs[i]));
  }

  p = q;
  if(!p)
    goto success;

  /* parse scope. skip "??"
   */
  q = strchr(p, '?');
  if(q)
    *q++ = '\0';

  if(*p && *p != '?') {
    ludp->lud_scope = str2scope(p);
    if(ludp->lud_scope == -1) {
      return LDAP_INVALID_SYNTAX;
    }
    LDAP_TRACE (("scope %d\n", ludp->lud_scope));
  }

  p = q;
  if(!p)
    goto success;

  /* parse filter
   */
  q = strchr(p, '?');
  if(q)
    *q++ = '\0';
  if(!*p) {
    return LDAP_INVALID_SYNTAX;
  }

  ludp->lud_filter = p;
  LDAP_TRACE (("filter '%s'\n", ludp->lud_filter));

  success:
  if(!unescape_elements(conn->data, ludp))
    return LDAP_NO_MEMORY;
  return LDAP_SUCCESS;
}
/**
 * Parse the URL provided into an apr_ldap_url_desc_t object.
 *
 * APR_SUCCESS is returned on success, APR_EGENERAL on failure.
 * The LDAP result code and reason string is returned in the
 * apr_ldap_err_t structure.
 */
APU_DECLARE(int) apr_ldap_url_parse_ext(apr_pool_t *pool,
                                        const char *url_in,
                                        apr_ldap_url_desc_t **ludpp,
                                        apr_ldap_err_t **result_err)
{
    apr_ldap_url_desc_t *ludp;
    char        *p, *q, *r;
    int         i, enclosed;
    const char  *scheme = NULL;
    const char  *url_tmp;
    char        *url;

    apr_ldap_err_t *result = (apr_ldap_err_t *)apr_pcalloc(pool, sizeof(apr_ldap_err_t));
    *result_err = result;

    /* sanity check our parameters */
    if( url_in == NULL || ludpp == NULL ) {
        result->reason = "Either the LDAP URL, or the URL structure was NULL. Oops.";
        result->rc = APR_LDAP_URL_ERR_PARAM;
        return APR_EGENERAL;
    }

    *ludpp = NULL;  /* pessimistic */

    url_tmp = skip_url_prefix( url_in, &enclosed, &scheme );
    if ( url_tmp == NULL ) {
        result->reason = "The scheme was not recognised as a valid LDAP URL scheme.";
        result->rc = APR_LDAP_URL_ERR_BADSCHEME;
        return APR_EGENERAL;
    }

    /* make working copy of the remainder of the URL */
    url = (char *)apr_pstrdup(pool, url_tmp);
    if ( url == NULL ) {
        result->reason = "Out of memory parsing LDAP URL.";
        result->rc = APR_LDAP_URL_ERR_MEM;
        return APR_EGENERAL;
    }

    if ( enclosed ) {
        p = &url[strlen(url)-1];

        if( *p != '>' ) {
            result->reason = "Bad enclosure error while parsing LDAP URL.";
            result->rc = APR_LDAP_URL_ERR_BADENCLOSURE;
            return APR_EGENERAL;
        }

        *p = '\0';
    }

    /* allocate return struct */
    ludp = (apr_ldap_url_desc_t *)apr_pcalloc(pool, sizeof(apr_ldap_url_desc_t));
    if ( ludp == NULL ) {
        result->reason = "Out of memory parsing LDAP URL.";
        result->rc = APR_LDAP_URL_ERR_MEM;
        return APR_EGENERAL;
    }

    ludp->lud_next = NULL;
    ludp->lud_host = NULL;
    ludp->lud_port = LDAP_PORT;
    ludp->lud_dn = NULL;
    ludp->lud_attrs = NULL;
    ludp->lud_filter = NULL;
    ludp->lud_scope = -1;
    ludp->lud_filter = NULL;
    ludp->lud_exts = NULL;

    ludp->lud_scheme = (char *)apr_pstrdup(pool, scheme);
    if ( ludp->lud_scheme == NULL ) {
        result->reason = "Out of memory parsing LDAP URL.";
        result->rc = APR_LDAP_URL_ERR_MEM;
        return APR_EGENERAL;
    }

    if( strcasecmp( ludp->lud_scheme, "ldaps" ) == 0 ) {
        ludp->lud_port = LDAPS_PORT;
    }

    /* scan forward for '/' that marks end of hostport and begin. of dn */
    p = strchr( url, '/' );

    if( p != NULL ) {
        /* terminate hostport; point to start of dn */
        *p++ = '\0';
    }

    /* IPv6 syntax with [ip address]:port */
    if ( *url == '[' ) {
        r = strchr( url, ']' );
        if ( r == NULL ) {
            result->reason = "Bad LDAP URL while parsing IPV6 syntax.";
            result->rc = APR_LDAP_URL_ERR_BADURL;
            return APR_EGENERAL;
        }
        *r++ = '\0';
        q = strrchr( r, ':' );
    } else {
        q = strrchr( url, ':' );
    }

    if ( q != NULL ) {
        apr_ldap_pvt_hex_unescape( ++q );

        if( *q == '\0' ) {
            result->reason = "Bad LDAP URL while parsing.";
            result->rc = APR_LDAP_URL_ERR_BADURL;
            return APR_EGENERAL;
        }

        ludp->lud_port = atoi( q );
    }

    apr_ldap_pvt_hex_unescape( url );

    /* If [ip address]:port syntax, url is [ip and we skip the [ */
    ludp->lud_host = (char *)apr_pstrdup(pool, url + ( *url == '[' ));
    if( ludp->lud_host == NULL ) {
        result->reason = "Out of memory parsing LDAP URL.";
        result->rc = APR_LDAP_URL_ERR_MEM;
        return APR_EGENERAL;
    }

    /*
     * Kludge.  ldap://111.222.333.444:389??cn=abc,o=company
     *
     * On early Novell releases, search references/referrals were returned
     * in this format, i.e., the dn was kind of in the scope position,
     * but the required slash is missing. The whole thing is illegal syntax,
     * but we need to account for it. Fortunately it can't be confused with
     * anything real.
     */
    if( (p == NULL) && (q != NULL) && ((q = strchr( q, '?')) != NULL)) {
        q++;
        /* ? immediately followed by question */
        if( *q == '?') {
            q++;
            if( *q != '\0' ) {
                /* parse dn part */
                apr_ldap_pvt_hex_unescape( q );
                ludp->lud_dn = (char *)apr_pstrdup(pool, q);
            } else {
                ludp->lud_dn = (char *)apr_pstrdup(pool, "");
            }

            if( ludp->lud_dn == NULL ) {
                result->reason = "Out of memory parsing LDAP URL.";
                result->rc = APR_LDAP_URL_ERR_MEM;
                return APR_EGENERAL;
            }
        }
    }

    if( p == NULL ) {
        *ludpp = ludp;
        return APR_SUCCESS;
    }

    /* scan forward for '?' that may marks end of dn */
    q = strchr( p, '?' );

    if( q != NULL ) {
        /* terminate dn part */
        *q++ = '\0';
    }

    if( *p != '\0' ) {
        /* parse dn part */
        apr_ldap_pvt_hex_unescape( p );
        ludp->lud_dn = (char *)apr_pstrdup(pool, p);
    } else {
        ludp->lud_dn = (char *)apr_pstrdup(pool, "");
    }

    if( ludp->lud_dn == NULL ) {
        result->reason = "Out of memory parsing LDAP URL.";
        result->rc = APR_LDAP_URL_ERR_MEM;
        return APR_EGENERAL;
    }

    if( q == NULL ) {
        /* no more */
        *ludpp = ludp;
        return APR_SUCCESS;
    }

    /* scan forward for '?' that may marks end of attributes */
    p = q;
    q = strchr( p, '?' );

    if( q != NULL ) {
        /* terminate attributes part */
        *q++ = '\0';
    }

    if( *p != '\0' ) {
        /* parse attributes */
        apr_ldap_pvt_hex_unescape( p );
        ludp->lud_attrs = apr_ldap_str2charray(pool, p, ",");

        if( ludp->lud_attrs == NULL ) {
            result->reason = "Bad attributes encountered while parsing LDAP URL.";
            result->rc = APR_LDAP_URL_ERR_BADATTRS;
            return APR_EGENERAL;
        }
    }

    if ( q == NULL ) {
        /* no more */
        *ludpp = ludp;
        return APR_SUCCESS;
    }

    /* scan forward for '?' that may marks end of scope */
    p = q;
    q = strchr( p, '?' );

    if( q != NULL ) {
        /* terminate the scope part */
        *q++ = '\0';
    }

    if( *p != '\0' ) {
        /* parse the scope */
        apr_ldap_pvt_hex_unescape( p );
        ludp->lud_scope = str2scope( p );

        if( ludp->lud_scope == -1 ) {
            result->reason = "Bad scope encountered while parsing LDAP URL.";
            result->rc = APR_LDAP_URL_ERR_BADSCOPE;
            return APR_EGENERAL;
        }
    }

    if ( q == NULL ) {
        /* no more */
        *ludpp = ludp;
        return APR_SUCCESS;
    }

    /* scan forward for '?' that may marks end of filter */
    p = q;
    q = strchr( p, '?' );

    if( q != NULL ) {
        /* terminate the filter part */
        *q++ = '\0';
    }

    if( *p != '\0' ) {
        /* parse the filter */
        apr_ldap_pvt_hex_unescape( p );

        if( ! *p ) {
            /* missing filter */
            result->reason = "Bad filter encountered while parsing LDAP URL.";
            result->rc = APR_LDAP_URL_ERR_BADFILTER;
            return APR_EGENERAL;
        }

        ludp->lud_filter = (char *)apr_pstrdup(pool, p);
        if( ludp->lud_filter == NULL ) {
            result->reason = "Out of memory parsing LDAP URL.";
            result->rc = APR_LDAP_URL_ERR_MEM;
            return APR_EGENERAL;
        }
    }

    if ( q == NULL ) {
        /* no more */
        *ludpp = ludp;
        return APR_SUCCESS;
    }

    /* scan forward for '?' that may marks end of extensions */
    p = q;
    q = strchr( p, '?' );

    if( q != NULL ) {
        /* extra '?' */
        result->reason = "Bad URL encountered while parsing LDAP URL.";
        result->rc = APR_LDAP_URL_ERR_BADURL;
        return APR_EGENERAL;
    }

    /* parse the extensions */
    ludp->lud_exts = apr_ldap_str2charray(pool, p, ",");
    if( ludp->lud_exts == NULL ) {
        result->reason = "Bad extensions encountered while parsing LDAP URL.";
        result->rc = APR_LDAP_URL_ERR_BADEXTS;
        return APR_EGENERAL;
    }

    for( i=0; ludp->lud_exts[i] != NULL; i++ ) {
        apr_ldap_pvt_hex_unescape( ludp->lud_exts[i] );

        if( *ludp->lud_exts[i] == '!' ) {
            /* count the number of critical extensions */
            ludp->lud_crit_exts++;
        }
    }

    if( i == 0 ) {
        /* must have 1 or more */
        result->reason = "Bad extensions encountered while parsing LDAP URL.";
        result->rc = APR_LDAP_URL_ERR_BADEXTS;
        return APR_EGENERAL;
    }

    /* no more */
    *ludpp = ludp;
    return APR_SUCCESS;
}