Bump to 2.4.3
[platform/upstream/gpg2.git] / dirmngr / ldap-parse-uri.c
1 /* ldap-parse-uri.c - Parse an LDAP URI.
2  * Copyright (C) 2015  g10 Code GmbH
3  *
4  * This file is part of GnuPG.
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
20 #include <config.h>
21
22 #include <gpg-error.h>
23
24 #ifdef HAVE_W32_SYSTEM
25 # include "ldap-url.h"
26 #else
27 # include <ldap.h>
28 #endif
29
30 #include "../common/util.h"
31 #include "http.h"
32
33 /* Returns 1 if the string is an LDAP URL.  */
34 int
35 ldap_uri_p (const char *url)
36 {
37   parsed_uri_t puri;
38   int result;
39
40   if (http_parse_uri (&puri, url, 1))
41     result = 0;
42   else
43     result = !!puri->is_ldap;
44
45   http_release_parsed_uri (puri);
46
47   return result;
48 }
49
50
51 /* Parse a URI and put the result into *purip.  On success the
52    caller must use http_release_parsed_uri() to releases the resources.
53
54    uri->path is the base DN (or NULL for the default).
55    uri->auth is the bindname (or NULL for none).
56    The uri->query variable "password" is the password.
57
58    Note: any specified scope, any attributes, any filter and any
59    unknown extensions are simply ignored.  */
60 gpg_error_t
61 ldap_parse_uri (parsed_uri_t *purip, const char *uri)
62 {
63   gpg_err_code_t err = 0;
64   parsed_uri_t puri = NULL;
65
66   int result;
67   LDAPURLDesc *lud = NULL;
68
69   char *scheme = NULL;
70   char *host = NULL;
71   char *dn = NULL;
72   char *bindname = NULL;
73   char *password = NULL;
74   char *gpg_ntds = NULL;
75
76   char **s;
77
78   char *buffer;
79   int len;
80
81   result = ldap_url_parse (uri, &lud);
82   if (result != 0)
83     {
84       log_error ("Unable to parse LDAP uri '%s'\n", uri);
85       err = GPG_ERR_GENERAL;
86       goto out;
87     }
88
89   scheme = lud->lud_scheme;
90   host = lud->lud_host;
91   dn = lud->lud_dn;
92
93   for (s = lud->lud_exts; s && *s; s ++)
94     {
95       if (strncmp (*s, "bindname=", 9) == 0)
96         {
97           if (bindname)
98             log_error ("bindname given multiple times in URL '%s', ignoring.\n",
99                        uri);
100           else
101             bindname = *s + 9;
102         }
103       else if (strncmp (*s, "password=", 9) == 0)
104         {
105           if (password)
106             log_error ("password given multiple times in URL '%s', ignoring.\n",
107                        uri);
108           else
109             password = *s + 9;
110         }
111       else if (!ascii_strncasecmp (*s, "gpgNtds=", 8)
112               || !strncmp (*s, "1.3.6.1.4.1.11591.2.5.1=", 24))
113         {
114           if (gpg_ntds)
115             log_error ("gpgNtds given multiple times in URL '%s', ignoring.\n",
116                        uri);
117           else
118             gpg_ntds = *s + (**s == 'g'? 8 : 24);
119         }
120       else
121         log_error ("Unhandled extension (%s) in URL '%s', ignoring.",
122                    *s, uri);
123     }
124
125   len = 0;
126
127 #define add(s) do { if (s) len += strlen (s) + 1; } while (0)
128
129   add (scheme);
130   add (host);
131   add (dn);
132   add (bindname);
133   add (password);
134
135   puri = xtrycalloc (1, sizeof *puri + len);
136   if (! puri)
137     {
138       err = gpg_err_code_from_syserror ();
139       goto out;
140     }
141
142   buffer = puri->buffer;
143
144 #define copy(to, s)                             \
145   do                                            \
146     {                                           \
147       if (s)                                    \
148         {                                       \
149           to = buffer;                          \
150           buffer = stpcpy (buffer, s) + 1;      \
151         }                                       \
152     }                                           \
153   while (0)
154
155   copy (puri->scheme, scheme);
156   /* Make sure the scheme is lower case.  */
157   ascii_strlwr (puri->scheme);
158
159   copy (puri->host, host);
160   copy (puri->path, dn);
161   copy (puri->auth, bindname);
162
163   if (password)
164     {
165       puri->query = calloc (sizeof (*puri->query), 1);
166       if (!puri->query)
167         {
168           err = gpg_err_code_from_syserror ();
169           goto out;
170         }
171       puri->query->name = "password";
172       copy (puri->query->value, password);
173       puri->query->valuelen = strlen (password) + 1;
174     }
175
176   puri->use_tls = !strcmp (puri->scheme, "ldaps");
177   puri->port = lud->lud_port;
178
179   /* On Windows detect whether this is ldap:// or ldaps:// to indicate
180    * that authentication via AD and the current user is requested.
181    * This is shortform of adding "gpgNtDs=1" as extension parameter to
182    * the URL.  */
183   puri->ad_current = 0;
184   if (gpg_ntds && atoi (gpg_ntds) == 1)
185     puri->ad_current = 1;
186 #ifdef HAVE_W32_SYSTEM
187   else if ((!puri->host || !*puri->host)
188       && (!puri->path || !*puri->path)
189       && (!puri->auth || !*puri->auth)
190       && !password
191       )
192     puri->ad_current = 1;
193 #endif
194
195  out:
196   if (lud)
197     ldap_free_urldesc (lud);
198
199   if (err)
200     {
201       if (puri)
202         http_release_parsed_uri (puri);
203     }
204   else
205     *purip = puri;
206
207   return gpg_err_make (default_errsource, err);
208 }
209
210 /* The following characters need to be escaped to be part of an LDAP
211    filter: *, (, ), \, NUL and /.  Note: we don't handle NUL, since a
212    NUL can't be part of a C string.
213
214    This function always allocates a new string on success.  It is the
215    caller's responsibility to free it.
216 */
217 char *
218 ldap_escape_filter (const char *filter)
219 {
220   int l = strcspn (filter, "*()\\/");
221   if (l == strlen (filter))
222     /* Nothing to escape.  */
223     return xstrdup (filter);
224
225   {
226     /* In the worst case we need to escape every letter.  */
227     char *escaped = xmalloc (1 + 3 * strlen (filter));
228
229     /* Indices into filter and escaped.  */
230     int filter_i = 0;
231     int escaped_i = 0;
232
233     for (filter_i = 0; filter_i < strlen (filter); filter_i ++)
234       {
235         switch (filter[filter_i])
236           {
237           case '*':
238           case '(':
239           case ')':
240           case '\\':
241           case '/':
242             snprintf (&escaped[escaped_i], 4, "%%%02x",
243                      ((const unsigned char *)filter)[filter_i]);
244             escaped_i += 3;
245             break;
246
247           default:
248             escaped[escaped_i ++] = filter[filter_i];
249             break;
250           }
251       }
252     /* NUL terminate it.  */
253     escaped[escaped_i] = 0;
254
255     /* We could shrink escaped to be just escaped_i bytes, but the
256        result will probably be freed very quickly anyways.  */
257     return escaped;
258   }
259 }