1 /*
2 * Copyright (C) 1998-2008 Luke Howard.
3 * This file is part of the pam_ldap library.
4 * Contributed by Luke Howard, <lukeh@padl.com>, 1998.
5 *
6 * The pam_ldap library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
10 *
11 * The pam_ldap library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with the pam_ldap library; see the file COPYING.LIB. If not,
18 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 */
21
22 /*
23 * Portions Copyright Andrew Morgan, 1996. All rights reserved.
24 * Modified by Alexander O. Yuriev
25 *
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
28 * are met:
29 * 1. Redistributions of source code must retain the above copyright
30 * notice, and the entire permission notice in its entirety,
31 * including the disclaimer of warranties.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 3. The name of the author may not be used to endorse or promote
36 * products derived from this software without specific prior
37 * written permission.
38 *
39 * ALTERNATIVELY, this product may be distributed under the terms of
40 * the GNU Public License, in which case the provisions of the GPL are
41 * required INSTEAD OF the above restrictions. (This clause is
42 * necessary due to a potential bad interaction between the GPL and
43 * the restrictions contained in a BSD-style copyright.)
44 *
45 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
46 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
47 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
48 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
49 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
50 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
51 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
53 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
54 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
55 * OF THE POSSIBILITY OF SUCH DAMAGE.
56 *
57 * Portions by Elliot Lee <sopwith@redhat.com>, Red Hat Software.
58 * Copyright (C) 1996.
59 *
60 * Redistribution and use in source and binary forms, with or without
61 * modification, are permitted provided that the following conditions
62 * are met:
63 * 1. Redistributions of source code must retain the above copyright
64 * notice, and the entire permission notice in its entirety,
65 * including the disclaimer of warranties.
66 * 2. Redistributions in binary form must reproduce the above copyright
67 * notice, this list of conditions and the following disclaimer in the
68 * documentation and/or other materials provided with the distribution.
69 * 3. The name of the author may not be used to endorse or promote
70 * products derived from this software without specific prior
71 * written permission.
72 *
73 * ALTERNATIVELY, this product may be distributed under the terms of
74 * the GNU Public License, in which case the provisions of the GPL are
75 * required INSTEAD OF the above restrictions. (This clause is
76 * necessary due to a potential bad interaction between the GPL and
77 * the restrictions contained in a BSD-style copyright.)
78 *
79 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
80 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
81 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
82 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
83 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
84 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
85 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
86 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
87 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
88 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
89 * OF THE POSSIBILITY OF SUCH DAMAGE.
90 */
91
92 #include "config.h"
93
94 #include <stdio.h>
95 #include <stdlib.h>
96 #include <string.h>
97 #include <time.h>
98 #include <sys/time.h>
99 #include <sys/param.h>
100 #include <unistd.h>
101 #include <syslog.h>
102 #include <netdb.h>
103 #include <errno.h>
104
105 #if defined(HAVE_CRYPT_H)
106 #include <crypt.h>
107 #elif defined(HAVE_DES_H)
108 #include <des.h>
109 #endif
110
111 #ifdef HAVE_LBER_H
112 #include <lber.h>
113 #endif
114 #ifdef HAVE_LDAP_H
115 #include <ldap.h>
116 #endif
117 #ifdef HAVE_LDAP_SSL_H
118 #include <ldap_ssl.h>
119 #endif
120 #ifdef HAVE_SASL_SASL_H
121 #include <sasl/sasl.h>
122 #elif defined(HAVE_SASL_H)
123 #include <sasl.h>
124 #endif
125
126 #ifdef YPLDAPD
127 #include <rpcsvc/yp_prot.h>
128 #include <rpcsvc/ypclnt.h>
129 #endif /* YPLDAPD */
130
131 #include "pam_ldap.h"
132 #include "md5.h"
133
134 #define CONST_ARG const
135
136 #ifndef HAVE_LDAP_MEMFREE
137 #define ldap_memfree(x) free(x)
138 #endif
139
140 #ifdef __GNUC__
141 #define __UNUSED__ __attribute__ ((unused))
142 #else
143 #define __UNUSED__
144 #endif
145
146 static char rcsid[] __UNUSED__ =
147 "$Id: pam_ldap.c,v 1.215 2010/11/08 00:58:36 lukeh Exp $";
148 #if LDAP_SET_REBIND_PROC_ARGS < 3
149 static pam_ldap_session_t *global_session = 0;
150 #endif
151 static int pam_debug_level __UNUSED__ = 0;
152
153 #ifdef HAVE_LDAPSSL_INIT
154 static int ssl_initialized = 0;
155 #endif
156
157 #ifdef LBER_OPT_LOG_PRINT_FILE
158 static FILE *debugfile = NULL;
159 #endif
160
161 static const char *policy_error_table[] = {
162 "Password Expired",
163 "Account Locked",
164 "Change After Reset",
165 "Password Modification Not Allowed",
166 "Must Supply Old Password",
167 "Insufficient Password Quality",
168 "Password Too Short",
169 "Password Too Young",
170 "Password Insufficient"
171 };
172
173 #ifdef __GNUC__
174 #define DEBUG_MSG(level, fmt, args...) \
175 do { \
176 if (level >= pam_debug_level) \
177 syslog(LOG_DEBUG, "%s:%i " fmt , __FUNCTION__ , __LINE__ , ## args); \
178 } while (0)
179 #else
180 #define DEBUG_MSG(level, fmt, ...) \
181 do { \
182 if (level >= pam_debug_level) \
183 syslog(LOG_DEBUG, "%s:%i " fmt , __FUNCTION__ , __LINE__ , __VA_ARGS__); \
184 } while (0)
185 #endif /* __GNUC__ */
186
187 static int i64c (int i);
188
189 #ifndef HAVE_LDAP_GET_LDERRNO
190 static int ldap_get_lderrno (LDAP * ld, char **m, char **s);
191 #endif
192 #ifndef HAVE_LDAP_SET_LDERRNO
193 static int ldap_set_lderrno (LDAP * ld, int e, const char *m, const char *s);
194 #endif
195
196 static void _release_config (pam_ldap_config_t ** pconfig);
197 static void _release_user_info (pam_ldap_user_info_t ** info);
198 static void _pam_ldap_cleanup_session (pam_handle_t * pamh, void *data,
199 int error_status);
200 static void _cleanup_data (pam_handle_t * pamh, void *data, int error_status);
201 static void _cleanup_authtok_data (pam_handle_t * pamh, void *data,
202 int error_status);
203 static int _alloc_config (pam_ldap_config_t ** presult);
204 static int _get_password_policy_response_value (struct berval *response_value,
205 pam_ldap_session_t * session);
206 #ifdef YPLDAPD
207 static int _ypldapd_read_config (pam_ldap_config_t ** presult);
208 #endif
209 static int _read_config (const char *configFile,
210 pam_ldap_config_t ** presult);
211 static int _open_session (pam_ldap_session_t * session);
212
213 /* TLS routines */
214 #if defined HAVE_LDAP_START_TLS_S || (defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS))
215 static int _set_ssl_default_options (pam_ldap_session_t *);
216 static int _set_ssl_options (pam_ldap_session_t *);
217 #endif
218
219 static int _connect_anonymously (pam_ldap_session_t * session);
220 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
221 #if LDAP_SET_REBIND_PROC_ARGS == 3
222 static int _rebind_proc (LDAP * ld, LDAP_CONST char *url, ber_tag_t request,
223 ber_int_t msgid, void *arg);
224 #else
225 static int _rebind_proc (LDAP * ld, LDAP_CONST char *url, int request,
226 ber_int_t msgid);
227 #endif
228 #else
229 #if LDAP_SET_REBIND_PROC_ARGS == 3
230 static int _rebind_proc (LDAP * ld,
231 char **whop, char **credp, int *methodp, int freeit,
232 void *arg);
233 #else
234 static int _rebind_proc (LDAP * ld, char **whop, char **credp, int *methodp,
235 int freeit);
236 #endif
237 #endif
238
239 #if (defined(HAVE_SASL_SASL_H) || defined(HAVE_SASL_H)) && defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S)
240 static int _do_sasl_interaction (pam_handle_t *handle, pam_ldap_session_t *session, unsigned flags, sasl_interact_t *interact);
241 static int _do_sasl_interact (LDAP *ld, unsigned flags, void *defaults, void *interact);
242 #endif
243
244 static int _connect_as_user (pam_handle_t *handle,
245 pam_ldap_session_t * session,
246 const char *password);
247 static int _get_integer_value (LDAP * ld, LDAPMessage * e, const char *attr,
248 int *ptr);
249 static int _get_long_integer_value (LDAP * ld, LDAPMessage * e,
250 const char *attr, long int *ptr);
251 static int _get_string_value (LDAP * ld, LDAPMessage * e, const char *attr,
252 char **ptr);
253 static int _get_string_values (LDAP * ld, LDAPMessage * e, const char *attr,
254 char ***ptr);
255 static int _has_deny_value (char **src, const char *tgt);
256 static int _has_value (char **src, const char *tgt);
257 static int _host_ok (pam_ldap_session_t * session);
258 static int _service_ok (pam_handle_t * handle, pam_ldap_session_t * session);
259 static char *_get_md5_salt (char saltbuf[16]);
260 static char *_get_salt (char salt[16]);
261 static int _escape_string (const char *str, char *buf, size_t buflen);
262 static int _get_user_info (pam_ldap_session_t * session, const char *user);
263 static int _pam_ldap_get_session (pam_handle_t * pamh, const char *username,
264 const char *configFile,
265 pam_ldap_session_t ** psession);
266 static int _session_reopen (pam_ldap_session_t * session);
267 static int _get_password_policy (pam_ldap_session_t * session,
268 pam_ldap_password_policy_t * policy);
269 static int _do_authentication (pam_handle_t *pamh, pam_ldap_session_t * session,
270 const char *user, const char *password);
271 static int _update_authtok (pam_handle_t *pamh,
272 pam_ldap_session_t * session,
273 const char *user,
274 const char *old_password,
275 const char *new_password);
276 static int _get_authtok (pam_handle_t * pamh, int flags, int first);
277 static int _conv_sendmsg (struct pam_conv *aconv,
278 const char *message, int style, int no_warn);
279
280 #if defined(HAVE_LIBPTHREAD) || defined(HAVE_LDAPSSL_INIT)
281 #include <dlfcn.h>
282 #endif
283
284 #ifdef HAVE_LIBPTHREAD
285
286 /*
287 * on Linux at least, the pthread library registers an atexit
288 * handler in it's constructor. Since we are in a library and linking with
289 * libpthread, if the client program is not linked with libpthread, it
290 * segfaults on exit. So we open an extra reference to the library.
291 *
292 * If there is a better way of doing this, let us know.
293 */
294 #ifdef __GNUC__
295 void nasty_pthread_hack (void) __attribute__ ((constructor));
296 #else
297 # ifdef __SUNPRO_C
298 # pragma init(nasty_pthread_hack)
299 # endif /* __SUNPRO_C */
300 #endif /* __GNUC__ */
301
302 void
nasty_pthread_hack(void)303 nasty_pthread_hack (void)
304 {
305 (void) dlopen ("libpthread.so", RTLD_LAZY);
306 }
307 #endif /* HAVE_LIBPTHREAD */
308
309 #ifdef HAVE_LDAPSSL_INIT
310 /*
311 * We need to keep ourselves loaded so that ssl_initialized
312 * is set across PAM sessions.
313 */
314 #ifdef __GNUC__
315 void nasty_ssl_hack (void) __attribute__ ((constructor));
316 #else
317 # ifdef __SUNPRO_C
318 # pragma init(nasty_ssl_hack)
319 # endif /* __SUNPRO_C */
320 #endif /* __GNUC__ */
321
322 void
nasty_ssl_hack(void)323 nasty_ssl_hack (void)
324 {
325 (void) dlopen ("/lib/security/pam_ldap.so", RTLD_LAZY);
326 }
327 #endif /* HAVE_LDAPSSL_INIT */
328
329 /* i64c - convert an integer to a radix 64 character */
330 static int
i64c(int i)331 i64c (int i)
332 {
333 const char *base64 =
334 "./01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
335 if (i < 0)
336 i = 0;
337 else if (i > 63)
338 i = 63;
339
340 return base64[i];
341 }
342
343 #ifndef HAVE_LDAP_GET_LDERRNO
344 static int
ldap_get_lderrno(LDAP * ld,char ** m,char ** s)345 ldap_get_lderrno (LDAP * ld, char **m, char **s)
346 {
347 #ifdef HAVE_LDAP_GET_OPTION
348 int rc;
349 #endif
350 int lderrno;
351
352 #if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_NUMBER)
353 /* is this needed? */
354 rc = ldap_get_option (ld, LDAP_OPT_ERROR_NUMBER, &lderrno);
355 if (rc != LDAP_SUCCESS)
356 return rc;
357 #else
358 lderrno = ld->ld_errno;
359 #endif
360
361 if (s != NULL)
362 {
363 #if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_STRING)
364 rc = ldap_get_option (ld, LDAP_OPT_ERROR_STRING, s);
365 if (rc != LDAP_SUCCESS)
366 return rc;
367 #else
368 *s = ld->ld_error;
369 #endif
370 }
371
372 if (m != NULL)
373 {
374 #if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_MATCHED_DN)
375 rc = ldap_get_option (ld, LDAP_OPT_MATCHED_DN, m);
376 if (rc != LDAP_SUCCESS)
377 return rc;
378 #else
379 *m = ld->ld_matched;
380 #endif
381 }
382
383 return lderrno;
384 }
385 #endif
386
387 #ifndef HAVE_LDAP_SET_LDERRNO
388 static int
ldap_set_lderrno(LDAP * ld,int lderrno,const char * m,const char * s)389 ldap_set_lderrno (LDAP * ld, int lderrno, const char *m, const char *s)
390 {
391 #ifdef HAVE_LDAP_SET_OPTION
392 int rc;
393 #endif
394
395 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_ERROR_NUMBER)
396 /* is this needed? */
397 rc = ldap_set_option (ld, LDAP_OPT_ERROR_NUMBER, &lderrno);
398 if (rc != LDAP_SUCCESS)
399 return rc;
400 #else
401 ld->ld_errno = lderrno;
402 #endif
403
404 if (s != NULL)
405 {
406 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_ERROR_STRING)
407 rc = ldap_set_option (ld, LDAP_OPT_ERROR_STRING, s);
408 if (rc != LDAP_SUCCESS)
409 return rc;
410 #else
411 ld->ld_error = s;
412 #endif
413 }
414
415 if (m != NULL)
416 {
417 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_MATCHED_DN)
418 rc = ldap_set_option (ld, LDAP_OPT_MATCHED_DN, m);
419 if (rc != LDAP_SUCCESS)
420 return rc;
421 #else
422 ld->ld_matched = m;
423 #endif
424 }
425
426 return LDAP_SUCCESS;
427 }
428 #endif
429
430 static void
_release_config(pam_ldap_config_t ** pconfig)431 _release_config (pam_ldap_config_t ** pconfig)
432 {
433 pam_ldap_config_t *c;
434
435 c = *pconfig;
436 if (c == NULL)
437 return;
438
439 if (c->configFile != NULL)
440 free (c->configFile);
441
442 if (c->host != NULL)
443 free (c->host);
444
445 if (c->base != NULL)
446 free (c->base);
447
448 if (c->binddn != NULL)
449 free (c->binddn);
450
451 if (c->bindpw != NULL)
452 {
453 _pam_overwrite (c->bindpw);
454 _pam_drop (c->bindpw);
455 }
456
457 if (c->rootbinddn != NULL)
458 free (c->rootbinddn);
459
460 if (c->rootbindpw != NULL)
461 {
462 _pam_overwrite (c->rootbindpw);
463 _pam_drop (c->rootbindpw);
464 }
465
466 if (c->sslpath != NULL)
467 {
468 free (c->sslpath);
469 }
470
471 if (c->userattr != NULL)
472 {
473 free (c->userattr);
474 }
475
476 if (c->tmplattr != NULL)
477 {
478 free (c->tmplattr);
479 }
480
481 if (c->tmpluser != NULL)
482 {
483 free (c->tmpluser);
484 }
485
486 if (c->groupattr != NULL)
487 {
488 free (c->groupattr);
489 }
490
491 if (c->groupdn != NULL)
492 {
493 free (c->groupdn);
494 }
495
496 if (c->filter != NULL)
497 {
498 free (c->filter);
499 }
500
501 if (c->logdir != NULL)
502 {
503 free (c->logdir);
504 }
505
506 if (c->sasl_mechanism != NULL)
507 {
508 free (c->sasl_mechanism);
509 }
510
511 if (c->password_prohibit_message != NULL)
512 {
513 free (c->password_prohibit_message);
514 }
515
516 memset (c, 0, sizeof (*c));
517 free (c);
518 *pconfig = NULL;
519
520 return;
521 }
522
523 static void
_release_user_info(pam_ldap_user_info_t ** info)524 _release_user_info (pam_ldap_user_info_t ** info)
525 {
526 if (*info == NULL)
527 return;
528
529 if ((*info)->userdn != NULL)
530 {
531 ldap_memfree ((void *) (*info)->userdn);
532 }
533
534 /*
535 * Clobber the password.
536 */
537 _pam_overwrite ((*info)->userpw);
538 _pam_drop ((*info)->userpw);
539
540 if ((*info)->hosts_allow != NULL)
541 {
542 ldap_value_free ((*info)->hosts_allow);
543 }
544
545 if ((*info)->services_allow != NULL)
546 {
547 ldap_value_free ((*info)->services_allow);
548 }
549
550 if ((*info)->tmpluser != NULL)
551 {
552 free ((void *) (*info)->tmpluser);
553 }
554
555 free ((void *) (*info)->username);
556 free (*info);
557
558 *info = NULL;
559 return;
560 }
561
562 static void
_pam_ldap_cleanup_session(pam_handle_t * pamh,void * data,int error_status)563 _pam_ldap_cleanup_session (pam_handle_t * pamh, void *data, int error_status)
564 {
565 pam_ldap_session_t *session = (pam_ldap_session_t *) data;
566
567 if (session == NULL)
568 return;
569
570 if (session->ld != NULL)
571 {
572 ldap_unbind (session->ld);
573 session->ld = NULL;
574 }
575
576 _release_config (&session->conf);
577 _release_user_info (&session->info);
578
579 free (data);
580 #if LDAP_SET_REBIND_PROC_ARGS < 3
581 global_session = 0;
582 #endif
583
584 return;
585 }
586
587 static void
_cleanup_data(pam_handle_t * pamh,void * data,int error_status)588 _cleanup_data (pam_handle_t * pamh, void *data, int error_status)
589 {
590 if (data != NULL)
591 free (data);
592
593 return;
594 }
595
596 static void
_cleanup_authtok_data(pam_handle_t * pamh,void * data,int error_status)597 _cleanup_authtok_data (pam_handle_t * pamh, void *data, int error_status)
598 {
599 _pam_overwrite ((char *) data);
600 _pam_drop (data);
601
602 return;
603 }
604
605 static int
_alloc_config(pam_ldap_config_t ** presult)606 _alloc_config (pam_ldap_config_t ** presult)
607 {
608 pam_ldap_config_t *result;
609
610 if (*presult == NULL)
611 {
612 *presult = (pam_ldap_config_t *) calloc (1, sizeof (*result));
613 if (*presult == NULL)
614 return PAM_BUF_ERR;
615 }
616
617 result = *presult;
618
619 result->scope = LDAP_SCOPE_SUBTREE;
620 result->deref = LDAP_DEREF_NEVER;
621 result->configFile = NULL;
622 result->host = NULL;
623 result->base = NULL;
624 result->port = 0;
625 result->binddn = NULL;
626 result->bindpw = NULL;
627 result->rootbinddn = NULL;
628 result->rootbindpw = NULL;
629 result->ssl_on = SSL_OFF;
630 result->sslpath = NULL;
631 result->filter = NULL;
632 result->ssd = NULL;
633 result->userattr = NULL;
634 result->groupattr = NULL;
635 result->groupdn = NULL;
636 result->getpolicy = 0;
637 result->checkhostattr = 0;
638 result->checkserviceattr = 0;
639 #ifdef LDAP_VERSION3
640 result->version = LDAP_VERSION3;
641 #else
642 result->version = LDAP_VERSION2;
643 #endif /* LDAP_VERSION2 */
644 result->timelimit = LDAP_NO_LIMIT;
645 result->bind_timelimit = 10;
646 result->referrals = 1;
647 result->restart = 1;
648 result->password_type = PASSWORD_CLEAR;
649 result->min_uid = 0;
650 result->max_uid = 0;
651 result->tmplattr = NULL;
652 result->tmpluser = NULL;
653 result->tls_checkpeer = -1;
654 result->tls_cacertfile = NULL;
655 result->tls_cacertdir = NULL;
656 result->tls_ciphers = NULL;
657 result->tls_cert = NULL;
658 result->tls_key = NULL;
659 result->tls_randfile = NULL;
660 result->logdir = NULL;
661 result->sasl_mechanism = NULL;
662 result->debug = 0;
663 return PAM_SUCCESS;
664 }
665
666
667 #ifdef YPLDAPD
668 /*
669 * Use the "internal" ypldapd.conf map to figure some things
670 * out.
671 */
672 static int
_ypldapd_read_config(pam_ldap_config_t ** presult)673 _ypldapd_read_config (pam_ldap_config_t ** presult)
674 {
675 pam_ldap_config_t *result;
676 char *domain;
677 int len;
678 char *tmp;
679
680 if (_alloc_config (presult) != PAM_SUCCESS)
681 {
682 return PAM_BUF_ERR;
683 }
684
685 result = *presult;
686
687 yp_get_default_domain (&domain);
688 yp_bind (domain);
689 if (yp_match (domain,
690 "ypldapd.conf",
691 "ldaphost", sizeof ("ldaphost") - 1, &tmp, &len))
692 {
693 return PAM_SERVICE_ERR;
694 }
695
696 result->host = (char *) malloc (len + 1);
697 if (result->host == NULL)
698 return PAM_BUF_ERR;
699
700 memcpy (result->host, tmp, len);
701 result->host[len] = '\0';
702 free (tmp);
703
704 if (yp_match (domain,
705 "ypldapd.conf", "basedn", sizeof ("basedn") - 1, &tmp, &len))
706 {
707 result->base = NULL;
708 }
709 else
710 {
711 result->base = (char *) malloc (len + 1);
712 if (result->base == NULL)
713 return PAM_BUF_ERR;
714 memcpy (result->base, tmp, len);
715 result->base[len] = '\0';
716 free (tmp);
717 }
718
719 if (yp_match (domain,
720 "ypldapd.conf",
721 "ldapport", sizeof ("ldapport") - 1, &tmp, &len))
722 {
723 result->port = LDAP_PORT;
724 }
725 else
726 {
727 char *p = (char *) malloc (len + 1);
728 if (p == NULL)
729 return PAM_BUF_ERR;
730 memcpy (p, tmp, len);
731 result->port = atoi (p);
732 free (tmp);
733 free (p);
734 }
735
736 yp_unbind (domain);
737
738 result->userattr = strdup ("uid");
739 if (result->userattr == NULL)
740 {
741 return PAM_BUF_ERR;
742 }
743
744 /* turn on getting policies */
745 result->getpolicy = 1;
746 #ifdef LDAP_VERSION3
747 result->version = LDAP_VERSION3;
748 #endif
749
750 return PAM_SUCCESS;
751 }
752 #endif /* YPLDAPD */
753
754 #define CHECKPOINTER(ptr) do { if ((ptr) == NULL) { \
755 fclose(fp); \
756 return PAM_BUF_ERR; \
757 } \
758 } while (0)
759
760 static int
_read_config(const char * configFile,pam_ldap_config_t ** presult)761 _read_config (const char *configFile, pam_ldap_config_t ** presult)
762 {
763 /* this is the same configuration file as nss_ldap */
764 FILE *fp;
765 char b[BUFSIZ];
766 pam_ldap_config_t *result;
767
768 if (_alloc_config (presult) != PAM_SUCCESS)
769 {
770 return PAM_BUF_ERR;
771 }
772
773 result = *presult;
774
775 /* configuration file location is configurable; default /etc/ldap.conf */
776 if (configFile == NULL)
777 {
778 configFile = PAM_LDAP_PATH_CONF;
779 result->configFile = NULL;
780 }
781 else
782 {
783 result->configFile = strdup (configFile);
784 if (result->configFile == NULL)
785 return PAM_BUF_ERR;
786 }
787
788 fp = fopen (configFile, "r");
789
790 if (fp == NULL)
791 {
792 /*
793 * According to PAM Documentation, such an error in a config file
794 * SHOULD be logged at LOG_ALERT level
795 */
796 syslog (LOG_ALERT, "pam_ldap: missing file \"%s\"", configFile);
797 return PAM_SERVICE_ERR;
798 }
799
800 result->scope = LDAP_SCOPE_SUBTREE;
801
802 while (fgets (b, sizeof (b), fp) != NULL)
803 {
804 char *k, *v;
805 int len;
806
807 if (*b == '\n' || *b == '#')
808 continue;
809
810 k = b;
811 v = k;
812 while (*v != '\0' && *v != ' ' && *v != '\t')
813 v++;
814
815 if (*v == '\0')
816 continue;
817
818 *(v++) = '\0';
819
820 /* skip all whitespaces between keyword and value */
821 /* Lars Oergel <lars.oergel@innominate.de>, 05.10.2000 */
822 while (*v == ' ' || *v == '\t')
823 v++;
824
825 /* kick off all whitespaces and newline at the end of value */
826 /* Bob Guo <bob@mail.ied.ac.cn>, 08.10.2001 */
827 len = strlen (v) - 1;
828 while (v[len] == ' ' || v[len] == '\t' || v[len] == '\n')
829 --len;
830 v[len + 1] = '\0';
831
832 if (!strcasecmp (k, "host"))
833 {
834 CHECKPOINTER (result->host = strdup (v));
835 }
836 else if (!strcasecmp (k, "uri"))
837 {
838 CHECKPOINTER (result->uri = strdup (v));
839 }
840 else if (!strcasecmp (k, "base"))
841 {
842 CHECKPOINTER (result->base = strdup (v));
843 }
844 else if (!strcasecmp (k, "binddn"))
845 {
846 CHECKPOINTER (result->binddn = strdup (v));
847 }
848 else if (!strcasecmp (k, "bindpw"))
849 {
850 CHECKPOINTER (result->bindpw = strdup (v));
851 }
852 else if (!strcasecmp (k, "rootbinddn"))
853 {
854 CHECKPOINTER (result->rootbinddn = strdup (v));
855 }
856 else if (!strcasecmp (k, "scope"))
857 {
858 if (!strncasecmp (v, "sub", 3))
859 result->scope = LDAP_SCOPE_SUBTREE;
860 else if (!strncasecmp (v, "one", 3))
861 result->scope = LDAP_SCOPE_ONELEVEL;
862 else if (!strncasecmp (v, "base", 4))
863 result->scope = LDAP_SCOPE_BASE;
864 }
865 else if (!strcasecmp (k, "deref"))
866 {
867 if (!strcasecmp (v, "never"))
868 result->deref = LDAP_DEREF_NEVER;
869 else if (!strcasecmp (v, "searching"))
870 result->deref = LDAP_DEREF_SEARCHING;
871 else if (!strcasecmp (v, "finding"))
872 result->deref = LDAP_DEREF_FINDING;
873 else if (!strcasecmp (v, "always"))
874 result->deref = LDAP_DEREF_ALWAYS;
875 }
876 else if (!strcasecmp (k, "pam_password"))
877 {
878 if (!strcasecmp (v, "clear"))
879 result->password_type = PASSWORD_CLEAR;
880 else if (!strcasecmp (v, "crypt"))
881 result->password_type = PASSWORD_CRYPT;
882 else if (!strcasecmp (v, "md5"))
883 result->password_type = PASSWORD_MD5;
884 else if (!strcasecmp (v, "clear_remove_old") || !strcasecmp (v, "nds") || (!strcasecmp (v, "racf")))
885 result->password_type = PASSWORD_CLEAR_REMOVE_OLD;
886 else if (!strcasecmp (v, "ad"))
887 result->password_type = PASSWORD_AD;
888 else if (!strcasecmp (v, "exop"))
889 result->password_type = PASSWORD_EXOP;
890 else if (!strcasecmp (v, "exop_send_old"))
891 result->password_type = PASSWORD_EXOP_SEND_OLD;
892 }
893 else if (!strcasecmp (k, "pam_password_prohibit_message"))
894 {
895 CHECKPOINTER (result->password_prohibit_message = strdup (v));
896 }
897 else if (!strcasecmp (k, "pam_crypt"))
898 {
899 /*
900 * we still support this even though it is
901 * deprecated, as it could be a security
902 * hole to change this behaviour on
903 * unsuspecting users of pam_ldap.
904 */
905 if (!strcasecmp (v, "local"))
906 result->password_type = PASSWORD_CRYPT;
907 else
908 result->password_type = PASSWORD_CLEAR;
909 }
910 else if (!strcasecmp (k, "port"))
911 {
912 result->port = atoi (v);
913 }
914 else if (!strcasecmp (k, "timelimit"))
915 {
916 result->timelimit = atoi (v);
917 }
918 else if (!strcasecmp (k, "bind_timelimit"))
919 {
920 result->bind_timelimit = atoi (v);
921 }
922 else if (!strcasecmp (k, "nss_base_passwd"))
923 {
924 char *s;
925 pam_ssd_t *p, *ssd = calloc (1, sizeof (pam_ssd_t));
926
927 /* this doesn't do any escaping. XXX. */
928 s = strchr (v, '?');
929 if (s != NULL)
930 {
931 len = s - v;
932 if (s[-1] == ',' && result->base)
933 {
934 ssd->base = malloc (len + strlen (result->base) + 1);
935 strncpy (ssd->base, v, len);
936 strcpy (ssd->base + len, result->base);
937 }
938 else
939 {
940 ssd->base = malloc (len + 1);
941 strncpy (ssd->base, v, len);
942 ssd->base[len] = '\0';
943 }
944 s++;
945 if (!strncasecmp (s, "sub", 3))
946 ssd->scope = LDAP_SCOPE_SUBTREE;
947 else if (!strncasecmp (s, "one", 3))
948 ssd->scope = LDAP_SCOPE_ONELEVEL;
949 else if (!strncasecmp (s, "base", 4))
950 ssd->scope = LDAP_SCOPE_BASE;
951 s = strchr (s, '?');
952 if (s != NULL)
953 {
954 s++;
955 CHECKPOINTER (ssd->filter = strdup (s));
956 }
957 }
958 else
959 {
960 ssd->base = strdup (v);
961 ssd->scope = LDAP_SCOPE_SUBTREE;
962 }
963
964 for (p = result->ssd; p && p->next; p = p->next);
965 if (p)
966 {
967 p->next = ssd;
968 }
969 else
970 {
971 result->ssd = ssd;
972 }
973 }
974 else if (!strcasecmp (k, "ldap_version"))
975 {
976 result->version = atoi (v);
977 }
978 else if (!strcasecmp (k, "sslpath"))
979 {
980 CHECKPOINTER (result->sslpath = strdup (v));
981 }
982 else if (!strcasecmp (k, "ssl"))
983 {
984 if (!strcasecmp (v, "on") || !strcasecmp (v, "yes")
985 || !strcasecmp (v, "true"))
986 {
987 result->ssl_on = SSL_LDAPS;
988 }
989 else if (!strcasecmp (v, "start_tls"))
990 {
991 result->ssl_on = SSL_START_TLS;
992 }
993 }
994 else if (!strcasecmp (k, "referrals"))
995 {
996 result->referrals = (!strcasecmp (v, "on") || !strcasecmp (v, "yes")
997 || !strcasecmp (v, "true"));
998 }
999 else if (!strcasecmp (k, "restart"))
1000 {
1001 result->restart = (!strcasecmp (v, "on") || !strcasecmp (v, "yes")
1002 || !strcasecmp (v, "true"));
1003 }
1004 else if (!strcasecmp (k, "pam_filter"))
1005 {
1006 CHECKPOINTER (result->filter = strdup (v));
1007 }
1008 else if (!strcasecmp (k, "pam_login_attribute"))
1009 {
1010 CHECKPOINTER (result->userattr = strdup (v));
1011 }
1012 else if (!strcasecmp (k, "pam_template_login_attribute"))
1013 {
1014 CHECKPOINTER (result->tmplattr = strdup (v));
1015 }
1016 else if (!strcasecmp (k, "pam_template_login"))
1017 {
1018 CHECKPOINTER (result->tmpluser = strdup (v));
1019 }
1020 else if (!strcasecmp (k, "pam_lookup_policy"))
1021 {
1022 result->getpolicy = !strcasecmp (v, "yes");
1023 }
1024 else if (!strcasecmp (k, "pam_check_host_attr"))
1025 {
1026 result->checkhostattr = !strcasecmp (v, "yes");
1027 }
1028 else if (!strcasecmp (k, "pam_check_service_attr"))
1029 {
1030 result->checkserviceattr = !strcasecmp (v, "yes");
1031 }
1032 else if (!strcasecmp (k, "pam_groupdn"))
1033 {
1034 CHECKPOINTER (result->groupdn = strdup (v));
1035 }
1036 else if (!strcasecmp (k, "pam_member_attribute"))
1037 {
1038 CHECKPOINTER (result->groupattr = strdup (v));
1039 }
1040 else if (!strcasecmp (k, "pam_min_uid"))
1041 {
1042 result->min_uid = (uid_t) atol (v);
1043 }
1044 else if (!strcasecmp (k, "pam_max_uid"))
1045 {
1046 result->max_uid = (uid_t) atol (v);
1047 }
1048 else if (!strcasecmp (k, "tls_checkpeer"))
1049 {
1050 if (!strcasecmp (v, "on") || !strcasecmp (v, "yes")
1051 || !strcasecmp (v, "true"))
1052 {
1053 result->tls_checkpeer = 1; /* LDAP_OPT_X_TLS_HARD */
1054 }
1055 else if (!strcasecmp (v, "off") || !strcasecmp (v, "no")
1056 || !strcasecmp (v, "false"))
1057 {
1058 result->tls_checkpeer = 0; /* LDAP_OPT_X_TLS_NEVER */
1059 }
1060 }
1061 else if (!strcasecmp (k, "tls_cacertfile"))
1062 {
1063 CHECKPOINTER (result->tls_cacertfile = strdup (v));
1064 }
1065 else if (!strcasecmp (k, "tls_cacertdir"))
1066 {
1067 CHECKPOINTER (result->tls_cacertdir = strdup (v));
1068 }
1069 else if (!strcasecmp (k, "tls_ciphers"))
1070 {
1071 CHECKPOINTER (result->tls_ciphers = strdup (v));
1072 }
1073 else if (!strcasecmp (k, "tls_cert"))
1074 {
1075 CHECKPOINTER (result->tls_cert = strdup (v));
1076 }
1077 else if (!strcasecmp (k, "tls_key"))
1078 {
1079 CHECKPOINTER (result->tls_key = strdup (v));
1080 }
1081 else if (!strcasecmp (k, "tls_randfile"))
1082 {
1083 CHECKPOINTER (result->tls_randfile = strdup (v));
1084 }
1085 else if (!strcasecmp (k, "logdir"))
1086 {
1087 CHECKPOINTER (result->logdir = strdup (v));
1088 }
1089 else if (!strcasecmp (k, "pam_sasl_mech"))
1090 {
1091 CHECKPOINTER (result->sasl_mechanism = strdup (v));
1092 }
1093 else if (!strcasecmp (k, "debug"))
1094 {
1095 result->debug = atol (v);
1096 }
1097 }
1098
1099 #ifdef HAVE_LDAP_INITIALIZE
1100 if (result->host == NULL && result->uri == NULL)
1101 #else
1102 if (result->host == NULL)
1103 #endif
1104 {
1105 /*
1106 * According to PAM Documentation, such an error in a config file
1107 * SHOULD be logged at LOG_ALERT level
1108 */
1109 syslog (LOG_ALERT, "pam_ldap: missing \"host\" in file \"%s\"",
1110 configFile);
1111 return PAM_SERVICE_ERR;
1112 }
1113
1114 #if !(defined(HAVE_SASL_SASL_H) || defined(HAVE_SASL_H)) && !defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S)
1115 if (result->sasl_mechanism != NULL)
1116 {
1117 syslog (LOG_ERR, "pam_ldap: SASL mechanism \"%s\" requested, "
1118 "but module not built with SASL support", result->sasl_mechanism);
1119 return PAM_SERVICE_ERR;
1120 }
1121 #endif
1122
1123 if (result->userattr == NULL)
1124 {
1125 CHECKPOINTER (result->userattr = strdup ("uid"));
1126 }
1127
1128 if (result->groupattr == NULL)
1129 {
1130 CHECKPOINTER (result->groupattr = strdup ("uniquemember"));
1131 }
1132
1133 if (result->port == 0)
1134 {
1135 #if defined(HAVE_LDAPSSL_INIT) || defined(HAVE_LDAP_START_TLS_S)
1136 if (result->ssl_on == SSL_LDAPS)
1137 {
1138 result->port = LDAPS_PORT;
1139 }
1140 else
1141 #endif
1142 result->port = LDAP_PORT;
1143 }
1144
1145 fclose (fp);
1146
1147 if ((result->rootbinddn != NULL) && (geteuid () == 0))
1148 {
1149 fp = fopen (PAM_LDAP_PATH_ROOTPASSWD, "r");
1150 if (fp != NULL)
1151 {
1152 if (fgets (b, sizeof (b), fp) != NULL)
1153 {
1154 int len;
1155 len = strlen (b);
1156 if (len > 0 && b[len - 1] == '\n')
1157 len--;
1158
1159 b[len] = '\0';
1160 result->rootbindpw = strdup (b);
1161 }
1162 fclose (fp);
1163 }
1164 else
1165 {
1166 _pam_drop (result->rootbinddn);
1167 syslog (LOG_WARNING,
1168 "pam_ldap: could not open secret file %s (%s)",
1169 PAM_LDAP_PATH_ROOTPASSWD, strerror (errno));
1170 }
1171 }
1172
1173 /* can't use _pam_overwrite because it only goes to end of string,
1174 * not the buffer
1175 */
1176 memset (b, 0, BUFSIZ);
1177 return PAM_SUCCESS;
1178 }
1179
1180 static int
_open_session(pam_ldap_session_t * session)1181 _open_session (pam_ldap_session_t * session)
1182 {
1183 #ifdef LDAP_X_OPT_CONNECT_TIMEOUT
1184 int timeout;
1185 #endif
1186 #ifdef LDAP_OPT_NETWORK_TIMEOUT
1187 struct timeval tv;
1188 #endif
1189
1190 #ifdef HAVE_LDAP_SET_OPTION
1191 if (session->conf->debug)
1192 {
1193 #ifdef LBER_OPT_LOG_PRINT_FILE
1194 if (session->conf->logdir && !debugfile)
1195 {
1196 char *name = malloc (strlen (session->conf->logdir) + 18);
1197 if (name)
1198 {
1199 sprintf (name, "%s/ldap.%d", session->conf->logdir,
1200 (int) getpid ());
1201 debugfile = fopen (name, "a");
1202 free (name);
1203 }
1204 if (debugfile)
1205 {
1206 ber_set_option (NULL, LBER_OPT_LOG_PRINT_FILE, debugfile);
1207 }
1208 }
1209 #endif
1210 if (session->conf->debug)
1211 {
1212 #ifdef LBER_OPT_DEBUG_LEVEL
1213 ber_set_option (NULL, LBER_OPT_DEBUG_LEVEL, &session->conf->debug);
1214 #endif /* LBER_OPT_DEBUG_LEVEL */
1215 #ifdef LDAP_OPT_DEBUG_LEVEL
1216 ldap_set_option (NULL, LDAP_OPT_DEBUG_LEVEL, &session->conf->debug);
1217 #endif /* LDAP_OPT_DEBUG_LEVEL */
1218 }
1219 }
1220 #endif /* HAVE_LDAP_SET_OPTION */
1221
1222 #ifdef HAVE_LDAPSSL_INIT
1223 if (session->conf->ssl_on == SSL_LDAPS && ssl_initialized == 0)
1224 {
1225 int rc = ldapssl_client_init (session->conf->sslpath, NULL);
1226 if (rc != LDAP_SUCCESS)
1227 {
1228 syslog (LOG_ERR, "pam_ldap: ldapssl_client_init %s",
1229 ldap_err2string (rc));
1230 return PAM_SERVICE_ERR;
1231 }
1232 ssl_initialized = 1;
1233 }
1234
1235 if (session->conf->ssl_on)
1236 {
1237 session->ld = ldapssl_init (session->conf->host,
1238 session->conf->port, TRUE);
1239 }
1240 else
1241 #endif /* HAVE_LDAPSSL_INIT */
1242 {
1243 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS)
1244 /* set defaults for global TLS-related options */
1245 if (_set_ssl_default_options (session) != LDAP_SUCCESS)
1246 {
1247 syslog (LOG_ERR, "pam_ldap: _set_ssl_default_options failed");
1248 }
1249 #endif
1250 #ifdef HAVE_LDAP_INITIALIZE
1251 if (session->conf->uri != NULL)
1252 {
1253 int rc = ldap_initialize (&session->ld, session->conf->uri);
1254 if (rc != LDAP_SUCCESS)
1255 {
1256 syslog (LOG_ERR, "pam_ldap: ldap_initialize %s",
1257 ldap_err2string (rc));
1258 return PAM_SERVICE_ERR;
1259 }
1260 }
1261 else
1262 {
1263 #endif /* HAVE_LDAP_INTITIALIZE */
1264 #ifdef HAVE_LDAP_INIT
1265 session->ld = ldap_init (session->conf->host, session->conf->port);
1266 #else
1267 session->ld = ldap_open (session->conf->host, session->conf->port);
1268 #endif /* HAVE_LDAP_INIT */
1269 #ifdef HAVE_LDAP_INITIALIZE
1270 }
1271 #endif /* HAVE_LDAP_INTIALIZE */
1272 }
1273
1274 if (session->ld == NULL)
1275 {
1276 return PAM_SERVICE_ERR;
1277 }
1278
1279 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS)
1280 if (session->conf->ssl_on == SSL_LDAPS)
1281 {
1282 int tls = LDAP_OPT_X_TLS_HARD;
1283 int rc = ldap_set_option (session->ld, LDAP_OPT_X_TLS, &tls);
1284 if (rc != LDAP_SUCCESS)
1285 {
1286 syslog (LOG_ERR, "pam_ldap: ldap_set_option(LDAP_OPT_X_TLS) %s",
1287 ldap_err2string (rc));
1288 return PAM_SERVICE_ERR;
1289 }
1290
1291 /* set up SSL per-context settings */
1292 if (_set_ssl_options (session) != LDAP_SUCCESS)
1293 {
1294 syslog (LOG_ERR, "pam_ldap: _set_ssl_options failed");
1295 }
1296 }
1297 #endif /* LDAP_OPT_X_TLS */
1298
1299 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_PROTOCOL_VERSION)
1300 (void) ldap_set_option (session->ld, LDAP_OPT_PROTOCOL_VERSION,
1301 &session->conf->version);
1302 #else
1303 session->ld->ld_version = session->conf->version;
1304 #endif
1305
1306 #if LDAP_SET_REBIND_PROC_ARGS == 3
1307 ldap_set_rebind_proc (session->ld, _rebind_proc, (void *) session);
1308 #elif LDAP_SET_REBIND_PROC_ARGS == 2
1309 ldap_set_rebind_proc (session->ld, _rebind_proc);
1310 #endif
1311
1312 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_DEREF)
1313 (void) ldap_set_option (session->ld, LDAP_OPT_DEREF, &session->conf->deref);
1314 #else
1315 session->ld->ld_deref = session->conf->deref;
1316 #endif
1317
1318 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_TIMELIMIT)
1319 (void) ldap_set_option (session->ld, LDAP_OPT_TIMELIMIT,
1320 &session->conf->timelimit);
1321 #else
1322 session->ld->ld_timelimit = session->conf->timelimit;
1323 #endif
1324
1325
1326 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_X_OPT_CONNECT_TIMEOUT)
1327 /*
1328 * This is a new option in the Netscape SDK which sets
1329 * the TCP connect timeout. For want of a better value,
1330 * we use the bind_timelimit to control this.
1331 */
1332 timeout = session->conf->bind_timelimit * 1000;
1333 (void) ldap_set_option (session->ld, LDAP_X_OPT_CONNECT_TIMEOUT, &timeout);
1334 #endif
1335
1336 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_NETWORK_TIMEOUT)
1337 tv.tv_sec = session->conf->bind_timelimit;
1338 tv.tv_usec = 0;
1339 (void) ldap_set_option (session->ld, LDAP_OPT_NETWORK_TIMEOUT, &tv);
1340 #endif
1341
1342 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_REFERRALS)
1343 (void) ldap_set_option (session->ld, LDAP_OPT_REFERRALS,
1344 session->conf->
1345 referrals ? LDAP_OPT_ON : LDAP_OPT_OFF);
1346 #endif
1347
1348 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_RESTART)
1349 (void) ldap_set_option (session->ld, LDAP_OPT_RESTART,
1350 session->conf->
1351 restart ? LDAP_OPT_ON : LDAP_OPT_OFF);
1352 #endif
1353
1354 #ifdef HAVE_LDAP_START_TLS_S
1355 if (session->conf->ssl_on == SSL_START_TLS)
1356 {
1357 int version, rc;
1358
1359 if (ldap_get_option (session->ld, LDAP_OPT_PROTOCOL_VERSION, &version)
1360 == LDAP_SUCCESS)
1361 {
1362 if (version < LDAP_VERSION3)
1363 {
1364 version = LDAP_VERSION3;
1365 (void) ldap_set_option (session->ld, LDAP_OPT_PROTOCOL_VERSION,
1366 &version);
1367 }
1368
1369 /* set up SSL context */
1370 if (_set_ssl_options (session) != LDAP_SUCCESS)
1371 {
1372 syslog (LOG_ERR, "pam_ldap: _set_ssl_options failed");
1373 }
1374
1375 rc = ldap_start_tls_s (session->ld, NULL, NULL);
1376 if (rc != LDAP_SUCCESS)
1377 {
1378 syslog (LOG_ERR, "pam_ldap: ldap_starttls_s: %s",
1379 ldap_err2string (rc));
1380 return PAM_AUTHINFO_UNAVAIL;
1381 }
1382 }
1383 }
1384 #endif /* HAVE_LDAP_START_TLS_S */
1385 return PAM_SUCCESS;
1386 }
1387
1388 #if defined HAVE_LDAP_START_TLS_S || (defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS))
1389 /* Some global TLS-specific options need to be set before we create our
1390 * session context, so we set them here. */
1391 static int
_set_ssl_default_options(pam_ldap_session_t * session)1392 _set_ssl_default_options (pam_ldap_session_t * session)
1393 {
1394 int rc;
1395
1396 #ifdef LDAP_OPT_X_TLS_RANDOM_FILE
1397 /* rand file */
1398 if (session->conf->tls_randfile != NULL)
1399 {
1400 rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_RANDOM_FILE,
1401 session->conf->tls_randfile);
1402 if (rc != LDAP_SUCCESS)
1403 {
1404 syslog (LOG_ERR,
1405 "pam_ldap: ldap_set_option(LDAP_OPT_X_TLS_RANDOM_FILE): %s",
1406 ldap_err2string (rc));
1407 return LDAP_OPERATIONS_ERROR;
1408 }
1409 }
1410 #endif /* LDAP_OPT_X_TLS_RANDOM_FILE */
1411
1412 /* ca cert file */
1413 if (session->conf->tls_cacertfile != NULL)
1414 {
1415 rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTFILE,
1416 session->conf->tls_cacertfile);
1417 if (rc != LDAP_SUCCESS)
1418 {
1419 syslog (LOG_ERR,
1420 "pam_ldap: ldap_set_option(LDAP_OPT_X_TLS_CACERTFILE): %s",
1421 ldap_err2string (rc));
1422 return LDAP_OPERATIONS_ERROR;
1423 }
1424 }
1425
1426 if (session->conf->tls_cacertdir != NULL)
1427 {
1428 /* ca cert directory */
1429 rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTDIR,
1430 session->conf->tls_cacertdir);
1431 if (rc != LDAP_SUCCESS)
1432 {
1433 syslog (LOG_ERR,
1434 "pam_ldap: ldap_set_option(LDAP_OPT_X_TLS_CACERTDIR): %s",
1435 ldap_err2string (rc));
1436 return LDAP_OPERATIONS_ERROR;
1437 }
1438 }
1439
1440 if (session->conf->tls_checkpeer > -1)
1441 {
1442 /* require cert? */
1443 rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_REQUIRE_CERT,
1444 &session->conf->tls_checkpeer);
1445 if (rc != LDAP_SUCCESS)
1446 {
1447 syslog (LOG_ERR,
1448 "pam_ldap: ldap_set_option(LDAP_OPT_X_TLS_REQUIRE_CERT): %s",
1449 ldap_err2string (rc));
1450 return LDAP_OPERATIONS_ERROR;
1451 }
1452 }
1453
1454 if (session->conf->tls_ciphers != NULL)
1455 {
1456 /* set cipher suite, certificate and private key: */
1457 rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CIPHER_SUITE,
1458 session->conf->tls_ciphers);
1459 if (rc != LDAP_SUCCESS)
1460 {
1461 syslog (LOG_ERR,
1462 "pam_ldap: ldap_set_option(LDAP_OPT_X_TLS_CIPHER_SUITE): %s",
1463 ldap_err2string (rc));
1464 return LDAP_OPERATIONS_ERROR;
1465 }
1466 }
1467
1468 if (session->conf->tls_cert != NULL)
1469 {
1470 rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CERTFILE,
1471 session->conf->tls_cert);
1472 if (rc != LDAP_SUCCESS)
1473 {
1474 syslog (LOG_ERR,
1475 "pam_ldap: ldap_set_option(LDAP_OPT_X_TLS_CERTFILE): %s",
1476 ldap_err2string (rc));
1477 return LDAP_OPERATIONS_ERROR;
1478 }
1479 }
1480
1481 if (session->conf->tls_key != NULL)
1482 {
1483 rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_KEYFILE,
1484 session->conf->tls_key);
1485 if (rc != LDAP_SUCCESS)
1486 {
1487 syslog (LOG_ERR,
1488 "pam_ldap: ldap_set_option(LDAP_OPT_X_TLS_KEYFILE): %s",
1489 ldap_err2string (rc));
1490 return LDAP_OPERATIONS_ERROR;
1491 }
1492 }
1493
1494 return LDAP_SUCCESS;
1495 }
1496
1497 /* Now we can set the per-context TLS-specific options. */
1498 static int
_set_ssl_options(pam_ldap_session_t * session)1499 _set_ssl_options (pam_ldap_session_t * session)
1500 {
1501 return LDAP_SUCCESS;
1502 }
1503 #endif
1504
1505 static int
_connect_anonymously(pam_ldap_session_t * session)1506 _connect_anonymously (pam_ldap_session_t * session)
1507 {
1508 int rc;
1509 int msgid;
1510 struct timeval timeout;
1511 LDAPMessage *result;
1512 int reconnect = 0;
1513
1514 retry:
1515 if (reconnect)
1516 {
1517 if (session->ld != NULL)
1518 {
1519 ldap_unbind (session->ld);
1520 session->ld = NULL;
1521 }
1522 syslog(LOG_ERR, "pam_ldap: reconnecting to LDAP server...");
1523 }
1524 if (session->ld == NULL)
1525 {
1526 rc = _open_session (session);
1527 if (rc != PAM_SUCCESS)
1528 return rc;
1529 }
1530
1531 if (session->conf->rootbinddn && geteuid () == 0)
1532 {
1533 msgid = ldap_simple_bind (session->ld,
1534 session->conf->rootbinddn,
1535 session->conf->rootbindpw);
1536 }
1537 else
1538 {
1539 msgid = ldap_simple_bind (session->ld,
1540 session->conf->binddn, session->conf->bindpw);
1541 }
1542
1543 if (msgid == -1)
1544 {
1545 int ld_errno = ldap_get_lderrno (session->ld, 0, 0);
1546
1547 syslog (LOG_ERR, "pam_ldap: ldap_simple_bind %s",
1548 ldap_err2string (ld_errno));
1549 if (ld_errno == LDAP_SERVER_DOWN && !reconnect)
1550 {
1551 reconnect = 1;
1552 goto retry;
1553 }
1554 return PAM_AUTHINFO_UNAVAIL;
1555 }
1556
1557 timeout.tv_sec = session->conf->bind_timelimit; /* default 10 */
1558 timeout.tv_usec = 0;
1559 rc = ldap_result (session->ld, msgid, FALSE, &timeout, &result);
1560 if (rc == -1 || rc == 0)
1561 {
1562 int ld_errno = ldap_get_lderrno (session->ld, 0, 0);
1563
1564 syslog (LOG_ERR, "pam_ldap: ldap_result %s",
1565 ldap_err2string (ld_errno));
1566 if (ld_errno == LDAP_SERVER_DOWN && !reconnect)
1567 {
1568 reconnect = 1;
1569 goto retry;
1570 }
1571 return PAM_AUTHINFO_UNAVAIL;
1572 }
1573
1574 #ifdef HAVE_LDAP_PARSE_RESULT
1575 ldap_parse_result (session->ld, result, &rc, 0, 0, 0, 0, TRUE);
1576 #else
1577 rc = ldap_result2error (session->ld, result, TRUE);
1578 #endif
1579
1580 if (rc != LDAP_SUCCESS)
1581 {
1582 syslog (LOG_ERR, "pam_ldap: error trying to bind (%s)",
1583 ldap_err2string (rc));
1584 return PAM_CRED_INSUFFICIENT;
1585 }
1586
1587 if (session->info != NULL)
1588 {
1589 session->info->bound_as_user = 0;
1590 }
1591
1592 return PAM_SUCCESS;
1593 }
1594
1595 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
1596 #if LDAP_SET_REBIND_PROC_ARGS == 3
1597 static int
_rebind_proc(LDAP * ld,LDAP_CONST char * url,ber_tag_t request,ber_int_t msgid,void * arg)1598 _rebind_proc (LDAP * ld, LDAP_CONST char *url, ber_tag_t request,
1599 ber_int_t msgid, void *arg)
1600 #else
1601 static int
1602 _rebind_proc (LDAP * ld, LDAP_CONST char *url, int request, ber_int_t msgid)
1603 #endif
1604 {
1605 #if LDAP_SET_REBIND_PROC_ARGS == 3
1606 pam_ldap_session_t *session = (pam_ldap_session_t *) arg;
1607 #else
1608 /* ugly hack */
1609 pam_ldap_session_t *session = global_session;
1610 #endif
1611 char *who, *cred;
1612 struct timeval timeout;
1613 int rc;
1614 #if defined(HAVE_LDAP_PARSE_RESULT) && defined(HAVE_LDAP_CONTROLS_FREE)
1615 int parserc;
1616 LDAPMessage *result;
1617 LDAPControl **controls;
1618 LDAPControl passwd_policy_req;
1619 LDAPControl *srvctrls[2], **psrvctrls = NULL;
1620 struct berval userpw;
1621 #endif /* HAVE_LDAP_PARSE_RESULT && HAVE_LDAP_CONTROLS_FREE */
1622
1623 if (session->info != NULL && session->info->bound_as_user == 1)
1624 {
1625 who = session->info->userdn;
1626 cred = session->info->userpw;
1627 }
1628 else
1629 {
1630 if (session->conf->rootbinddn != NULL && geteuid () == 0)
1631 {
1632 who = session->conf->rootbinddn;
1633 cred = session->conf->rootbindpw;
1634 }
1635 else
1636 {
1637 who = session->conf->binddn;
1638 cred = session->conf->bindpw;
1639 }
1640 }
1641
1642 if (session->conf->ssl_on == SSL_START_TLS)
1643 {
1644 rc = ldap_start_tls_s (session->ld, NULL, NULL);
1645 if (rc != LDAP_SUCCESS)
1646 {
1647 syslog (LOG_ERR, "pam_ldap: ldap_starttls_s: %s",
1648 ldap_err2string (rc));
1649 return LDAP_OPERATIONS_ERROR;
1650 }
1651 }
1652
1653 #if !defined(HAVE_LDAP_PARSE_RESULT) || !defined(HAVE_LDAP_CONTROLS_FREE)
1654 return ldap_simple_bind_s (ld, who, cred);
1655 #else
1656 #if !defined(HAVE_LDAP_SASL_BIND) || !defined(LDAP_SASL_SIMPLE)
1657 msgid = ldap_simple_bind (ld, who, cred);
1658 #else
1659 if (session->conf->getpolicy)
1660 {
1661 passwd_policy_req.ldctl_oid = LDAP_CONTROL_PASSWORDPOLICYREQUEST;
1662 passwd_policy_req.ldctl_value.bv_val = 0; /* none */
1663 passwd_policy_req.ldctl_value.bv_len = 0;
1664 passwd_policy_req.ldctl_iscritical = 0; /* not critical */
1665 srvctrls[0] = &passwd_policy_req;
1666 srvctrls[1] = 0;
1667
1668 psrvctrls = srvctrls;
1669 }
1670 userpw.bv_val = cred;
1671 userpw.bv_len = (userpw.bv_val != 0) ? strlen (userpw.bv_val) : 0;
1672
1673 rc =
1674 ldap_sasl_bind (session->ld, who, LDAP_SASL_SIMPLE,
1675 &userpw, psrvctrls, 0, &msgid);
1676 if (rc != LDAP_SUCCESS )
1677 {
1678 return rc;
1679 }
1680 #endif
1681 if (msgid == -1)
1682 {
1683 syslog (LOG_ERR, "pam_ldap: ldap_simple_bind %s",
1684 ldap_err2string (ldap_get_lderrno (ld, 0, 0)));
1685 return LDAP_OPERATIONS_ERROR;
1686 }
1687
1688 timeout.tv_sec = session->conf->bind_timelimit;
1689 timeout.tv_usec = 0;
1690 result = NULL;
1691 rc = ldap_result (ld, msgid, FALSE, &timeout, &result);
1692 if (rc == -1 || rc == 0)
1693 {
1694 syslog (LOG_ERR, "pam_ldap: ldap_result %s",
1695 ldap_err2string (ldap_get_lderrno (ld, 0, 0)));
1696 ldap_msgfree (result);
1697 return LDAP_OPERATIONS_ERROR;
1698 }
1699
1700 controls = NULL;
1701 parserc = ldap_parse_result (ld, result, &rc, 0, 0, 0, &controls, TRUE);
1702 if (parserc != LDAP_SUCCESS)
1703 {
1704 syslog (LOG_ERR, "pam_ldap: ldap_parse_result %s",
1705 ldap_err2string (parserc));
1706 _pam_overwrite (session->info->userpw);
1707 _pam_drop (session->info->userpw);
1708 return PAM_SERVICE_ERR;
1709 }
1710 if (controls != NULL)
1711 {
1712 LDAPControl **ctlp;
1713 for (ctlp = controls; *ctlp != NULL; ctlp++)
1714 {
1715 if (!strcmp ((*ctlp)->ldctl_oid, LDAP_CONTROL_PWEXPIRED))
1716 {
1717 if (session->info->policy_error == POLICY_ERROR_SUCCESS)
1718 session->info->policy_error = POLICY_ERROR_PASSWORD_EXPIRED;
1719 }
1720 else if (!strcmp ((*ctlp)->ldctl_oid, LDAP_CONTROL_PASSWORDPOLICYRESPONSE))
1721 _get_password_policy_response_value (&(*ctlp)->ldctl_value,
1722 session);
1723 }
1724 ldap_controls_free (controls);
1725 /* suppress a failure due to password expiration or needs-changing if we
1726 * appear to be in the middle of changing a password */
1727 switch (request)
1728 {
1729 case LDAP_REQ_MODIFY:
1730 case LDAP_REQ_EXTENDED:
1731 switch (session->info->policy_error)
1732 {
1733 case POLICY_ERROR_PASSWORD_EXPIRED:
1734 case POLICY_ERROR_CHANGE_AFTER_RESET:
1735 rc = LDAP_SUCCESS;
1736 break;
1737 default:
1738 break;
1739 }
1740 default:
1741 break;
1742 }
1743 }
1744 return rc;
1745 #endif
1746 }
1747 #else
1748 #if LDAP_SET_REBIND_PROC_ARGS == 3
1749 static int
_rebind_proc(LDAP * ld,char ** whop,char ** credp,int * methodp,int freeit,void * arg)1750 _rebind_proc (LDAP * ld,
1751 char **whop, char **credp, int *methodp, int freeit, void *arg)
1752 #else
1753 static int
1754 _rebind_proc (LDAP * ld, char **whop, char **credp, int *methodp, int freeit)
1755 #endif
1756 {
1757 #if LDAP_SET_REBIND_PROC_ARGS == 3
1758 pam_ldap_session_t *session = (pam_ldap_session_t *) arg;
1759 #else
1760 /* ugly hack */
1761 pam_ldap_session_t *session = global_session;
1762 #endif
1763
1764 if (freeit)
1765 {
1766 _pam_drop (*whop);
1767 _pam_overwrite (*credp);
1768 _pam_drop (*credp);
1769 return LDAP_SUCCESS;
1770 }
1771
1772 if (session->info != NULL && session->info->bound_as_user == 1)
1773 {
1774 /*
1775 * We're authenticating as a user.
1776 */
1777 *whop = strdup (session->info->userdn);
1778 *credp = strdup (session->info->userpw);
1779 }
1780 else
1781 {
1782 if (session->conf->rootbinddn != NULL && geteuid () == 0)
1783 {
1784 *whop = strdup (session->conf->rootbinddn);
1785 *credp = session->conf->rootbindpw != NULL ?
1786 strdup (session->conf->rootbindpw) : NULL;
1787 }
1788 else
1789 {
1790 *whop = session->conf->binddn != NULL ?
1791 strdup (session->conf->binddn) : NULL;
1792 *credp = session->conf->bindpw != NULL ?
1793 strdup (session->conf->bindpw) : NULL;
1794 }
1795 }
1796
1797 *methodp = LDAP_AUTH_SIMPLE;
1798
1799 return LDAP_SUCCESS;
1800 }
1801 #endif
1802
1803 /*
1804 * See Internet Draft "Password Policy for LDAP Directories".
1805 * draft-behera-ldap-password-policy-07.txt
1806 */
1807 static int
_get_password_policy_response_value(struct berval * response_value,pam_ldap_session_t * session)1808 _get_password_policy_response_value (struct berval *response_value,
1809 pam_ldap_session_t * session)
1810 {
1811 char *opaque;
1812 BerElement *ber;
1813 unsigned long tag;
1814 unsigned long len;
1815 int rc = LDAP_SUCCESS;
1816
1817 if (!response_value || !session)
1818 return LDAP_PARAM_ERROR;
1819
1820 /* create a BerElement from the berval returned in the control */
1821 ber = ber_init (response_value);
1822 if (ber == NULL)
1823 return LDAP_LOCAL_ERROR;
1824
1825 /* parse the PasswordPolicyResponseValue */
1826 for (tag = ber_first_element (ber, &len, &opaque);
1827 tag != LBER_DEFAULT; tag = ber_next_element (ber, &len, opaque))
1828 {
1829 unsigned long ttag;
1830 int error;
1831 int value;
1832
1833 if (tag == 160) /* warning [0] CHOICE { ... } */
1834 {
1835 if (ber_skip_tag (ber, &len) == 160)
1836 {
1837 ttag = ber_peek_tag (ber, &len);
1838 switch (ttag)
1839 {
1840 case POLICY_WARN_TIME_BEFORE_EXPIRATION:
1841 case POLICY_WARN_GRACE_LOGINS_REMAINING:
1842 if (ber_scanf (ber, "i", &value) != LBER_ERROR)
1843 {
1844 if (ttag == POLICY_WARN_TIME_BEFORE_EXPIRATION)
1845 session->info->password_expiration_time = value;
1846 else
1847 session->info->grace_logins_remaining = value;
1848 continue;
1849 }
1850 }
1851 }
1852 }
1853 else if (tag == 129) /* error [1] ENUMERATED { ... } */
1854 {
1855 ttag = ber_scanf (ber, "e", &error);
1856 if (ttag != LBER_ERROR)
1857 {
1858 if (session->info->policy_error == POLICY_ERROR_SUCCESS)
1859 session->info->policy_error = error;
1860 continue;
1861 }
1862 }
1863 rc = LDAP_DECODING_ERROR;
1864 break;
1865 }
1866
1867 ber_free (ber, 1);
1868 return rc;
1869 }
1870
1871 #if (defined(HAVE_SASL_SASL_H) || defined(HAVE_SASL_H)) && defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S)
1872 /*
1873 * Assign a single value as a result of a SASL interaction
1874 */
1875 static int
_do_sasl_assign_cb(sasl_interact_t * interact,const char * dflt)1876 _do_sasl_assign_cb (sasl_interact_t *interact, const char *dflt)
1877 {
1878 const char *result;
1879
1880 if (dflt != NULL)
1881 result = dflt;
1882 else if (interact->defresult != NULL)
1883 result = interact->defresult;
1884 else
1885 result = "";
1886
1887 #if SASL_VERSION_MAJOR < 2
1888 interact->result = strdup (result);
1889 if (interact->result == NULL)
1890 {
1891 return LDAP_NO_MEMORY;
1892 }
1893 #else
1894 interact->result = result;
1895 #endif
1896
1897 interact->len = strlen(interact->result);
1898
1899 return LDAP_SUCCESS;
1900 }
1901
1902 /*
1903 * Provide a value to the SASL layer based on pam_ldap defaults or
1904 * interaction with the user via the application-supplied conversation
1905 * function
1906 */
1907 static int
_do_sasl_interaction(pam_handle_t * pamh,pam_ldap_session_t * session,unsigned flags,sasl_interact_t * interact)1908 _do_sasl_interaction (pam_handle_t *pamh, pam_ldap_session_t *session,
1909 unsigned flags, sasl_interact_t *interact)
1910 {
1911 int rc;
1912 const char *dflt = NULL;
1913
1914 switch (interact->id)
1915 {
1916 case SASL_CB_AUTHNAME:
1917 dflt = session->info->username;
1918 break;
1919 case SASL_CB_PASS:
1920 dflt = session->info->userpw;
1921 break;
1922 default:
1923 dflt = NULL;
1924 break;
1925 }
1926
1927 if (dflt != NULL && dflt[0] == '\0')
1928 dflt = NULL;
1929
1930 if (dflt == NULL &&
1931 #ifdef LDAP_SASL_QUIET
1932 flags != LDAP_SASL_QUIET &&
1933 #endif
1934 (interact->id == SASL_CB_ECHOPROMPT || interact->id == SASL_CB_NOECHOPROMPT))
1935 {
1936 struct pam_message *pmsg[2];
1937 struct pam_message challenge_msg;
1938 struct pam_message prompt_msg;
1939 struct pam_response *resp = NULL;
1940 struct pam_conv *conv;
1941 int i = 0;
1942
1943 if (interact->challenge != NULL)
1944 {
1945 challenge_msg.msg_style = PAM_TEXT_INFO;
1946 challenge_msg.msg = (char *)interact->challenge;
1947 pmsg[i++] = &challenge_msg;
1948 }
1949
1950 prompt_msg.msg_style = (interact->id == SASL_CB_ECHOPROMPT) ?
1951 PAM_PROMPT_ECHO_ON : PAM_PROMPT_ECHO_OFF;
1952 prompt_msg.msg = (interact->prompt != NULL) ? (char *)interact->prompt : "Enter SASL response: ";
1953 pmsg[i++] = &prompt_msg;
1954
1955 rc = pam_get_item(pamh, PAM_CONV, (CONST_ARG void **)&conv);
1956 if (rc != PAM_SUCCESS)
1957 return LDAP_OTHER;
1958
1959 rc = conv->conv (i,
1960 (CONST_ARG struct pam_message **)pmsg,
1961 &resp, conv->appdata_ptr);
1962 if (rc != PAM_SUCCESS || resp == NULL)
1963 return LDAP_OTHER;
1964
1965 /* XXX leaks with SASL v2 */
1966 dflt = resp->resp;
1967 free (resp);
1968 }
1969
1970 rc = _do_sasl_assign_cb (interact, dflt);
1971
1972 return rc;
1973 }
1974
1975 static int
_do_sasl_interact(LDAP * ld,unsigned flags,void * defaults,void * _interact)1976 _do_sasl_interact (LDAP *ld, unsigned flags, void *defaults, void *_interact)
1977 {
1978 sasl_interact_t *interact = (sasl_interact_t *)_interact;
1979 void **args = (void **)defaults;
1980 int rc;
1981
1982 while (interact->id != SASL_CB_LIST_END)
1983 {
1984 rc = _do_sasl_interaction((pam_handle_t *)args[0], (pam_ldap_session_t *)args[1], flags, interact);
1985 if (rc != LDAP_SUCCESS)
1986 return rc;
1987
1988 interact++;
1989 }
1990
1991 return LDAP_SUCCESS;
1992 }
1993 #endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */
1994
1995
1996 static int
_connect_as_user(pam_handle_t * pamh,pam_ldap_session_t * session,const char * password)1997 _connect_as_user (pam_handle_t * pamh, pam_ldap_session_t * session, const char *password)
1998 {
1999 int rc, msgid;
2000 struct timeval timeout;
2001 #if defined(HAVE_LDAP_PARSE_RESULT) && defined(HAVE_LDAP_CONTROLS_FREE)
2002 int parserc;
2003 LDAPMessage *result;
2004 LDAPControl **controls;
2005 LDAPControl passwd_policy_req;
2006 LDAPControl *srvctrls[2], **psrvctrls = NULL;
2007 struct berval userpw;
2008 int reconnect = 0;
2009 #endif /* HAVE_LDAP_PARSE_RESULT && HAVE_LDAP_CONTROLS_FREE */
2010
2011 /* avoid binding anonymously with a DN but no password */
2012 if (password == NULL || password[0] == '\0')
2013 return PAM_AUTH_ERR;
2014
2015 /* this shouldn't ever happen */
2016 if (session->info == NULL)
2017 return PAM_SYSTEM_ERR;
2018
2019 /* if we already bound as the user don't bother retrying */
2020 if (session->info->bound_as_user)
2021 return PAM_SUCCESS;
2022
2023 retry:
2024 if (reconnect)
2025 {
2026 if (session->ld != NULL)
2027 {
2028 ldap_unbind (session->ld);
2029 session->ld = NULL;
2030 }
2031 session->info->bound_as_user = 0;
2032 syslog(LOG_INFO, "pam_ldap: reconnecting to LDAP server...");
2033 }
2034
2035 if (session->ld == NULL)
2036 {
2037 rc = _open_session (session);
2038 if (rc != PAM_SUCCESS)
2039 return rc;
2040 }
2041
2042 /*
2043 * We copy the password temporarily so that when referrals are
2044 * chased, the correct credentials are set by the rebind
2045 * procedure.
2046 */
2047 if (session->info->userpw != NULL)
2048 {
2049 _pam_overwrite (session->info->userpw);
2050 _pam_drop (session->info->userpw);
2051 }
2052
2053 session->info->userpw = strdup (password);
2054 if (session->info->userpw == NULL)
2055 return PAM_BUF_ERR;
2056
2057 #if defined(HAVE_LDAP_PARSE_RESULT) && defined(HAVE_LDAP_CONTROLS_FREE)
2058 if (session->conf->getpolicy)
2059 {
2060 passwd_policy_req.ldctl_oid = LDAP_CONTROL_PASSWORDPOLICYREQUEST;
2061 passwd_policy_req.ldctl_value.bv_val = 0; /* none */
2062 passwd_policy_req.ldctl_value.bv_len = 0;
2063 passwd_policy_req.ldctl_iscritical = 0; /* not critical */
2064 srvctrls[0] = &passwd_policy_req;
2065 srvctrls[1] = 0;
2066
2067 psrvctrls = srvctrls;
2068 }
2069 #endif
2070
2071 #if (defined(HAVE_SASL_SASL_H) || defined(HAVE_SASL_H)) && defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S)
2072 if (session->conf->sasl_mechanism != NULL)
2073 {
2074 void *args[] = { pamh, session };
2075
2076 /*
2077 * XXX this API is broken - how can we extract the password policy
2078 * controls? do we need to implement DIGEST-MD5 ourself?
2079 */
2080 rc = ldap_sasl_interactive_bind_s (session->ld, session->info->userdn,
2081 session->conf->sasl_mechanism,
2082 psrvctrls, NULL,
2083 #ifdef LDAP_SASL_AUTOMATIC
2084 LDAP_SASL_AUTOMATIC,
2085 #else
2086 0,
2087 #endif
2088 _do_sasl_interact, &args);
2089 if (rc != LDAP_SUCCESS)
2090 {
2091 int ld_errno = ldap_get_lderrno (session->ld, 0, 0);
2092
2093 syslog (LOG_ERR, "pam_ldap: ldap_sasl_interactive_bind %s",
2094 ldap_err2string (ld_errno));
2095 if (ld_errno == LDAP_SERVER_DOWN && !reconnect)
2096 {
2097 reconnect = 1;
2098 goto retry;
2099 }
2100 _pam_overwrite (session->info->userpw);
2101 _pam_drop (session->info->userpw);
2102 return PAM_AUTHINFO_UNAVAIL;
2103 }
2104 session->info->bound_as_user = 1;
2105 return PAM_SUCCESS;
2106 }
2107 #endif
2108 #if defined(HAVE_LDAP_SASL_BIND) && defined(LDAP_SASL_SIMPLE)
2109 if (session->conf->version > LDAP_VERSION2)
2110 {
2111 userpw.bv_val = session->info->userpw;
2112 userpw.bv_len = (userpw.bv_val != 0) ? strlen (userpw.bv_val) : 0;
2113
2114 rc =
2115 ldap_sasl_bind (session->ld, session->info->userdn, LDAP_SASL_SIMPLE,
2116 &userpw, psrvctrls, 0, &msgid);
2117 if (rc != LDAP_SUCCESS || msgid == -1)
2118 {
2119 int ld_errno = ldap_get_lderrno (session->ld, 0, 0);
2120
2121 syslog (LOG_ERR, "pam_ldap: ldap_sasl_bind %s",
2122 ldap_err2string (ld_errno));
2123 if (ld_errno == LDAP_SERVER_DOWN && !reconnect)
2124 {
2125 reconnect = 1;
2126 goto retry;
2127 }
2128 _pam_overwrite (session->info->userpw);
2129 _pam_drop (session->info->userpw);
2130 return PAM_AUTHINFO_UNAVAIL;
2131 }
2132 }
2133 else
2134 {
2135 msgid = ldap_simple_bind (session->ld, session->info->userdn,
2136 session->info->userpw);
2137 if (msgid == -1)
2138 {
2139 int ld_errno = ldap_get_lderrno (session->ld, 0, 0);
2140
2141 syslog (LOG_ERR, "pam_ldap: ldap_simple_bind %s",
2142 ldap_err2string (ld_errno));
2143 if (ld_errno == LDAP_SERVER_DOWN && !reconnect)
2144 {
2145 reconnect = 1;
2146 goto retry;
2147 }
2148 _pam_overwrite (session->info->userpw);
2149 _pam_drop (session->info->userpw);
2150 return PAM_AUTHINFO_UNAVAIL;
2151 }
2152 }
2153 #else
2154 msgid =
2155 ldap_simple_bind (session->ld, session->info->userdn,
2156 session->info->userpw);
2157 if (msgid == -1)
2158 {
2159 int ld_errno = ldap_get_lderrno (session->ld, 0, 0);
2160
2161
2162
2163
2164 syslog (LOG_ERR, "pam_ldap: ldap_simple_bind %s",
2165 ldap_err2string (ld_errno));
2166 if (ld_errno == LDAP_SERVER_DOWN && !reconnect)
2167 {
2168 reconnect = 1;
2169 goto retry;
2170 }
2171 _pam_overwrite (session->info->userpw);
2172 _pam_drop (session->info->userpw);
2173 return PAM_AUTHINFO_UNAVAIL;
2174 }
2175 #endif /* HAVE_LDAP_SASL_BIND && LDAP_SASL_SIMPLE */
2176
2177 timeout.tv_sec = 10;
2178 timeout.tv_usec = 0;
2179 rc = ldap_result (session->ld, msgid, FALSE, &timeout, &result);
2180 if (rc == -1 || rc == 0)
2181 {
2182 int ld_errno = ldap_get_lderrno (session->ld, 0, 0);
2183
2184 syslog (LOG_ERR, "pam_ldap: ldap_result %s",
2185 ldap_err2string (ld_errno));
2186 if (ld_errno == LDAP_SERVER_DOWN && !reconnect)
2187 {
2188 reconnect = 1;
2189 goto retry;
2190 }
2191 _pam_overwrite (session->info->userpw);
2192 _pam_drop (session->info->userpw);
2193 return PAM_AUTHINFO_UNAVAIL;
2194 }
2195
2196 #if defined(HAVE_LDAP_PARSE_RESULT) && defined(HAVE_LDAP_CONTROLS_FREE)
2197 controls = 0;
2198 parserc =
2199 ldap_parse_result (session->ld, result, &rc, 0, 0, 0, &controls, TRUE);
2200 if (parserc != LDAP_SUCCESS)
2201 {
2202 syslog (LOG_ERR, "pam_ldap: ldap_parse_result %s",
2203 ldap_err2string (parserc));
2204 _pam_overwrite (session->info->userpw);
2205 _pam_drop (session->info->userpw);
2206 return PAM_SERVICE_ERR;
2207 }
2208 if (controls != NULL)
2209 {
2210 LDAPControl **ctlp;
2211 for (ctlp = controls; *ctlp != NULL; ctlp++)
2212 {
2213 if (!strcmp ((*ctlp)->ldctl_oid, LDAP_CONTROL_PWEXPIRING))
2214 {
2215 char seconds[32];
2216 snprintf (seconds, sizeof seconds, "%.*s",
2217 (int) (*ctlp)->ldctl_value.bv_len,
2218 (*ctlp)->ldctl_value.bv_val);
2219 session->info->password_expiration_time = atol (seconds);
2220 }
2221 else if (!strcmp ((*ctlp)->ldctl_oid, LDAP_CONTROL_PWEXPIRED))
2222 {
2223 if (session->info->policy_error == POLICY_ERROR_SUCCESS)
2224 session->info->policy_error = POLICY_ERROR_PASSWORD_EXPIRED;
2225 rc = LDAP_SUCCESS;
2226 /* That may be a lie, but we need to get to the acct_mgmt
2227 * step and force the change...
2228 */
2229 }
2230 else if (!strcmp ((*ctlp)->ldctl_oid, LDAP_CONTROL_PASSWORDPOLICYRESPONSE))
2231 {
2232 int rc2;
2233
2234 rc2 = _get_password_policy_response_value (&(*ctlp)->ldctl_value,
2235 session);
2236
2237 if (rc2 != LDAP_SUCCESS)
2238 {
2239 /*
2240 * If decoding policy control failed, and we're not already
2241 * planning to report an error, return the decoding error.
2242 */
2243 if (rc == LDAP_SUCCESS)
2244 {
2245 rc = rc2;
2246 }
2247 }
2248 else
2249 {
2250 /*
2251 * If we have a policy error, and it's one which the PAM spec
2252 * expects us to communicate via the acct_mgmt callback,
2253 * then we suppress the error. If it's a different kind of
2254 * policy error, then make sure we indicate the error now.
2255 */
2256 switch (session->info->policy_error)
2257 {
2258 case POLICY_ERROR_SUCCESS:
2259 break;
2260 case POLICY_ERROR_CHANGE_AFTER_RESET:
2261 case POLICY_ERROR_PASSWORD_EXPIRED:
2262 rc = LDAP_SUCCESS;
2263 break;
2264 case POLICY_ERROR_ACCOUNT_LOCKED:
2265 case POLICY_ERROR_PASSWORD_MOD_NOT_ALLOWED:
2266 case POLICY_ERROR_MUST_SUPPLY_OLD_PASSWORD:
2267 case POLICY_ERROR_INSUFFICIENT_PASSWORD_QUALITY:
2268 case POLICY_ERROR_PASSWORD_TOO_SHORT:
2269 case POLICY_ERROR_PASSWORD_TOO_YOUNG:
2270 case POLICY_ERROR_PASSWORD_INSUFFICIENT:
2271 default:
2272 ldap_controls_free (controls);
2273 _pam_overwrite (session->info->userpw);
2274 _pam_drop (session->info->userpw);
2275 return PAM_AUTH_ERR;
2276 break;
2277 }
2278 }
2279 }
2280 }
2281 ldap_controls_free (controls);
2282 }
2283 #else
2284 rc = ldap_result2error (session->ld, result, TRUE);
2285 #endif
2286
2287 if (rc != LDAP_SUCCESS)
2288 {
2289 syslog (LOG_ERR, "pam_ldap: error trying to bind as user \"%s\" (%s)",
2290 session->info->userdn, ldap_err2string (rc));
2291 _pam_overwrite (session->info->userpw);
2292 _pam_drop (session->info->userpw);
2293 return PAM_AUTH_ERR;
2294 }
2295
2296 /* check if we need to unset userpw */
2297 switch (session->info->policy_error)
2298 {
2299 case POLICY_ERROR_SUCCESS:
2300 case POLICY_ERROR_PASSWORD_EXPIRED:
2301 case POLICY_ERROR_CHANGE_AFTER_RESET:
2302 break;
2303 default:
2304 _pam_overwrite (session->info->userpw);
2305 _pam_drop (session->info->userpw);
2306 break;
2307 }
2308 /* else userpw is now set. Be sure to clobber it later. */
2309
2310 session->info->bound_as_user = 1;
2311
2312 return PAM_SUCCESS;
2313 }
2314
2315 static int
_get_integer_value(LDAP * ld,LDAPMessage * e,const char * attr,int * ptr)2316 _get_integer_value (LDAP * ld, LDAPMessage * e, const char *attr, int *ptr)
2317 {
2318 char **vals;
2319
2320 vals = ldap_get_values (ld, e, (char *) attr);
2321 if (vals == NULL)
2322 {
2323 return PAM_AUTHINFO_UNAVAIL;
2324 }
2325 *ptr = atoi (vals[0]);
2326 ldap_value_free (vals);
2327
2328 return PAM_SUCCESS;
2329 }
2330
2331 static int
_get_long_integer_value(LDAP * ld,LDAPMessage * e,const char * attr,long int * ptr)2332 _get_long_integer_value (LDAP * ld, LDAPMessage * e, const char *attr,
2333 long int *ptr)
2334 {
2335 char **vals;
2336
2337 vals = ldap_get_values (ld, e, (char *) attr);
2338 if (vals == NULL)
2339 {
2340 return PAM_AUTHINFO_UNAVAIL;
2341 }
2342 *ptr = atol (vals[0]);
2343 ldap_value_free (vals);
2344
2345 return PAM_SUCCESS;
2346 }
2347
2348
2349 #ifdef notdef
2350 static int
_oc_check(LDAP * ld,LDAPMessage * e,const char * oc)2351 _oc_check (LDAP * ld, LDAPMessage * e, const char *oc)
2352 {
2353 char **vals, **p;
2354 int rc = 0;
2355
2356 vals = ldap_get_values (ld, e, "objectClass");
2357 if (vals == NULL)
2358 {
2359 return PAM_AUTHINFO_UNAVAIL;
2360 }
2361
2362 for (p = vals; *p != NULL; p++)
2363 {
2364 if (!strcasecmp (*p, oc))
2365 {
2366 rc = 1;
2367 break;
2368 }
2369 }
2370
2371 ldap_value_free (vals);
2372
2373 return rc;
2374 }
2375 #endif /* notdef */
2376
2377 static int
_get_string_value(LDAP * ld,LDAPMessage * e,const char * attr,char ** ptr)2378 _get_string_value (LDAP * ld, LDAPMessage * e, const char *attr, char **ptr)
2379 {
2380 char **vals;
2381 int rc;
2382
2383 vals = ldap_get_values (ld, e, (char *) attr);
2384 if (vals == NULL)
2385 {
2386 return PAM_AUTHINFO_UNAVAIL;
2387 }
2388 *ptr = strdup (vals[0]);
2389 if (*ptr == NULL)
2390 {
2391 rc = PAM_BUF_ERR;
2392 }
2393 else
2394 {
2395 rc = PAM_SUCCESS;
2396 }
2397
2398 ldap_value_free (vals);
2399
2400 return rc;
2401 }
2402
2403 static int
_get_string_values(LDAP * ld,LDAPMessage * e,const char * attr,char *** ptr)2404 _get_string_values (LDAP * ld, LDAPMessage * e, const char *attr, char ***ptr)
2405 {
2406 char **vals;
2407
2408 vals = ldap_get_values (ld, e, (char *) attr);
2409 if (vals == NULL)
2410 {
2411 return PAM_AUTHINFO_UNAVAIL;
2412 }
2413 *ptr = vals;
2414
2415 return PAM_SUCCESS;
2416 }
2417
2418 static int
_has_deny_value(char ** src,const char * tgt)2419 _has_deny_value (char **src, const char *tgt)
2420 {
2421
2422 char **p;
2423
2424 for (p = src; *p != NULL; p++)
2425 {
2426 if (**p == '!' && !strcasecmp (*p + 1, tgt))
2427 {
2428 return 1;
2429 }
2430 }
2431
2432 return 0;
2433 }
2434
2435 static int
_has_value(char ** src,const char * tgt)2436 _has_value (char **src, const char *tgt)
2437 {
2438 char **p;
2439
2440 for (p = src; *p != NULL; p++)
2441 {
2442 if (!strcasecmp (*p, tgt))
2443 {
2444 return 1;
2445 }
2446 }
2447
2448 return 0;
2449 }
2450
2451 static int
_service_ok(pam_handle_t * pamh,pam_ldap_session_t * session)2452 _service_ok (pam_handle_t * pamh, pam_ldap_session_t * session)
2453 {
2454 int rc;
2455 char *service = NULL;
2456
2457 /* simple host based access authorization */
2458 if (session->info->services_allow == NULL)
2459 {
2460 return PAM_PERM_DENIED;
2461 }
2462
2463 rc = pam_get_item (pamh, PAM_SERVICE, (CONST_ARG void **) &service);
2464 if (rc != PAM_SUCCESS)
2465 {
2466 service = NULL;
2467 }
2468
2469 if (service != NULL)
2470 {
2471 if (_has_deny_value (session->info->services_allow, service))
2472 return PAM_PERM_DENIED;
2473 else if (_has_value (session->info->services_allow, service))
2474 return PAM_SUCCESS;
2475 }
2476
2477 /* allow wild-card entries */
2478 return (_has_value (session->info->services_allow, "*")) ? PAM_SUCCESS :
2479 PAM_PERM_DENIED;
2480 }
2481
2482 static int
_host_ok(pam_ldap_session_t * session)2483 _host_ok (pam_ldap_session_t * session)
2484 {
2485 char hostname[MAXHOSTNAMELEN];
2486 struct hostent *h;
2487 #ifdef HAVE_GETHOSTBYNAME_R
2488 struct hostent hbuf;
2489 #if GETHOSTBYNAME_R_ARGS == 3
2490 struct hostent_data buf;
2491 #else
2492 int herr;
2493 char buf[1024];
2494 #endif /* GETHOSTBYNAME_R_ARGS == 3 */
2495 #endif /* HAVE_GETHOSTBYNAME_R */
2496 char **q;
2497
2498 /* simple host based access authorization */
2499 if (session->info->hosts_allow == NULL)
2500 {
2501 return PAM_PERM_DENIED;
2502 }
2503
2504
2505 if (gethostname (hostname, sizeof hostname) < 0)
2506 {
2507 return PAM_SYSTEM_ERR;
2508 }
2509
2510 #if defined(HAVE_GETHOSTBYNAME_R)
2511 #if GETHOSTBYNAME_R_ARGS == 6
2512 if (gethostbyname_r (hostname, &hbuf, buf, sizeof buf, &h, &herr) != 0)
2513 {
2514 return PAM_SYSTEM_ERR;
2515 }
2516 #elif GETHOSTBYNAME_R_ARGS == 5
2517 h = gethostbyname_r (hostname, &hbuf, buf, sizeof buf, &herr);
2518 if (h == NULL)
2519 {
2520 return PAM_SYSTEM_ERR;
2521 }
2522 #elif GETHOSTBYNAME_R_ARGS == 3
2523 if (gethostbyname_r (hostname, &hbuf, &buf) != 0)
2524 {
2525 return PAM_SYSTEM_ERR;
2526 }
2527 h = &hbuf;
2528 #else
2529 #error Unknown gethostbyname_r() implementation
2530 #endif
2531 #else
2532 h = gethostbyname (hostname);
2533 if (h == NULL)
2534 {
2535 return PAM_SYSTEM_ERR;
2536 }
2537 #endif
2538
2539 if (h == NULL || h->h_name == NULL)
2540 return PAM_SYSTEM_ERR;
2541
2542 if (_has_deny_value (session->info->hosts_allow, h->h_name))
2543 return PAM_PERM_DENIED;
2544 else if (_has_value (session->info->hosts_allow, h->h_name))
2545 return PAM_SUCCESS;
2546
2547 if (h->h_aliases != NULL)
2548 {
2549 for (q = h->h_aliases; *q != NULL; q++)
2550 {
2551 if (_has_value (session->info->hosts_allow, *q))
2552 return PAM_SUCCESS;
2553 if (_has_deny_value (session->info->hosts_allow, *q))
2554 return PAM_PERM_DENIED;
2555 }
2556 }
2557
2558 /* allow wild-card entries */
2559 if (_has_value (session->info->hosts_allow, "*"))
2560 {
2561 return PAM_SUCCESS;
2562 }
2563
2564 return PAM_PERM_DENIED;
2565 }
2566
2567 static char *
_get_md5_salt(char saltbuf[16])2568 _get_md5_salt (char saltbuf[16])
2569 {
2570 md5_state_t state;
2571 md5_byte_t digest[16];
2572 struct timeval tv;
2573 int i;
2574
2575 _pam_ldap_md5_init (&state);
2576 gettimeofday (&tv, NULL);
2577 _pam_ldap_md5_append (&state, (unsigned char *) &tv, sizeof (tv));
2578 i = getpid ();
2579 _pam_ldap_md5_append (&state, (unsigned char *) &i, sizeof (i));
2580 i = clock ();
2581 _pam_ldap_md5_append (&state, (unsigned char *) &i, sizeof (i));
2582 _pam_ldap_md5_append (&state, (unsigned char *) saltbuf, sizeof (saltbuf));
2583 _pam_ldap_md5_finish (&state, digest);
2584
2585 strcpy (saltbuf, "$1$");
2586 for (i = 0; i < 8; i++)
2587 saltbuf[i + 3] = i64c (digest[i] & 0x3f);
2588
2589 saltbuf[i + 3] = '\0';
2590
2591 return saltbuf;
2592 }
2593
2594 static char *
_get_salt(char salt[16])2595 _get_salt (char salt[16])
2596 {
2597 int i;
2598 int j;
2599
2600 srand (time (NULL));
2601
2602 for (j = 0; j < 2; j++)
2603 {
2604 i = rand () % 3;
2605 switch (i)
2606 {
2607 case 0:
2608 i = (rand () % (57 - 46)) + 46;
2609 break;
2610 case 1:
2611 i = (rand () % (90 - 65)) + 65;
2612 break;
2613 case 2:
2614 i = (rand () % (122 - 97)) + 97;
2615 break;
2616 }
2617 salt[j] = i;
2618 }
2619 salt[2] = '\0';
2620 return salt;
2621 }
2622
2623 static int
_escape_string(const char * str,char * buf,size_t buflen)2624 _escape_string (const char *str, char *buf, size_t buflen)
2625 {
2626 int ret = PAM_BUF_ERR;
2627 char *p = buf;
2628 char *limit = p + buflen - 3;
2629 const char *s = str;
2630
2631 while (p < limit && *s)
2632 {
2633 switch (*s)
2634 {
2635 case '*':
2636 strcpy (p, "\\2a");
2637 p += 3;
2638 break;
2639 case '(':
2640 strcpy (p, "\\28");
2641 p += 3;
2642 break;
2643 case ')':
2644 strcpy (p, "\\29");
2645 p += 3;
2646 break;
2647 case '\\':
2648 strcpy (p, "\\5c");
2649 p += 3;
2650 break;
2651 default:
2652 *p++ = *s;
2653 break;
2654 }
2655 s++;
2656 }
2657
2658 if (*s == '\0')
2659 {
2660 /* got to end */
2661 *p = '\0';
2662 ret = PAM_SUCCESS;
2663 }
2664
2665 return ret;
2666 }
2667
2668 static char *_pam_ldap_attrs[] = {
2669 "host",
2670 "authorizedService",
2671 "shadowExpire",
2672 "shadowFlag",
2673 "shadowInactive",
2674 "shadowLastChange",
2675 "shadowMax",
2676 "shadowMin",
2677 "shadowWarning",
2678 "uidNumber",
2679 NULL
2680 };
2681
2682 static int
_get_user_info(pam_ldap_session_t * session,const char * user)2683 _get_user_info (pam_ldap_session_t * session, const char *user)
2684 {
2685 char filter[LDAP_FILT_MAXSIZ], escapedUser[LDAP_FILT_MAXSIZ];
2686 int rc;
2687 LDAPMessage *res, *msg;
2688 pam_ssd_t *ssd, ssdummy;
2689
2690 rc = _connect_anonymously (session);
2691 if (rc != PAM_SUCCESS)
2692 return rc;
2693
2694 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_SIZELIMIT)
2695 rc = 1;
2696 (void) ldap_set_option (session->ld, LDAP_OPT_SIZELIMIT, &rc);
2697 #else
2698 session->ld->ld_sizelimit = 1;
2699 #endif
2700
2701 rc = _escape_string (user, escapedUser, sizeof (escapedUser));
2702 if (rc != PAM_SUCCESS)
2703 {
2704 return rc;
2705 }
2706
2707 ssd = session->conf->ssd;
2708 if (ssd == NULL)
2709 {
2710 ssd = &ssdummy;
2711 ssd->filter = session->conf->filter;
2712 ssd->base = session->conf->base;
2713 ssd->scope = session->conf->scope;
2714 ssd->next = NULL;
2715 }
2716 nxt:
2717 if (session->conf->filter != NULL && ssd->filter != NULL)
2718 {
2719 snprintf (filter, sizeof filter, "(&(%s)(%s)(%s=%s))",
2720 ssd->filter, session->conf->filter, session->conf->userattr,
2721 escapedUser);
2722 }
2723 else if (ssd->filter != NULL)
2724 {
2725 snprintf (filter, sizeof filter, "(&(%s)(%s=%s))",
2726 ssd->filter, session->conf->userattr, escapedUser);
2727 }
2728 else if (session->conf->filter != NULL)
2729 {
2730 snprintf (filter, sizeof filter, "(&(%s)(%s=%s))",
2731 session->conf->filter, session->conf->userattr, escapedUser);
2732 }
2733 else
2734 {
2735 snprintf (filter, sizeof filter, "(%s=%s)",
2736 session->conf->userattr, escapedUser);
2737 }
2738
2739 rc = ldap_search_s (session->ld, ssd->base, ssd->scope,
2740 filter, _pam_ldap_attrs, 0, &res);
2741
2742 if (rc != LDAP_SUCCESS &&
2743 rc != LDAP_TIMELIMIT_EXCEEDED && rc != LDAP_SIZELIMIT_EXCEEDED)
2744 {
2745 syslog (LOG_ERR, "pam_ldap: ldap_search_s %s", ldap_err2string (rc));
2746 return PAM_USER_UNKNOWN;
2747 }
2748
2749 msg = ldap_first_entry (session->ld, res);
2750 if (msg == NULL)
2751 {
2752 ldap_msgfree (res);
2753 if (ssd->next)
2754 {
2755 ssd = ssd->next;
2756 goto nxt;
2757 }
2758 return PAM_USER_UNKNOWN;
2759 }
2760
2761 if (session->info != NULL)
2762 {
2763 _release_user_info (&session->info);
2764 }
2765
2766 session->info =
2767 (pam_ldap_user_info_t *) calloc (1, sizeof (pam_ldap_user_info_t));
2768 if (session->info == NULL)
2769 {
2770 ldap_msgfree (res);
2771 return PAM_BUF_ERR;
2772 }
2773
2774 rc = _get_string_value (session->ld, msg, session->conf->userattr,
2775 &session->info->username);
2776 if (rc != PAM_SUCCESS)
2777 {
2778 session->info->username = strdup (user);
2779 }
2780
2781 if (session->info->username == NULL)
2782 {
2783 ldap_msgfree (res);
2784 _release_user_info (&session->info);
2785 return PAM_BUF_ERR;
2786 }
2787
2788 session->info->userdn = ldap_get_dn (session->ld, msg);
2789 if (session->info->userdn == NULL)
2790 {
2791 ldap_msgfree (res);
2792 _release_user_info (&session->info);
2793 return PAM_SERVICE_ERR;
2794 }
2795
2796 session->info->bound_as_user = 0;
2797 session->info->policy_error = POLICY_ERROR_SUCCESS;
2798
2799 /*
2800 * it might be better to do a compare later, that way we can
2801 * avoid fetching any attributes at all
2802 */
2803 _get_string_values (session->ld, msg, "host", &session->info->hosts_allow);
2804 _get_string_values (session->ld, msg, "authorizedService",
2805 &session->info->services_allow);
2806
2807 /* get UID */
2808 #ifdef UID_NOBODY
2809 session->info->uid = UID_NOBODY;
2810 #else
2811 session->info->uid = (uid_t) - 2;
2812 #endif /* UID_NOBODY */
2813 _get_integer_value (session->ld, msg, "uidNumber",
2814 (int *) &session->info->uid);
2815
2816 /*
2817 * get mapped user; some PAM host applications let PAM_USER be reset
2818 * by the user (such as some of those provided with FreeBSD).
2819 */
2820 session->info->tmpluser = NULL;
2821 if (session->conf->tmplattr != NULL)
2822 {
2823 if (_get_string_value (session->ld,
2824 msg,
2825 session->conf->tmplattr,
2826 &session->info->tmpluser) != PAM_SUCCESS)
2827 {
2828 /* set to default template user */
2829 session->info->tmpluser =
2830 session->conf->tmpluser ? strdup (session->conf->tmpluser) : NULL;
2831 }
2832 }
2833
2834 /* Assume shadow controls. Allocate shadow structure and link to session. */
2835 session->info->shadow.lstchg = -1;
2836 session->info->shadow.min = 0;
2837 session->info->shadow.max = 0;
2838 session->info->shadow.warn = 0;
2839 session->info->shadow.inact = 0;
2840 session->info->shadow.expire = 0;
2841 session->info->shadow.flag = 0;
2842
2843 _get_long_integer_value (session->ld, msg, "shadowLastChange",
2844 &session->info->shadow.lstchg);
2845 _get_long_integer_value (session->ld, msg, "shadowMin",
2846 &session->info->shadow.min);
2847 _get_long_integer_value (session->ld, msg, "shadowMax",
2848 &session->info->shadow.max);
2849 _get_long_integer_value (session->ld, msg, "shadowWarning",
2850 &session->info->shadow.warn);
2851 _get_long_integer_value (session->ld, msg, "shadowInactive",
2852 &session->info->shadow.inact);
2853 _get_long_integer_value (session->ld, msg, "shadowExpire",
2854 &session->info->shadow.expire);
2855 _get_long_integer_value (session->ld, msg, "shadowFlag",
2856 &session->info->shadow.flag);
2857
2858 ldap_msgfree (res);
2859
2860 return PAM_SUCCESS;
2861 }
2862
2863 static int
_pam_ldap_get_session(pam_handle_t * pamh,const char * username,const char * configFile,pam_ldap_session_t ** psession)2864 _pam_ldap_get_session (pam_handle_t * pamh, const char *username,
2865 const char *configFile, pam_ldap_session_t ** psession)
2866 {
2867 pam_ldap_session_t *session;
2868 int rc;
2869
2870 if (pam_get_data
2871 (pamh, PADL_LDAP_SESSION_DATA, (const void **) &session) == PAM_SUCCESS)
2872 {
2873 /*
2874 * we cache the information retrieved from the LDAP server, however
2875 * we need to flush this if the application has changed the user
2876 * or configuration file.
2877 *
2878 * For template users, note that pam_ldap may _RESET_ the username!
2879 */
2880 if (session->info != NULL &&
2881 (strcmp (username, session->info->username) != 0))
2882 {
2883 _release_user_info (&session->info);
2884 }
2885
2886 if (configFile == NULL)
2887 {
2888 /* Default configuration file requested. */
2889 if (session->conf->configFile != NULL)
2890 _release_user_info (&session->info);
2891 }
2892 else
2893 {
2894 /* Non-default configuration file requested. */
2895 if (session->conf->configFile == NULL ||
2896 (strcmp (configFile, session->conf->configFile) != 0))
2897 {
2898 _release_user_info (&session->info);
2899 }
2900 }
2901
2902 *psession = session;
2903 #if LDAP_SET_REBIND_PROC_ARGS < 3
2904 global_session = *psession;
2905 #endif
2906 return PAM_SUCCESS;
2907 }
2908
2909 *psession = NULL;
2910
2911 session = (pam_ldap_session_t *) calloc (1, sizeof (*session));
2912 #if LDAP_SET_REBIND_PROC_ARGS < 3
2913 global_session = session;
2914 #endif
2915 if (session == NULL)
2916 {
2917 return PAM_BUF_ERR;
2918 }
2919
2920 session->ld = NULL;
2921 session->conf = NULL;
2922 session->info = NULL;
2923
2924 #ifdef YPLDAPD
2925 rc = _ypldapd_read_config (&session->conf);
2926 if (rc != PAM_SUCCESS)
2927 {
2928 _release_config (&session->conf);
2929 #endif /* YPLDAPD */
2930 rc = _read_config (configFile, &session->conf);
2931 if (rc != PAM_SUCCESS)
2932 {
2933 _release_config (&session->conf);
2934 free (session);
2935 return rc;
2936 }
2937 #ifdef YPLDAPD
2938 }
2939 #endif /* YPLDAPD */
2940
2941 rc =
2942 pam_set_data (pamh, PADL_LDAP_SESSION_DATA, (void *) session,
2943 _pam_ldap_cleanup_session);
2944 if (rc != PAM_SUCCESS)
2945 {
2946 _release_config (&session->conf);
2947 free (session);
2948 return rc;
2949 }
2950
2951 *psession = session;
2952
2953 return PAM_SUCCESS;
2954 }
2955
2956 static int
_session_reopen(pam_ldap_session_t * session)2957 _session_reopen (pam_ldap_session_t * session)
2958 {
2959 /* FYI: V3 lets us avoid five unneeded binds in a password change */
2960 if (session->conf->version == LDAP_VERSION2)
2961 {
2962 if (session->ld != NULL)
2963 {
2964 ldap_unbind (session->ld);
2965 session->ld = NULL;
2966 }
2967 if (session->info != NULL)
2968 {
2969 session->info->bound_as_user = 0;
2970 }
2971 return _open_session (session);
2972 }
2973 return PAM_SUCCESS;
2974 }
2975
2976 static int
_get_password_policy(pam_ldap_session_t * session,pam_ldap_password_policy_t * policy)2977 _get_password_policy (pam_ldap_session_t * session,
2978 pam_ldap_password_policy_t * policy)
2979 {
2980 int rc = PAM_SUCCESS;
2981 LDAPMessage *res, *msg;
2982
2983 /* set some reasonable defaults */
2984 memset (policy, 0, sizeof (*policy));
2985 policy->password_min_length = 6;
2986 policy->password_max_failure = 3;
2987
2988 if (session->conf->getpolicy == 0)
2989 {
2990 return PAM_SUCCESS;
2991 }
2992
2993 rc = _connect_anonymously (session);
2994 if (rc != PAM_SUCCESS)
2995 {
2996 return rc;
2997 }
2998
2999 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_SIZELIMIT)
3000 rc = 1;
3001 (void) ldap_set_option (session->ld, LDAP_OPT_SIZELIMIT, &rc);
3002 #else
3003 session->ld->ld_sizelimit = 1;
3004 #endif /* LDAP_VERSION3_API */
3005
3006 rc = ldap_search_s (session->ld,
3007 "",
3008 LDAP_SCOPE_BASE,
3009 "(objectclass=passwordPolicy)", NULL, 0, &res);
3010
3011 if (rc == LDAP_SUCCESS ||
3012 rc == LDAP_TIMELIMIT_EXCEEDED || rc == LDAP_SIZELIMIT_EXCEEDED)
3013 {
3014 msg = ldap_first_entry (session->ld, res);
3015 if (msg != NULL)
3016 {
3017 _get_integer_value (session->ld, msg, "passwordMaxFailure",
3018 &policy->password_max_failure);
3019 _get_integer_value (session->ld, msg, "passwordMinLength",
3020 &policy->password_min_length);
3021 }
3022 ldap_msgfree (res);
3023 }
3024
3025 return PAM_SUCCESS;
3026 }
3027
3028 static int
_do_authentication(pam_handle_t * pamh,pam_ldap_session_t * session,const char * user,const char * password)3029 _do_authentication (pam_handle_t *pamh,
3030 pam_ldap_session_t * session,
3031 const char *user, const char *password)
3032 {
3033 int rc = PAM_SUCCESS;
3034
3035 if (session->info == NULL)
3036 {
3037 rc = _get_user_info (session, user);
3038 if (rc != PAM_SUCCESS)
3039 return rc;
3040 }
3041
3042 rc = _session_reopen (session);
3043 if (rc != PAM_SUCCESS)
3044 return rc;
3045
3046 rc = _connect_as_user (pamh, session, password);
3047 _session_reopen (session);
3048 _connect_anonymously (session);
3049 return rc;
3050 }
3051
3052 static int
_update_authtok(pam_handle_t * pamh,pam_ldap_session_t * session,const char * user,const char * old_password,const char * new_password)3053 _update_authtok (pam_handle_t *pamh,
3054 pam_ldap_session_t * session,
3055 const char *user,
3056 const char *old_password, const char *new_password)
3057 {
3058 char *strvalsold[2];
3059 char *strvalsnew[2];
3060 LDAPMod mod, mod2;
3061 LDAPMod *mods[3];
3062 char buf[64], saltbuf[16];
3063 int rc = PAM_SUCCESS;
3064 size_t i;
3065
3066 /* for Active Directory */
3067
3068 struct berval bvalold;
3069 struct berval bvalnew;
3070 struct berval *bvalsold[2];
3071 struct berval *bvalsnew[2];
3072 char old_password_with_quotes[17], new_password_with_quotes[17];
3073 char old_unicode_password[34], new_unicode_password[34];
3074
3075 #ifdef LDAP_EXOP_MODIFY_PASSWD
3076 /* for OpenLDAP password change extended operation */
3077 BerElement *ber;
3078 struct berval *bv;
3079 char *retoid;
3080 struct berval *retdata;
3081 #endif /* LDAP_EXOP_MODIFY_PASSWD */
3082
3083 if (session->info == NULL)
3084 {
3085 rc = _get_user_info (session, user);
3086 if (rc != PAM_SUCCESS)
3087 {
3088 return rc;
3089 }
3090 }
3091
3092 if (!session->conf->rootbinddn || geteuid () != 0)
3093 {
3094 /* We're not root or don't have a rootbinddn so
3095 * let's try binding as the user.
3096 *
3097 * FIXME:
3098 * Do we really want to do this? It allows the
3099 * system to be configured in such a way that the
3100 * user can bypass local password policy
3101 */
3102 rc = _session_reopen (session);
3103 if (rc != PAM_SUCCESS)
3104 return rc;
3105
3106 rc = _connect_as_user (pamh, session, old_password);
3107 if (rc != PAM_SUCCESS)
3108 return rc;
3109 }
3110
3111 switch (session->conf->password_type)
3112 {
3113 case PASSWORD_CLEAR:
3114 strvalsnew[0] = (char *) new_password;
3115 strvalsnew[1] = NULL;
3116
3117 mod.mod_op = LDAP_MOD_REPLACE;
3118 mod.mod_type = (char *) "userPassword";
3119 mod.mod_values = strvalsnew;
3120
3121 mods[0] = &mod;
3122 mods[1] = NULL;
3123
3124 break;
3125
3126 case PASSWORD_CRYPT:
3127 _get_salt (saltbuf);
3128 snprintf (buf, sizeof buf, "{crypt}%s", crypt (new_password, saltbuf));
3129 strvalsnew[0] = buf;
3130 strvalsnew[1] = NULL;
3131
3132 mod.mod_op = LDAP_MOD_REPLACE;
3133 mod.mod_type = (char *) "userPassword";
3134 mod.mod_values = strvalsnew;
3135
3136 mods[0] = &mod;
3137 mods[1] = NULL;
3138
3139 break;
3140
3141 case PASSWORD_MD5:
3142 _get_md5_salt (saltbuf);
3143 snprintf (buf, sizeof buf, "{crypt}%s", crypt (new_password, saltbuf));
3144 strvalsnew[0] = buf;
3145 strvalsnew[1] = NULL;
3146
3147 mod.mod_op = LDAP_MOD_REPLACE;
3148 mod.mod_type = (char *) "userPassword";
3149 mod.mod_values = strvalsnew;
3150
3151 mods[0] = &mod;
3152 mods[1] = NULL;
3153
3154 break;
3155
3156 case PASSWORD_CLEAR_REMOVE_OLD:
3157 /* NDSrequires that the old password is first removed */
3158 strvalsold[0] = (char *) old_password;
3159 strvalsold[1] = NULL;
3160 strvalsnew[0] = (char *) new_password;
3161 strvalsnew[1] = NULL;
3162
3163 mod.mod_vals.modv_strvals = strvalsold;
3164 mod.mod_type = (char *) "userPassword";
3165 mod.mod_op = LDAP_MOD_DELETE;
3166
3167 mod2.mod_vals.modv_strvals = strvalsnew;
3168 mod2.mod_type = (char *) "userPassword";
3169 mod2.mod_op = LDAP_MOD_ADD;
3170
3171 mods[0] = &mod;
3172 mods[1] = &mod2;
3173 mods[2] = NULL;
3174
3175 break;
3176
3177 case PASSWORD_AD:
3178 /*
3179 * Patch from Norbert Klasen <klasen@zdv.uni-tuebingen.de>:
3180 *
3181 * To be able to change a password in AD via LDAP, an SSL connection
3182 * with a cipher strength of at least 128 bit must be established.
3183 * http://support.microsoft.com/support/kb/articles/q264/4/80.ASP
3184 * http://support.microsoft.com/support/kb/articles/Q247/0/78.ASP
3185 *
3186 * The password attribute used by AD is unicodePwd. Its syntax is octect
3187 * string. The actual value is the password surrounded by quotes in
3188 * Unicode (LSBFirst).
3189 *
3190 * NT passwords can have max. 14 characters.
3191 *
3192 * FIXME:
3193 * The conversion to Unicode only works if the locale is
3194 * ISO-8859-1 (aka Latin-1) [of which ASCII is a subset].
3195 */
3196
3197 snprintf (new_password_with_quotes, sizeof (new_password_with_quotes),
3198 "\"%s\"", new_password);
3199 memset (new_unicode_password, 0, sizeof (new_unicode_password));
3200 for (i = 0; i < strlen (new_password_with_quotes); i++)
3201 new_unicode_password[i * 2] = new_password_with_quotes[i];
3202 bvalnew.bv_val = new_unicode_password;
3203 bvalnew.bv_len = strlen (new_password_with_quotes) * 2;
3204
3205 bvalsnew[0] = &bvalnew;
3206 bvalsnew[1] = NULL;
3207 mod.mod_vals.modv_bvals = bvalsnew;
3208 mod.mod_type = (char *) "unicodePwd";
3209
3210 if (!session->conf->rootbinddn || getuid () != 0)
3211 {
3212 /* user must supply old password */
3213 snprintf (old_password_with_quotes,
3214 sizeof (old_password_with_quotes), "\"%s\"",
3215 old_password);
3216 memset (old_unicode_password, 0, sizeof (old_unicode_password));
3217 for (i = 0; i < strlen (old_password_with_quotes); i++)
3218 old_unicode_password[i * 2] = old_password_with_quotes[i];
3219 bvalold.bv_val = old_unicode_password;
3220 bvalold.bv_len = strlen (old_password_with_quotes) * 2;
3221
3222 bvalsold[0] = &bvalold;
3223 bvalsold[1] = NULL;
3224 mod2.mod_vals.modv_bvals = bvalsold;
3225 mod2.mod_type = (char *) "unicodePwd";
3226 mod2.mod_op = LDAP_MOD_DELETE | LDAP_MOD_BVALUES;
3227
3228 mod.mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
3229
3230 mods[0] = &mod2;
3231 mods[1] = &mod;
3232 mods[2] = NULL;
3233 }
3234 else
3235 {
3236 mod.mod_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
3237
3238 mods[0] = &mod;
3239 mods[1] = NULL;
3240 }
3241
3242 break;
3243
3244 case PASSWORD_EXOP:
3245 case PASSWORD_EXOP_SEND_OLD:
3246 #ifdef LDAP_EXOP_MODIFY_PASSWD
3247 ber = ber_alloc_t (LBER_USE_DER);
3248
3249 if (ber == NULL)
3250 {
3251 return PAM_BUF_ERR;
3252 }
3253
3254 ber_printf (ber, "{");
3255 ber_printf (ber, "ts", LDAP_TAG_EXOP_MODIFY_PASSWD_ID,
3256 session->info->userdn);
3257 if (session->conf->password_type == PASSWORD_EXOP_SEND_OLD)
3258 {
3259 ber_printf (ber, "ts", LDAP_TAG_EXOP_MODIFY_PASSWD_OLD, old_password);
3260 }
3261 ber_printf (ber, "ts", LDAP_TAG_EXOP_MODIFY_PASSWD_NEW, new_password);
3262 ber_printf (ber, "N}");
3263
3264 rc = ber_flatten (ber, &bv);
3265 if (rc < 0)
3266 {
3267 ber_free (ber, 1);
3268 return PAM_BUF_ERR;
3269 }
3270
3271 ber_free (ber, 1);
3272
3273 rc =
3274 ldap_extended_operation_s (session->ld, LDAP_EXOP_MODIFY_PASSWD, bv,
3275 NULL, NULL, &retoid, &retdata);
3276 ber_bvfree (bv);
3277
3278 if (rc != LDAP_SUCCESS)
3279 {
3280 syslog (LOG_ERR, "pam_ldap: ldap_extended_operation_s %s",
3281 ldap_err2string (rc));
3282 rc = PAM_PERM_DENIED;
3283 }
3284 else
3285 {
3286 ber_bvfree (retdata);
3287 ber_memfree (retoid);
3288 rc = PAM_SUCCESS;
3289 }
3290 #else
3291 rc = PAM_SERVICE_ERR;
3292 #endif /* LDAP_EXOP_MODIFY_PASSWD */
3293
3294 break;
3295 } /* end switch */
3296
3297 if (session->conf->password_type != PASSWORD_EXOP)
3298 {
3299 rc = ldap_modify_s (session->ld, session->info->userdn, mods);
3300 if (rc != LDAP_SUCCESS)
3301 {
3302 syslog (LOG_ERR, "pam_ldap: ldap_modify_s %s",
3303 ldap_err2string (rc));
3304 rc = ldap_set_lderrno (session->ld, rc, NULL, NULL);
3305 if (rc != LDAP_SUCCESS)
3306 {
3307 syslog (LOG_ERR, "pam_ldap: ldap_set_lderrno %s",
3308 ldap_err2string (rc));
3309 }
3310 rc = PAM_PERM_DENIED;
3311 }
3312 else
3313 {
3314 rc = PAM_SUCCESS;
3315 }
3316 }
3317
3318 if (rc == LDAP_SUCCESS)
3319 {
3320 _pam_overwrite (session->info->userpw);
3321 _pam_drop (session->info->userpw);
3322 session->info->userpw = strdup (new_password);
3323 if (session->info->userpw == NULL)
3324 {
3325 rc = PAM_BUF_ERR;
3326 }
3327 }
3328
3329 return rc;
3330 }
3331
3332 static int
_get_authtok(pam_handle_t * pamh,int flags,int first)3333 _get_authtok (pam_handle_t * pamh, int flags, int first)
3334 {
3335 int rc;
3336 char *p;
3337 struct pam_message msg[1], *pmsg[1];
3338 struct pam_response *resp;
3339 struct pam_conv *conv;
3340
3341 pmsg[0] = &msg[0];
3342 msg[0].msg_style = PAM_PROMPT_ECHO_OFF;
3343 msg[0].msg = first ? "Password: " : "LDAP Password: ";
3344 resp = NULL;
3345
3346 rc = pam_get_item (pamh, PAM_CONV, (CONST_ARG void **) &conv);
3347 if (rc == PAM_SUCCESS)
3348 {
3349 rc = conv->conv (1,
3350 (CONST_ARG struct pam_message **) pmsg,
3351 &resp, conv->appdata_ptr);
3352 }
3353 else
3354 {
3355 return rc;
3356 }
3357
3358 if (resp != NULL)
3359 {
3360 if ((flags & PAM_DISALLOW_NULL_AUTHTOK) && resp[0].resp == NULL)
3361 {
3362 free (resp);
3363 return PAM_AUTH_ERR;
3364 }
3365
3366 p = resp[0].resp;
3367 /* leak if resp[0].resp is malloced. */
3368 resp[0].resp = NULL;
3369 }
3370 else
3371 {
3372 return PAM_CONV_ERR;
3373 }
3374
3375 free (resp);
3376 pam_set_item (pamh, PAM_AUTHTOK, p);
3377
3378 return PAM_SUCCESS;
3379 }
3380
3381 static int
_conv_sendmsg(struct pam_conv * aconv,const char * message,int style,int no_warn)3382 _conv_sendmsg (struct pam_conv *aconv,
3383 const char *message, int style, int no_warn)
3384 {
3385 struct pam_message msg, *pmsg;
3386 struct pam_response *resp;
3387
3388 if (no_warn)
3389 return PAM_SUCCESS;
3390
3391 pmsg = &msg;
3392
3393 msg.msg_style = style;
3394 msg.msg = (char *) message;
3395 resp = NULL;
3396
3397 return aconv->conv (1,
3398 (CONST_ARG struct pam_message **) &pmsg,
3399 &resp, aconv->appdata_ptr);
3400 }
3401
3402 PAM_EXTERN int
pam_sm_authenticate(pam_handle_t * pamh,int flags,int argc,const char ** argv)3403 pam_sm_authenticate (pam_handle_t * pamh,
3404 int flags, int argc, const char **argv)
3405 {
3406 int rc;
3407 const char *username;
3408 char *p;
3409 int use_first_pass = 0, try_first_pass = 0, ignore_flags = 0, migrate = 0;
3410 int i;
3411 pam_ldap_session_t *session = NULL;
3412 const char *configFile = NULL;
3413
3414 for (i = 0; i < argc; i++)
3415 {
3416 if (!strcmp (argv[i], "use_first_pass"))
3417 use_first_pass = 1;
3418 else if (!strcmp (argv[i], "try_first_pass"))
3419 try_first_pass = 1;
3420 else if (!strncmp (argv[i], "config=", 7))
3421 configFile = argv[i] + 7;
3422 else if (!strcmp (argv[i], "ignore_unknown_user"))
3423 ignore_flags |= IGNORE_UNKNOWN_USER;
3424 else if (!strcmp (argv[i], "ignore_authinfo_unavail"))
3425 ignore_flags |= IGNORE_AUTHINFO_UNAVAIL;
3426 else if (!strcmp (argv[i], "no_warn"))
3427 ;
3428 else if (!strcmp (argv[i], "debug"))
3429 ;
3430 else if (!strcmp (argv[i], "migrate"))
3431 migrate = 1;
3432 else
3433 syslog (LOG_ERR, "illegal option %s", argv[i]);
3434 }
3435
3436 rc = pam_get_user (pamh, (CONST_ARG char **) &username, NULL);
3437 if (rc != PAM_SUCCESS)
3438 return rc;
3439
3440 rc = _pam_ldap_get_session (pamh, username, configFile, &session);
3441 if (rc != PAM_SUCCESS)
3442 return rc;
3443
3444 rc = pam_get_item (pamh, PAM_AUTHTOK, (CONST_ARG void **) &p);
3445 /* start of migrate facility in "pam_ldap authentication" */
3446 if (migrate==1 && rc==PAM_SUCCESS)
3447 {
3448 /* check if specified username exists in LDAP */
3449 if (_get_user_info(session,username)==PAM_SUCCESS)
3450 {
3451 /*
3452 overwrite old LDAP userPassword with a new password
3453 obtained during pam authentication process
3454 - rootbinddn and ldap.secret must be set
3455 */
3456 rc=_update_authtok(pamh,session,username,NULL,p);
3457 return PAM_IGNORE;
3458 }
3459 }
3460 /* end of migrate facility in "pam_ldap authentication" */
3461 if (rc == PAM_SUCCESS && (use_first_pass || try_first_pass))
3462 {
3463 rc = _do_authentication (pamh, session, username, p);
3464 if (rc == PAM_SUCCESS || use_first_pass)
3465 {
3466 STATUS_MAP_IGNORE_POLICY (rc, ignore_flags);
3467
3468 if (rc == PAM_SUCCESS && session->info->tmpluser != NULL &&
3469 session->conf->tmpluser != NULL &&
3470 strcmp (session->info->tmpluser, session->conf->tmpluser) == 0)
3471 {
3472 (void) pam_set_data (pamh, PADL_LDAP_AUTH_DATA,
3473 (void *) strdup (session->info->username),
3474 _cleanup_data);
3475 rc =
3476 pam_set_item (pamh, PAM_USER,
3477 (void *) session->info->tmpluser);
3478 }
3479 else if (rc == PAM_SUCCESS && session->info->username != NULL)
3480 {
3481 (void) pam_set_data (pamh, PADL_LDAP_AUTH_DATA,
3482 (void *) strdup (session->info->username),
3483 _cleanup_data);
3484 rc = pam_set_item (pamh, PAM_USER, (void *) session->info->username);
3485 }
3486 return rc;
3487 }
3488 }
3489
3490 /* can prompt for authentication token */
3491 rc = _get_authtok (pamh, flags, (p == NULL) ? 1 : 0);
3492 if (rc != PAM_SUCCESS)
3493 return rc;
3494
3495 rc = pam_get_item (pamh, PAM_AUTHTOK, (CONST_ARG void **) &p);
3496 if (rc == PAM_SUCCESS)
3497 rc = _do_authentication (pamh, session, username, p);
3498 STATUS_MAP_IGNORE_POLICY (rc, ignore_flags);
3499
3500 /*
3501 * reset username to template user if necessary
3502 * FreeBSD pam_radius does this in pam_sm_authenticate() but
3503 * I think pam_sm_acct_mgmt() is the right place.
3504 */
3505 if (rc == PAM_SUCCESS && session->info->tmpluser != NULL &&
3506 session->conf->tmpluser != NULL &&
3507 strcmp (session->info->tmpluser, session->conf->tmpluser) == 0)
3508 {
3509 /* keep original username for posterity */
3510
3511 (void) pam_set_data (pamh, PADL_LDAP_AUTH_DATA,
3512 (void *) strdup (session->info->username),
3513 _cleanup_data);
3514 rc = pam_set_item (pamh, PAM_USER, (void *) session->info->tmpluser);
3515 }
3516 else if (rc == PAM_SUCCESS && session->info->username != NULL)
3517 {
3518 (void) pam_set_data (pamh, PADL_LDAP_AUTH_DATA,
3519 (void *) strdup (session->info->username),
3520 _cleanup_data);
3521 rc = pam_set_item (pamh, PAM_USER, (void *) session->info->username);
3522 }
3523
3524 return rc;
3525 }
3526
3527 PAM_EXTERN int
pam_sm_setcred(pam_handle_t * pamh,int flags,int argc,const char ** argv)3528 pam_sm_setcred (pam_handle_t * pamh, int flags, int argc, const char **argv)
3529 {
3530 return PAM_SUCCESS;
3531 }
3532
3533 PAM_EXTERN int
pam_sm_open_session(pam_handle_t * pamh,int flags,int argc,const char ** argv)3534 pam_sm_open_session (pam_handle_t * pamh,
3535 int flags, int argc, const char **argv)
3536 {
3537 /*
3538 * Bug #120 fix: close the LDAP connection as it may time out
3539 * before pam_sm_close_session() is called.
3540 */
3541 void *session;
3542
3543 if (pam_get_data
3544 (pamh, PADL_LDAP_SESSION_DATA, (const void **) &session) == PAM_SUCCESS)
3545 pam_set_data (pamh, PADL_LDAP_SESSION_DATA, NULL, NULL);
3546
3547 return PAM_SUCCESS;
3548 }
3549
3550 PAM_EXTERN int
pam_sm_close_session(pam_handle_t * pamh,int flags,int argc,const char ** argv)3551 pam_sm_close_session (pam_handle_t * pamh,
3552 int flags, int argc, const char **argv)
3553 {
3554 return PAM_SUCCESS;
3555 }
3556
3557 PAM_EXTERN int
pam_sm_chauthtok(pam_handle_t * pamh,int flags,int argc,const char ** argv)3558 pam_sm_chauthtok (pam_handle_t * pamh, int flags, int argc, const char **argv)
3559 {
3560 int rc = PAM_SUCCESS;
3561 char *username, *curpass = NULL, *newpass = NULL, *expuser = NULL;
3562 char buf[32], *strvals[2];
3563 struct pam_conv *appconv;
3564 struct pam_message msg, *pmsg;
3565 struct pam_response *resp;
3566 const char *cmiscptr = NULL;
3567 int tries = 0, i, canabort = 1;
3568 pam_ldap_session_t *session = NULL;
3569 int use_first_pass = 0, try_first_pass = 0, no_warn = 0;
3570 int use_authtok = 0, ignore_flags = 0;
3571 char errmsg[1024];
3572 pam_ldap_password_policy_t policy;
3573 LDAPMod *mods[2], mod;
3574 const char *configFile = NULL;
3575
3576 for (i = 0; i < argc; i++)
3577 {
3578 if (!strcmp (argv[i], "use_first_pass"))
3579 use_first_pass = 1;
3580 else if (!strcmp (argv[i], "try_first_pass"))
3581 try_first_pass = 1;
3582 else if (!strncmp (argv[i], "config=", 7))
3583 configFile = argv[i] + 7;
3584 else if (!strcmp (argv[i], "no_warn"))
3585 no_warn = 1;
3586 else if (!strcmp (argv[i], "ignore_unknown_user"))
3587 ignore_flags |= IGNORE_UNKNOWN_USER;
3588 else if (!strcmp (argv[i], "ignore_authinfo_unavail"))
3589 ignore_flags |= IGNORE_AUTHINFO_UNAVAIL;
3590 else if (!strcmp (argv[i], "debug"))
3591 ;
3592 else if (!strcmp (argv[i], "use_authtok"))
3593 use_authtok = 1;
3594 else
3595 syslog (LOG_ERR, "illegal option %s", argv[i]);
3596 }
3597
3598 if (flags & PAM_SILENT)
3599 no_warn = 1;
3600
3601 rc = pam_get_item (pamh, PAM_CONV, (CONST_ARG void **) &appconv);
3602 if (rc != PAM_SUCCESS)
3603 return rc;
3604
3605 /*
3606 * Call pam_get_data() to see whether the pre-mapped
3607 * (non-template) user is available to us. If so,
3608 * use that instead.
3609 */
3610 rc = pam_get_data (pamh, PADL_LDAP_AUTH_DATA, (const void **) &username);
3611 if (rc != PAM_SUCCESS)
3612 {
3613 rc = pam_get_user (pamh, (CONST_ARG char **) &username, NULL);
3614 if (rc != PAM_SUCCESS)
3615 return rc;
3616 }
3617
3618 if (username == NULL)
3619 return PAM_USER_UNKNOWN;
3620
3621 rc = pam_get_data (pamh, PADL_LDAP_AUTHTOK_DATA, (const void **) &expuser);
3622 if (rc == PAM_SUCCESS && expuser != NULL)
3623 canabort = (strcmp (username, expuser) == 0) ? 0 : 1;
3624
3625 rc = _pam_ldap_get_session (pamh, username, configFile, &session);
3626 if (rc != PAM_SUCCESS)
3627 return rc;
3628
3629 /* do we prohibit changes */
3630 if (session->conf->password_prohibit_message)
3631 {
3632 rc = _get_user_info (session, username);
3633 STATUS_MAP_IGNORE_POLICY (rc, ignore_flags);
3634 /* skip non-ldap users */
3635 if (rc != PAM_SUCCESS)
3636 return rc;
3637 /* prohibit ldap users */
3638 _conv_sendmsg (appconv, session->conf->password_prohibit_message,
3639 PAM_ERROR_MSG, no_warn);
3640 return PAM_PERM_DENIED;
3641 }
3642
3643 if (flags & PAM_PRELIM_CHECK)
3644 {
3645 /* see whether the user exists */
3646 rc = _get_user_info (session, username);
3647 STATUS_MAP_IGNORE_POLICY (rc, ignore_flags);
3648 if (rc != PAM_SUCCESS)
3649 return rc;
3650
3651 if (!(session->conf->rootbinddn && getuid () == 0))
3652 {
3653 /* we are not root, authenticate old password */
3654 if (try_first_pass || use_first_pass)
3655 {
3656 if (pam_get_item
3657 (pamh, PAM_OLDAUTHTOK,
3658 (CONST_ARG void **) &curpass) == PAM_SUCCESS &&
3659 curpass != NULL)
3660 {
3661 rc = _do_authentication (pamh, session, username, curpass);
3662 if (rc != PAM_SUCCESS)
3663 {
3664 if (use_first_pass)
3665 {
3666 _conv_sendmsg (appconv, "LDAP Password incorrect",
3667 PAM_ERROR_MSG, no_warn);
3668 }
3669 else
3670 {
3671 _conv_sendmsg (appconv,
3672 "LDAP Password incorrect: try again",
3673 PAM_ERROR_MSG, no_warn);
3674 }
3675 return rc;
3676 }
3677 }
3678 else
3679 {
3680 curpass = NULL;
3681 }
3682 }
3683
3684 tries = 0;
3685
3686 /* support Netscape Directory Server's password policy */
3687 rc = _get_password_policy (session, &policy);
3688 if (rc != PAM_SUCCESS)
3689 return rc;
3690
3691 while ((curpass == NULL) && (tries++ < policy.password_max_failure))
3692 {
3693 pmsg = &msg;
3694 msg.msg_style = PAM_PROMPT_ECHO_OFF;
3695 msg.msg = OLD_PASSWORD_PROMPT;
3696 resp = NULL;
3697
3698 rc = appconv->conv (1, (CONST_ARG struct pam_message **) &pmsg,
3699 &resp, appconv->appdata_ptr);
3700
3701 if (rc != PAM_SUCCESS)
3702 return rc;
3703
3704 curpass = resp->resp;
3705 free (resp);
3706
3707 /* authenticate the old password */
3708 rc = _do_authentication (pamh, session, username, curpass);
3709 if (rc != PAM_SUCCESS)
3710 {
3711 int abortme = 0;
3712
3713 if (curpass != NULL && curpass[0] == '\0')
3714 abortme = 1;
3715
3716 _pam_overwrite (curpass);
3717 _pam_drop (curpass);
3718
3719 if (canabort && abortme)
3720 {
3721 _conv_sendmsg (appconv, "Password change aborted",
3722 PAM_ERROR_MSG, no_warn);
3723 return PAM_AUTHTOK_RECOVERY_ERR;
3724 }
3725 else
3726 {
3727 _conv_sendmsg (appconv,
3728 "LDAP Password incorrect: try again",
3729 PAM_ERROR_MSG, no_warn);
3730 }
3731 }
3732 } /* while */
3733
3734 if (curpass == NULL)
3735 return PAM_MAXTRIES; /* maximum tries exceeded */
3736 else
3737 pam_set_item (pamh, PAM_OLDAUTHTOK, (void *) strdup(curpass));
3738 }
3739 else
3740 {
3741 /* we are root */
3742 curpass = NULL;
3743 }
3744
3745 pam_set_data (pamh, PADL_LDAP_OLDAUTHTOK_DATA,
3746 (curpass == NULL) ? NULL : (void *) strdup (curpass),
3747 _cleanup_authtok_data);
3748 return rc;
3749 } /* prelim */
3750 else if (session->info == NULL) /* this is no LDAP user */
3751 return (ignore_flags & IGNORE_UNKNOWN_USER) ? PAM_IGNORE :
3752 PAM_USER_UNKNOWN;
3753
3754
3755 if (use_authtok)
3756 use_first_pass = 1;
3757
3758 rc =
3759 pam_get_data (pamh, PADL_LDAP_OLDAUTHTOK_DATA, (const void **) &curpass);
3760 if (rc != PAM_SUCCESS)
3761 {
3762 syslog (LOG_ERR,
3763 "pam_ldap: error getting old authentication token (%s)",
3764 pam_strerror (pamh, rc));
3765 return PAM_AUTHTOK_RECOVERY_ERR;
3766 }
3767
3768 if (try_first_pass || use_first_pass)
3769 {
3770 if (pam_get_item (pamh, PAM_AUTHTOK, (CONST_ARG void **) &newpass) !=
3771 PAM_SUCCESS)
3772 newpass = NULL;
3773
3774 if (use_first_pass && newpass == NULL)
3775 return PAM_AUTHTOK_RECOVERY_ERR;
3776 }
3777
3778 tries = 0;
3779
3780 /* support Netscape Directory Server's password policy */
3781 rc = _get_password_policy (session, &policy);
3782 if (rc != PAM_SUCCESS)
3783 return rc;
3784
3785 while ((newpass == NULL) && (tries++ < policy.password_max_failure))
3786 {
3787 pmsg = &msg;
3788 msg.msg_style = PAM_PROMPT_ECHO_OFF;
3789 msg.msg = NEW_PASSWORD_PROMPT;
3790 resp = NULL;
3791
3792 rc = appconv->conv (1, (CONST_ARG struct pam_message **) &pmsg,
3793 &resp, appconv->appdata_ptr);
3794
3795 if (rc != PAM_SUCCESS)
3796 return rc;
3797
3798 newpass = resp->resp;
3799 free (resp);
3800
3801 if (newpass != NULL && newpass[0] == '\0')
3802 {
3803 free (newpass);
3804 newpass = NULL;
3805 }
3806
3807 if (newpass != NULL)
3808 {
3809 if (getuid () != 0)
3810 {
3811 if (curpass != NULL && !strcmp (curpass, newpass))
3812 {
3813 cmiscptr = "Passwords must differ";
3814 newpass = NULL;
3815 }
3816 else if (strlen (newpass) < (size_t) policy.password_min_length)
3817 {
3818 cmiscptr = "Password too short";
3819 newpass = NULL;
3820 }
3821 }
3822 }
3823 else
3824 {
3825 return PAM_AUTHTOK_RECOVERY_ERR;
3826 }
3827
3828 if (cmiscptr == NULL)
3829 {
3830 /* get password again */
3831 char *miscptr = NULL;
3832
3833 pmsg = &msg;
3834 msg.msg_style = PAM_PROMPT_ECHO_OFF;
3835 msg.msg = AGAIN_PASSWORD_PROMPT;
3836 resp = NULL;
3837
3838 rc = appconv->conv (1, (CONST_ARG struct pam_message **) &pmsg,
3839 &resp, appconv->appdata_ptr);
3840
3841 if (rc == PAM_SUCCESS)
3842 {
3843 miscptr = resp->resp;
3844 free (resp);
3845 if (miscptr[0] == '\0')
3846 {
3847 free (miscptr);
3848 miscptr = NULL;
3849 }
3850 }
3851 if (miscptr == NULL)
3852 {
3853 if (canabort)
3854 {
3855 _conv_sendmsg (appconv, "Password change aborted",
3856 PAM_ERROR_MSG, no_warn);
3857 return PAM_AUTHTOK_RECOVERY_ERR;
3858 }
3859 }
3860 else if (!strcmp (newpass, miscptr))
3861 {
3862 miscptr = NULL;
3863 break;
3864 }
3865
3866 _conv_sendmsg (appconv, "You must enter the same password",
3867 PAM_ERROR_MSG, no_warn);
3868 miscptr = NULL;
3869 newpass = NULL;
3870 }
3871 else
3872 {
3873 _conv_sendmsg (appconv, cmiscptr, PAM_ERROR_MSG, no_warn);
3874 cmiscptr = NULL;
3875 newpass = NULL;
3876 }
3877 } /* while */
3878
3879 if (cmiscptr != NULL || newpass == NULL)
3880 return PAM_MAXTRIES;
3881
3882 rc = _update_authtok (pamh, session, username, curpass, newpass);
3883 if (rc != PAM_SUCCESS)
3884 {
3885 int lderr;
3886 char *reason = NULL;
3887
3888 lderr = ldap_get_lderrno (session->ld, NULL, &reason);
3889 if (reason != NULL)
3890 snprintf (errmsg, sizeof errmsg,
3891 "LDAP password information update failed: %s\n%s",
3892 ldap_err2string (lderr), reason);
3893 else
3894 snprintf (errmsg, sizeof errmsg,
3895 "LDAP password information update failed: %s",
3896 ldap_err2string (lderr));
3897
3898 _conv_sendmsg (appconv, errmsg, PAM_ERROR_MSG, no_warn);
3899 }
3900 else
3901 {
3902 /* update shadowLastChange; may fail if not shadowAccount */
3903 snprintf (buf, sizeof buf, "%ld", time (NULL) / (60 * 60 * 24));
3904 strvals[0] = buf;
3905 strvals[1] = NULL;
3906
3907 mod.mod_values = strvals;
3908 mod.mod_type = (char *) "shadowLastChange";
3909 mod.mod_op = LDAP_MOD_REPLACE;
3910
3911 mods[0] = &mod;
3912 mods[1] = NULL;
3913
3914 /* do this silently because it may fail */
3915 (void) ldap_modify_s (session->ld, session->info->userdn, mods);
3916
3917 snprintf (errmsg, sizeof errmsg,
3918 "LDAP password information changed for %s", username);
3919 _conv_sendmsg (appconv, errmsg, PAM_TEXT_INFO,
3920 (flags & PAM_SILENT) ? 1 : 0);
3921 session->info->policy_error = POLICY_ERROR_SUCCESS;
3922 }
3923
3924 pam_set_item (pamh, PAM_AUTHTOK, (void *) newpass);
3925
3926 return rc;
3927 }
3928
3929 PAM_EXTERN int
pam_sm_acct_mgmt(pam_handle_t * pamh,int flags,int argc,const char ** argv)3930 pam_sm_acct_mgmt (pam_handle_t * pamh, int flags, int argc, const char **argv)
3931 {
3932 /*
3933 * check whether the user can login.
3934 * returns one of:
3935 * PAM_ACCT_EXPIRED (account expired)
3936 * PAM_PERM_DENIED (authorization failed)
3937 * PAM_AUTHTOKEN_REQD (authtoken expired)
3938 * PAM_USER_UNKNOWN
3939 */
3940 int rc;
3941 const char *username;
3942 int no_warn = 0, ignore_flags = 0;
3943 int i, success = PAM_SUCCESS;
3944 struct pam_conv *appconv;
3945 pam_ldap_session_t *session = NULL;
3946 char buf[1024];
3947 time_t currenttime;
3948 long int currentday;
3949 long int expirein = 0; /* seconds until password expires */
3950 const char *configFile = NULL;
3951
3952 for (i = 0; i < argc; i++)
3953 {
3954 if (!strcmp (argv[i], "use_first_pass"))
3955 ;
3956 else if (!strcmp (argv[i], "try_first_pass"))
3957 ;
3958 else if (!strncmp (argv[i], "config=", 7))
3959 configFile = argv[i] + 7;
3960 else if (!strcmp (argv[i], "no_warn"))
3961 no_warn = 1;
3962 else if (!strcmp (argv[i], "ignore_unknown_user"))
3963 ignore_flags |= IGNORE_UNKNOWN_USER;
3964 else if (!strcmp (argv[i], "ignore_authinfo_unavail"))
3965 ignore_flags |= IGNORE_AUTHINFO_UNAVAIL;
3966 else if (!strcmp (argv[i], "debug"))
3967 ;
3968 else
3969 syslog (LOG_ERR, "illegal option %s", argv[i]);
3970 }
3971
3972 if (flags & PAM_SILENT)
3973 no_warn = 1;
3974
3975 rc = pam_get_item (pamh, PAM_CONV, (CONST_ARG void **) &appconv);
3976 if (rc != PAM_SUCCESS)
3977 return rc;
3978
3979 /*
3980 * Call pam_get_data() to see whether the pre-mapped
3981 * (non-template) user is available to us. If so,
3982 * use that instead.
3983 */
3984 rc = pam_get_data (pamh, PADL_LDAP_AUTH_DATA, (const void **) &username);
3985 if (rc != PAM_SUCCESS)
3986 {
3987 rc = pam_get_user (pamh, (CONST_ARG char **) &username, NULL);
3988 if (rc != PAM_SUCCESS)
3989 return rc;
3990 }
3991
3992 if (username == NULL)
3993 return PAM_USER_UNKNOWN;
3994
3995 rc = _pam_ldap_get_session (pamh, username, configFile, &session);
3996 if (rc != PAM_SUCCESS)
3997 {
3998 return rc;
3999 }
4000
4001 if (session->info == NULL)
4002 {
4003 rc = _get_user_info (session, username);
4004 if (rc != PAM_SUCCESS)
4005 {
4006 STATUS_MAP_IGNORE_POLICY (rc, ignore_flags);
4007
4008 return rc;
4009 }
4010 }
4011
4012 /* Grab the current time */
4013 time (¤ttime);
4014 currentday = (long int) (currenttime / SECSPERDAY);
4015
4016 /* Check shadow expire conditions */
4017 /* Do we have an absolute expiry date? */
4018 if (session->info->shadow.expire > 0)
4019 {
4020 if (currentday >= session->info->shadow.expire)
4021 {
4022 return PAM_ACCT_EXPIRED;
4023 }
4024 }
4025
4026 if (session->info->shadow.lstchg == 0)
4027 {
4028 /*
4029 * Adhere to convention of a shadow last change
4030 * value of 0 implying that the password has
4031 * expired. Apparently this is documented in the
4032 * shadow suite (libmisc/isexpired.c).
4033 */
4034 session->info->policy_error = POLICY_ERROR_PASSWORD_EXPIRED;
4035 }
4036
4037 /*
4038 * Also check if user hasn't changed password for the inactive
4039 * amount of time. This also counts as an expired account.
4040 */
4041 if ((session->info->shadow.lstchg > 0) &&
4042 (session->info->shadow.max > 0) && (session->info->shadow.inact > 0))
4043 {
4044 if (currentday >= (session->info->shadow.lstchg +
4045 session->info->shadow.max +
4046 session->info->shadow.inact))
4047 {
4048 return PAM_ACCT_EXPIRED;
4049 }
4050 }
4051
4052 /* Our shadow information should be populated, so do some calculations */
4053 if ((session->info->shadow.lstchg > 0) && (session->info->shadow.max > 0))
4054 {
4055 if (currentday >= (session->info->shadow.lstchg +
4056 session->info->shadow.max))
4057 {
4058 session->info->policy_error = POLICY_ERROR_PASSWORD_EXPIRED;
4059 }
4060 }
4061
4062 /* check whether the password has expired */
4063 switch (session->info->policy_error)
4064 {
4065 case POLICY_ERROR_SUCCESS:
4066 break;
4067 case POLICY_ERROR_PASSWORD_EXPIRED:
4068 case POLICY_ERROR_CHANGE_AFTER_RESET:
4069 _conv_sendmsg (appconv,
4070 "You are required to change your LDAP password immediately.",
4071 PAM_ERROR_MSG, no_warn);
4072 #ifdef LINUX
4073 rc = success = PAM_AUTHTOKEN_REQD;
4074 #else
4075 rc = success = PAM_NEW_AUTHTOK_REQD;
4076 #endif /* LINUX */
4077 break;
4078 case POLICY_ERROR_ACCOUNT_LOCKED:
4079 case POLICY_ERROR_PASSWORD_MOD_NOT_ALLOWED:
4080 case POLICY_ERROR_MUST_SUPPLY_OLD_PASSWORD:
4081 case POLICY_ERROR_INSUFFICIENT_PASSWORD_QUALITY:
4082 case POLICY_ERROR_PASSWORD_TOO_SHORT:
4083 case POLICY_ERROR_PASSWORD_TOO_YOUNG:
4084 case POLICY_ERROR_PASSWORD_INSUFFICIENT:
4085 _conv_sendmsg (appconv,
4086 policy_error_table[session->info->policy_error],
4087 PAM_ERROR_MSG, no_warn);
4088 return PAM_PERM_DENIED;
4089 break;
4090 default:
4091 snprintf (buf, sizeof buf,
4092 "Unknown password policy error %d received.",
4093 session->info->policy_error);
4094 _conv_sendmsg (appconv, buf, PAM_ERROR_MSG, no_warn);
4095 return PAM_PERM_DENIED;
4096 break;
4097 }
4098
4099 /*
4100 * Warnings. First, check if we've got a non-zero warning time
4101 * in the shadow struct. If so, we're a shadow account, and set
4102 * things accordingly. Otherwise, check the Netscape controls.
4103 */
4104
4105 /*
4106 * If the password's expired, no sense warning
4107 */
4108 if (session->info->policy_error != POLICY_ERROR_PASSWORD_EXPIRED)
4109 {
4110 if (session->info->shadow.warn > 0) /* shadowAccount */
4111 {
4112 /*
4113 * Are we within warning period?
4114 */
4115
4116 expirein = session->info->shadow.lstchg +
4117 session->info->shadow.max - currentday;
4118
4119 if (session->info->shadow.warn <= expirein)
4120 {
4121 expirein = 0; /* Not within warning period yet */
4122 }
4123 }
4124 else
4125 {
4126 expirein = session->info->password_expiration_time / SECSPERDAY;
4127 }
4128
4129 if (expirein > 0)
4130 {
4131 snprintf (buf, sizeof buf,
4132 "Your LDAP password will expire in %ld day%s.",
4133 expirein, (expirein == 1) ? "" : "s");
4134 _conv_sendmsg (appconv, buf, PAM_ERROR_MSG, no_warn);
4135
4136 /* we set this to make sure that user can't abort a password change */
4137 (void) pam_set_data (pamh, PADL_LDAP_AUTHTOK_DATA,
4138 (void *) strdup (username), _cleanup_data);
4139 }
4140 } /* password expired */
4141
4142 /* group auth, per Chris's pam_ldap_auth module */
4143 if (session->conf->groupdn != NULL)
4144 {
4145 rc = ldap_compare_s (session->ld,
4146 session->conf->groupdn,
4147 session->conf->groupattr, session->info->userdn);
4148 if (rc != LDAP_COMPARE_TRUE)
4149 {
4150 snprintf (buf, sizeof buf, "You must be a %s of %s to login.",
4151 session->conf->groupattr, session->conf->groupdn);
4152 _conv_sendmsg (appconv, buf, PAM_ERROR_MSG, no_warn);
4153 return PAM_PERM_DENIED;
4154 }
4155 else
4156 rc = success;
4157 }
4158
4159 if (rc == success && session->conf->checkserviceattr)
4160 {
4161 rc = _service_ok (pamh, session);
4162 if (rc != PAM_SUCCESS)
4163 _conv_sendmsg (appconv, "Access denied for this service",
4164 PAM_ERROR_MSG, no_warn);
4165 else
4166 rc = success;
4167 }
4168
4169 if (rc == success && session->conf->checkhostattr)
4170 {
4171 rc = _host_ok (session);
4172 if (rc != PAM_SUCCESS)
4173 _conv_sendmsg (appconv, "Access denied for this host", PAM_ERROR_MSG,
4174 no_warn);
4175 else
4176 rc = success;
4177 }
4178
4179 if (rc == success && session->conf->min_uid
4180 && session->info->uid < session->conf->min_uid)
4181 {
4182 snprintf (buf, sizeof buf, "UID must be greater than %ld",
4183 (long) session->conf->min_uid);
4184 _conv_sendmsg (appconv, buf, PAM_ERROR_MSG, no_warn);
4185 return PAM_PERM_DENIED;
4186 }
4187
4188 if (rc == success && session->conf->max_uid
4189 && session->info->uid > session->conf->max_uid)
4190 {
4191 snprintf (buf, sizeof buf, "UID must be less than %ld",
4192 (long) session->conf->max_uid);
4193 _conv_sendmsg (appconv, buf, PAM_ERROR_MSG, no_warn);
4194 return PAM_PERM_DENIED;
4195 }
4196
4197 return rc;
4198 }
4199
4200 /* static module data */
4201 #ifdef PAM_STATIC
4202 struct pam_module _modstruct = {
4203 "pam_ldap",
4204 pam_sm_authenticate,
4205 pam_sm_setcred,
4206 pam_sm_acct_mgmt,
4207 pam_sm_open_session,
4208 pam_sm_close_session,
4209 pam_sm_chauthtok
4210 };
4211 #endif /* PAM_STATIC */
4212