1 /* ldap-parse-uri.c - Parse an LDAP URI.
2 * Copyright (C) 2015 g10 Code GmbH
4 * This file is part of GnuPG.
6 * GnuPG is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * GnuPG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <https://www.gnu.org/licenses/>.
22 #include <gpg-error.h>
24 #ifdef HAVE_W32_SYSTEM
25 # include "ldap-url.h"
33 /* Returns 1 if the string is an LDAP URL (begins with ldap:, ldaps:
36 ldap_uri_p (const char *url)
38 char *colon = strchr (url, ':');
43 int offset = (uintptr_t) colon - (uintptr_t) url;
45 if (/* All lower case. */
46 (offset == 4 && memcmp (url, "ldap", 4) == 0)
48 && (memcmp (url, "ldaps", 5) == 0
49 && memcmp (url, "ldapi", 5) == 0))
51 || ((url[0] == 'l' || url[0] == 'L')
52 && (url[1] == 'd' || url[1] == 'D')
53 && (url[2] == 'a' || url[2] == 'A')
54 && (url[3] == 'p' || url[3] == 'P')
56 || ((url[4] == 's' || url[4] == 'S'
57 || url[4] == 'i' || url[4] == 'i')
64 /* Parse a URI and put the result into *purip. On success the
65 caller must use http_release_parsed_uri() to releases the resources.
67 uri->path is the base DN (or NULL for the default).
68 uri->auth is the bindname (or NULL for none).
69 The uri->query variable "password" is the password.
71 Note: any specified scope, any attributes, any filter and any
72 unknown extensions are simply ignored. */
74 ldap_parse_uri (parsed_uri_t *purip, const char *uri)
76 gpg_err_code_t err = 0;
77 parsed_uri_t puri = NULL;
80 LDAPURLDesc *lud = NULL;
85 char *bindname = NULL;
86 char *password = NULL;
93 result = ldap_url_parse (uri, &lud);
96 log_error ("Unable to parse LDAP uri '%s'\n", uri);
97 err = GPG_ERR_GENERAL;
101 scheme = lud->lud_scheme;
102 host = lud->lud_host;
105 for (s = lud->lud_exts; s && *s; s ++)
107 if (strncmp (*s, "bindname=", 9) == 0)
110 log_error ("bindname given multiple times in URL '%s', ignoring.\n",
115 else if (strncmp (*s, "password=", 9) == 0)
118 log_error ("password given multiple times in URL '%s', ignoring.\n",
124 log_error ("Unhandled extension (%s) in URL '%s', ignoring.",
130 #define add(s) do { if (s) len += strlen (s) + 1; } while (0)
138 puri = xtrycalloc (1, sizeof *puri + len);
141 err = gpg_err_code_from_syserror ();
145 buffer = puri->buffer;
147 #define copy(to, s) \
153 buffer = stpcpy (buffer, s) + 1; \
158 copy (puri->scheme, scheme);
159 /* Make sure the scheme is lower case. */
160 ascii_strlwr (puri->scheme);
162 copy (puri->host, host);
163 copy (puri->path, dn);
164 copy (puri->auth, bindname);
168 puri->query = calloc (sizeof (*puri->query), 1);
171 err = gpg_err_code_from_syserror ();
174 puri->query->name = "password";
175 copy (puri->query->value, password);
176 puri->query->valuelen = strlen (password) + 1;
179 puri->use_tls = strcmp (puri->scheme, "ldaps") == 0;
180 puri->port = lud->lud_port;
184 ldap_free_urldesc (lud);
189 http_release_parsed_uri (puri);
194 return gpg_err_make (default_errsource, err);
197 /* The following characters need to be escaped to be part of an LDAP
198 filter: *, (, ), \, NUL and /. Note: we don't handle NUL, since a
199 NUL can't be part of a C string.
201 This function always allocates a new string on success. It is the
202 caller's responsibility to free it.
205 ldap_escape_filter (const char *filter)
207 int l = strcspn (filter, "*()\\/");
208 if (l == strlen (filter))
209 /* Nothing to escape. */
210 return xstrdup (filter);
213 /* In the worst case we need to escape every letter. */
214 char *escaped = xmalloc (1 + 3 * strlen (filter));
216 /* Indices into filter and escaped. */
220 for (filter_i = 0; filter_i < strlen (filter); filter_i ++)
222 switch (filter[filter_i])
229 snprintf (&escaped[escaped_i], 4, "%%%02x",
230 ((const unsigned char *)filter)[filter_i]);
235 escaped[escaped_i ++] = filter[filter_i];
239 /* NUL terminate it. */
240 escaped[escaped_i] = 0;
242 /* We could shrink escaped to be just escaped_i bytes, but the
243 result will probably be freed very quickly anyways. */