"Fossies" - the Fresh Open Source Software Archive 
Member "nss_ldap-265/ldap-nss.c" (6 Nov 2009, 105007 Bytes) of package /linux/privat/old/nss_ldap-265.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /* Copyright (C) 1997-2006 Luke Howard.
2 This file is part of the nss_ldap library.
3 Contributed by Luke Howard, <lukeh@padl.com>, 1997.
4
5 The nss_ldap library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 The nss_ldap library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with the nss_ldap library; see the file COPYING.LIB. If not,
17 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
21 static char rcsId[] =
22 "$Id: ldap-nss.c,v 2.302 2009/11/06 10:15:26 lukeh Exp $";
23
24 #include "config.h"
25
26 #ifdef HAVE_PORT_BEFORE_H
27 #include <port_before.h>
28 #endif
29
30 #if defined(HAVE_THREAD_H) && !defined(_AIX)
31 #include <thread.h>
32 #elif defined(HAVE_PTHREAD_H)
33 #include <pthread.h>
34 #endif
35
36 #include <assert.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <string.h>
40 #ifdef HAVE_STRINGS_H
41 #include <strings.h>
42 #endif
43 #include <stdio.h>
44 #include <syslog.h>
45 #include <signal.h>
46 #include <fcntl.h>
47 #include <sys/time.h>
48 #include <sys/socket.h>
49 #include <sys/param.h>
50 #include <errno.h>
51 #ifdef HAVE_SYS_UN_H
52 #include <sys/un.h>
53 #endif
54 #include <netinet/in.h>
55 #ifdef HAVE_LBER_H
56 #include <lber.h>
57 #endif
58 #ifdef HAVE_LDAP_H
59 #include <ldap.h>
60 #endif
61 #ifdef HAVE_LDAP_SSL_H
62 #include <ldap_ssl.h>
63 #endif
64 #ifdef HAVE_GSSLDAP_H
65 #include <gssldap.h>
66 #endif
67 #ifdef HAVE_GSSSASL_H
68 #include <gsssasl.h>
69 #endif
70
71 /* Try to handle systems with both SASL libraries installed */
72 #if defined(HAVE_SASL_SASL_H) && defined(HAVE_SASL_AUXPROP_REQUEST)
73 #include <sasl/sasl.h>
74 #elif defined(HAVE_SASL_H)
75 #include <sasl.h>
76 #endif
77
78 #ifndef HAVE_SNPRINTF
79 #include "snprintf.h"
80 #endif
81 #ifdef HAVE_GSSAPI_H
82 #include <gssapi.h>
83 #elif defined(HAVE_GSSAPI_GSSAPI_KRB5_H)
84 #include <gssapi/gssapi.h>
85 #include <gssapi/gssapi_krb5.h>
86 #endif
87 #ifdef CONFIGURE_KRB5_CCNAME
88 #include <krb5.h>
89 #endif
90
91 #include "ldap-nss.h"
92 #include "ltf.h"
93 #include "util.h"
94 #include "dnsconfig.h"
95 #include "pagectrl.h"
96
97 #if defined(HAVE_THREAD_H) && !defined(_AIX)
98 #ifdef HAVE_PTHREAD_ATFORK
99 #undef HAVE_PTHREAD_ATFORK
100 #endif
101 #endif
102
103 /* how many messages to retrieve results for */
104 #ifndef LDAP_MSG_ONE
105 #define LDAP_MSG_ONE 0x00
106 #endif
107 #ifndef LDAP_MSG_ALL
108 #define LDAP_MSG_ALL 0x01
109 #endif
110 #ifndef LDAP_MSG_RECEIVED
111 #define LDAP_MSG_RECEIVED 0x02
112 #endif
113
114 #ifdef HAVE_LDAP_LD_FREE
115 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
116 extern int ldap_ld_free (LDAP * ld, int close, LDAPControl **,
117 LDAPControl **);
118 #else
119 extern int ldap_ld_free (LDAP * ld, int close);
120 #endif /* OPENLDAP 2.x */
121 #endif /* HAVE_LDAP_LD_FREE */
122
123 NSS_LDAP_DEFINE_LOCK (__lock);
124
125 /*
126 * the configuration is read by the first call to do_open().
127 * Pointers to elements of the list are passed around but should not
128 * be freed.
129 */
130 static char __configbuf[NSS_LDAP_CONFIG_BUFSIZ];
131 static ldap_config_t *__config = NULL;
132
133 #ifdef HAVE_SIGACTION
134 static struct sigaction __stored_handler;
135 static int __sigaction_retval = -1;
136 #else
137 static void (*__sigpipe_handler) (int) = SIG_DFL;
138 #endif /* HAVE_SIGACTION */
139
140 /*
141 * Global LDAP session.
142 */
143 static ldap_session_t __session = { NULL, NULL, 0, LS_UNINITIALIZED };
144
145 #if defined(HAVE_PTHREAD_ATFORK) || defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
146 static pthread_once_t __once = PTHREAD_ONCE_INIT;
147 #endif
148
149 #ifdef LBER_OPT_LOG_PRINT_FILE
150 static FILE *__debugfile;
151 #endif /* LBER_OPT_LOG_PRINT_FILE */
152
153 #ifndef HAVE_PTHREAD_ATFORK
154 /*
155 * Process ID that opened the session.
156 */
157 static pid_t __pid = -1;
158 #endif
159 static uid_t __euid = -1;
160
161 #ifdef HAVE_LDAPSSL_CLIENT_INIT
162 static int __ssl_initialized = 0;
163 #endif /* HAVE_LDAPSSL_CLIENT_INIT */
164
165 #if defined(HAVE_PTHREAD_ATFORK) || defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
166 /*
167 * Prepare for fork(); lock mutex.
168 */
169 static void do_atfork_prepare (void);
170
171 /*
172 * Forked in parent, unlock mutex.
173 */
174 static void do_atfork_parent (void);
175
176 /*
177 * Forked in child; close LDAP socket, unlock mutex.
178 */
179 static void do_atfork_child (void);
180
181 /*
182 * Install handlers for atfork, called once.
183 */
184 static void do_atfork_setup (void);
185 #endif
186
187 /*
188 * Close the global session, sending an unbind.
189 */
190 static void do_close (void);
191
192 /*
193 * Close the global session without sending an unbind.
194 */
195 static void do_close_no_unbind (void);
196
197 /*
198 * Disable keepalive on a LDAP connection's socket.
199 */
200 static void do_set_sockopts (void);
201
202 /*
203 * TLS routines: set global SSL session options.
204 */
205 #if defined(HAVE_LDAP_START_TLS_S) || defined(HAVE_LDAP_START_TLS) || (defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS))
206 static int do_ssl_options (ldap_config_t * cfg);
207 static int do_start_tls (ldap_session_t * session);
208 #endif
209
210 /*
211 * Read configuration file and initialize schema
212 */
213 static NSS_STATUS do_init (void);
214
215 /*
216 * Open the global session
217 */
218 static NSS_STATUS do_open (void);
219
220 /*
221 * Perform an asynchronous search.
222 */
223 static int do_search (const char *base, int scope,
224 const char *filter, const char **attrs,
225 int sizelimit, int *);
226
227 /*
228 * Perform a synchronous search.
229 */
230 static int do_search_s (const char *base, int scope,
231 const char *filter, const char **attrs,
232 int sizelimit, LDAPMessage **);
233
234 /*
235 * Fetch an LDAP result.
236 */
237 static NSS_STATUS do_result (ent_context_t * ctx, int all);
238
239 /*
240 * Format a filter given a prototype.
241 */
242 static NSS_STATUS do_filter (const ldap_args_t * args, const char *filterprot,
243 ldap_service_search_descriptor_t * sd,
244 char *filter, size_t filterlen,
245 char **dynamicFilter, const char **retFilter);
246
247 /*
248 * Parse a result, fetching new results until a successful parse
249 * or exceptional condition.
250 */
251 static NSS_STATUS do_parse (ent_context_t * ctx, void *result, char *buffer,
252 size_t buflen, int *errnop, parser_t parser);
253
254 /*
255 * Parse a result, fetching results from the result chain
256 * rather than the server.
257 */
258 static NSS_STATUS do_parse_s (ent_context_t * ctx, void *result, char *buffer,
259 size_t buflen, int *errnop, parser_t parser);
260
261 /*
262 * Function to be braced by reconnect harness. Used so we
263 * can apply the reconnect code to both asynchronous and
264 * synchronous searches.
265 */
266 typedef int (*search_func_t) (const char *, int, const char *,
267 const char **, int, void *);
268
269 /*
270 * Do a search with a reconnect harness.
271 */
272 static NSS_STATUS
273 do_with_reconnect (const char *base, int scope,
274 const char *filter, const char **attrs, int sizelimit,
275 void *private, search_func_t func);
276
277 /*
278 * Map error from LDAP status code to NSS status code
279 */
280 static NSS_STATUS do_map_error (int rc);
281
282 /*
283 * Do a bind with a defined timeout
284 */
285 static int do_bind (LDAP * ld, int timelimit, const char *dn, const char *pw,
286 int with_sasl);
287
288 #if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))
289 static int do_sasl_interact (LDAP * ld, unsigned flags, void *defaults,
290 void *p);
291 #endif
292
293 static int
294 do_get_our_socket(int *sd);
295
296 static int
297 do_dupfd(int oldfd, int newfd);
298
299 static void
300 do_drop_connection(int sd, int closeSd);
301
302 static NSS_STATUS
303 do_map_error (int rc)
304 {
305 NSS_STATUS stat;
306
307 switch (rc)
308 {
309 case LDAP_SUCCESS:
310 case LDAP_SIZELIMIT_EXCEEDED:
311 case LDAP_TIMELIMIT_EXCEEDED:
312 stat = NSS_SUCCESS;
313 break;
314 case LDAP_NO_SUCH_ATTRIBUTE:
315 case LDAP_UNDEFINED_TYPE:
316 case LDAP_INAPPROPRIATE_MATCHING:
317 case LDAP_CONSTRAINT_VIOLATION:
318 case LDAP_TYPE_OR_VALUE_EXISTS:
319 case LDAP_INVALID_SYNTAX:
320 case LDAP_NO_SUCH_OBJECT:
321 case LDAP_ALIAS_PROBLEM:
322 case LDAP_INVALID_DN_SYNTAX:
323 case LDAP_IS_LEAF:
324 case LDAP_ALIAS_DEREF_PROBLEM:
325 case LDAP_FILTER_ERROR:
326 stat = NSS_NOTFOUND;
327 break;
328 case LDAP_SERVER_DOWN:
329 case LDAP_TIMEOUT:
330 case LDAP_UNAVAILABLE:
331 case LDAP_BUSY:
332 #ifdef LDAP_CONNECT_ERROR
333 case LDAP_CONNECT_ERROR:
334 #endif /* LDAP_CONNECT_ERROR */
335 case LDAP_LOCAL_ERROR:
336 case LDAP_INVALID_CREDENTIALS:
337 default:
338 stat = NSS_UNAVAIL;
339 break;
340 }
341 return stat;
342 }
343
344 /*
345 * Rebind functions.
346 */
347
348 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
349 #if LDAP_SET_REBIND_PROC_ARGS == 3
350 static int
351 do_rebind (LDAP * ld, LDAP_CONST char *url, ber_tag_t request,
352 ber_int_t msgid, void *arg)
353 #else
354 static int
355 do_rebind (LDAP * ld, LDAP_CONST char *url, int request, ber_int_t msgid)
356 #endif
357 {
358 char *who, *cred;
359 int timelimit;
360 int with_sasl = 0;
361
362 if (geteuid () == 0 && __session.ls_config->ldc_rootbinddn)
363 {
364 who = __session.ls_config->ldc_rootbinddn;
365 #if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))
366 with_sasl = __session.ls_config->ldc_rootusesasl;
367 if (with_sasl)
368 {
369 cred = __session.ls_config->ldc_rootsaslid;
370 }
371 else
372 {
373 #endif
374 cred = __session.ls_config->ldc_rootbindpw;
375 #if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))
376 }
377 #endif
378 }
379 else
380 {
381 who = __session.ls_config->ldc_binddn;
382 #if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))
383 with_sasl = __session.ls_config->ldc_usesasl;
384 if (with_sasl)
385 {
386 cred = __session.ls_config->ldc_saslid;
387 }
388 else
389 {
390 #endif
391 cred = __session.ls_config->ldc_bindpw;
392 #if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))
393 }
394 #endif
395 }
396
397 timelimit = __session.ls_config->ldc_bind_timelimit;
398
399 #ifdef HAVE_LDAP_START_TLS_S
400 if (__session.ls_config->ldc_ssl_on == SSL_START_TLS)
401 {
402 int version;
403
404 if (ldap_get_option
405 (__session.ls_conn, LDAP_OPT_PROTOCOL_VERSION,
406 &version) == LDAP_OPT_SUCCESS)
407 {
408 if (version < LDAP_VERSION3)
409 {
410 version = LDAP_VERSION3;
411 ldap_set_option (__session.ls_conn, LDAP_OPT_PROTOCOL_VERSION,
412 &version);
413 }
414 }
415
416 if (do_start_tls (&__session) == LDAP_SUCCESS)
417 {
418 debug ("TLS startup succeeded");
419 }
420 else
421 {
422 debug ("TLS startup failed");
423 return NSS_UNAVAIL;
424 }
425 }
426 #endif /* HAVE_LDAP_START_TLS_S */
427
428 return do_bind (ld, timelimit, who, cred, with_sasl);
429 }
430 #else
431 #if LDAP_SET_REBIND_PROC_ARGS == 3
432 static int
433 do_rebind (LDAP * ld, char **whop, char **credp, int *methodp,
434 int freeit, void *arg)
435 #elif LDAP_SET_REBIND_PROC_ARGS == 2
436 static int
437 do_rebind (LDAP * ld, char **whop, char **credp, int *methodp, int freeit)
438 #endif
439 {
440 if (freeit)
441 {
442 if (*whop != NULL)
443 free (*whop);
444 if (*credp != NULL)
445 free (*credp);
446 }
447
448 *whop = *credp = NULL;
449 if (geteuid () == 0 && __session.ls_config->ldc_rootbinddn)
450 {
451 *whop = strdup (__session.ls_config->ldc_rootbinddn);
452 if (__session.ls_config->ldc_rootbindpw != NULL)
453 *credp = strdup (__session.ls_config->ldc_rootbindpw);
454 }
455 else
456 {
457 if (__session.ls_config->ldc_binddn != NULL)
458 *whop = strdup (__session.ls_config->ldc_binddn);
459 if (__session.ls_config->ldc_bindpw != NULL)
460 *credp = strdup (__session.ls_config->ldc_bindpw);
461 }
462
463 *methodp = LDAP_AUTH_SIMPLE;
464
465 return LDAP_SUCCESS;
466 }
467 #endif
468
469 #ifdef HAVE_NSSWITCH_H
470 /*
471 * Default destructor.
472 * The entry point for this function is the destructor in the dispatch
473 * table for the switch. Thus, it's safe to grab the mutex from this
474 * function.
475 */
476 NSS_STATUS
477 _nss_ldap_default_destr (nss_backend_t * be, void *args)
478 {
479 debug ("==> _nss_ldap_default_destr");
480
481 if ((((nss_ldap_backend_t *) be)->state) != NULL)
482 {
483 _nss_ldap_enter ();
484 _nss_ldap_ent_context_release (&(((nss_ldap_backend_t *) be)->state));
485 _nss_ldap_leave ();
486 }
487
488 /* Ditch the backend. */
489 free (be);
490
491 debug ("<== _nss_ldap_default_destr");
492
493 return NSS_SUCCESS;
494 }
495
496 /*
497 * This is the default "constructor" which gets called from each
498 * constructor, in the NSS dispatch table.
499 */
500 NSS_STATUS
501 _nss_ldap_default_constr (nss_ldap_backend_t * be)
502 {
503 debug ("==> _nss_ldap_default_constr");
504
505 be->state = NULL;
506 #ifdef HPUX
507 __thread_mutex_init (&__lock, NULL);
508 #endif
509
510 debug ("<== _nss_ldap_default_constr");
511
512 return NSS_SUCCESS;
513 }
514 #endif /* HAVE_NSSWITCH_H */
515
516 #if defined(HAVE_PTHREAD_ATFORK) || defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
517 static void
518 do_atfork_prepare (void)
519 {
520 debug ("==> do_atfork_prepare");
521 _nss_ldap_enter ();
522 debug ("<== do_atfork_prepare");
523 }
524
525 static void
526 do_atfork_parent (void)
527 {
528 debug ("==> do_atfork_parent");
529 _nss_ldap_leave ();
530 debug ("<== do_atfork_parent");
531 }
532
533 static void
534 do_atfork_child (void)
535 {
536 debug ("==> do_atfork_child");
537 do_close_no_unbind ();
538 _nss_ldap_leave ();
539 debug ("<== do_atfork_child");
540 }
541
542 static void
543 do_atfork_setup (void)
544 {
545 debug ("==> do_atfork_setup");
546
547 #ifdef HAVE_PTHREAD_ATFORK
548 (void) pthread_atfork (do_atfork_prepare, do_atfork_parent,
549 do_atfork_child);
550 #elif defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
551 (void) __libc_atfork (do_atfork_prepare, do_atfork_parent, do_atfork_child);
552 #endif
553
554 debug ("<== do_atfork_setup");
555 }
556 #endif
557
558 /*
559 * Acquires global lock, blocks SIGPIPE.
560 */
561 void
562 _nss_ldap_enter (void)
563 {
564
565 #ifdef HAVE_SIGACTION
566 struct sigaction new_handler;
567
568 memset (&new_handler, 0, sizeof (new_handler));
569 #if 0
570 /* XXX need to test for sa_sigaction, not on all platforms */
571 new_handler.sa_sigaction = NULL;
572 #endif
573 new_handler.sa_handler = SIG_IGN;
574 sigemptyset (&new_handler.sa_mask);
575 new_handler.sa_flags = 0;
576 #endif /* HAVE_SIGACTION */
577
578 debug ("==> _nss_ldap_enter");
579
580 NSS_LDAP_LOCK (__lock);
581
582 /*
583 * Patch for Debian Bug 130006:
584 * ignore SIGPIPE for all LDAP operations.
585 *
586 * The following bug was reintroduced in nss_ldap-213 and is fixed here:
587 * http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=84344
588 *
589 * See:
590 * http://www.gnu.org/software/libc/manual/html_node/Signal-and-Sigaction.html
591 * for more details.
592 */
593 #ifdef HAVE_SIGACTION
594 __sigaction_retval = sigaction (SIGPIPE, &new_handler, &__stored_handler);
595 #elif defined(HAVE_SIGSET)
596 __sigpipe_handler = sigset (SIGPIPE, SIG_IGN);
597 #else
598 __sigpipe_handler = signal (SIGPIPE, SIG_IGN);
599 #endif /* HAVE_SIGSET */
600
601 debug ("<== _nss_ldap_enter");
602 }
603
604 /*
605 * Releases global mutex, releases SIGPIPE.
606 */
607 void
608 _nss_ldap_leave (void)
609 {
610 debug ("==> _nss_ldap_leave");
611
612 #ifdef HAVE_SIGACTION
613 if (__sigaction_retval == 0)
614 (void) sigaction (SIGPIPE, &__stored_handler, NULL);
615 #else
616 if (__sigpipe_handler != SIG_ERR && __sigpipe_handler != SIG_IGN)
617 {
618 # ifdef HAVE_SIGSET
619 (void) sigset (SIGPIPE, __sigpipe_handler);
620 # else
621 (void) signal (SIGPIPE, __sigpipe_handler);
622 # endif /* HAVE_SIGSET */
623 }
624 #endif /* HAVE_SIGACTION */
625
626 NSS_LDAP_UNLOCK (__lock);
627
628 debug ("<== _nss_ldap_leave");
629 }
630
631 static void
632 do_set_sockopts (void)
633 {
634 /*
635 * Netscape SSL-enabled LDAP library does not
636 * return the real socket.
637 */
638 #ifndef HAVE_LDAPSSL_CLIENT_INIT
639 int sd = -1;
640
641 debug ("==> do_set_sockopts");
642 #if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_DESC)
643 if (ldap_get_option (__session.ls_conn, LDAP_OPT_DESC, &sd) == 0)
644 #else
645 if ((sd = __session.ls_conn->ld_sb.sb_sd) > 0)
646 #endif /* LDAP_OPT_DESC */
647 {
648 int off = 0;
649 NSS_LDAP_SOCKLEN_T socknamelen = sizeof (NSS_LDAP_SOCKADDR_STORAGE);
650 NSS_LDAP_SOCKLEN_T peernamelen = sizeof (NSS_LDAP_SOCKADDR_STORAGE);
651
652 (void) setsockopt (sd, SOL_SOCKET, SO_KEEPALIVE, (void *) &off,
653 sizeof (off));
654 (void) fcntl (sd, F_SETFD, FD_CLOEXEC);
655 /*
656 * NSS modules shouldn't open file descriptors that the program/utility
657 * linked against NSS doesn't know about. The LDAP library opens a
658 * connection to the LDAP server transparently. There's an edge case
659 * where a daemon might fork a child and, being written well, closes
660 * all its file descriptors. This will close the socket descriptor
661 * being used by the LDAP library! Worse, the daemon might open many
662 * files and sockets, eventually opening a descriptor with the same number
663 * as that originally used by the LDAP library. The only way to know that
664 * this isn't "our" socket descriptor is to save the local and remote
665 * sockaddr_in structures for later comparison.
666 */
667 (void) getsockname (sd, (struct sockaddr *) &__session.ls_sockname,
668 &socknamelen);
669 (void) getpeername (sd, (struct sockaddr *) &__session.ls_peername,
670 &peernamelen);
671 }
672 debug ("<== do_set_sockopts");
673 #endif /* HAVE_LDAPSSL_CLIENT_INIT */
674
675 return;
676 }
677
678 /*
679 * Closes connection to the LDAP server.
680 * This assumes that we have exclusive access to __session.ls_conn,
681 * either by some other function having acquired a lock, or by
682 * using a thread safe libldap.
683 */
684 static void
685 do_close (void)
686 {
687 #if defined(DEBUG) || defined(DEBUG_SOCKETS)
688 int sd = -1;
689 #endif
690
691 debug ("==> do_close");
692
693 if (__session.ls_conn != NULL)
694 {
695 #if defined(DEBUG) || defined(DEBUG_SOCKETS)
696 # if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_DESC)
697 ldap_get_option (__session.ls_conn, LDAP_OPT_DESC, &sd);
698 # else
699 sd = __session.ls_conn->ld_sb.sb_sd;
700 # endif /* LDAP_OPT_DESC */
701 syslog (LOG_INFO, "nss_ldap: closing connection %p fd %d",
702 __session.ls_conn, sd);
703 #endif /* DEBUG */
704
705 ldap_unbind (__session.ls_conn);
706 __session.ls_conn = NULL;
707 __session.ls_state = LS_UNINITIALIZED;
708 }
709
710 debug ("<== do_close");
711 }
712
713 static int
714 do_sockaddr_isequal (NSS_LDAP_SOCKADDR_STORAGE *_s1,
715 NSS_LDAP_SOCKLEN_T _slen1,
716 NSS_LDAP_SOCKADDR_STORAGE *_s2,
717 NSS_LDAP_SOCKLEN_T _slen2)
718 {
719 int ret;
720
721 if (_s1->ss_family != _s2->ss_family)
722 return 0;
723
724 if (_slen1 != _slen2)
725 return 0;
726
727 ret = 0;
728
729 switch (_s1->ss_family)
730 {
731 case AF_INET:
732 {
733 struct sockaddr_in *s1 = (struct sockaddr_in *) _s1;
734 struct sockaddr_in *s2 = (struct sockaddr_in *) _s2;
735
736 ret = (s1->sin_port == s2->sin_port &&
737 memcmp (&s1->sin_addr, &s2->sin_addr, sizeof(struct in_addr)) == 0);
738 break;
739 }
740 case AF_UNIX:
741 {
742 struct sockaddr_un *s1 = (struct sockaddr_un *) _s1;
743 struct sockaddr_un *s2 = (struct sockaddr_un *) _s2;
744
745 ret = (memcmp (s1->sun_path, s2->sun_path,
746 _slen1 - sizeof (_s1->ss_family)) == 0);
747 break;
748 }
749 #ifdef INET6
750 case AF_INET6:
751 {
752 struct sockaddr_in6 *s1 = (struct sockaddr_in6 *) _s1;
753 struct sockaddr_in6 *s2 = (struct sockaddr_in6 *) _s2;
754
755 ret = (s1->sin6_port == s2->sin6_port &&
756 memcmp (&s1->sin6_addr, &s2->sin6_addr, sizeof(struct in6_addr)) == 0 &&
757 s1->sin6_scope_id == s2->sin6_scope_id);
758 break;
759 }
760 #endif
761 default:
762 ret = (memcmp (_s1, _s2, _slen1) == 0);
763 break;
764 }
765
766 return ret;
767 }
768
769 static int
770 do_get_our_socket(int *sd)
771 {
772 /*
773 * Before freeing the LDAP context or closing the socket descriptor,
774 * we must ensure that it is *our* socket descriptor. See the much
775 * lengthier description of this at the end of do_open () where the
776 * values __session.ls_sockname and __session.ls_peername are saved.
777 * With HAVE_LDAPSSL_CLIENT_INIT this returns 0 if the socket has
778 * been closed or reopened, and sets *sd to the ldap socket
779 * descriptor.. Returns 1 in all other cases.
780 */
781
782 int isOurSocket = 1;
783
784 #ifndef HAVE_LDAPSSL_CLIENT_INIT
785 #if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_DESC)
786 if (ldap_get_option (__session.ls_conn, LDAP_OPT_DESC, sd) == 0)
787 #else
788 if ((*sd = __session.ls_conn->ld_sb.sb_sd) > 0)
789 #endif /* LDAP_OPT_DESC */
790 {
791 NSS_LDAP_SOCKADDR_STORAGE sockname;
792 NSS_LDAP_SOCKADDR_STORAGE peername;
793 NSS_LDAP_SOCKLEN_T socknamelen = sizeof (sockname);
794 NSS_LDAP_SOCKLEN_T peernamelen = sizeof (peername);
795
796 if (getsockname (*sd, (struct sockaddr *) &sockname, &socknamelen) != 0 ||
797 !do_sockaddr_isequal (&__session.ls_sockname,
798 socknamelen,
799 &sockname,
800 socknamelen))
801 {
802 isOurSocket = 0;
803 }
804 /*
805 * XXX: We don't pay any attention to return codes in places such as
806 * do_search_s so we never observe when the other end has disconnected
807 * our socket. In that case we'll get an ENOTCONN error here... and
808 * it's best we ignore the error -- otherwise we'll leak a filedescriptor.
809 * The correct fix would be to test error codes in many places.
810 */
811 else if (getpeername (*sd, (struct sockaddr *) &peername, &peernamelen) != 0)
812 {
813 if (errno != ENOTCONN)
814 isOurSocket = 0;
815 }
816 else
817 {
818 isOurSocket = do_sockaddr_isequal (&__session.ls_peername,
819 peernamelen,
820 &peername,
821 peernamelen);
822 }
823 }
824 #endif /* HAVE_LDAPSSL_CLIENT_INIT */
825 return isOurSocket;
826 }
827
828 static int
829 do_dupfd(int oldfd, int newfd)
830 {
831 int d = -1;
832 int flags;
833
834 flags = fcntl(oldfd, F_GETFD);
835
836 while (1)
837 {
838 d = (newfd > -1) ? dup2 (oldfd, newfd) : dup (oldfd);
839 if (d > -1)
840 break;
841
842 if (errno == EBADF)
843 return -1; /* not open */
844
845 if (errno != EINTR
846 #ifdef EBUSY
847 && errno != EBUSY
848 #endif
849 )
850 return -1;
851 }
852
853 /* duplicate close-on-exec flag */
854 (void) fcntl (d, F_SETFD, flags);
855
856 return d;
857 }
858
859 static int
860 do_closefd(int fd)
861 {
862 int rc;
863
864 while ((rc = close(fd)) < 0 && errno == EINTR)
865 ;
866
867 return rc;
868 }
869
870 static void
871 do_drop_connection(int sd, int closeSd)
872 {
873 /* Close the LDAP connection without writing anything to the
874 underlying socket. The socket will be left open afterwards if
875 closeSd is 0 */
876 #ifndef HAVE_LDAPSSL_CLIENT_INIT
877 {
878 int dummyfd = -1, savedfd = -1;
879 /* Under OpenLDAP 2.x, ldap_set_option (..., LDAP_OPT_DESC, ...) is
880 a no-op, so to shut down the LDAP connection without writing
881 anything to the socket, we swap a dummy socket onto that file
882 descriptor, and then swap the real fd back once the shutdown is
883 done. */
884 savedfd = do_dupfd (sd, -1);
885 dummyfd = socket (AF_INET, SOCK_STREAM, 0);
886 if (dummyfd > -1 && dummyfd != sd)
887 {
888 /* we must let dup2 close sd for us to avoid race conditions
889 * in multithreaded code.
890 */
891 do_dupfd (dummyfd, sd);
892 do_closefd (dummyfd);
893 }
894
895 #ifdef HAVE_LDAP_LD_FREE
896 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
897 /* XXX: when using openssl this will *ALWAYS* close the fd */
898 (void) ldap_ld_free (__session.ls_conn, 0, NULL, NULL);
899 #else
900 (void) ldap_ld_free (__session.ls_conn, 0);
901 #endif /* OPENLDAP 2.x */
902 #else
903 ldap_unbind (__session.ls_conn);
904 #endif /* HAVE_LDAP_LD_FREE */
905
906 /* Do we want our original sd back? */
907 if (savedfd > -1)
908 {
909 if (closeSd == 0)
910 do_dupfd (savedfd, sd);
911 else
912 do_closefd (sd);
913 do_closefd (savedfd);
914 }
915 else
916 {
917 do_closefd (sd);
918 }
919 }
920 #else /* No sd available */
921 {
922 int bogusSd = -1;
923 if (closeSd == 0)
924 {
925 sd = -1; /* don't want to really close the socket */
926 #ifdef HAVE_LDAP_LD_FREE
927 #if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_DESC)
928 (void) ldap_set_option (__session.ls_conn, LDAP_OPT_DESC, &sd);
929 #else
930 __session.ls_conn->ld_sb.sb_sd = -1;
931 #endif /* LDAP_OPT_DESC */
932 #endif /* HAVE_LDAP_LD_FREE */
933 }
934
935 #ifdef HAVE_LDAP_LD_FREE
936
937 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
938 (void) ldap_ld_free (__session.ls_conn, 0, NULL, NULL);
939 #else
940 (void) ldap_ld_free (__session.ls_conn, 0);
941 #endif /* OPENLDAP 2.x */
942
943 #else
944
945 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_DESC)
946 (void) ldap_set_option (__session.ls_conn, LDAP_OPT_DESC, &bogusSd);
947 #else
948 __session.ls_conn->ld_sb.sb_sd = bogusSd;
949 #endif /* LDAP_OPT_DESC */
950
951 /* hope we closed it OK! */
952 ldap_unbind (__session.ls_conn);
953
954 #endif /* HAVE_LDAP_LD_FREE */
955
956 }
957 #endif /* HAVE_LDAPSSL_CLIENT_INIT */
958 __session.ls_conn = NULL;
959 __session.ls_state = LS_UNINITIALIZED;
960
961 return;
962 }
963
964 /*
965 * If we've forked, then we need to open a new session.
966 * Careful: we have the socket shared with our parent,
967 * so we don't want to send an unbind to the server.
968 * However, we want to close the descriptor to avoid
969 * leaking it, and we also want to release the memory
970 * used by __session.ls_conn. The only entry point
971 * we have is ldap_unbind() which does both of these
972 * things, so we use an internal API, at the expense
973 * of compatibility.
974 */
975 static void
976 do_close_no_unbind (void)
977 {
978 int sd = -1;
979 int closeSd = 1;
980
981 debug ("==> do_close_no_unbind");
982
983 if (__session.ls_state == LS_UNINITIALIZED)
984 {
985 assert (__session.ls_conn == NULL);
986 debug ("<== do_close_no_unbind (connection was not open)");
987 return;
988 }
989
990 closeSd = do_get_our_socket (&sd);
991
992 #if defined(DEBUG) || defined(DEBUG_SOCKETS)
993 syslog (LOG_INFO, "nss_ldap: %sclosing connection (no unbind) %p fd %d",
994 closeSd ? "" : "not ", __session.ls_conn, sd);
995 #endif /* DEBUG */
996
997 do_drop_connection(sd, closeSd);
998
999 debug ("<== do_close_no_unbind");
1000
1001 return;
1002 }
1003
1004 /*
1005 * A simple alias around do_init().
1006 */
1007 NSS_STATUS
1008 _nss_ldap_init (void)
1009 {
1010 return do_init ();
1011 }
1012
1013 /*
1014 * A simple alias around do_close().
1015 */
1016 void
1017 _nss_ldap_close (void)
1018 {
1019 do_close ();
1020 }
1021
1022 static NSS_STATUS
1023 do_init_session (LDAP ** ld, const char *uri, int defport)
1024 {
1025 int rc;
1026 int ldaps;
1027 char uribuf[NSS_BUFSIZ];
1028 char *p;
1029 NSS_STATUS stat;
1030
1031 ldaps = (strncasecmp (uri, "ldaps://", sizeof ("ldaps://") - 1) == 0);
1032 p = strchr (uri, ':');
1033 /* we should be looking for the second instance to find the port number */
1034 if (p != NULL)
1035 {
1036 p = strchr (++p, ':');
1037 }
1038
1039 # ifdef CONFIGURE_KRB5_KEYTAB
1040 (void)do_init_krb5_cache(__config);
1041 # endif /* CONFIGURE_KRB5_KEYTAB */
1042 #ifdef HAVE_LDAP_INITIALIZE
1043 if (p == NULL && defport != 0 &&
1044 ((ldaps && defport != LDAPS_PORT) || (!ldaps && defport != LDAP_PORT)))
1045 {
1046 /* No port specified in URI and non-default port specified */
1047 snprintf (uribuf, sizeof (uribuf), "%s:%d", uri, defport);
1048 uri = uribuf;
1049 }
1050
1051 rc = ldap_initialize (ld, uri);
1052 #else
1053 if (strncasecmp (uri, "ldap://", sizeof ("ldap://") - 1) != 0)
1054 {
1055 return NSS_UNAVAIL;
1056 }
1057
1058 uri += sizeof ("ldap://") - 1;
1059 p = strchr (uri, ':');
1060
1061 if (p != NULL)
1062 {
1063 size_t urilen = (p - uri);
1064
1065 if (urilen >= sizeof (uribuf))
1066 {
1067 return NSS_UNAVAIL;
1068 }
1069
1070 memcpy (uribuf, uri, urilen);
1071 uribuf[urilen] = '\0';
1072
1073 defport = atoi (p + 1);
1074 uri = uribuf;
1075 }
1076 # ifdef HAVE_LDAP_INIT
1077 *ld = ldap_init (uri, defport);
1078 # else
1079 *ld = ldap_open (uri, defport);
1080 # endif
1081
1082 rc = (*ld == NULL) ? LDAP_SERVER_DOWN : LDAP_SUCCESS;
1083
1084 #endif /* HAVE_LDAP_INITIALIZE */
1085
1086 stat = do_map_error (rc);
1087 if (stat == NSS_SUCCESS && *ld == NULL)
1088 {
1089 stat = NSS_UNAVAIL;
1090 }
1091 return stat;
1092 }
1093
1094
1095 static NSS_STATUS
1096 do_init (void)
1097 {
1098 ldap_config_t *cfg;
1099 #ifndef HAVE_PTHREAD_ATFORK
1100 pid_t pid;
1101 #endif
1102 uid_t euid;
1103 NSS_STATUS stat;
1104 int sd=-1;
1105
1106 debug ("==> do_init");
1107
1108 if (_nss_ldap_validateconfig (__config) != NSS_SUCCESS)
1109 {
1110 do_close ();
1111 __config = NULL;
1112 __session.ls_current_uri = 0;
1113 }
1114
1115 #ifndef HAVE_PTHREAD_ATFORK
1116 #if defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
1117 /*
1118 * This bogosity is necessary because Linux uses different
1119 * PIDs for different threads (like IRIX, which we don't
1120 * support). We can tell whether we are linked against
1121 * libpthreads by whether __pthread_once is NULL or
1122 * not. If it is NULL, then we're not linked with the
1123 * threading library, and we need to compare the current
1124 * process ID against the saved one to figure out
1125 * whether we've forked.
1126 *
1127 * --
1128 * __pthread_once does not imply __pthread_atfork being non-NULL!
1129 * <tjanouse@redhat.com>
1130 * --
1131 *
1132 * Once we know whether we have forked or not,
1133 * courtesy of pthread_atfork() or us checking
1134 * ourselves, we can close the socket to the LDAP
1135 * server to avoid leaking a socket, and reopen
1136 * another connection. Under no circumstances do we
1137 * wish to use the same connection, or to send an
1138 * unbind PDU over the parents connection, as that
1139 * will wreak all sorts of havoc or inefficiencies,
1140 * respectively.
1141 */
1142 if (__pthread_once == NULL || __pthread_atfork == NULL)
1143 pid = getpid ();
1144 else
1145 pid = -1; /* linked against libpthreads, don't care */
1146 #else
1147 pid = getpid ();
1148 #endif /* HAVE_LIBC_LOCK_H || HAVE_BITS_LIBC_LOCK_H */
1149 #endif /* HAVE_PTHREAD_ATFORK */
1150
1151 euid = geteuid ();
1152
1153 #ifdef DEBUG
1154 #ifdef HAVE_PTHREAD_ATFORK
1155 syslog (LOG_DEBUG,
1156 "nss_ldap: __session.ls_state=%d, __session.ls_conn=%p, __euid=%i, euid=%i",
1157 __session.ls_state, __session.ls_conn, __euid, euid);
1158 #elif defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
1159 syslog (LOG_DEBUG,
1160 "nss_ldap: libpthreads=%s, __session.ls_state=%d, __session.ls_conn=%p, __pid=%i, pid=%i, __euid=%i, euid=%i",
1161 ((__pthread_once == NULL || __pthread_atfork == NULL) ? "FALSE" : "TRUE"),
1162 __session.ls_state,
1163 __session.ls_conn,
1164 ((__pthread_once == NULL || __pthread_atfork == NULL) ? __pid : -1),
1165 ((__pthread_once == NULL || __pthread_atfork == NULL) ? pid : -1), __euid, euid);
1166 #else
1167 syslog (LOG_DEBUG,
1168 "nss_ldap: __session.ls_state=%d, __session.ls_conn=%p, __pid=%i, pid=%i, __euid=%i, euid=%i",
1169 __session.ls_state, __session.ls_conn, __pid, pid, __euid, euid);
1170 #endif
1171 #endif /* DEBUG */
1172
1173 if (__session.ls_state == LS_CONNECTED_TO_DSA &&
1174 do_get_our_socket (&sd) == 0)
1175 {
1176 /* The calling app has stolen our socket. */
1177 debug (":== do_init (stolen socket detected)");
1178 do_drop_connection (sd, 0);
1179 }
1180 else
1181 #ifndef HAVE_PTHREAD_ATFORK
1182 #if defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
1183 if ((__pthread_once == NULL || __pthread_atfork == NULL) && __pid != pid)
1184 #else
1185 if (__pid != pid)
1186 #endif /* HAVE_LIBC_LOCK_H || HAVE_BITS_LIBC_LOCK_H */
1187 {
1188 do_close_no_unbind ();
1189 }
1190 else
1191 #endif /* HAVE_PTHREAD_ATFORK */
1192 if (__euid != euid && (__euid == 0 || euid == 0))
1193 {
1194 /*
1195 * If we've changed user ids, close the session so we can
1196 * rebind as the correct user.
1197 */
1198 do_close ();
1199 }
1200 else if (__session.ls_state == LS_CONNECTED_TO_DSA)
1201 {
1202 time_t current_time;
1203
1204 /*
1205 * Otherwise we can hand back this process' global
1206 * LDAP session.
1207 *
1208 * Patch from Steven Barrus <sbarrus@eng.utah.edu> to
1209 * close the session after an idle timeout.
1210 */
1211
1212 assert (__session.ls_conn != NULL);
1213 assert (__session.ls_config != NULL);
1214
1215 if (__session.ls_config->ldc_idle_timelimit)
1216 {
1217 time (¤t_time);
1218 if ((__session.ls_timestamp +
1219 __session.ls_config->ldc_idle_timelimit) < current_time)
1220 {
1221 debug ("idle_timelimit reached");
1222 do_close ();
1223 }
1224 }
1225
1226 /*
1227 * If the connection is still there (ie. do_close() wasn't
1228 * called) then we can return the cached connection.
1229 */
1230 if (__session.ls_state == LS_CONNECTED_TO_DSA)
1231 {
1232 debug ("<== do_init (cached session)");
1233 return NSS_SUCCESS;
1234 }
1235 }
1236
1237 __session.ls_conn = NULL;
1238 __session.ls_timestamp = 0;
1239 __session.ls_state = LS_UNINITIALIZED;
1240
1241 #if defined(HAVE_PTHREAD_ONCE) && defined(HAVE_PTHREAD_ATFORK)
1242 if (pthread_once (&__once, do_atfork_setup) != 0)
1243 {
1244 debug ("<== do_init (pthread_once failed)");
1245 return NSS_UNAVAIL;
1246 }
1247 #elif defined(HAVE_PTHREAD_ATFORK) && ( defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H) )
1248 __libc_once (__once, do_atfork_setup);
1249 #elif defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
1250 /*
1251 * Only install the pthread_atfork() handlers i
1252 * we are linked against libpthreads. Otherwise,
1253 * do close the session when the PID changes.
1254 */
1255 if (__pthread_once == NULL || __pthread_atfork == NULL)
1256 __pid = pid;
1257 else
1258 __libc_once (__once, do_atfork_setup);
1259 #else
1260 __pid = pid;
1261 #endif
1262
1263 __euid = euid;
1264
1265 /* Initialize schema and LDAP handle (but do not connect) */
1266 if (__config == NULL)
1267 {
1268 char *configbufp = __configbuf;
1269 size_t configbuflen = sizeof (__configbuf);
1270
1271 stat = _nss_ldap_readconfig (&__config, &configbufp, &configbuflen);
1272 if (stat == NSS_NOTFOUND)
1273 {
1274 /* Config was read but no host information specified; try DNS */
1275 stat = _nss_ldap_mergeconfigfromdns (__config, &configbufp, &configbuflen);
1276 if (stat != NSS_SUCCESS)
1277 {
1278 syslog (LOG_ERR, "nss_ldap: could not determine LDAP server from ldap.conf or DNS");
1279 }
1280 }
1281
1282 if (stat != NSS_SUCCESS)
1283 {
1284 debug ("<== do_init (failed to read config)");
1285 __config = NULL;
1286 return NSS_UNAVAIL;
1287 }
1288 }
1289
1290 cfg = __config;
1291
1292 _nss_ldap_init_attributes (cfg->ldc_attrtab, (cfg->ldc_flags & NSS_LDAP_FLAGS_GETGRENT_SKIPMEMBERS) != 0);
1293 _nss_ldap_init_filters ();
1294
1295 #ifdef HAVE_LDAP_SET_OPTION
1296 if (cfg->ldc_debug)
1297 {
1298 # ifdef LBER_OPT_LOG_PRINT_FILE
1299 if (cfg->ldc_logdir && !__debugfile)
1300 {
1301 char namebuf[PATH_MAX];
1302
1303 snprintf (namebuf, sizeof (namebuf), "%s/ldap.%d", cfg->ldc_logdir,
1304 (int) getpid ());
1305 __debugfile = fopen (namebuf, "a");
1306
1307 if (__debugfile != NULL)
1308 {
1309 ber_set_option (NULL, LBER_OPT_LOG_PRINT_FILE, __debugfile);
1310 }
1311 }
1312 # endif /* LBER_OPT_LOG_PRINT_FILE */
1313 # ifdef LBER_OPT_DEBUG_LEVEL
1314 if (cfg->ldc_debug)
1315 {
1316 ber_set_option (NULL, LBER_OPT_DEBUG_LEVEL, &cfg->ldc_debug);
1317 ldap_set_option (NULL, LDAP_OPT_DEBUG_LEVEL, &cfg->ldc_debug);
1318 }
1319 # endif /* LBER_OPT_DEBUG_LEVEL */
1320 }
1321 #endif /* HAVE_LDAP_SET_OPTION */
1322
1323 #ifdef HAVE_LDAPSSL_CLIENT_INIT
1324 /*
1325 * Initialize the SSL library.
1326 */
1327 if (cfg->ldc_ssl_on == SSL_LDAPS)
1328 {
1329 int rc = 0;
1330 if (__ssl_initialized == 0
1331 && (rc = ldapssl_client_init (cfg->ldc_sslpath, NULL)) != LDAP_SUCCESS)
1332 {
1333 debug ("<== do_init (ldapssl_client_init failed with rc = %d)", rc);
1334 return NSS_UNAVAIL;
1335 }
1336 __ssl_initialized = 1;
1337 }
1338 #endif /* SSL */
1339
1340 __session.ls_conn = NULL;
1341
1342 assert (__session.ls_current_uri <= NSS_LDAP_CONFIG_URI_MAX);
1343 assert (cfg->ldc_uris[__session.ls_current_uri] != NULL);
1344
1345 stat = do_init_session (&__session.ls_conn,
1346 cfg->ldc_uris[__session.ls_current_uri],
1347 cfg->ldc_port);
1348 if (stat != NSS_SUCCESS)
1349 {
1350 debug ("<== do_init (failed to initialize LDAP session)");
1351 return stat;
1352 }
1353
1354 __session.ls_config = cfg;
1355 __session.ls_state = LS_INITIALIZED;
1356
1357 debug ("<== do_init (initialized session)");
1358
1359 return NSS_SUCCESS;
1360 }
1361
1362 #if defined(HAVE_LDAP_START_TLS_S) || defined(HAVE_LDAP_START_TLS)
1363 static int
1364 do_start_tls (ldap_session_t * session)
1365 {
1366 int rc;
1367 #ifdef HAVE_LDAP_START_TLS
1368 int msgid;
1369 struct timeval tv, *timeout;
1370 LDAPMessage *res = NULL;
1371
1372 debug ("==> do_start_tls");
1373
1374 rc = ldap_start_tls (session->ls_conn, NULL, NULL, &msgid);
1375 if (rc != LDAP_SUCCESS)
1376 {
1377 debug ("<== do_start_tls (ldap_start_tls failed: %s)", ldap_err2string (rc));
1378 return rc;
1379 }
1380
1381 if (session->ls_config->ldc_bind_timelimit == LDAP_NO_LIMIT)
1382 {
1383 timeout = NULL;
1384 }
1385 else
1386 {
1387 tv.tv_sec = session->ls_config->ldc_bind_timelimit;
1388 tv.tv_usec = 0;
1389 timeout = &tv;
1390 }
1391
1392 rc = ldap_result (session->ls_conn, msgid, 1, timeout, &res);
1393 if (rc > 0)
1394 {
1395 rc = ldap_result2error (session->ls_conn, res, 1);
1396 if (rc != LDAP_SUCCESS)
1397 {
1398 debug ("<== do_start_tls (ldap_result2error failed: %s)", ldap_err2string (rc));
1399 return rc;
1400 }
1401 }
1402 else
1403 {
1404 if (rc == -1)
1405 {
1406 #if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_NUMBER)
1407 if (ldap_get_option (session->ls_conn, LDAP_OPT_ERROR_NUMBER, &rc) != LDAP_SUCCESS)
1408 {
1409 rc = LDAP_UNAVAILABLE;
1410 }
1411 #else
1412 rc = session->ls_conn->ld_errno;
1413 #endif /* LDAP_OPT_ERROR_NUMBER */
1414 }
1415 else if (rc == 0) /* took too long */
1416 {
1417 ldap_abandon (session->ls_conn, msgid);
1418 rc = LDAP_TIMEOUT;
1419 }
1420
1421 syslog (LOG_INFO, "nss_ldap: ldap_start_tls failed: %s", ldap_err2string (rc));
1422 debug ("<== do_start_tls (ldap_start_tls failed: %s)", ldap_err2string (rc));
1423 return rc;
1424 }
1425
1426 rc = ldap_install_tls (session->ls_conn);
1427 #else
1428 rc = ldap_start_tls_s (session->ls_conn, NULL, NULL);
1429 #endif /* HAVE_LDAP_START_TLS */
1430
1431 if (rc != LDAP_SUCCESS)
1432 {
1433 debug ("<== do_start_tls (start TLS failed: %s)", ldap_err2string(rc));
1434 return rc;
1435 }
1436
1437 return LDAP_SUCCESS;
1438 }
1439 #endif
1440
1441 /*
1442 * Opens connection to an LDAP server - should only be called from search
1443 * API. Other API that just needs access to configuration and schema should
1444 * call do_init().
1445 *
1446 * As with do_close(), this assumes ownership of sess.
1447 * It also wants to own __config: is there a potential deadlock here? XXX
1448 */
1449 static NSS_STATUS
1450 do_open (void)
1451 {
1452 ldap_config_t *cfg;
1453 int usesasl;
1454 char *bindarg;
1455 NSS_STATUS stat;
1456 #ifdef LDAP_OPT_NETWORK_TIMEOUT
1457 struct timeval tv;
1458 #endif
1459 #ifdef LDAP_X_OPT_CONNECT_TIMEOUT
1460 int timeout;
1461 #endif
1462 int rc;
1463
1464 debug ("==> do_open");
1465
1466 /* Moved the head part of do_open() into do_init() */
1467 stat = do_init ();
1468 if (stat != NSS_SUCCESS)
1469 {
1470 debug ("<== do_open (session initialization failed)");
1471 return stat;
1472 }
1473
1474 assert (__session.ls_conn != NULL);
1475 assert (__session.ls_config != NULL);
1476 assert (__session.ls_state != LS_UNINITIALIZED);
1477
1478 cfg = __session.ls_config;
1479
1480 if (__session.ls_state == LS_CONNECTED_TO_DSA)
1481 {
1482 debug ("<== do_open (cached session)");
1483 return NSS_SUCCESS;
1484 }
1485 #ifdef LDAP_OPT_THREAD_FN_PTRS
1486 if (_nss_ldap_ltf_thread_init (__session.ls_conn) != NSS_SUCCESS)
1487 {
1488 do_close ();
1489 debug ("<== do_open (thread initialization failed)");
1490 return NSS_UNAVAIL;
1491 }
1492 #endif /* LDAP_OPT_THREAD_FN_PTRS */
1493
1494 #if LDAP_SET_REBIND_PROC_ARGS == 3
1495 ldap_set_rebind_proc (__session.ls_conn, do_rebind, NULL);
1496 #elif LDAP_SET_REBIND_PROC_ARGS == 2
1497 ldap_set_rebind_proc (__session.ls_conn, do_rebind);
1498 #endif
1499
1500 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_PROTOCOL_VERSION)
1501 ldap_set_option (__session.ls_conn, LDAP_OPT_PROTOCOL_VERSION,
1502 &cfg->ldc_version);
1503 #else
1504 __session.ls_conn->ld_version = cfg->ldc_version;
1505 #endif /* LDAP_OPT_PROTOCOL_VERSION */
1506
1507 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_DEREF)
1508 ldap_set_option (__session.ls_conn, LDAP_OPT_DEREF, &cfg->ldc_deref);
1509 #else
1510 __session.ls_conn->ld_deref = cfg->ldc_deref;
1511 #endif /* LDAP_OPT_DEREF */
1512
1513 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_TIMELIMIT)
1514 ldap_set_option (__session.ls_conn, LDAP_OPT_TIMELIMIT,
1515 &cfg->ldc_timelimit);
1516 #else
1517 __session.ls_conn->ld_timelimit = cfg->ldc_timelimit;
1518 #endif /* LDAP_OPT_TIMELIMIT */
1519
1520 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_X_OPT_CONNECT_TIMEOUT)
1521 /*
1522 * This is a new option in the Netscape SDK which sets
1523 * the TCP connect timeout. For want of a better value,
1524 * we use the bind_timelimit to control this.
1525 */
1526 timeout = cfg->ldc_bind_timelimit * 1000;
1527 ldap_set_option (__session.ls_conn, LDAP_X_OPT_CONNECT_TIMEOUT, &timeout);
1528 #endif /* LDAP_X_OPT_CONNECT_TIMEOUT */
1529
1530 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_NETWORK_TIMEOUT)
1531 tv.tv_sec = cfg->ldc_bind_timelimit;
1532 tv.tv_usec = 0;
1533 ldap_set_option (__session.ls_conn, LDAP_OPT_NETWORK_TIMEOUT, &tv);
1534 #endif /* LDAP_OPT_NETWORK_TIMEOUT */
1535
1536 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_REFERRALS)
1537 ldap_set_option (__session.ls_conn, LDAP_OPT_REFERRALS,
1538 cfg->ldc_referrals ? LDAP_OPT_ON : LDAP_OPT_OFF);
1539 #endif
1540
1541 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_RESTART)
1542 ldap_set_option (__session.ls_conn, LDAP_OPT_RESTART,
1543 cfg->ldc_restart ? LDAP_OPT_ON : LDAP_OPT_OFF);
1544 #endif
1545
1546 #if defined(HAVE_LDAP_START_TLS_S) || defined(HAVE_LDAP_START_TLS)
1547 if (cfg->ldc_ssl_on == SSL_START_TLS)
1548 {
1549 int version;
1550
1551 if (ldap_get_option
1552 (__session.ls_conn, LDAP_OPT_PROTOCOL_VERSION,
1553 &version) == LDAP_OPT_SUCCESS)
1554 {
1555 if (version < LDAP_VERSION3)
1556 {
1557 version = LDAP_VERSION3;
1558 ldap_set_option (__session.ls_conn, LDAP_OPT_PROTOCOL_VERSION,
1559 &version);
1560 }
1561 }
1562
1563 /* set up SSL context */
1564 if (do_ssl_options (cfg) != LDAP_SUCCESS)
1565 {
1566 do_close ();
1567 debug ("<== do_open (SSL setup failed)");
1568 return NSS_UNAVAIL;
1569 }
1570
1571 stat = do_map_error (do_start_tls (&__session));
1572 if (stat == NSS_SUCCESS)
1573 {
1574 debug (":== do_open (TLS startup succeeded)");
1575 }
1576 else
1577 {
1578 do_close ();
1579 debug ("<== do_open (TLS startup failed)");
1580 return stat;
1581 }
1582 }
1583 else
1584 #endif /* HAVE_LDAP_START_TLS_S || HAVE_LDAP_START_TLS */
1585
1586 /*
1587 * If SSL is desired, either by the "ssl" option or if this
1588 * is a "ldaps" URI, then enable it.
1589 */
1590 if (cfg->ldc_ssl_on == SSL_LDAPS ||
1591 strncasecmp(cfg->ldc_uris[__session.ls_current_uri],
1592 "ldaps://", sizeof ("ldaps://") - 1) == 0
1593 )
1594 {
1595 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS)
1596 int tls = LDAP_OPT_X_TLS_HARD;
1597 if (ldap_set_option (__session.ls_conn, LDAP_OPT_X_TLS, &tls) !=
1598 LDAP_SUCCESS)
1599 {
1600 do_close ();
1601 debug ("<== do_open (TLS setup failed)");
1602 return NSS_UNAVAIL;
1603 }
1604
1605 /* set up SSL context */
1606 if (do_ssl_options (cfg) != LDAP_SUCCESS)
1607 {
1608 do_close ();
1609 debug ("<== do_open (SSL setup failed)");
1610 return NSS_UNAVAIL;
1611 }
1612
1613 #elif defined(HAVE_LDAPSSL_CLIENT_INIT)
1614 if (ldapssl_install_routines (__session.ls_conn) != LDAP_SUCCESS)
1615 {
1616 do_close ();
1617 debug ("<== do_open (SSL setup failed)");
1618 return NSS_UNAVAIL;
1619 }
1620 /* not in Solaris 9? */
1621 #ifndef LDAP_OPT_SSL
1622 #define LDAP_OPT_SSL 0x0A
1623 #endif
1624 if (ldap_set_option (__session.ls_conn, LDAP_OPT_SSL, LDAP_OPT_ON) !=
1625 LDAP_SUCCESS)
1626 {
1627 do_close ();
1628 debug ("<== do_open (SSL setup failed)");
1629 return NSS_UNAVAIL;
1630 }
1631 #endif
1632 }
1633
1634 /*
1635 * If we're running as root, let us bind as a special
1636 * user, so we can fake shadow passwords.
1637 * Thanks to Doug Nazar <nazard@dragoninc.on.ca> for this
1638 * patch.
1639 */
1640 if (__euid == 0 && cfg->ldc_rootbinddn != NULL)
1641 {
1642 #if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))
1643 usesasl = cfg->ldc_rootusesasl;
1644 bindarg =
1645 cfg->ldc_rootusesasl ? cfg->ldc_rootsaslid : cfg->ldc_rootbindpw;
1646 #else
1647 usesasl = 0;
1648 bindarg = cfg->ldc_rootbindpw;
1649 #endif
1650
1651 rc = do_bind (__session.ls_conn,
1652 cfg->ldc_bind_timelimit,
1653 cfg->ldc_rootbinddn, bindarg, usesasl);
1654 }
1655 else
1656 {
1657 #if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))
1658 usesasl = cfg->ldc_usesasl;
1659 bindarg = cfg->ldc_usesasl ? cfg->ldc_saslid : cfg->ldc_bindpw;
1660 #else
1661 usesasl = 0;
1662 bindarg = cfg->ldc_bindpw;
1663 #endif
1664
1665 rc = do_bind (__session.ls_conn,
1666 cfg->ldc_bind_timelimit,
1667 cfg->ldc_binddn,
1668 cfg->ldc_bindpw, usesasl);
1669 }
1670
1671 if (rc != LDAP_SUCCESS)
1672 {
1673 /* log actual LDAP error code */
1674 syslog (LOG_INFO,
1675 "nss_ldap: failed to bind to LDAP server %s: %s",
1676 cfg->ldc_uris[__session.ls_current_uri],
1677 ldap_err2string (rc));
1678 stat = do_map_error (rc);
1679 do_close ();
1680 debug ("<== do_open (failed to bind to DSA");
1681 }
1682 else
1683 {
1684 do_set_sockopts ();
1685 time (&__session.ls_timestamp);
1686 __session.ls_state = LS_CONNECTED_TO_DSA;
1687 stat = NSS_SUCCESS;
1688 debug ("<== do_open (session connected to DSA)");
1689 }
1690
1691 return stat;
1692 }
1693
1694 #if defined HAVE_LDAP_START_TLS_S || (defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS))
1695 static int
1696 do_ssl_options (ldap_config_t * cfg)
1697 {
1698 int rc;
1699
1700 debug ("==> do_ssl_options");
1701
1702 #ifdef LDAP_OPT_X_TLS_RANDOM_FILE
1703 if (cfg->ldc_tls_randfile != NULL)
1704 {
1705 /* rand file */
1706 rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_RANDOM_FILE,
1707 cfg->ldc_tls_randfile);
1708 if (rc != LDAP_SUCCESS)
1709 {
1710 debug
1711 ("<== do_ssl_options: Setting of LDAP_OPT_X_TLS_RANDOM_FILE failed");
1712 return LDAP_OPERATIONS_ERROR;
1713 }
1714 }
1715 #endif /* LDAP_OPT_X_TLS_RANDOM_FILE */
1716
1717 if (cfg->ldc_tls_cacertfile != NULL)
1718 {
1719 /* ca cert file */
1720 rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTFILE,
1721 cfg->ldc_tls_cacertfile);
1722 if (rc != LDAP_SUCCESS)
1723 {
1724 debug
1725 ("<== do_ssl_options: Setting of LDAP_OPT_X_TLS_CACERTFILE failed");
1726 return LDAP_OPERATIONS_ERROR;
1727 }
1728 }
1729
1730 if (cfg->ldc_tls_cacertdir != NULL)
1731 {
1732 /* ca cert directory */
1733 rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTDIR,
1734 cfg->ldc_tls_cacertdir);
1735 if (rc != LDAP_SUCCESS)
1736 {
1737 debug
1738 ("<== do_ssl_options: Setting of LDAP_OPT_X_TLS_CACERTDIR failed");
1739 return LDAP_OPERATIONS_ERROR;
1740 }
1741 }
1742
1743 /* require cert? */
1744 if (cfg->ldc_tls_checkpeer > -1)
1745 {
1746 rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_REQUIRE_CERT,
1747 &cfg->ldc_tls_checkpeer);
1748 if (rc != LDAP_SUCCESS)
1749 {
1750 debug
1751 ("<== do_ssl_options: Setting of LDAP_OPT_X_TLS_REQUIRE_CERT failed");
1752 return LDAP_OPERATIONS_ERROR;
1753 }
1754 }
1755
1756 if (cfg->ldc_tls_ciphers != NULL)
1757 {
1758 /* set cipher suite, certificate and private key: */
1759 rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CIPHER_SUITE,
1760 cfg->ldc_tls_ciphers);
1761 if (rc != LDAP_SUCCESS)
1762 {
1763 debug
1764 ("<== do_ssl_options: Setting of LDAP_OPT_X_TLS_CIPHER_SUITE failed");
1765 return LDAP_OPERATIONS_ERROR;
1766 }
1767 }
1768
1769 if (cfg->ldc_tls_cert != NULL)
1770 {
1771 rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CERTFILE, cfg->ldc_tls_cert);
1772 if (rc != LDAP_SUCCESS)
1773 {
1774 debug
1775 ("<== do_ssl_options: Setting of LDAP_OPT_X_TLS_CERTFILE failed");
1776 return LDAP_OPERATIONS_ERROR;
1777 }
1778 }
1779
1780 if (cfg->ldc_tls_key != NULL)
1781 {
1782 rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_KEYFILE, cfg->ldc_tls_key);
1783 if (rc != LDAP_SUCCESS)
1784 {
1785 debug
1786 ("<== do_ssl_options: Setting of LDAP_OPT_X_TLS_KEYFILE failed");
1787 return LDAP_OPERATIONS_ERROR;
1788 }
1789 }
1790
1791 debug ("<== do_ssl_options");
1792
1793 return LDAP_SUCCESS;
1794 }
1795 #endif
1796
1797 static int
1798 do_bind (LDAP * ld, int timelimit, const char *dn, const char *pw,
1799 int with_sasl)
1800 {
1801 int rc;
1802 int msgid;
1803 struct timeval tv;
1804 LDAPMessage *result;
1805
1806 debug("==> do_bind");
1807
1808 /*
1809 * set timelimit in ld for select() call in ldap_pvt_connect()
1810 * function implemented in libldap2's os-ip.c
1811 */
1812 tv.tv_sec = timelimit;
1813 tv.tv_usec = 0;
1814
1815 #if (defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))) || defined(HAVE_LDAP_GSS_BIND)
1816 if (!with_sasl)
1817 {
1818 #endif
1819 msgid = ldap_simple_bind (ld, dn, pw);
1820
1821 if (msgid < 0)
1822 {
1823 #if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_NUMBER)
1824 if (ldap_get_option (ld, LDAP_OPT_ERROR_NUMBER, &rc) !=
1825 LDAP_SUCCESS)
1826 {
1827 rc = LDAP_UNAVAILABLE;
1828 }
1829 #else
1830 rc = ld->ld_errno;
1831 #endif /* LDAP_OPT_ERROR_NUMBER */
1832 debug ("<== do_bind");
1833
1834 return rc;
1835 }
1836
1837 rc = ldap_result (ld, msgid, 0, &tv, &result);
1838 if (rc > 0)
1839 {
1840 debug ("<== do_bind");
1841 return ldap_result2error (ld, result, 1);
1842 }
1843
1844 /* took too long */
1845 if (rc == 0)
1846 {
1847 ldap_abandon (ld, msgid);
1848 }
1849 #if (defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))) || defined(HAVE_LDAP_GSS_BIND)
1850 }
1851 else
1852 {
1853 #ifdef HAVE_LDAP_GSS_BIND
1854 return ldap_gss_bind (ld, dn, pw, GSSSASL_NO_SECURITY_LAYER,
1855 LDAP_SASL_GSSAPI);
1856 #else
1857 # ifdef CONFIGURE_KRB5_CCNAME
1858 # ifndef CONFIGURE_KRB5_CCNAME_GSSAPI
1859 char tmpbuf[256];
1860 static char envbuf[256];
1861 # endif
1862 char *ccname;
1863 const char *oldccname = NULL;
1864 int retval;
1865 # endif /* CONFIGURE_KRB5_CCNAME */
1866
1867 if (__config->ldc_sasl_secprops != NULL)
1868 {
1869 rc =
1870 ldap_set_option (ld, LDAP_OPT_X_SASL_SECPROPS,
1871 (void *) __config->ldc_sasl_secprops);
1872 if (rc != LDAP_SUCCESS)
1873 {
1874 debug ("do_bind: unable to set SASL security properties");
1875 return rc;
1876 }
1877 }
1878
1879 #ifdef CONFIGURE_KRB5_KEYTAB
1880 if (do_select_krb5_cache(__config)) { return -1; }
1881 #else
1882 # ifdef CONFIGURE_KRB5_CCNAME
1883 /* Set default Kerberos ticket cache for SASL-GSSAPI */
1884 /* There are probably race conditions here XXX */
1885 ccname = __config->ldc_krb5_ccname;
1886 if (ccname != NULL)
1887 {
1888 char *ccfile = ccname;
1889 /* Check that cache exists and is readable */
1890 if ((strncasecmp(ccfile, "FILE:", sizeof("FILE:") - 1) == 0)
1891 || (strncasecmp(ccfile, "WRFILE:", sizeof("WRFILE:") - 1) == 0))
1892 {
1893 ccfile = strchr(ccfile, ':') + 1;
1894 }
1895 if (access(ccfile, R_OK) != 0)
1896 {
1897 ccname = NULL;
1898 }
1899 }
1900 if (ccname != NULL)
1901 {
1902 # ifdef CONFIGURE_KRB5_CCNAME_ENV
1903 oldccname = getenv ("KRB5CCNAME");
1904 if (oldccname != NULL)
1905 {
1906 strncpy (tmpbuf, oldccname, sizeof (tmpbuf));
1907 tmpbuf[sizeof (tmpbuf) - 1] = '\0';
1908 }
1909 else
1910 {
1911 tmpbuf[0] = '\0';
1912 }
1913 oldccname = tmpbuf;
1914 snprintf (envbuf, sizeof (envbuf), "KRB5CCNAME=%s", ccname);
1915 putenv (envbuf);
1916 # elif defined(CONFIGURE_KRB5_CCNAME_GSSAPI)
1917 if (gss_krb5_ccache_name (&retval, ccname, &oldccname) !=
1918 GSS_S_COMPLETE)
1919 {
1920 debug ("do_bind: unable to set default credential cache");
1921 return -1;
1922 }
1923 # endif
1924 }
1925 # endif /* CONFIGURE_KRB5_CCNAME */
1926 #endif /* CONFIGURE_KRB5_KEYTAB */
1927 rc = ldap_sasl_interactive_bind_s (ld, dn, "GSSAPI", NULL, NULL,
1928 LDAP_SASL_QUIET,
1929 do_sasl_interact, (void *) pw);
1930 #ifdef CONFIGURE_KRB5_KEYTAB
1931 if (do_restore_krb5_cache(__config)) { return -1; }
1932 #else
1933 # ifdef CONFIGURE_KRB5_CCNAME
1934 /* Restore default Kerberos ticket cache. */
1935 if (oldccname != NULL)
1936 {
1937 # ifdef CONFIGURE_KRB5_CCNAME_ENV
1938 snprintf (envbuf, sizeof (envbuf), "KRB5CCNAME=%s", oldccname);
1939 putenv (envbuf);
1940 # elif defined(CONFIGURE_KRB5_CCNAME_GSSAPI)
1941 if (gss_krb5_ccache_name (&retval, oldccname, NULL) !=
1942 GSS_S_COMPLETE)
1943 {
1944 debug ("do_bind: unable to restore default credential cache");
1945 return -1;
1946 }
1947 # endif
1948 }
1949 # endif /* CONFIGURE_KRB5_CCNAME */
1950 #endif /* CONFIGURE_KRB5_KEYTAB */
1951 return rc;
1952 #endif /* HAVE_LDAP_GSS_BIND */
1953 }
1954 #endif
1955
1956 debug ("<== do_bind");
1957
1958 return -1;
1959 }
1960
1961 /*
1962 * This function initializes an enumeration context, acquiring
1963 * the global mutex.
1964 *
1965 * It could be done from the default constructor, under Solaris, but we
1966 * delay it until the setXXent() function is called.
1967 */
1968 ent_context_t *
1969 _nss_ldap_ent_context_init (ent_context_t ** pctx)
1970 {
1971 ent_context_t *ctx;
1972
1973 _nss_ldap_enter ();
1974
1975 ctx = _nss_ldap_ent_context_init_locked (pctx);
1976
1977 _nss_ldap_leave ();
1978
1979 return ctx;
1980 }
1981
1982 /*
1983 * This function initializes an enumeration context.
1984 *
1985 * It could be done from the default constructor, under Solaris, but we
1986 * delay it until the setXXent() function is called.
1987 */
1988 ent_context_t *
1989 _nss_ldap_ent_context_init_locked (ent_context_t ** pctx)
1990 {
1991 ent_context_t *ctx;
1992
1993 debug ("==> _nss_ldap_ent_context_init_locked");
1994
1995 ctx = *pctx;
1996
1997 if (ctx == NULL)
1998 {
1999 ctx = (ent_context_t *) malloc (sizeof (*ctx));
2000 if (ctx == NULL)
2001 {
2002 debug ("<== _nss_ldap_ent_context_init_locked");
2003 return NULL;
2004 }
2005 *pctx = ctx;
2006 }
2007 else
2008 {
2009 if (ctx->ec_res != NULL)
2010 {
2011 ldap_msgfree (ctx->ec_res);
2012 ctx->ec_res = NULL;
2013 }
2014 if (ctx->ec_cookie != NULL)
2015 {
2016 ber_bvfree (ctx->ec_cookie);
2017 }
2018 if (ctx->ec_msgid > -1 && do_result (ctx, LDAP_MSG_ONE) == NSS_SUCCESS)
2019 {
2020 ldap_abandon (__session.ls_conn, ctx->ec_msgid);
2021 }
2022 }
2023
2024 ctx->ec_cookie = NULL;
2025 ctx->ec_res = NULL;
2026 ctx->ec_msgid = -1;
2027 ctx->ec_sd = NULL;
2028 ctx->ec_eof = 0;
2029
2030 LS_INIT (ctx->ec_state);
2031
2032 debug ("<== _nss_ldap_ent_context_init_locked");
2033
2034 return ctx;
2035 }
2036
2037 static void
2038 do_context_release (ent_context_t * ctx, int free_context)
2039 {
2040 /*
2041 * Abandon the search if there were more results to fetch.
2042 */
2043 if (ctx->ec_msgid > -1 && do_result (ctx, LDAP_MSG_ONE) == NSS_SUCCESS)
2044 {
2045 ldap_abandon (__session.ls_conn, ctx->ec_msgid);
2046 ctx->ec_msgid = -1;
2047 }
2048
2049 if (ctx->ec_res != NULL)
2050 {
2051 ldap_msgfree (ctx->ec_res);
2052 ctx->ec_res = NULL;
2053 }
2054
2055 if (ctx->ec_cookie != NULL)
2056 {
2057 ber_bvfree (ctx->ec_cookie);
2058 ctx->ec_cookie = NULL;
2059 }
2060
2061 ctx->ec_sd = NULL;
2062 ctx->ec_eof = 0;
2063
2064 LS_INIT (ctx->ec_state);
2065
2066 if (_nss_ldap_test_config_flag (NSS_LDAP_FLAGS_CONNECT_POLICY_ONESHOT))
2067 {
2068 do_close ();
2069 }
2070
2071 if (free_context)
2072 free (ctx);
2073 }
2074
2075 /*
2076 * Clears a given context; we require the caller
2077 * to acquire the lock.
2078 */
2079 void
2080 _nss_ldap_ent_context_release (ent_context_t ** ctx)
2081 {
2082 debug ("==> _nss_ldap_ent_context_release");
2083
2084 if (ctx == NULL || *ctx == NULL)
2085 {
2086 debug ("<== _nss_ldap_ent_context_release");
2087 return;
2088 }
2089
2090 do_context_release (*ctx, 1);
2091 *ctx = NULL;
2092
2093 debug ("<== _nss_ldap_ent_context_release");
2094
2095 return;
2096 }
2097
2098 #if defined(HAVE_NSSWITCH_H) || defined(HAVE_IRS_H)
2099 /*
2100 * Make all triple permutations
2101 */
2102 static NSS_STATUS
2103 do_triple_permutations (const char *machine, const char *user,
2104 const char *domain, char *bufptr, size_t buflen)
2105 {
2106 /*
2107 * Map a triple
2108 *
2109 * (M,U,D)
2110 *
2111 * to the filter
2112 *
2113 * (|(nisNetgroupTriple=P1)...(nisNetgroupTriple=PN))
2114 *
2115 * where P1..PN are all permutations of triples that may match
2116 * ie. including wildcards. Certainly this would be preferable
2117 * to do server-side with an appropriate matching rule.
2118 */
2119 char escaped_machine[3 * (MAXHOSTNAMELEN + 1)];
2120 char escaped_user[3 * (LOGNAME_MAX + 1)];
2121 char escaped_domain[3 * (MAXHOSTNAMELEN + 1)];
2122 const char *AT_NISNETGROUPTRIPLE = AT (nisNetgroupTriple);
2123 NSS_STATUS stat;
2124
2125 #define ESCAPE_TRIPLE_COMPONENT(component) do { \
2126 if ((component) == NULL) \
2127 { \
2128 (escaped_##component)[0] = '*'; \
2129 (escaped_##component)[1] = '\0'; \
2130 } \
2131 else \
2132 { \
2133 stat = _nss_ldap_escape_string((component), (escaped_##component), \
2134 (sizeof((escaped_##component)))); \
2135 if (stat != NSS_SUCCESS) \
2136 return stat; \
2137 } \
2138 } while (0)
2139
2140 ESCAPE_TRIPLE_COMPONENT (machine);
2141 ESCAPE_TRIPLE_COMPONENT (user);
2142 ESCAPE_TRIPLE_COMPONENT (domain);
2143
2144 #define _APPEND_STRING(_buffer, _buflen, _s, _len) do { \
2145 if ((_buflen) < (size_t)((_len) + 1)) \
2146 { \
2147 return NSS_TRYAGAIN; \
2148 } \
2149 memcpy((_buffer), (_s), (_len)); \
2150 (_buffer)[(_len)] = '\0'; \
2151 (_buffer) += (_len); \
2152 (_buflen) -= (_len); \
2153 } while (0)
2154
2155 #define APPEND_STRING(_buffer, _buflen, _s) _APPEND_STRING(_buffer, _buflen, _s, strlen((_s)))
2156 #define APPEND_CONSTANT_STRING(_buffer, _buflen, _s) _APPEND_STRING(_buffer, _buflen, _s, (sizeof((_s)) - 1))
2157
2158 #define APPEND_TRIPLE(_buffer, _buflen, _machine, _user, _domain) do { \
2159 APPEND_CONSTANT_STRING((_buffer), (_buflen), "("); \
2160 APPEND_STRING((_buffer), (_buflen), AT_NISNETGROUPTRIPLE); \
2161 APPEND_CONSTANT_STRING((_buffer), (_buflen), "=\\("); \
2162 if ((_machine) != NULL) \
2163 { \
2164 APPEND_STRING((_buffer), (_buflen), (_machine)); \
2165 } \
2166 APPEND_CONSTANT_STRING((_buffer), (_buflen), ","); \
2167 if ((_user) != NULL) \
2168 { \
2169 APPEND_STRING((_buffer), (_buflen), (_user)); \
2170 } \
2171 APPEND_CONSTANT_STRING((_buffer), (_buflen), ","); \
2172 if ((_domain) != NULL) \
2173 { \
2174 APPEND_STRING((_buffer), (_buflen), (_domain)); \
2175 } \
2176 APPEND_CONSTANT_STRING((_buffer), (_buflen), "\\))"); \
2177 } while (0)
2178
2179 APPEND_CONSTANT_STRING (bufptr, buflen, "(&(");
2180 APPEND_STRING (bufptr, buflen, AT (objectClass));
2181 APPEND_CONSTANT_STRING (bufptr, buflen, "=");
2182 APPEND_STRING (bufptr, buflen, OC (nisNetgroup));
2183 APPEND_CONSTANT_STRING (bufptr, buflen, ")(|");
2184
2185 APPEND_TRIPLE (bufptr, buflen, escaped_machine, escaped_user,
2186 escaped_domain);
2187 APPEND_TRIPLE (bufptr, buflen, escaped_machine, escaped_user, NULL);
2188 APPEND_TRIPLE (bufptr, buflen, escaped_machine, NULL, NULL);
2189 APPEND_TRIPLE (bufptr, buflen, NULL, escaped_user, escaped_domain);
2190 APPEND_TRIPLE (bufptr, buflen, NULL, escaped_user, NULL);
2191 APPEND_TRIPLE (bufptr, buflen, escaped_machine, NULL, escaped_domain);
2192 APPEND_TRIPLE (bufptr, buflen, NULL, NULL, escaped_domain);
2193 APPEND_TRIPLE (bufptr, buflen, NULL, NULL, NULL);
2194
2195 APPEND_CONSTANT_STRING (bufptr, buflen, "))");
2196
2197 return NSS_SUCCESS;
2198 }
2199 #endif /* HAVE_NSSWITCH_H || HAVE_IRS_H */
2200
2201 /*
2202 * AND or OR a set of filters.
2203 */
2204 static NSS_STATUS
2205 do_aggregate_filter (const char **values,
2206 ldap_args_types_t type,
2207 const char *filterprot, char *bufptr, size_t buflen)
2208 {
2209 NSS_STATUS stat;
2210 const char **valueP;
2211
2212 assert (buflen > sizeof ("(|)"));
2213
2214 bufptr[0] = '(';
2215 bufptr[1] = (type == LA_TYPE_STRING_LIST_AND) ? '&' : '|';
2216
2217 bufptr += 2;
2218 buflen -= 2;
2219
2220 for (valueP = values; *valueP != NULL; valueP++)
2221 {
2222 size_t len;
2223 char filter[LDAP_FILT_MAXSIZ], escapedBuf[LDAP_FILT_MAXSIZ];
2224
2225 stat =
2226 _nss_ldap_escape_string (*valueP, escapedBuf, sizeof (escapedBuf));
2227 if (stat != NSS_SUCCESS)
2228 return stat;
2229
2230 snprintf (filter, sizeof (filter), filterprot, escapedBuf);
2231 len = strlen (filter);
2232
2233 if (buflen < len + 1 /* ')' */ )
2234 return NSS_TRYAGAIN;
2235
2236 memcpy (bufptr, filter, len);
2237 bufptr[len] = '\0';
2238 bufptr += len;
2239 buflen -= len;
2240 }
2241
2242 if (buflen < 2)
2243 return NSS_TRYAGAIN;
2244
2245 *bufptr++ = ')';
2246 *bufptr++ = '\0';
2247
2248 buflen -= 2;
2249
2250 return NSS_SUCCESS;
2251 }
2252
2253 /*
2254 * Do the necessary formatting to create a string filter.
2255 */
2256 static NSS_STATUS
2257 do_filter (const ldap_args_t * args, const char *filterprot,
2258 ldap_service_search_descriptor_t * sd, char *userBuf,
2259 size_t userBufSiz, char **dynamicUserBuf, const char **retFilter)
2260 {
2261 char buf1[LDAP_FILT_MAXSIZ], buf2[LDAP_FILT_MAXSIZ];
2262 char *filterBufP, filterBuf[LDAP_FILT_MAXSIZ];
2263 size_t filterSiz;
2264 NSS_STATUS stat = NSS_SUCCESS;
2265
2266 debug ("==> do_filter");
2267
2268 *dynamicUserBuf = NULL;
2269
2270 if (args != NULL && args->la_type != LA_TYPE_NONE)
2271 {
2272 /* choose what to use for temporary storage */
2273
2274 if (sd != NULL && sd->lsd_filter != NULL)
2275 {
2276 filterBufP = filterBuf;
2277 filterSiz = sizeof (filterBuf);
2278 }
2279 else
2280 {
2281 filterBufP = userBuf;
2282 filterSiz = userBufSiz;
2283 }
2284
2285 switch (args->la_type)
2286 {
2287 case LA_TYPE_STRING:
2288 stat = _nss_ldap_escape_string (args->la_arg1.la_string, buf1,
2289 sizeof (buf1));
2290 if (stat != NSS_SUCCESS)
2291 break;
2292
2293 snprintf (filterBufP, filterSiz, filterprot, buf1);
2294 break;
2295 case LA_TYPE_NUMBER:
2296 snprintf (filterBufP, filterSiz, filterprot,
2297 args->la_arg1.la_number);
2298 break;
2299 case LA_TYPE_STRING_AND_STRING:
2300 stat = _nss_ldap_escape_string (args->la_arg1.la_string, buf1,
2301 sizeof (buf1));
2302 if (stat != NSS_SUCCESS)
2303 break;
2304
2305 stat = _nss_ldap_escape_string (args->la_arg2.la_string, buf2,
2306 sizeof (buf2));
2307 if (stat != NSS_SUCCESS)
2308 break;
2309
2310 snprintf (filterBufP, filterSiz, filterprot, buf1, buf2);
2311 break;
2312 case LA_TYPE_NUMBER_AND_STRING:
2313 stat = _nss_ldap_escape_string (args->la_arg2.la_string, buf1,
2314 sizeof (buf1));
2315 if (stat != NSS_SUCCESS)
2316 break;
2317
2318 snprintf (filterBufP, filterSiz, filterprot,
2319 args->la_arg1.la_number, buf1);
2320 break;
2321 #if defined(HAVE_NSSWITCH_H) || defined(HAVE_IRS_H)
2322 case LA_TYPE_TRIPLE:
2323 do
2324 {
2325 stat = do_triple_permutations (args->la_arg1.la_triple.host,
2326 args->la_arg1.la_triple.user,
2327 args->la_arg1.la_triple.domain,
2328 filterBufP, filterSiz);
2329 if (stat == NSS_TRYAGAIN)
2330 {
2331 filterBufP = *dynamicUserBuf = realloc (*dynamicUserBuf,
2332 2 * filterSiz);
2333 if (filterBufP == NULL)
2334 return NSS_UNAVAIL;
2335 filterSiz *= 2;
2336 }
2337 }
2338 while (stat == NSS_TRYAGAIN);
2339 break;
2340 #endif /* HAVE_NSSWITCH_H || HAVE_IRS_H */
2341 case LA_TYPE_STRING_LIST_OR:
2342 case LA_TYPE_STRING_LIST_AND:
2343 do
2344 {
2345 stat = do_aggregate_filter (args->la_arg1.la_string_list,
2346 args->la_type,
2347 filterprot, filterBufP, filterSiz);
2348 if (stat == NSS_TRYAGAIN)
2349 {
2350 filterBufP = *dynamicUserBuf = realloc (*dynamicUserBuf,
2351 2 * filterSiz);
2352 if (filterBufP == NULL)
2353 return NSS_UNAVAIL;
2354 filterSiz *= 2;
2355 }
2356 }
2357 while (stat == NSS_TRYAGAIN);
2358 break;
2359 default:
2360 return NSS_UNAVAIL;
2361 break;
2362 }
2363
2364 if (stat != NSS_SUCCESS)
2365 return stat;
2366
2367 /*
2368 * This code really needs to be cleaned up.
2369 */
2370 if (sd != NULL && sd->lsd_filter != NULL)
2371 {
2372 size_t filterBufPLen = strlen (filterBufP);
2373
2374 /* remove trailing bracket */
2375 if (filterBufP[filterBufPLen - 1] == ')')
2376 filterBufP[filterBufPLen - 1] = '\0';
2377
2378 if (*dynamicUserBuf != NULL)
2379 {
2380 char *oldDynamicUserBuf = *dynamicUserBuf;
2381 size_t dynamicUserBufSiz;
2382
2383 dynamicUserBufSiz = filterBufPLen + strlen (sd->lsd_filter) +
2384 sizeof ("())");
2385 *dynamicUserBuf = malloc (dynamicUserBufSiz);
2386 if (*dynamicUserBuf == NULL)
2387 {
2388 free (oldDynamicUserBuf);
2389 return NSS_UNAVAIL;
2390 }
2391
2392 snprintf (*dynamicUserBuf, dynamicUserBufSiz, "%s(%s))",
2393 filterBufP, sd->lsd_filter);
2394 free (oldDynamicUserBuf);
2395 }
2396 else
2397 {
2398 snprintf (userBuf, userBufSiz, "%s(%s))",
2399 filterBufP, sd->lsd_filter);
2400 }
2401 }
2402
2403 if (*dynamicUserBuf != NULL)
2404 *retFilter = *dynamicUserBuf;
2405 else
2406 *retFilter = userBuf;
2407 }
2408 else
2409 {
2410 /* no arguments, probably an enumeration filter */
2411 if (sd != NULL && sd->lsd_filter != NULL)
2412 {
2413 snprintf (userBuf, userBufSiz, "(&%s(%s))",
2414 filterprot, sd->lsd_filter);
2415 *retFilter = userBuf;
2416 }
2417 else
2418 {
2419 *retFilter = filterprot;
2420 }
2421 }
2422
2423 debug (":== do_filter: %s", *retFilter);
2424
2425 debug ("<== do_filter");
2426
2427 return NSS_SUCCESS;
2428 }
2429
2430 /*
2431 * Wrapper around ldap_result() to skip over search references
2432 * and deal transparently with the last entry.
2433 */
2434 static NSS_STATUS
2435 do_result (ent_context_t * ctx, int all)
2436 {
2437 int rc = LDAP_UNAVAILABLE;
2438 NSS_STATUS stat = NSS_TRYAGAIN;
2439 struct timeval tv, *tvp;
2440
2441 debug ("==> do_result");
2442
2443 if (__session.ls_state != LS_CONNECTED_TO_DSA)
2444 {
2445 debug ("<== do_result");
2446 return NSS_UNAVAIL;
2447 }
2448
2449 if (__session.ls_config->ldc_timelimit == LDAP_NO_LIMIT)
2450 {
2451 tvp = NULL;
2452 }
2453 else
2454 {
2455 tv.tv_sec = __session.ls_config->ldc_timelimit;
2456 tv.tv_usec = 0;
2457 tvp = &tv;
2458 }
2459
2460 do
2461 {
2462 if (ctx->ec_res != NULL)
2463 {
2464 ldap_msgfree (ctx->ec_res);
2465 ctx->ec_res = NULL;
2466 }
2467
2468 rc =
2469 ldap_result (__session.ls_conn, ctx->ec_msgid, all, tvp,
2470 &ctx->ec_res);
2471 switch (rc)
2472 {
2473 case -1:
2474 case 0:
2475 #if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_NUMBER)
2476 if (ldap_get_option
2477 (__session.ls_conn, LDAP_OPT_ERROR_NUMBER, &rc) != LDAP_SUCCESS)
2478 {
2479 rc = LDAP_UNAVAILABLE;
2480 }
2481 #else
2482 rc = __session.ls_conn->ld_errno;
2483 #endif /* LDAP_OPT_ERROR_NUMBER */
2484 syslog (LOG_ERR, "nss_ldap: could not get LDAP result - %s",
2485 ldap_err2string (rc));
2486 do_close();
2487 stat = NSS_UNAVAIL;
2488 break;
2489 case LDAP_RES_SEARCH_ENTRY:
2490 stat = NSS_SUCCESS;
2491 break;
2492 case LDAP_RES_SEARCH_RESULT:
2493 if (all == LDAP_MSG_ALL)
2494 {
2495 /* we asked for the result chain, we got it. */
2496 stat = NSS_SUCCESS;
2497 }
2498 else
2499 {
2500 #ifdef LDAP_MORE_RESULTS_TO_RETURN
2501 int parserc;
2502 /* NB: this frees ctx->ec_res */
2503 LDAPControl **resultControls = NULL;
2504
2505 if (ctx->ec_cookie != NULL)
2506 {
2507 ber_bvfree(ctx->ec_cookie);
2508 ctx->ec_cookie = NULL;
2509 }
2510
2511 parserc =
2512 ldap_parse_result (__session.ls_conn, ctx->ec_res, &rc, NULL,
2513 NULL, NULL, &resultControls, 1);
2514 if (parserc != LDAP_SUCCESS
2515 && parserc != LDAP_MORE_RESULTS_TO_RETURN)
2516 {
2517 ldap_abandon (__session.ls_conn, ctx->ec_msgid);
2518 syslog (LOG_ERR,
2519 "nss_ldap: could not get LDAP result - %s",
2520 ldap_err2string (rc));
2521 do_close();
2522 stat = NSS_UNAVAIL;
2523 }
2524 else if (resultControls != NULL)
2525 {
2526 /* See if there are any more pages to come */
2527 parserc = ldap_parse_page_control (__session.ls_conn,
2528 resultControls, NULL,
2529 &(ctx->ec_cookie));
2530 ldap_controls_free (resultControls);
2531 stat = NSS_NOTFOUND;
2532 }
2533 else
2534 {
2535 stat = NSS_NOTFOUND;
2536 }
2537 #else
2538 stat = NSS_NOTFOUND;
2539 #endif /* LDAP_MORE_RESULTS_TO_RETURN */
2540 ctx->ec_res = NULL;
2541 ctx->ec_msgid = -1;
2542 }
2543 break;
2544 default:
2545 stat = NSS_UNAVAIL;
2546 break;
2547 }
2548 }
2549 #ifdef LDAP_RES_SEARCH_REFERENCE
2550 while (rc == LDAP_RES_SEARCH_REFERENCE);
2551 #else
2552 while (0);
2553 #endif /* LDAP_RES_SEARCH_REFERENCE */
2554
2555 if (stat == NSS_SUCCESS)
2556 time (&__session.ls_timestamp);
2557
2558 debug ("<== do_result");
2559
2560 return stat;
2561 }
2562
2563 /*
2564 * Function to call either do_search() or do_search_s() with
2565 * reconnection logic.
2566 */
2567 static NSS_STATUS
2568 do_with_reconnect (const char *base, int scope,
2569 const char *filter, const char **attrs, int sizelimit,
2570 void *private, search_func_t search_func)
2571 {
2572 int rc = LDAP_UNAVAILABLE, tries = 0, backoff = 0;
2573 int hard = 1, start_uri = 0, log = 0;
2574 NSS_STATUS stat = NSS_UNAVAIL;
2575 int maxtries;
2576
2577 debug ("==> do_with_reconnect");
2578
2579 /* caller must successfully call do_init() first */
2580 assert (__session.ls_config != NULL);
2581
2582 maxtries = __session.ls_config->ldc_reconnect_maxconntries +
2583 __session.ls_config->ldc_reconnect_tries;
2584
2585 while (stat == NSS_UNAVAIL && hard && tries < maxtries)
2586 {
2587 if (tries >= __session.ls_config->ldc_reconnect_maxconntries)
2588 {
2589 if (backoff == 0)
2590 backoff = __session.ls_config->ldc_reconnect_sleeptime;
2591 else if (backoff < __session.ls_config->ldc_reconnect_maxsleeptime)
2592 backoff *= 2;
2593
2594 syslog (LOG_INFO,
2595 "nss_ldap: reconnecting to LDAP server (sleeping %d seconds)...",
2596 backoff);
2597 (void) sleep (backoff);
2598 }
2599 else if (tries > 1)
2600 {
2601 /* Don't sleep, reconnect immediately. */
2602 syslog (LOG_INFO, "nss_ldap: reconnecting to LDAP server...");
2603 }
2604
2605 /* For each "try", attempt to connect to all specified URIs */
2606 start_uri = __session.ls_current_uri;
2607 do
2608 {
2609 stat = do_open ();
2610 if (stat == NSS_SUCCESS)
2611 {
2612 stat = do_map_error (search_func (base, scope, filter,
2613 attrs, sizelimit, private));
2614 }
2615 if (stat != NSS_UNAVAIL)
2616 break;
2617
2618 log++;
2619
2620 /* test in case config file could not be read */
2621 if (__session.ls_config != NULL)
2622 {
2623 assert (__session.ls_config->
2624 ldc_uris[__session.ls_current_uri] != NULL);
2625
2626 __session.ls_current_uri++;
2627
2628 if (__session.ls_config->ldc_uris[__session.ls_current_uri] ==
2629 NULL)
2630 __session.ls_current_uri = 0;
2631 }
2632 }
2633 while (__session.ls_current_uri != start_uri);
2634
2635 if (stat == NSS_UNAVAIL)
2636 {
2637 do_close ();
2638
2639 /*
2640 * If a soft reconnect policy is specified, then do not
2641 * try to reconnect to the LDAP server if it is down.
2642 */
2643 if (__session.ls_config->ldc_reconnect_pol == LP_RECONNECT_SOFT)
2644 hard = 0;
2645
2646 ++tries;
2647 }
2648 }
2649
2650 switch (stat)
2651 {
2652 case NSS_UNAVAIL:
2653 syslog (LOG_ERR, "nss_ldap: could not search LDAP server - %s",
2654 ldap_err2string (rc));
2655 break;
2656 case NSS_TRYAGAIN:
2657 syslog (LOG_ERR,
2658 "nss_ldap: could not %s %sconnect to LDAP server - %s",
2659 hard ? "hard" : "soft", tries ? "re" : "",
2660 ldap_err2string (rc));
2661 stat = NSS_UNAVAIL;
2662 break;
2663 case NSS_SUCCESS:
2664 if (log)
2665 {
2666 char *uri = __session.ls_config->ldc_uris[__session.ls_current_uri];
2667
2668 if (uri == NULL)
2669 uri = "(null)";
2670
2671 if (tries)
2672 syslog (LOG_INFO,
2673 "nss_ldap: reconnected to LDAP server %s after %d attempt%s",
2674 uri, tries, (tries == 1) ? "" : "s");
2675 else
2676 syslog (LOG_INFO, "nss_ldap: reconnected to LDAP server %s", uri);
2677 }
2678 time (&__session.ls_timestamp);
2679 break;
2680 default:
2681 break;
2682 }
2683
2684 debug ("<== do_with_reconnect");
2685 return stat;
2686 }
2687
2688 /*
2689 * Synchronous search function. Don't call this directly;
2690 * always wrap calls to this with do_with_reconnect(), or,
2691 * better still, use _nss_ldap_search_s().
2692 */
2693 static int
2694 do_search_s (const char *base, int scope,
2695 const char *filter, const char **attrs, int sizelimit,
2696 LDAPMessage ** res)
2697 {
2698 int rc;
2699 struct timeval tv, *tvp;
2700
2701 debug ("==> do_search_s");
2702
2703 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_SIZELIMIT)
2704 ldap_set_option (__session.ls_conn, LDAP_OPT_SIZELIMIT,
2705 (void *) &sizelimit);
2706 #else
2707 __session.ls_conn->ld_sizelimit = sizelimit;
2708 #endif /* LDAP_OPT_SIZELIMIT */
2709
2710 if (__session.ls_config->ldc_timelimit == LDAP_NO_LIMIT)
2711 {
2712 tvp = NULL;
2713 }
2714 else
2715 {
2716 tv.tv_sec = __session.ls_config->ldc_timelimit;
2717 tv.tv_usec = 0;
2718 tvp = &tv;
2719 }
2720
2721 rc = ldap_search_st (__session.ls_conn, base, scope, filter,
2722 (char **) attrs, 0, tvp, res);
2723
2724 debug ("<== do_search_s");
2725
2726 return rc;
2727 }
2728
2729 /*
2730 * Asynchronous search function. Don't call this directly;
2731 * always wrap calls to this with do_with_reconnect(), or,
2732 * better still, use _nss_ldap_search().
2733 */
2734 static int
2735 do_search (const char *base, int scope,
2736 const char *filter, const char **attrs, int sizelimit, int *msgid)
2737 {
2738 int rc;
2739 LDAPControl *serverCtrls[2];
2740 LDAPControl **pServerCtrls;
2741
2742 debug ("==> do_search");
2743
2744 #ifdef HAVE_LDAP_SEARCH_EXT
2745 if (_nss_ldap_test_config_flag (NSS_LDAP_FLAGS_PAGED_RESULTS))
2746 {
2747 rc = ldap_create_page_control (__session.ls_conn,
2748 __session.ls_config->ldc_pagesize,
2749 NULL, 0, &serverCtrls[0]);
2750 if (rc != LDAP_SUCCESS)
2751 return rc;
2752
2753 serverCtrls[1] = NULL;
2754 pServerCtrls = serverCtrls;
2755 }
2756 else
2757 {
2758 pServerCtrls = NULL;
2759 }
2760
2761 rc = ldap_search_ext (__session.ls_conn, base, scope, filter,
2762 (char **) attrs, 0, pServerCtrls, NULL,
2763 LDAP_NO_LIMIT, sizelimit, msgid);
2764
2765 if (pServerCtrls != NULL)
2766 {
2767 ldap_control_free (serverCtrls[0]);
2768 serverCtrls[0] = NULL;
2769 }
2770
2771 #else
2772 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_SIZELIMIT)
2773 ldap_set_option (__session.ls_conn, LDAP_OPT_SIZELIMIT,
2774 (void *) &sizelimit);
2775 #else
2776 __session.ls_conn->ld_sizelimit = sizelimit;
2777 #endif /* LDAP_OPT_SIZELIMIT */
2778
2779 *msgid = ldap_search (__session.ls_conn, base, scope, filter,
2780 (char **) attrs, 0);
2781 if (*msgid < 0)
2782 {
2783 #if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_NUMBER)
2784 if (ldap_get_option
2785 (__session.ls_conn, LDAP_OPT_ERROR_NUMBER, &rc) != LDAP_SUCCESS)
2786 {
2787 rc = LDAP_UNAVAILABLE;
2788 }
2789 #else
2790 rc = __session.ls_conn->ld_errno;
2791 #endif /* LDAP_OPT_ERROR_NUMBER */
2792 }
2793 else
2794 {
2795 rc = LDAP_SUCCESS;
2796 }
2797 #endif /* HAVE_LDAP_SEARCH_EXT */
2798
2799 debug ("<== do_search");
2800
2801 return rc;
2802 }
2803
2804 static void
2805 do_map_errno (NSS_STATUS status, int *errnop)
2806 {
2807 if (status == NSS_TRYAGAIN)
2808 {
2809 #ifdef HAVE_NSSWITCH_H
2810 errno = ERANGE;
2811 *errnop = 1; /* this is really erange */
2812 #else
2813 *errnop = errno = ERANGE;
2814 #endif
2815 }
2816 else
2817 {
2818 *errnop = 0;
2819 }
2820 }
2821
2822 /*
2823 * Tries parser function "parser" on entries, calling do_result()
2824 * to retrieve them from the LDAP server until one parses
2825 * correctly or there is an exceptional condition.
2826 */
2827 static NSS_STATUS
2828 do_parse (ent_context_t * ctx, void *result, char
2829 *buffer, size_t buflen, int *errnop, parser_t parser)
2830 {
2831 NSS_STATUS parseStat = NSS_NOTFOUND;
2832
2833 debug ("==> do_parse");
2834
2835 /*
2836 * if ec_state.ls_info.ls_index is non-zero, then we don't collect another
2837 * entry off the LDAP chain, and instead refeed the existing result to
2838 * the parser. Once the parser has finished with it, it will return
2839 * NSS_NOTFOUND and reset the index to -1, at which point we'll retrieve
2840 * another entry.
2841 */
2842 do
2843 {
2844 NSS_STATUS resultStat = NSS_SUCCESS;
2845
2846 if (ctx->ec_state.ls_retry == 0 &&
2847 (ctx->ec_state.ls_type == LS_TYPE_KEY
2848 || ctx->ec_state.ls_info.ls_index == -1))
2849 {
2850 resultStat = do_result (ctx, LDAP_MSG_ONE);
2851 }
2852
2853 if (resultStat != NSS_SUCCESS)
2854 {
2855 /* Could not get a result; bail */
2856 parseStat = resultStat;
2857 break;
2858 }
2859
2860 /*
2861 * We have an entry; now, try to parse it.
2862 *
2863 * If we do not parse the entry because of a schema
2864 * violation, the parser should return NSS_NOTFOUND.
2865 * We'll keep on trying subsequent entries until we
2866 * find one which is parseable, or exhaust avialable
2867 * entries, whichever is first.
2868 */
2869 parseStat = parser (ctx->ec_res, &ctx->ec_state, result,
2870 buffer, buflen);
2871
2872 /* hold onto the state if we're out of memory XXX */
2873 ctx->ec_state.ls_retry = (parseStat == NSS_TRYAGAIN && buffer != NULL ? 1 : 0);
2874
2875 /* free entry is we're moving on */
2876 if (ctx->ec_state.ls_retry == 0 &&
2877 (ctx->ec_state.ls_type == LS_TYPE_KEY
2878 || ctx->ec_state.ls_info.ls_index == -1))
2879 {
2880 /* we don't need the result anymore, ditch it. */
2881 ldap_msgfree (ctx->ec_res);
2882 ctx->ec_res = NULL;
2883 }
2884 }
2885 while (parseStat == NSS_NOTFOUND);
2886
2887 do_map_errno (parseStat, errnop);
2888
2889 debug ("<== do_parse");
2890
2891 return parseStat;
2892 }
2893
2894 /*
2895 * Parse, fetching reuslts from chain instead of server.
2896 */
2897 static NSS_STATUS
2898 do_parse_s (ent_context_t * ctx, void *result, char
2899 *buffer, size_t buflen, int *errnop, parser_t parser)
2900 {
2901 NSS_STATUS parseStat = NSS_NOTFOUND;
2902 LDAPMessage *e = NULL;
2903
2904 debug ("==> do_parse_s");
2905
2906 /*
2907 * if ec_state.ls_info.ls_index is non-zero, then we don't collect another
2908 * entry off the LDAP chain, and instead refeed the existing result to
2909 * the parser. Once the parser has finished with it, it will return
2910 * NSS_NOTFOUND and reset the index to -1, at which point we'll retrieve
2911 * another entry.
2912 */
2913 do
2914 {
2915 if (ctx->ec_state.ls_retry == 0 &&
2916 (ctx->ec_state.ls_type == LS_TYPE_KEY
2917 || ctx->ec_state.ls_info.ls_index == -1))
2918 {
2919 if (e == NULL)
2920 e = ldap_first_entry (__session.ls_conn, ctx->ec_res);
2921 else
2922 e = ldap_next_entry (__session.ls_conn, e);
2923 }
2924
2925 if (e == NULL)
2926 {
2927 /* Could not get a result; bail */
2928 parseStat = NSS_NOTFOUND;
2929 break;
2930 }
2931
2932 /*
2933 * We have an entry; now, try to parse it.
2934 *
2935 * If we do not parse the entry because of a schema
2936 * violation, the parser should return NSS_NOTFOUND.
2937 * We'll keep on trying subsequent entries until we
2938 * find one which is parseable, or exhaust avialable
2939 * entries, whichever is first.
2940 */
2941 parseStat = parser (e, &ctx->ec_state, result, buffer, buflen);
2942
2943 /* hold onto the state if we're out of memory XXX */
2944 ctx->ec_state.ls_retry = (parseStat == NSS_TRYAGAIN && buffer != NULL ? 1 : 0);
2945 }
2946 while (parseStat == NSS_NOTFOUND);
2947
2948 do_map_errno (parseStat, errnop);
2949
2950 debug ("<== do_parse_s");
2951
2952 return parseStat;
2953 }
2954
2955 /*
2956 * Read an entry from the directory, a la X.500. This is used
2957 * for functions that need to retrieve attributes from a DN,
2958 * such as the RFC2307bis group expansion function.
2959 */
2960 NSS_STATUS
2961 _nss_ldap_read (const char *dn, const char **attributes, LDAPMessage ** res)
2962 {
2963 return do_with_reconnect (dn, LDAP_SCOPE_BASE, "(objectclass=*)",
2964 attributes, 1, /* sizelimit */ res,
2965 (search_func_t) do_search_s);
2966 }
2967
2968 /*
2969 * Simple wrapper around ldap_get_values(). Requires that
2970 * session is already established.
2971 */
2972 char **
2973 _nss_ldap_get_values (LDAPMessage * e, const char *attr)
2974 {
2975 if (__session.ls_state != LS_CONNECTED_TO_DSA)
2976 {
2977 return NULL;
2978 }
2979 assert (__session.ls_conn != NULL);
2980
2981 return ldap_get_values (__session.ls_conn, e, (char *) attr);
2982 }
2983
2984 /*
2985 * Simple wrapper around ldap_get_dn(). Requires that
2986 * session is already established.
2987 */
2988 char *
2989 _nss_ldap_get_dn (LDAPMessage * e)
2990 {
2991 if (__session.ls_state != LS_CONNECTED_TO_DSA)
2992 {
2993 return NULL;
2994 }
2995 assert (__session.ls_conn != NULL);
2996
2997 return ldap_get_dn (__session.ls_conn, e);
2998 }
2999
3000 /*
3001 * Simple wrapper around ldap_first_entry(). Requires that
3002 * session is already established.
3003 */
3004 LDAPMessage *
3005 _nss_ldap_first_entry (LDAPMessage * res)
3006 {
3007 if (__session.ls_state != LS_CONNECTED_TO_DSA)
3008 {
3009 return NULL;
3010 }
3011 assert (__session.ls_conn != NULL);
3012
3013 return ldap_first_entry (__session.ls_conn, res);
3014 }
3015
3016 /*
3017 * Simple wrapper around ldap_next_entry(). Requires that
3018 * session is already established.
3019 */
3020 LDAPMessage *
3021 _nss_ldap_next_entry (LDAPMessage * res)
3022 {
3023 if (__session.ls_state != LS_CONNECTED_TO_DSA)
3024 {
3025 return NULL;
3026 }
3027 assert (__session.ls_conn != NULL);
3028
3029 return ldap_next_entry (__session.ls_conn, res);
3030 }
3031
3032 char *
3033 _nss_ldap_first_attribute (LDAPMessage * entry, BerElement ** berptr)
3034 {
3035 if (__session.ls_state != LS_CONNECTED_TO_DSA)
3036 {
3037 return NULL;
3038 }
3039 assert (__session.ls_conn != NULL);
3040
3041 return ldap_first_attribute (__session.ls_conn, entry, berptr);
3042 }
3043
3044 char *
3045 _nss_ldap_next_attribute (LDAPMessage * entry, BerElement * ber)
3046 {
3047 if (__session.ls_state != LS_CONNECTED_TO_DSA)
3048 {
3049 return NULL;
3050 }
3051 assert (__session.ls_conn != NULL);
3052
3053 return ldap_next_attribute (__session.ls_conn, entry, ber);
3054 }
3055
3056 /*
3057 * The generic synchronous lookup cover function.
3058 * Assumes caller holds lock.
3059 */
3060 NSS_STATUS
3061 _nss_ldap_search_s (const ldap_args_t * args,
3062 const char *filterprot, ldap_map_selector_t sel, const
3063 char **user_attrs, int sizelimit, LDAPMessage ** res)
3064 {
3065 char sdBase[LDAP_FILT_MAXSIZ];
3066 const char *base = NULL;
3067 char filterBuf[LDAP_FILT_MAXSIZ], *dynamicFilterBuf = NULL;
3068 const char **attrs, *filter;
3069 int scope;
3070 NSS_STATUS stat;
3071 ldap_service_search_descriptor_t *sd = NULL;
3072
3073 debug ("==> _nss_ldap_search_s");
3074
3075 stat = do_init ();
3076 if (stat != NSS_SUCCESS)
3077 {
3078 debug ("<== _nss_ldap_search_s");
3079 return stat;
3080 }
3081
3082 /* Set some reasonable defaults. */
3083 base = __session.ls_config->ldc_base;
3084 scope = __session.ls_config->ldc_scope;
3085 attrs = NULL;
3086
3087 if (args != NULL && args->la_base != NULL)
3088 {
3089 sel = LM_NONE;
3090 base = args->la_base;
3091 }
3092
3093 if (sel < LM_NONE)
3094 {
3095 sd = __session.ls_config->ldc_sds[sel];
3096 next:
3097 if (sd != NULL)
3098 {
3099 size_t len = strlen (sd->lsd_base);
3100 if (sd->lsd_base[len - 1] == ',')
3101 {
3102 /* is relative */
3103 snprintf (sdBase, sizeof (sdBase),
3104 "%s%s", sd->lsd_base,
3105 __session.ls_config->ldc_base);
3106 base = sdBase;
3107 }
3108 else
3109 {
3110 base = sd->lsd_base;
3111 }
3112
3113 if (sd->lsd_scope != -1)
3114 {
3115 scope = sd->lsd_scope;
3116 }
3117 }
3118 attrs = __session.ls_config->ldc_attrtab[sel];
3119 }
3120
3121 stat =
3122 do_filter (args, filterprot, sd, filterBuf, sizeof (filterBuf),
3123 &dynamicFilterBuf, &filter);
3124 if (stat != NSS_SUCCESS)
3125 return stat;
3126
3127 stat = do_with_reconnect (base, scope, filter,
3128 (user_attrs != NULL) ? user_attrs : attrs,
3129 sizelimit, res, (search_func_t) do_search_s);
3130
3131 if (dynamicFilterBuf != NULL)
3132 {
3133 free (dynamicFilterBuf);
3134 dynamicFilterBuf = NULL;
3135 }
3136
3137 if (stat == NSS_SUCCESS &&
3138 ldap_count_entries (__session.ls_conn, *res) == 0) /* No results */
3139 {
3140 stat = NSS_NOTFOUND;
3141 ldap_msgfree (*res);
3142 *res = NULL;
3143 }
3144
3145 /* If no entry was returned, try the next search descriptor. */
3146 if (sd != NULL && sd->lsd_next != NULL)
3147 {
3148 if (stat == NSS_NOTFOUND)
3149 {
3150 sd = sd->lsd_next;
3151 goto next;
3152 }
3153 }
3154
3155 debug ("<== _nss_ldap_search_s");
3156
3157 return stat;
3158 }
3159
3160 /*
3161 * The generic lookup cover function (asynchronous).
3162 * Assumes caller holds lock.
3163 */
3164 NSS_STATUS
3165 _nss_ldap_search (const ldap_args_t * args,
3166 const char *filterprot, ldap_map_selector_t sel,
3167 const char **user_attrs, int sizelimit, int *msgid,
3168 ldap_service_search_descriptor_t ** csd)
3169 {
3170 char sdBase[LDAP_FILT_MAXSIZ];
3171 const char *base = NULL;
3172 char filterBuf[LDAP_FILT_MAXSIZ], *dynamicFilterBuf = NULL;
3173 const char **attrs, *filter;
3174 int scope;
3175 NSS_STATUS stat;
3176 ldap_service_search_descriptor_t *sd = NULL;
3177
3178 debug ("==> _nss_ldap_search");
3179
3180 *msgid = -1;
3181
3182 stat = do_init ();
3183 if (stat != NSS_SUCCESS)
3184 {
3185 debug ("<== _nss_ldap_search");
3186 return stat;
3187 }
3188
3189 /* Set some reasonable defaults. */
3190 base = __session.ls_config->ldc_base;
3191 scope = __session.ls_config->ldc_scope;
3192 attrs = NULL;
3193
3194 if (args != NULL && args->la_base != NULL)
3195 {
3196 sel = LM_NONE;
3197 base = args->la_base;
3198 }
3199
3200 if (sel < LM_NONE || *csd != NULL)
3201 {
3202 /*
3203 * If we were chasing multiple descriptors and there are none left,
3204 * just quit with NSS_NOTFOUND.
3205 */
3206 if (*csd != NULL)
3207 {
3208 sd = (*csd)->lsd_next;
3209 if (sd == NULL)
3210 return NSS_NOTFOUND;
3211 }
3212 else
3213 {
3214 sd = __session.ls_config->ldc_sds[sel];
3215 }
3216
3217 *csd = sd;
3218
3219 if (sd != NULL)
3220 {
3221 size_t len = strlen (sd->lsd_base);
3222 if (sd->lsd_base[len - 1] == ',')
3223 {
3224 /* is relative */
3225 snprintf (sdBase, sizeof (sdBase), "%s%s", sd->lsd_base,
3226 __session.ls_config->ldc_base);
3227 base = sdBase;
3228 }
3229 else
3230 {
3231 base = sd->lsd_base;
3232 }
3233
3234 if (sd->lsd_scope != -1)
3235 {
3236 scope = sd->lsd_scope;
3237 }
3238 }
3239 attrs = __session.ls_config->ldc_attrtab[sel];
3240 }
3241
3242 stat =
3243 do_filter (args, filterprot, sd, filterBuf, sizeof (filterBuf),
3244 &dynamicFilterBuf, &filter);
3245 if (stat != NSS_SUCCESS)
3246 return stat;
3247
3248 stat = do_with_reconnect (base, scope, filter,
3249 (user_attrs != NULL) ? user_attrs : attrs,
3250 sizelimit, msgid, (search_func_t) do_search);
3251
3252 if (dynamicFilterBuf != NULL)
3253 free (dynamicFilterBuf);
3254
3255 debug ("<== _nss_ldap_search");
3256
3257 return stat;
3258 }
3259
3260 #ifdef HAVE_LDAP_SEARCH_EXT
3261 static NSS_STATUS
3262 do_next_page (const ldap_args_t * args,
3263 const char *filterprot, ldap_map_selector_t sel, int
3264 sizelimit, int *msgid, struct berval *pCookie)
3265 {
3266 char sdBase[LDAP_FILT_MAXSIZ];
3267 const char *base = NULL;
3268 char filterBuf[LDAP_FILT_MAXSIZ], *dynamicFilterBuf = NULL;
3269 const char **attrs, *filter;
3270 int scope;
3271 NSS_STATUS stat;
3272 ldap_service_search_descriptor_t *sd = NULL;
3273 LDAPControl *serverctrls[2] = {
3274 NULL, NULL
3275 };
3276
3277 /* Set some reasonable defaults. */
3278 base = __session.ls_config->ldc_base;
3279 scope = __session.ls_config->ldc_scope;
3280 attrs = NULL;
3281
3282 if (args != NULL && args->la_base != NULL)
3283 {
3284 sel = LM_NONE;
3285 base = args->la_base;
3286 }
3287
3288 if (sel < LM_NONE)
3289 {
3290 sd = __session.ls_config->ldc_sds[sel];
3291 if (sd != NULL)
3292 {
3293 size_t len = strlen (sd->lsd_base);
3294 if (sd->lsd_base[len - 1] == ',')
3295 {
3296 snprintf (sdBase, sizeof (sdBase), "%s%s", sd->lsd_base,
3297 __session.ls_config->ldc_base);
3298 base = sdBase;
3299 }
3300 else
3301 {
3302 base = sd->lsd_base;
3303 }
3304
3305 if (sd->lsd_scope != -1)
3306 {
3307 scope = sd->lsd_scope;
3308 }
3309 }
3310 attrs = __session.ls_config->ldc_attrtab[sel];
3311 }
3312
3313 stat =
3314 do_filter (args, filterprot, sd, filterBuf, sizeof (filterBuf),
3315 &dynamicFilterBuf, &filter);
3316 if (stat != NSS_SUCCESS)
3317 {
3318 return stat;
3319 }
3320
3321 stat =
3322 ldap_create_page_control (__session.ls_conn,
3323 __session.ls_config->ldc_pagesize,
3324 pCookie, 0, &serverctrls[0]);
3325 if (stat != LDAP_SUCCESS)
3326 {
3327 if (dynamicFilterBuf != NULL)
3328 free (dynamicFilterBuf);
3329 return NSS_UNAVAIL;
3330 }
3331
3332 stat =
3333 ldap_search_ext (__session.ls_conn, base,
3334 __session.ls_config->ldc_scope,
3335 filter,
3336 (char **) attrs, 0, serverctrls, NULL, LDAP_NO_LIMIT,
3337 sizelimit, msgid);
3338
3339 ldap_control_free (serverctrls[0]);
3340 if (dynamicFilterBuf != NULL)
3341 free (dynamicFilterBuf);
3342
3343 return (*msgid < 0) ? NSS_UNAVAIL : NSS_SUCCESS;
3344 }
3345 #endif /* HAVE_LDAP_SEARCH_EXT */
3346
3347 /*
3348 * General entry point for enumeration routines.
3349 * This should really use the asynchronous LDAP search API to avoid
3350 * pulling down all the entries at once, particularly if the
3351 * enumeration is not completed.
3352 * Locks mutex.
3353 */
3354 NSS_STATUS
3355 _nss_ldap_getent (ent_context_t ** ctx,
3356 void *result, char *buffer, size_t buflen,
3357 int *errnop, const char *filterprot,
3358 ldap_map_selector_t sel, parser_t parser)
3359 {
3360 NSS_STATUS status;
3361
3362 /*
3363 * we need to lock here as the context may not be thread-specific
3364 * data (under glibc, for example). Maybe we should make the lock part
3365 * of the context.
3366 */
3367
3368 _nss_ldap_enter ();
3369 status = _nss_ldap_getent_ex (NULL, ctx, result,
3370 buffer, buflen,
3371 errnop, filterprot, sel, NULL, parser);
3372 _nss_ldap_leave ();
3373
3374 return status;
3375 }
3376
3377 /*
3378 * Internal entry point for enumeration routines.
3379 * Caller holds global mutex
3380 */
3381 NSS_STATUS
3382 _nss_ldap_getent_ex (ldap_args_t * args,
3383 ent_context_t ** ctx, void *result,
3384 char *buffer, size_t buflen, int *errnop,
3385 const char *filterprot,
3386 ldap_map_selector_t sel,
3387 const char **user_attrs, parser_t parser)
3388 {
3389 NSS_STATUS stat = NSS_SUCCESS;
3390
3391 debug ("==> _nss_ldap_getent_ex");
3392
3393 if (*ctx != NULL && (*ctx)->ec_eof != 0)
3394 {
3395 debug ("<== _nss_ldap_getent_ex (EOF)");
3396 return NSS_NOTFOUND;
3397 }
3398 else if (*ctx == NULL || (*ctx)->ec_msgid < 0)
3399 {
3400 /*
3401 * implicitly call setent() if this is the first time
3402 * or there is no active search
3403 */
3404 if (_nss_ldap_ent_context_init_locked (ctx) == NULL)
3405 {
3406 debug ("<== _nss_ldap_getent_ex");
3407 return NSS_UNAVAIL;
3408 }
3409 }
3410
3411 next:
3412 /*
3413 * If ctx->ec_msgid < 0, then we haven't searched yet. Let's do it!
3414 */
3415 if ((*ctx)->ec_msgid < 0)
3416 {
3417 int msgid;
3418
3419 stat = _nss_ldap_search (args, filterprot, sel, user_attrs,
3420 LDAP_NO_LIMIT, &msgid, &(*ctx)->ec_sd);
3421 if (stat != NSS_SUCCESS)
3422 {
3423 debug ("<== _nss_ldap_getent_ex");
3424 return stat;
3425 }
3426
3427 (*ctx)->ec_msgid = msgid;
3428 }
3429
3430 stat = do_parse (*ctx, result, buffer, buflen, errnop, parser);
3431
3432 #ifdef HAVE_LDAP_SEARCH_EXT
3433 if (stat == NSS_NOTFOUND)
3434 {
3435 /* Is there another page of results? */
3436 if ((*ctx)->ec_cookie != NULL && (*ctx)->ec_cookie->bv_len != 0)
3437 {
3438 int msgid;
3439
3440 stat =
3441 do_next_page (NULL, filterprot, sel, LDAP_NO_LIMIT, &msgid,
3442 (*ctx)->ec_cookie);
3443 if (stat != NSS_SUCCESS)
3444 {
3445 debug ("<== _nss_ldap_getent_ex");
3446 return stat;
3447 }
3448 (*ctx)->ec_msgid = msgid;
3449 stat = do_parse (*ctx, result, buffer, buflen, errnop, parser);
3450 }
3451 }
3452 #endif /* HAVE_LDAP_SEARCH_EXT */
3453
3454 if (stat == NSS_NOTFOUND)
3455 {
3456 if ((*ctx)->ec_sd != NULL)
3457 {
3458 (*ctx)->ec_msgid = -1;
3459 goto next;
3460 }
3461 else
3462 {
3463 /* Mark notional end of file */
3464 (*ctx)->ec_eof = 1;
3465 }
3466 }
3467
3468 debug ("<== _nss_ldap_getent_ex");
3469
3470 return stat;
3471 }
3472
3473 /*
3474 * General match function.
3475 * Locks mutex.
3476 */
3477 NSS_STATUS
3478 _nss_ldap_getbyname (ldap_args_t * args,
3479 void *result, char *buffer, size_t buflen, int
3480 *errnop, const char *filterprot,
3481 ldap_map_selector_t sel, parser_t parser)
3482 {
3483 NSS_STATUS stat = NSS_NOTFOUND;
3484 ent_context_t ctx;
3485
3486 _nss_ldap_enter ();
3487
3488 debug ("==> _nss_ldap_getbyname");
3489
3490 ctx.ec_msgid = -1;
3491 ctx.ec_cookie = NULL;
3492 ctx.ec_eof = 0;
3493
3494 stat = _nss_ldap_search_s (args, filterprot, sel, NULL, 1, &ctx.ec_res);
3495 if (stat != NSS_SUCCESS)
3496 {
3497 _nss_ldap_leave ();
3498 debug ("<== _nss_ldap_getbyname");
3499 return stat;
3500 }
3501
3502 /*
3503 * we pass this along for the benefit of the services parser,
3504 * which uses it to figure out which protocol we really wanted.
3505 * we only pass the second argument along, as that's what we need
3506 * in services.
3507 */
3508 LS_INIT (ctx.ec_state);
3509 ctx.ec_state.ls_type = LS_TYPE_KEY;
3510 ctx.ec_state.ls_info.ls_key = args->la_arg2.la_string;
3511
3512 stat = do_parse_s (&ctx, result, buffer, buflen, errnop, parser);
3513
3514 do_context_release (&ctx, 0);
3515
3516 /* moved unlock here to avoid race condition bug #49 */
3517 _nss_ldap_leave ();
3518
3519 debug ("<== _nss_ldap_getbyname");
3520
3521 return stat;
3522 }
3523
3524 /*
3525 * These functions are called from within the parser, where it is assumed
3526 * to be safe to use the connection and the respective message.
3527 */
3528
3529 /*
3530 * Assign all values, bar omitvalue (if not NULL), to *valptr.
3531 */
3532 NSS_STATUS
3533 _nss_ldap_assign_attrvals (LDAPMessage * e,
3534 const char *attr, const char *omitvalue,
3535 char ***valptr, char **pbuffer, size_t *
3536 pbuflen, size_t * pvalcount)
3537 {
3538 char **vals;
3539 char **valiter;
3540 int valcount;
3541 char **p = NULL;
3542
3543 register int buflen = *pbuflen;
3544 register char *buffer = *pbuffer;
3545
3546 if (pvalcount != NULL)
3547 {
3548 *pvalcount = 0;
3549 }
3550
3551 if (__session.ls_conn == NULL)
3552 {
3553 return NSS_UNAVAIL;
3554 }
3555
3556 vals = ldap_get_values (__session.ls_conn, e, (char *) attr);
3557
3558 valcount = (vals == NULL) ? 0 : ldap_count_values (vals);
3559 if (bytesleft (buffer, buflen, char *) < (valcount + 1) * sizeof (char *))
3560 {
3561 ldap_value_free (vals);
3562 return NSS_TRYAGAIN;
3563 }
3564
3565 align (buffer, buflen, char *);
3566 p = *valptr = (char **) buffer;
3567
3568 buffer += (valcount + 1) * sizeof (char *);
3569 buflen -= (valcount + 1) * sizeof (char *);
3570
3571 if (valcount == 0)
3572 {
3573 *p = NULL;
3574 *pbuffer = buffer;
3575 *pbuflen = buflen;
3576 return NSS_SUCCESS;
3577 }
3578
3579 valiter = vals;
3580
3581 while (*valiter != NULL)
3582 {
3583 int vallen;
3584 char *elt = NULL;
3585
3586 if (omitvalue != NULL && strcmp (*valiter, omitvalue) == 0)
3587 {
3588 valcount--;
3589 }
3590 else
3591 {
3592 vallen = strlen (*valiter);
3593 if (buflen < (size_t) (vallen + 1))
3594 {
3595 ldap_value_free (vals);
3596 return NSS_TRYAGAIN;
3597 }
3598
3599 /* copy this value into the next block of buffer space */
3600 elt = buffer;
3601 buffer += vallen + 1;
3602 buflen -= vallen + 1;
3603
3604 strncpy (elt, *valiter, vallen);
3605 elt[vallen] = '\0';
3606 *p = elt;
3607 p++;
3608 }
3609 valiter++;
3610 }
3611
3612 *p = NULL;
3613 *pbuffer = buffer;
3614 *pbuflen = buflen;
3615
3616 if (pvalcount != NULL)
3617 {
3618 *pvalcount = valcount;
3619 }
3620
3621 ldap_value_free (vals);
3622 return NSS_SUCCESS;
3623 }
3624
3625 /* Assign a single value to *valptr. */
3626 NSS_STATUS
3627 _nss_ldap_assign_attrval (LDAPMessage * e,
3628 const char *attr, char **valptr, char **buffer,
3629 size_t * buflen)
3630 {
3631 char **vals;
3632 int vallen;
3633 const char *ovr, *def;
3634
3635 ovr = OV (attr);
3636 if (ovr != NULL)
3637 {
3638 vallen = strlen (ovr);
3639 if (*buflen < (size_t) (vallen + 1))
3640 {
3641 return NSS_TRYAGAIN;
3642 }
3643
3644 *valptr = *buffer;
3645
3646 strncpy (*valptr, ovr, vallen);
3647 (*valptr)[vallen] = '\0';
3648
3649 *buffer += vallen + 1;
3650 *buflen -= vallen + 1;
3651
3652 return NSS_SUCCESS;
3653 }
3654
3655 if (__session.ls_conn == NULL)
3656 {
3657 return NSS_UNAVAIL;
3658 }
3659
3660 vals = ldap_get_values (__session.ls_conn, e, (char *) attr);
3661 if (vals == NULL)
3662 {
3663 def = DF (attr);
3664 if (def != NULL)
3665 {
3666 vallen = strlen (def);
3667 if (*buflen < (size_t) (vallen + 1))
3668 {
3669 return NSS_TRYAGAIN;
3670 }
3671
3672 *valptr = *buffer;
3673
3674 strncpy (*valptr, def, vallen);
3675 (*valptr)[vallen] = '\0';
3676
3677 *buffer += vallen + 1;
3678 *buflen -= vallen + 1;
3679
3680 return NSS_SUCCESS;
3681 }
3682 else
3683 {
3684 return NSS_NOTFOUND;
3685 }
3686 }
3687
3688 vallen = strlen (*vals);
3689 if (*buflen < (size_t) (vallen + 1))
3690 {
3691 ldap_value_free (vals);
3692 return NSS_TRYAGAIN;
3693 }
3694
3695 *valptr = *buffer;
3696
3697 strncpy (*valptr, *vals, vallen);
3698 (*valptr)[vallen] = '\0';
3699
3700 *buffer += vallen + 1;
3701 *buflen -= vallen + 1;
3702
3703 ldap_value_free (vals);
3704
3705 return NSS_SUCCESS;
3706 }
3707
3708 const char *
3709 _nss_ldap_locate_userpassword (char **vals)
3710 {
3711 const char *token = NULL;
3712 size_t token_length = 0;
3713 char **valiter;
3714 const char *pwd = NULL;
3715
3716 if (__config != NULL)
3717 {
3718 switch (__config->ldc_password_type)
3719 {
3720 case LU_RFC2307_USERPASSWORD:
3721 token = "{CRYPT}";
3722 token_length = sizeof ("{CRYPT}") - 1;
3723 break;
3724 case LU_RFC3112_AUTHPASSWORD:
3725 token = "CRYPT$";
3726 token_length = sizeof ("CRYPT$") - 1;
3727 break;
3728 case LU_OTHER_PASSWORD:
3729 break;
3730 }
3731 }
3732
3733 if (vals != NULL)
3734 {
3735 for (valiter = vals; *valiter != NULL; valiter++)
3736 {
3737 if (token_length == 0 ||
3738 strncasecmp (*valiter, token, token_length) == 0)
3739 {
3740 pwd = *valiter;
3741 break;
3742 }
3743 }
3744 }
3745
3746 if (pwd == NULL)
3747 pwd = "*";
3748 else
3749 pwd += token_length;
3750
3751 return pwd;
3752 }
3753
3754 /*
3755 * Assign a single value to *valptr, after examining userPassword for
3756 * a syntactically suitable value.
3757 */
3758 NSS_STATUS
3759 _nss_ldap_assign_userpassword (LDAPMessage * e,
3760 const char *attr, char **valptr,
3761 char **buffer, size_t * buflen)
3762 {
3763 char **vals;
3764 const char *pwd;
3765 int vallen;
3766
3767 debug ("==> _nss_ldap_assign_userpassword");
3768
3769 if (__session.ls_conn == NULL)
3770 {
3771 return NSS_UNAVAIL;
3772 }
3773
3774 vals = ldap_get_values (__session.ls_conn, e, (char *) attr);
3775 pwd = _nss_ldap_locate_userpassword (vals);
3776
3777 vallen = strlen (pwd);
3778
3779 if (*buflen < (size_t) (vallen + 1))
3780 {
3781 if (vals != NULL)
3782 {
3783 ldap_value_free (vals);
3784 }
3785 debug ("<== _nss_ldap_assign_userpassword");
3786 return NSS_TRYAGAIN;
3787 }
3788
3789 *valptr = *buffer;
3790
3791 strncpy (*valptr, pwd, vallen);
3792 (*valptr)[vallen] = '\0';
3793
3794 *buffer += vallen + 1;
3795 *buflen -= vallen + 1;
3796
3797 if (vals != NULL)
3798 {
3799 ldap_value_free (vals);
3800 }
3801
3802 debug ("<== _nss_ldap_assign_userpassword");
3803
3804 return NSS_SUCCESS;
3805 }
3806
3807 NSS_STATUS
3808 _nss_ldap_oc_check (LDAPMessage * e, const char *oc)
3809 {
3810 char **vals, **valiter;
3811 NSS_STATUS ret = NSS_NOTFOUND;
3812
3813 if (__session.ls_conn == NULL)
3814 {
3815 return NSS_UNAVAIL;
3816 }
3817
3818 vals = ldap_get_values (__session.ls_conn, e, AT (objectClass));
3819 if (vals != NULL)
3820 {
3821 for (valiter = vals; *valiter != NULL; valiter++)
3822 {
3823 if (strcasecmp (*valiter, oc) == 0)
3824 {
3825 ret = NSS_SUCCESS;
3826 break;
3827 }
3828 }
3829 }
3830
3831 if (vals != NULL)
3832 {
3833 ldap_value_free (vals);
3834 }
3835
3836 return ret;
3837 }
3838
3839 #ifdef HAVE_SHADOW_H
3840 NSS_STATUS
3841 _nss_ldap_shadow_date (const char *val, long default_date, long *value)
3842 {
3843 int date;
3844 char *p;
3845 long long ll;
3846
3847 if (val == NULL || strlen(val) == 0)
3848 {
3849 *value = default_date;
3850 return NSS_NOTFOUND;
3851 }
3852 ll = strtoll(val, &p, 10);
3853 if (p == NULL || p == val || *p != '\0')
3854 {
3855 *value = default_date;
3856 return NSS_NOTFOUND;
3857 }
3858 if (__config->ldc_shadow_type == LS_AD_SHADOW)
3859 {
3860 date = ll / 864000000000LL - 134774LL;
3861 date = (date > 99999) ? 99999 : date;
3862 }
3863 else
3864 {
3865 date = ll;
3866 }
3867
3868 *value = date;
3869 return NSS_SUCCESS;
3870 }
3871
3872 void
3873 _nss_ldap_shadow_handle_flag (struct spwd *sp)
3874 {
3875 if (__config->ldc_shadow_type == LS_AD_SHADOW)
3876 {
3877 if (sp->sp_flag & UF_DONT_EXPIRE_PASSWD)
3878 sp->sp_max = 99999;
3879 sp->sp_flag = 0;
3880 }
3881 }
3882 #endif /* HAVE_SHADOW_H */
3883
3884 const char *
3885 _nss_ldap_map_at (ldap_map_selector_t sel, const char *attribute)
3886 {
3887 const char *mapped = NULL;
3888 NSS_STATUS stat;
3889
3890 stat = _nss_ldap_map_get (__config, sel, MAP_ATTRIBUTE, attribute, &mapped);
3891
3892 return (stat == NSS_SUCCESS) ? mapped : attribute;
3893 }
3894
3895 const char *
3896 _nss_ldap_unmap_at (ldap_map_selector_t sel, const char *attribute)
3897 {
3898 const char *mapped = NULL;
3899 NSS_STATUS stat;
3900
3901 stat = _nss_ldap_map_get (__config, sel, MAP_ATTRIBUTE_REVERSE, attribute, &mapped);
3902
3903 return (stat == NSS_SUCCESS) ? mapped : attribute;
3904 }
3905
3906 const char *
3907 _nss_ldap_map_oc (ldap_map_selector_t sel, const char *objectclass)
3908 {
3909 const char *mapped = NULL;
3910 NSS_STATUS stat;
3911
3912 stat = _nss_ldap_map_get (__config, sel, MAP_OBJECTCLASS, objectclass, &mapped);
3913
3914 return (stat == NSS_SUCCESS) ? mapped : objectclass;
3915 }
3916
3917 const char *
3918 _nss_ldap_unmap_oc (ldap_map_selector_t sel, const char *objectclass)
3919 {
3920 const char *mapped = NULL;
3921 NSS_STATUS stat;
3922
3923 stat = _nss_ldap_map_get (__config, sel, MAP_OBJECTCLASS_REVERSE, objectclass, &mapped);
3924
3925 return (stat == NSS_SUCCESS) ? mapped : objectclass;
3926 }
3927
3928 const char *
3929 _nss_ldap_map_ov (const char *attribute)
3930 {
3931 const char *value = NULL;
3932
3933 _nss_ldap_map_get (__config, LM_NONE, MAP_OVERRIDE, attribute, &value);
3934
3935 return value;
3936 }
3937
3938 const char *
3939 _nss_ldap_map_df (const char *attribute)
3940 {
3941 const char *value = NULL;
3942
3943 _nss_ldap_map_get (__config, LM_NONE, MAP_DEFAULT, attribute, &value);
3944
3945 return value;
3946 }
3947
3948 NSS_STATUS
3949 _nss_ldap_map_put (ldap_config_t * config,
3950 ldap_map_selector_t sel,
3951 ldap_map_type_t type,
3952 const char *from,
3953 const char *to)
3954 {
3955 ldap_datum_t key, val;
3956 void **map;
3957 NSS_STATUS stat;
3958
3959 switch (type)
3960 {
3961 case MAP_ATTRIBUTE:
3962 /* special handling for attribute mapping */ if (strcmp
3963 (from,
3964 "userPassword") == 0)
3965 {
3966 if (strcasecmp (to, "userPassword") == 0)
3967 config->ldc_password_type = LU_RFC2307_USERPASSWORD;
3968 else if (strcasecmp (to, "authPassword") == 0)
3969 config->ldc_password_type = LU_RFC3112_AUTHPASSWORD;
3970 else
3971 config->ldc_password_type = LU_OTHER_PASSWORD;
3972 }
3973 else if (strcmp (from, "shadowLastChange") == 0)
3974 {
3975 if (strcasecmp (to, "shadowLastChange") == 0)
3976 config->ldc_shadow_type = LS_RFC2307_SHADOW;
3977 else if (strcasecmp (to, "pwdLastSet") == 0)
3978 config->ldc_shadow_type = LS_AD_SHADOW;
3979 else
3980 config->ldc_shadow_type = LS_OTHER_SHADOW;
3981 }
3982 break;
3983 case MAP_OBJECTCLASS:
3984 case MAP_OVERRIDE:
3985 case MAP_DEFAULT:
3986 break;
3987 default:
3988 return NSS_NOTFOUND;
3989 break;
3990 }
3991
3992 assert (sel <= LM_NONE);
3993 map = &config->ldc_maps[sel][type];
3994 assert (*map != NULL);
3995
3996 NSS_LDAP_DATUM_ZERO (&key);
3997 key.data = (void *) from;
3998 key.size = strlen (from) + 1;
3999
4000 NSS_LDAP_DATUM_ZERO (&val);
4001 val.data = (void *) to;
4002 val.size = strlen (to) + 1;
4003
4004 stat = _nss_ldap_db_put (*map, NSS_LDAP_DB_NORMALIZE_CASE, &key, &val);
4005 if (stat == NSS_SUCCESS &&
4006 (type == MAP_ATTRIBUTE || type == MAP_OBJECTCLASS))
4007 {
4008 type = (type == MAP_ATTRIBUTE) ? MAP_ATTRIBUTE_REVERSE : MAP_OBJECTCLASS_REVERSE;
4009 map = &config->ldc_maps[sel][type];
4010
4011 stat = _nss_ldap_db_put (*map, NSS_LDAP_DB_NORMALIZE_CASE, &val, &key);
4012 }
4013
4014 return stat;
4015 }
4016
4017 NSS_STATUS
4018 _nss_ldap_map_get (ldap_config_t * config,
4019 ldap_map_selector_t sel,
4020 ldap_map_type_t type,
4021 const char *from, const char **to)
4022 {
4023 ldap_datum_t key, val;
4024 void *map;
4025 NSS_STATUS stat;
4026
4027 if (config == NULL || sel > LM_NONE || type > MAP_MAX)
4028 {
4029 return NSS_NOTFOUND;
4030 }
4031
4032 map = config->ldc_maps[sel][type];
4033 assert (map != NULL);
4034
4035 NSS_LDAP_DATUM_ZERO (&key);
4036 key.data = (void *) from;
4037 key.size = strlen (from) + 1;
4038
4039 NSS_LDAP_DATUM_ZERO (&val);
4040
4041 stat = _nss_ldap_db_get (map, NSS_LDAP_DB_NORMALIZE_CASE, &key, &val);
4042 if (stat == NSS_NOTFOUND && sel != LM_NONE)
4043 {
4044 map = config->ldc_maps[LM_NONE][type];
4045 assert (map != NULL);
4046 stat = _nss_ldap_db_get (map, NSS_LDAP_DB_NORMALIZE_CASE, &key, &val);
4047 }
4048
4049 if (stat == NSS_SUCCESS)
4050 *to = (char *) val.data;
4051 else
4052 *to = NULL;
4053
4054 return stat;
4055 }
4056
4057 /*
4058 * Proxy bind support for AIX. Very simple, but should do
4059 * the job.
4060 */
4061
4062 #if LDAP_SET_REBIND_PROC_ARGS < 3
4063 static ldap_proxy_bind_args_t __proxy_args = { NULL, NULL };
4064 #endif
4065
4066 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
4067 #if LDAP_SET_REBIND_PROC_ARGS == 3
4068 static int
4069 do_proxy_rebind (LDAP * ld, LDAP_CONST char *url, ber_tag_t request,
4070 ber_int_t msgid, void *arg)
4071 #else
4072 static int
4073 do_proxy_rebind (LDAP * ld, LDAP_CONST char *url, int request,
4074 ber_int_t msgid)
4075 #endif
4076 {
4077 int timelimit;
4078 #if LDAP_SET_REBIND_PROC_ARGS == 3
4079 ldap_proxy_bind_args_t *who = (ldap_proxy_bind_args_t *) arg;
4080 #else
4081 ldap_proxy_bind_args_t *who = &__proxy_args;
4082 #endif
4083
4084 timelimit = __session.ls_config->ldc_bind_timelimit;
4085
4086 return do_bind (ld, timelimit, who->binddn, who->bindpw, 0);
4087 }
4088 #else
4089 #if LDAP_SET_REBIND_PROC_ARGS == 3
4090 static int
4091 do_proxy_rebind (LDAP * ld, char **whop, char **credp, int *methodp,
4092 int freeit, void *arg)
4093 #elif LDAP_SET_REBIND_PROC_ARGS == 2
4094 static int
4095 do_proxy_rebind (LDAP * ld, char **whop, char **credp, int *methodp,
4096 int freeit)
4097 #endif
4098 {
4099 #if LDAP_SET_REBIND_PROC_ARGS == 3
4100 ldap_proxy_bind_args_t *who = (ldap_proxy_bind_args_t *) arg;
4101 #else
4102 ldap_proxy_bind_args_t *who = &__proxy_args;
4103 #endif
4104 if (freeit)
4105 {
4106 if (*whop != NULL)
4107 free (*whop);
4108 if (*credp != NULL)
4109 free (*credp);
4110 }
4111
4112 *whop = who->binddn ? strdup (who->binddn) : NULL;
4113 *credp = who->bindpw ? strdup (who->bindpw) : NULL;
4114
4115 *methodp = LDAP_AUTH_SIMPLE;
4116
4117 return LDAP_SUCCESS;
4118 }
4119 #endif
4120
4121 NSS_STATUS
4122 _nss_ldap_proxy_bind (const char *user, const char *password)
4123 {
4124 ldap_args_t args;
4125 LDAPMessage *res, *e;
4126 NSS_STATUS stat;
4127 int rc;
4128 #if LDAP_SET_REBIND_PROC_ARGS == 3
4129 ldap_proxy_bind_args_t proxy_args_buf;
4130 ldap_proxy_bind_args_t *proxy_args = &proxy_args_buf;
4131 #else
4132 ldap_proxy_bind_args_t *proxy_args = &__proxy_args;
4133 #endif
4134
4135 debug ("==> _nss_ldap_proxy_bind");
4136
4137 LA_INIT (args);
4138 LA_TYPE (args) = LA_TYPE_STRING;
4139 LA_STRING (args) = user;
4140
4141 /*
4142 * Binding with an empty password will always work, so don't let
4143 * the user in if they try that.
4144 */
4145 if (password == NULL || password[0] == '\0')
4146 {
4147 debug ("<== _nss_ldap_proxy_bind (empty password not permitted)");
4148 /* XXX overload */
4149 return NSS_TRYAGAIN;
4150 }
4151
4152 _nss_ldap_enter ();
4153
4154 stat = _nss_ldap_search_s (&args, _nss_ldap_filt_getpwnam,
4155 LM_PASSWD, NULL, 1, &res);
4156 if (stat == NSS_SUCCESS)
4157 {
4158 e = _nss_ldap_first_entry (res);
4159 if (e != NULL)
4160 {
4161 proxy_args->binddn = _nss_ldap_get_dn (e);
4162 proxy_args->bindpw = password;
4163
4164 if (proxy_args->binddn != NULL)
4165 {
4166 /* Use our special rebind procedure. */
4167 #if LDAP_SET_REBIND_PROC_ARGS == 3
4168 ldap_set_rebind_proc (__session.ls_conn, do_proxy_rebind, NULL);
4169 #elif LDAP_SET_REBIND_PROC_ARGS == 2
4170 ldap_set_rebind_proc (__session.ls_conn, do_proxy_rebind);
4171 #endif
4172
4173 debug (":== _nss_ldap_proxy_bind: %s", proxy_args->binddn);
4174
4175 rc = do_bind (__session.ls_conn,
4176 __session.ls_config->ldc_bind_timelimit,
4177 proxy_args->binddn, proxy_args->bindpw, 0);
4178 switch (rc)
4179 {
4180 case LDAP_INVALID_CREDENTIALS:
4181 /* XXX overload */
4182 stat = NSS_TRYAGAIN;
4183 break;
4184 case LDAP_NO_SUCH_OBJECT:
4185 stat = NSS_NOTFOUND;
4186 break;
4187 case LDAP_SUCCESS:
4188 stat = NSS_SUCCESS;
4189 break;
4190 default:
4191 stat = NSS_UNAVAIL;
4192 break;
4193 }
4194 /*
4195 * Close the connection, don't want to continue
4196 * being bound as this user or using this rebind proc.
4197 */
4198 do_close ();
4199 ldap_memfree (proxy_args->binddn);
4200 }
4201 else
4202 {
4203 stat = NSS_NOTFOUND;
4204 }
4205 proxy_args->binddn = NULL;
4206 proxy_args->bindpw = NULL;
4207 }
4208 else
4209 {
4210 stat = NSS_NOTFOUND;
4211 }
4212 ldap_msgfree (res);
4213 }
4214
4215 _nss_ldap_leave ();
4216
4217 debug ("<== _nss_ldap_proxy_bind");
4218
4219 return stat;
4220 }
4221
4222 #if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) ||defined (HAVE_SASL_SASL_H))
4223 static int
4224 do_sasl_interact (LDAP * ld, unsigned flags, void *defaults, void *_interact)
4225 {
4226 char *authzid = (char *) defaults;
4227 sasl_interact_t *interact = (sasl_interact_t *) _interact;
4228
4229 while (interact->id != SASL_CB_LIST_END)
4230 {
4231 if (interact->id == SASL_CB_USER)
4232 {
4233 if (authzid != NULL)
4234 {
4235 interact->result = authzid;
4236 interact->len = strlen (authzid);
4237 }
4238 else if (interact->defresult != NULL)
4239 {
4240 interact->result = interact->defresult;
4241 interact->len = strlen (interact->defresult);
4242 }
4243 else
4244 {
4245 interact->result = "";
4246 interact->len = 0;
4247 }
4248 #if SASL_VERSION_MAJOR < 2
4249 interact->result = strdup (interact->result);
4250 if (interact->result == NULL)
4251 {
4252 return LDAP_NO_MEMORY;
4253 }
4254 #endif /* SASL_VERSION_MAJOR < 2 */
4255 }
4256 else
4257 {
4258 return LDAP_PARAM_ERROR;
4259 }
4260 interact++;
4261 }
4262 return LDAP_SUCCESS;
4263 }
4264 #endif
4265
4266 const char **
4267 _nss_ldap_get_attributes (ldap_map_selector_t sel)
4268 {
4269 const char **attrs = NULL;
4270
4271 debug ("==> _nss_ldap_get_attributes");
4272
4273 if (sel < LM_NONE)
4274 {
4275 if (do_init () != NSS_SUCCESS)
4276 {
4277 debug ("<== _nss_ldap_get_attributes (init failed)");
4278 return NULL;
4279 }
4280
4281 attrs = __session.ls_config->ldc_attrtab[sel];
4282 }
4283
4284 debug ("<== _nss_ldap_get_attributes");
4285
4286 return attrs;
4287 }
4288
4289 int
4290 _nss_ldap_test_config_flag (unsigned int flag)
4291 {
4292 if (__config != NULL && (__config->ldc_flags & flag) != 0)
4293 return 1;
4294
4295 return 0;
4296 }
4297
4298 int
4299 _nss_ldap_test_initgroups_ignoreuser (const char *user)
4300 {
4301 char **p;
4302
4303 if (__config == NULL)
4304 return 0;
4305
4306 if (__config->ldc_initgroups_ignoreusers == NULL)
4307 return 0;
4308
4309 for (p = __config->ldc_initgroups_ignoreusers; *p != NULL; p++)
4310 {
4311 if (strcmp (*p, user) == 0)
4312 return 1;
4313 }
4314
4315 return 0;
4316 }
4317
4318 int
4319 _nss_ldap_get_ld_errno (char **m, char **s)
4320 {
4321 #ifdef HAVE_LDAP_GET_OPTION
4322 int rc;
4323 #endif
4324 int lderrno;
4325
4326 if (__session.ls_conn == NULL)
4327 {
4328 return LDAP_UNAVAILABLE;
4329 }
4330
4331 #if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_NUMBER)
4332 /* is this needed? */
4333 rc = ldap_get_option (__session.ls_conn, LDAP_OPT_ERROR_NUMBER, &lderrno);
4334 if (rc != LDAP_SUCCESS)
4335 return rc;
4336 #else
4337 lderrno = ld->ld_errno;
4338 #endif
4339
4340 if (s != NULL)
4341 {
4342 #if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_STRING)
4343 rc = ldap_get_option (__session.ls_conn, LDAP_OPT_ERROR_STRING, s);
4344 if (rc != LDAP_SUCCESS)
4345 return rc;
4346 #else
4347 *s = ld->ld_error;
4348 #endif
4349 }
4350
4351 if (m != NULL)
4352 {
4353 #if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_MATCHED_DN)
4354 rc = ldap_get_option (__session.ls_conn, LDAP_OPT_MATCHED_DN, m);
4355 if (rc != LDAP_SUCCESS)
4356 return rc;
4357 #else
4358 *m = ld->ld_matched;
4359 #endif
4360 }
4361
4362 return lderrno;
4363 }
4364
4365