Change all quotes in strings and comments to the new GNU standard.
[gnupg.git] / dirmngr / dirmngr_ldap.c
1 /* dirmngr-ldap.c  -  The LDAP helper for dirmngr.
2  * Copyright (C) 2004 g10 Code GmbH
3  * Copyright (C) 2010 Free Software Foundation, Inc.
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stddef.h>
26 #include <stdarg.h>
27 #include <string.h>
28 #ifdef HAVE_SIGNAL_H
29 # include <signal.h>
30 #endif
31 #include <errno.h>
32 #include <assert.h>
33 #include <sys/time.h>
34 #include <unistd.h>
35 #ifndef USE_LDAPWRAPPER
36 # include <npth.h>
37 #endif
38
39 #ifdef HAVE_W32_SYSTEM
40 #include <winsock2.h>
41 #include <winldap.h>
42 #include <fcntl.h>
43 #include "ldap-url.h"
44 #else
45 /* For OpenLDAP, to enable the API that we're using. */
46 #define LDAP_DEPRECATED 1
47 #include <ldap.h>
48 #endif
49
50
51 #define JNLIB_NEED_LOG_LOGV
52 #include "../common/logging.h"
53 #include "../common/argparse.h"
54 #include "../common/stringhelp.h"
55 #include "../common/mischelp.h"
56 #include "../common/strlist.h"
57
58 #include "i18n.h"
59 #include "util.h"
60 #include "../common/init.h"
61
62 /* With the ldap wrapper, there is no need for the npth_unprotect and leave
63    functions; thus we redefine them to nops.  If we are not using the
64    ldap wrapper process we need to include the prototype for our
65    module's main function.  */
66 #ifdef USE_LDAPWRAPPER
67 static void npth_unprotect (void) { }
68 static void npth_protect (void) { }
69 #else
70 # include "./ldap-wrapper.h"
71 #endif
72
73 #ifdef HAVE_W32CE_SYSTEM
74 # include "w32-ldap-help.h"
75 # define my_ldap_init(a,b)                      \
76   _dirmngr_ldap_init ((a), (b))
77 # define my_ldap_simple_bind_s(a,b,c)           \
78   _dirmngr_ldap_simple_bind_s ((a),(b),(c))
79 # define my_ldap_search_st(a,b,c,d,e,f,g,h)     \
80   _dirmngr_ldap_search_st ((a), (b), (c), (d), (e), (f), (g), (h))
81 # define my_ldap_first_attribute(a,b,c)         \
82   _dirmngr_ldap_first_attribute ((a),(b),(c))
83 # define my_ldap_next_attribute(a,b,c)          \
84   _dirmngr_ldap_next_attribute ((a),(b),(c))
85 # define my_ldap_get_values_len(a,b,c)          \
86   _dirmngr_ldap_get_values_len ((a),(b),(c))
87 # define my_ldap_free_attr(a)                   \
88   xfree ((a))
89 #else
90 # define my_ldap_init(a,b)              ldap_init ((a), (b))
91 # define my_ldap_simple_bind_s(a,b,c)   ldap_simple_bind_s ((a), (b), (c))
92 # define my_ldap_search_st(a,b,c,d,e,f,g,h)     \
93   ldap_search_st ((a), (b), (c), (d), (e), (f), (g), (h))
94 # define my_ldap_first_attribute(a,b,c) ldap_first_attribute ((a),(b),(c))
95 # define my_ldap_next_attribute(a,b,c)  ldap_next_attribute ((a),(b),(c))
96 # define my_ldap_get_values_len(a,b,c)  ldap_get_values_len ((a),(b),(c))
97 # define my_ldap_free_attr(a)           ldap_memfree ((a))
98 #endif
99
100 #define DEFAULT_LDAP_TIMEOUT 100 /* Arbitrary long timeout. */
101
102
103 /* Constants for the options.  */
104 enum
105   {
106     oQuiet        = 'q',
107     oVerbose      = 'v',
108
109     oTimeout      = 500,
110     oMulti,
111     oProxy,
112     oHost,
113     oPort,
114     oUser,
115     oPass,
116     oEnvPass,
117     oDN,
118     oFilter,
119     oAttr,
120
121     oOnlySearchTimeout,
122     oLogWithPID
123   };
124
125
126 /* The list of options as used by the argparse.c code.  */
127 static ARGPARSE_OPTS opts[] = {
128   { oVerbose,  "verbose",   0, N_("verbose") },
129   { oQuiet,    "quiet",     0, N_("be somewhat more quiet") },
130   { oTimeout,  "timeout",   1, N_("|N|set LDAP timeout to N seconds")},
131   { oMulti,    "multi",     0, N_("return all values in"
132                                   " a record oriented format")},
133   { oProxy,    "proxy",     2,
134     N_("|NAME|ignore host part and connect through NAME")},
135   { oHost,     "host",      2, N_("|NAME|connect to host NAME")},
136   { oPort,     "port",      1, N_("|N|connect to port N")},
137   { oUser,     "user",      2, N_("|NAME|use user NAME for authentication")},
138   { oPass,     "pass",      2, N_("|PASS|use password PASS"
139                                   " for authentication")},
140   { oEnvPass,  "env-pass",  0, N_("take password from $DIRMNGR_LDAP_PASS")},
141   { oDN,       "dn",        2, N_("|STRING|query DN STRING")},
142   { oFilter,   "filter",    2, N_("|STRING|use STRING as filter expression")},
143   { oAttr,     "attr",      2, N_("|STRING|return the attribute STRING")},
144   { oOnlySearchTimeout, "only-search-timeout", 0, "@"},
145   { oLogWithPID,"log-with-pid", 0, "@"},
146   { 0, NULL, 0, NULL }
147 };
148
149
150 /* A structure with module options.  This is not a static variable
151    because if we are not build as a standalone binary, each thread
152    using this module needs to handle its own values.  */
153 struct my_opt_s
154 {
155   int quiet;
156   int verbose;
157   struct timeval timeout; /* Timeout for the LDAP search functions.  */
158   unsigned int alarm_timeout; /* And for the alarm based timeout.  */
159   int multi;
160
161   estream_t outstream;    /* Send output to thsi stream.  */
162
163   /* Note that we can't use const for the strings because ldap_* are
164      not defined that way.  */
165   char *proxy; /* Host and Port override.  */
166   char *user;  /* Authentication user.  */
167   char *pass;  /* Authentication password.  */
168   char *host;  /* Override host.  */
169   int port;    /* Override port.  */
170   char *dn;    /* Override DN.  */
171   char *filter;/* Override filter.  */
172   char *attr;  /* Override attribute.  */
173 };
174 typedef struct my_opt_s *my_opt_t;
175
176
177 /* Prototypes.  */
178 #ifndef HAVE_W32_SYSTEM
179 static void catch_alarm (int dummy);
180 #endif
181 static int process_url (my_opt_t myopt, const char *url);
182
183
184
185 /* Function called by argparse.c to display information.  */
186 #ifdef USE_LDAPWRAPPER
187 static const char *
188 my_strusage (int level)
189 {
190   const char *p;
191
192   switch(level)
193     {
194     case 11: p = "dirmngr_ldap (GnuPG)";
195       break;
196     case 13: p = VERSION; break;
197     case 17: p = PRINTABLE_OS_NAME; break;
198     case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
199     case 49: p = PACKAGE_BUGREPORT; break;
200     case 1:
201     case 40: p =
202                _("Usage: dirmngr_ldap [options] [URL] (-h for help)\n");
203       break;
204     case 41: p =
205           _("Syntax: dirmngr_ldap [options] [URL]\n"
206             "Internal LDAP helper for Dirmngr.\n"
207             "Interface and options may change without notice.\n");
208       break;
209
210     default: p = NULL;
211     }
212   return p;
213 }
214 #endif /*!USE_LDAPWRAPPER*/
215
216
217 int
218 #ifdef USE_LDAPWRAPPER
219 main (int argc, char **argv)
220 #else
221 ldap_wrapper_main (char **argv, estream_t outstream)
222 #endif
223 {
224 #ifndef USE_LDAPWRAPPER
225   int argc;
226 #endif
227   ARGPARSE_ARGS pargs;
228   int any_err = 0;
229   char *p;
230   int only_search_timeout = 0;
231   struct my_opt_s my_opt_buffer;
232   my_opt_t myopt = &my_opt_buffer;
233   char *malloced_buffer1 = NULL;
234
235   memset (&my_opt_buffer, 0, sizeof my_opt_buffer);
236
237 #ifdef USE_LDAPWRAPPER
238   set_strusage (my_strusage);
239   log_set_prefix ("dirmngr_ldap", JNLIB_LOG_WITH_PREFIX);
240
241   /* Setup I18N and common subsystems. */
242   i18n_init();
243
244   init_common_subsystems (&argc, &argv);
245
246   es_set_binary (es_stdout);
247   myopt->outstream = es_stdout;
248 #else /*!USE_LDAPWRAPPER*/
249   myopt->outstream = outstream;
250   for (argc=0; argv[argc]; argc++)
251     ;
252 #endif /*!USE_LDAPWRAPPER*/
253
254   /* LDAP defaults */
255   myopt->timeout.tv_sec = DEFAULT_LDAP_TIMEOUT;
256   myopt->timeout.tv_usec = 0;
257   myopt->alarm_timeout = 0;
258
259   /* Parse the command line.  */
260   pargs.argc = &argc;
261   pargs.argv = &argv;
262   pargs.flags= 1;  /* Do not remove the args. */
263   while (arg_parse (&pargs, opts) )
264     {
265       switch (pargs.r_opt)
266         {
267         case oVerbose: myopt->verbose++; break;
268         case oQuiet: myopt->quiet++; break;
269         case oTimeout:
270           myopt->timeout.tv_sec = pargs.r.ret_int;
271           myopt->timeout.tv_usec = 0;
272           myopt->alarm_timeout = pargs.r.ret_int;
273           break;
274         case oOnlySearchTimeout: only_search_timeout = 1; break;
275         case oMulti: myopt->multi = 1; break;
276         case oUser: myopt->user = pargs.r.ret_str; break;
277         case oPass: myopt->pass = pargs.r.ret_str; break;
278         case oEnvPass:
279           myopt->pass = getenv ("DIRMNGR_LDAP_PASS");
280           break;
281         case oProxy: myopt->proxy = pargs.r.ret_str; break;
282         case oHost: myopt->host = pargs.r.ret_str; break;
283         case oPort: myopt->port = pargs.r.ret_int; break;
284         case oDN:   myopt->dn = pargs.r.ret_str; break;
285         case oFilter: myopt->filter = pargs.r.ret_str; break;
286         case oAttr: myopt->attr = pargs.r.ret_str; break;
287         case oLogWithPID:
288           {
289             unsigned int oldflags;
290             log_get_prefix (&oldflags);
291             log_set_prefix (NULL, oldflags | JNLIB_LOG_WITH_PID);
292           }
293           break;
294
295         default :
296 #ifdef USE_LDAPWRAPPER
297           pargs.err = ARGPARSE_PRINT_ERROR;
298 #else
299           pargs.err = ARGPARSE_PRINT_WARNING;  /* No exit() please.  */
300 #endif
301           break;
302         }
303     }
304
305   if (only_search_timeout)
306     myopt->alarm_timeout = 0;
307
308   if (myopt->proxy)
309     {
310       malloced_buffer1 = xtrystrdup (myopt->proxy);
311       if (!malloced_buffer1)
312         {
313           log_error ("error copying string: %s\n", strerror (errno));
314           return 1;
315         }
316       myopt->host = malloced_buffer1;
317       p = strchr (myopt->host, ':');
318       if (p)
319         {
320           *p++ = 0;
321           myopt->port = atoi (p);
322         }
323       if (!myopt->port)
324         myopt->port = 389;  /* make sure ports gets overridden.  */
325     }
326
327   if (myopt->port < 0 || myopt->port > 65535)
328     log_error (_("invalid port number %d\n"), myopt->port);
329
330 #ifdef USE_LDAPWRAPPER
331   if (log_get_errorcount (0))
332     exit (2);
333   if (argc < 1)
334     usage (1);
335 #else
336   /* All passed arguments should be fine in this case.  */
337   assert (argc);
338 #endif
339
340 #ifdef USE_LDAPWRAPPER
341   if (myopt->alarm_timeout)
342     {
343 #ifndef HAVE_W32_SYSTEM
344 # if defined(HAVE_SIGACTION) && defined(HAVE_STRUCT_SIGACTION)
345       struct sigaction act;
346
347       act.sa_handler = catch_alarm;
348       sigemptyset (&act.sa_mask);
349       act.sa_flags = 0;
350       if (sigaction (SIGALRM,&act,NULL))
351 # else
352       if (signal (SIGALRM, catch_alarm) == SIG_ERR)
353 # endif
354           log_fatal ("unable to register timeout handler\n");
355 #endif
356     }
357 #endif /*USE_LDAPWRAPPER*/
358
359   for (; argc; argc--, argv++)
360     if (process_url (myopt, *argv))
361       any_err = 1;
362
363   xfree (malloced_buffer1);
364   return any_err;
365 }
366
367 #ifndef HAVE_W32_SYSTEM
368 static void
369 catch_alarm (int dummy)
370 {
371   (void)dummy;
372   _exit (10);
373 }
374 #endif
375
376 static void
377 set_timeout (my_opt_t myopt)
378 {
379 #ifdef HAVE_W32_SYSTEM
380   /* FIXME for W32.  */
381   (void)myopt;
382 #else
383   if (myopt->alarm_timeout)
384     alarm (myopt->alarm_timeout);
385 #endif
386 }
387
388
389 /* Helper for fetch_ldap().  */
390 static int
391 print_ldap_entries (my_opt_t myopt, LDAP *ld, LDAPMessage *msg, char *want_attr)
392 {
393   LDAPMessage *item;
394   int any = 0;
395
396   for (npth_unprotect (), item = ldap_first_entry (ld, msg), npth_protect ();
397        item;
398        npth_unprotect (), item = ldap_next_entry (ld, item), npth_protect ())
399     {
400       BerElement *berctx;
401       char *attr;
402
403       if (myopt->verbose > 1)
404         log_info (_("scanning result for attribute '%s'\n"),
405                   want_attr? want_attr : "[all]");
406
407       if (myopt->multi)
408         { /*  Write item marker. */
409           if (es_fwrite ("I\0\0\0\0", 5, 1, myopt->outstream) != 1)
410             {
411               log_error (_("error writing to stdout: %s\n"),
412                          strerror (errno));
413               return -1;
414             }
415         }
416
417
418       for (npth_unprotect (), attr = my_ldap_first_attribute (ld, item, &berctx),
419              npth_protect ();
420            attr;
421            npth_unprotect (), attr = my_ldap_next_attribute (ld, item, berctx),
422              npth_protect ())
423         {
424           struct berval **values;
425           int idx;
426
427           if (myopt->verbose > 1)
428             log_info (_("          available attribute '%s'\n"), attr);
429
430           set_timeout (myopt);
431
432           /* I case we want only one attribute we do a case
433              insensitive compare without the optional extension
434              (i.e. ";binary").  Case insensitive is not really correct
435              but the best we can do.  */
436           if (want_attr)
437             {
438               char *cp1, *cp2;
439               int cmpres;
440
441               cp1 = strchr (want_attr, ';');
442               if (cp1)
443                 *cp1 = 0;
444               cp2 = strchr (attr, ';');
445               if (cp2)
446                 *cp2 = 0;
447               cmpres = ascii_strcasecmp (want_attr, attr);
448               if (cp1)
449                 *cp1 = ';';
450               if (cp2)
451                 *cp2 = ';';
452               if (cmpres)
453                 {
454                   my_ldap_free_attr (attr);
455                   continue; /* Not found:  Try next attribute.  */
456                 }
457             }
458
459           npth_unprotect ();
460           values = my_ldap_get_values_len (ld, item, attr);
461           npth_protect ();
462
463           if (!values)
464             {
465               if (myopt->verbose)
466                 log_info (_("attribute '%s' not found\n"), attr);
467               my_ldap_free_attr (attr);
468               continue;
469             }
470
471           if (myopt->verbose)
472             {
473               log_info (_("found attribute '%s'\n"), attr);
474               if (myopt->verbose > 1)
475                 for (idx=0; values[idx]; idx++)
476                   log_info ("         length[%d]=%d\n",
477                             idx, (int)values[0]->bv_len);
478
479             }
480
481           if (myopt->multi)
482             { /*  Write attribute marker. */
483               unsigned char tmp[5];
484               size_t n = strlen (attr);
485
486               tmp[0] = 'A';
487               tmp[1] = (n >> 24);
488               tmp[2] = (n >> 16);
489               tmp[3] = (n >> 8);
490               tmp[4] = (n);
491               if (es_fwrite (tmp, 5, 1, myopt->outstream) != 1
492                   || es_fwrite (attr, n, 1, myopt->outstream) != 1)
493                 {
494                   log_error (_("error writing to stdout: %s\n"),
495                              strerror (errno));
496                   ldap_value_free_len (values);
497                   my_ldap_free_attr (attr);
498                   ber_free (berctx, 0);
499                   return -1;
500                 }
501             }
502
503           for (idx=0; values[idx]; idx++)
504             {
505               if (myopt->multi)
506                 { /* Write value marker.  */
507                   unsigned char tmp[5];
508                   size_t n = values[0]->bv_len;
509
510                   tmp[0] = 'V';
511                   tmp[1] = (n >> 24);
512                   tmp[2] = (n >> 16);
513                   tmp[3] = (n >> 8);
514                   tmp[4] = (n);
515
516                   if (es_fwrite (tmp, 5, 1, myopt->outstream) != 1)
517                     {
518                       log_error (_("error writing to stdout: %s\n"),
519                                  strerror (errno));
520                       ldap_value_free_len (values);
521                       my_ldap_free_attr (attr);
522                       ber_free (berctx, 0);
523                       return -1;
524                     }
525                 }
526
527               if (es_fwrite (values[0]->bv_val, values[0]->bv_len,
528                              1, myopt->outstream) != 1)
529                 {
530                   log_error (_("error writing to stdout: %s\n"),
531                              strerror (errno));
532                   ldap_value_free_len (values);
533                   my_ldap_free_attr (attr);
534                   ber_free (berctx, 0);
535                   return -1;
536                 }
537
538               any = 1;
539               if (!myopt->multi)
540                 break; /* Print only the first value.  */
541             }
542           ldap_value_free_len (values);
543           my_ldap_free_attr (attr);
544           if (want_attr || !myopt->multi)
545             break; /* We only want to return the first attribute.  */
546         }
547       ber_free (berctx, 0);
548     }
549
550   if (myopt->verbose > 1 && any)
551     log_info ("result has been printed\n");
552
553   return any?0:-1;
554 }
555
556
557
558 /* Helper for the URL based LDAP query. */
559 static int
560 fetch_ldap (my_opt_t myopt, const char *url, const LDAPURLDesc *ludp)
561 {
562   LDAP *ld;
563   LDAPMessage *msg;
564   int rc = 0;
565   char *host, *dn, *filter, *attrs[2], *attr;
566   int port;
567   int ret;
568
569   host     = myopt->host?   myopt->host   : ludp->lud_host;
570   port     = myopt->port?   myopt->port   : ludp->lud_port;
571   dn       = myopt->dn?     myopt->dn     : ludp->lud_dn;
572   filter   = myopt->filter? myopt->filter : ludp->lud_filter;
573   attrs[0] = myopt->attr?   myopt->attr   : ludp->lud_attrs? ludp->lud_attrs[0]:NULL;
574   attrs[1] = NULL;
575   attr = attrs[0];
576
577   if (!port)
578     port = (ludp->lud_scheme && !strcmp (ludp->lud_scheme, "ldaps"))? 636:389;
579
580   if (myopt->verbose)
581     {
582       log_info (_("processing url '%s'\n"), url);
583       if (myopt->user)
584         log_info (_("          user '%s'\n"), myopt->user);
585       if (myopt->pass)
586         log_info (_("          pass '%s'\n"), *myopt->pass?"*****":"");
587       if (host)
588         log_info (_("          host '%s'\n"), host);
589       log_info (_("          port %d\n"), port);
590       if (dn)
591         log_info (_("            DN '%s'\n"), dn);
592       if (filter)
593         log_info (_("        filter '%s'\n"), filter);
594       if (myopt->multi && !myopt->attr && ludp->lud_attrs)
595         {
596           int i;
597           for (i=0; ludp->lud_attrs[i]; i++)
598             log_info (_("          attr '%s'\n"), ludp->lud_attrs[i]);
599         }
600       else if (attr)
601         log_info (_("          attr '%s'\n"), attr);
602     }
603
604
605   if (!host || !*host)
606     {
607       log_error (_("no host name in '%s'\n"), url);
608       return -1;
609     }
610   if (!myopt->multi && !attr)
611     {
612       log_error (_("no attribute given for query '%s'\n"), url);
613       return -1;
614     }
615
616   if (!myopt->multi && !myopt->attr
617       && ludp->lud_attrs && ludp->lud_attrs[0] && ludp->lud_attrs[1])
618     log_info (_("WARNING: using first attribute only\n"));
619
620
621   set_timeout (myopt);
622   npth_unprotect ();
623   ld = my_ldap_init (host, port);
624   npth_protect ();
625   if (!ld)
626     {
627       log_error (_("LDAP init to '%s:%d' failed: %s\n"),
628                  host, port, strerror (errno));
629       return -1;
630     }
631   npth_unprotect ();
632   /* Fixme:  Can we use MYOPT->user or is it shared with other theeads?.  */
633   ret = my_ldap_simple_bind_s (ld, myopt->user, myopt->pass);
634   npth_protect ();
635   if (ret)
636     {
637       log_error (_("binding to '%s:%d' failed: %s\n"),
638                  host, port, strerror (errno));
639       ldap_unbind (ld);
640       return -1;
641     }
642
643   set_timeout (myopt);
644   npth_unprotect ();
645   rc = my_ldap_search_st (ld, dn, ludp->lud_scope, filter,
646                           myopt->multi && !myopt->attr && ludp->lud_attrs?
647                           ludp->lud_attrs:attrs,
648                           0,
649                           &myopt->timeout, &msg);
650   npth_protect ();
651   if (rc == LDAP_SIZELIMIT_EXCEEDED && myopt->multi)
652     {
653       if (es_fwrite ("E\0\0\0\x09truncated", 14, 1, myopt->outstream) != 1)
654         {
655           log_error (_("error writing to stdout: %s\n"), strerror (errno));
656           return -1;
657         }
658     }
659   else if (rc)
660     {
661 #ifdef HAVE_W32CE_SYSTEM
662       log_error ("searching '%s' failed: %d\n", url, rc);
663 #else
664       log_error (_("searching '%s' failed: %s\n"),
665                  url, ldap_err2string (rc));
666 #endif
667       if (rc != LDAP_NO_SUCH_OBJECT)
668         {
669           /* FIXME: Need deinit (ld)?  */
670           /* Hmmm: Do we need to released MSG in case of an error? */
671           return -1;
672         }
673     }
674
675   rc = print_ldap_entries (myopt, ld, msg, myopt->multi? NULL:attr);
676
677   ldap_msgfree (msg);
678   ldap_unbind (ld);
679   return rc;
680 }
681
682
683
684
685 /* Main processing.  Take the URL and run the LDAP query. The result
686    is printed to stdout, errors are logged to the log stream. */
687 static int
688 process_url (my_opt_t myopt, const char *url)
689 {
690   int rc;
691   LDAPURLDesc *ludp = NULL;
692
693
694   if (!ldap_is_ldap_url (url))
695     {
696       log_error (_("'%s' is not an LDAP URL\n"), url);
697       return -1;
698     }
699
700   if (ldap_url_parse (url, &ludp))
701     {
702       log_error (_("'%s' is an invalid LDAP URL\n"), url);
703       return -1;
704     }
705
706   rc = fetch_ldap (myopt, url, ludp);
707
708   ldap_free_urldesc (ludp);
709   return rc;
710 }