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