Imported Upstream version 0.63.0
[hcoop/debian/courier-authlib.git] / authldaplib.c
1 /*
2 * authldap.c -
3 *
4 * courier-imap -
5 *
6 * Copyright 1999 Luc Saillard <luc.saillard@alcove.fr>.
7 *
8 * This module use a server LDAP to authenticate user.
9 * See the README.ldap
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 *
20 * See the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; see the file COPYING. If not, write to
24 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 * Boston, MA 02111-1307, USA.
26 */
27
28 /*
29 * Modified 28/11/2001 Iustin Pop <iusty@intensit.de>
30 * There was a bug regarding the LDAP_TLS option: if both LDAP_TLS
31 * and was LDAP_AUTHBIND were enabled, the ldap_start_tls function
32 * was called only for the first connection, resulting in the fact
33 * that the bind for checking the password was done without TLS,
34 * sending the password in clear text over the network. Detected
35 * when using OpenLDAP with "security ssf=128" (which disalows any
36 * clear-text communication).
37 */
38
39 /*
40 Modified 01/21/2000 James Golovich <james@wwnet.net>
41
42 1. If LDAP_AUTHBIND is set in the config file, then the ldap server will
43 handle passwords via authenticated binds, instead of checking these
44 internally.
45 2. Changed paramaters for authldap_get to include pass.
46
47 */
48
49 /*
50 Modified 12/31/99 Sam Varshavchik:
51
52 1. read_env reads from a configuration file, instead of the environment
53 2. read_config appropriately modified.
54 3. If 'user' contains the @ character, domain from config is NOT appended.
55 4. added 'homeDir' attribute. Use 'homeDir' instead of mailDir, and put
56 mailDir into MAILDIR=
57 5. read_config renamed to authldap_read_config
58 6. get_user_info renamed to authldap_get
59 7. Added authldap_free_config, to clean up all the allocated memory
60 (required for preauthldap).
61 8. Output LDAP attributes are defined in the configuration file as well.
62 9. Allow both plaintext and crypted passwords to be read from LDAP.
63 10. Added GLOB_UID GLOB_GID, as well as UID and GID params.
64
65 2/19/2000 Sam.
66
67 Rewrite to allow this code to be used in a long-running authentication daemon
68 (for Courier). authldap_get renamed to authldapcommon, will initialize and
69 maintain a persistent connection. Password checking moved entirely to
70 authldap.c. authldapclose() will unbind and close the connection.
71
72 connection gets closed and reopened automatically after a protocol error.
73
74 error return from authldapcommon will indicate whether this is a transient,
75 or a permanent failure.
76
77 authldap_free_config removed - no longer required.
78
79 */
80
81 #if HAVE_CONFIG_H
82 #include "courier_auth_config.h"
83 #endif
84 #include <stdio.h>
85 #include <stdlib.h>
86 #include <ctype.h>
87 #include <string.h>
88 #include <errno.h>
89 #include <pwd.h>
90 #include <grp.h>
91 #include <time.h>
92 #if HAVE_UNISTD_H
93 #include <unistd.h>
94 #endif
95 #if HAVE_LBER_H
96 #include <lber.h>
97 #endif
98 #if HAVE_LDAP_H
99 #include <ldap.h>
100 #if LDAP_VENDOR_VERSION > 20000
101 #define OPENLDAPV2
102 #endif
103 #endif
104 #if HAVE_SYS_TIME_H
105 #include <sys/time.h>
106 #endif
107 #if HAVE_SYS_STAT_H
108 #include <sys/stat.h>
109 #endif
110
111 #include "authldap.h"
112 #include "auth.h"
113 #include "authldaprc.h"
114 #include "courierauthdebug.h"
115
116 #define err courier_auth_err
117
118 #ifndef DEBUG_LDAP
119 #define DEBUG_LDAP 0
120 #endif
121
122 #ifndef LDAP_OPT_SUCCESS
123 #define LDAP_OPT_SUCCESS LDAP_SUCCESS
124 #endif
125
126 static char **l_get_values(LDAP *ld, LDAPMessage *entry, const char *attribut)
127 {
128 struct berval **p=ldap_get_values_len(ld, entry, attribut);
129 int i, n;
130 char **a;
131
132 if (!p)
133 return NULL;
134
135 n=ldap_count_values_len(p);
136
137
138 a=malloc((n + 1) * sizeof(char *));
139
140 if (!a)
141 {
142 DPRINTF("malloc failed");
143 ldap_value_free_len(p);
144 return NULL;
145 }
146
147 for (i=0; i<n; i++)
148 {
149 if ((a[i]=malloc(p[i]->bv_len+1)) == NULL)
150 {
151 DPRINTF("malloc failed");
152 while (i--)
153 {
154 free(a[i]);
155 }
156 free(a);
157 ldap_value_free_len(p);
158 return NULL;
159 }
160
161 memcpy(a[i], p[i]->bv_val, p[i]->bv_len);
162 a[i][p[i]->bv_len]=0;
163 }
164
165 ldap_value_free_len(p);
166 a[i]=NULL;
167 return a;
168 }
169
170 static void l_value_free(char **p)
171 {
172 int i;
173
174 for (i=0; p[i]; ++i)
175 free(p[i]);
176 free(p);
177 }
178
179 static int l_count_values(char **p)
180 {
181 int i;
182
183 for (i=0; p[i]; ++i)
184 ;
185 return i;
186 }
187
188 static int l_unbind(LDAP *ld)
189 {
190 return ldap_unbind_ext(ld, NULL, NULL);
191 }
192
193 static int l_simple_bind_s(LDAP *ld,
194 const char *who,
195 const char *passwd)
196 {
197 struct berval cred;
198
199 cred.bv_len=passwd ? strlen(passwd):0;
200 cred.bv_val=(char *)passwd;
201
202 return ldap_sasl_bind_s(ld, who, NULL, &cred, NULL, NULL, NULL);
203 }
204
205 static int l_search_st(LDAP *ld,
206 const char *base,
207 int scope,
208 const char *filter,
209 char **attrs,
210 int attrsonly,
211 struct timeval *timeout,
212 LDAPMessage **res)
213 {
214 return ldap_search_ext_s(ld, base, scope, filter, attrs,
215 attrsonly,
216 NULL, NULL,
217 timeout,
218 100,
219 res);
220 }
221
222 static int l_modify_s(LDAP *ld,
223 const char *dn,
224 LDAPMod **mods)
225 {
226 return ldap_modify_ext_s(ld, dn, mods, NULL, NULL);
227 }
228
229 static int l_search(LDAP *ld,
230 const char *base,
231 int scope,
232 const char *filter,
233 char **attrs,
234 int attrsonly)
235 {
236 struct timeval tv;
237 int msgid;
238
239 tv.tv_sec=60*60;
240 tv.tv_usec=0;
241
242 if (ldap_search_ext(ld, base, scope, filter, attrs, attrsonly,
243 NULL, NULL, &tv, 1000000, &msgid) !=
244 LDAP_SUCCESS)
245 return -1;
246
247 return msgid;
248 }
249
250 struct ldap_info
251 {
252 const char *uri;
253 const char *binddn;
254 const char *bindpw;
255 const char *basedn;
256 const char *mail;
257 const char *filter;
258 const char *enumerate_filter;
259 const char *domain;
260
261 uid_t uid;
262 gid_t gid;
263 int timeout;
264 int authbind;
265 int deref;
266 int protocol_version;
267 int tls;
268
269 const char *mailroot;
270
271 char **auxoptions;
272 char **auxnames;
273 const char **attrlist;
274
275 /* Optional emailmap to handle */
276
277 const char *emailmap;
278 const char *emailmap_basedn;
279 const char *emailmap_handle;
280 const char *emailmap_handle_lookup;
281 };
282
283 /*
284 ** There's a memory leak in OpenLDAP 1.2.11, presumably in earlier versions
285 ** too. See http://www.OpenLDAP.org/its/index.cgi?findid=864 for more
286 ** information. To work around the bug, the first time a connection fails
287 ** we stop trying for 60 seconds. After 60 seconds we kill the process,
288 ** and let the parent process restart it.
289 **
290 ** We'll control this behavior via LDAP_MEMORY_LEAK. Set it to ZERO to turn
291 ** off this behavior (whenever OpenLDAP gets fixed).
292 */
293
294 static time_t ldapfailflag=0;
295
296 static void ldapconnfailure()
297 {
298 const char *p=getenv("LDAP_MEMORY_LEAK");
299
300 if (!p)
301 {
302 #ifdef LDAP_VENDOR_NAME
303 #ifdef LDAP_VENDOR_VERSION
304 #define DO_OPENLDAP_CHECK
305 #endif
306 #endif
307
308 #ifdef DO_OPENLDAP_CHECK
309
310 /* It's supposed to be fixed in 20019 */
311
312 if (strcmp(LDAP_VENDOR_NAME, "OpenLDAP") == 0 &&
313 LDAP_VENDOR_VERSION < 20019)
314 p="1";
315 else
316 p="0";
317 #else
318 p="0";
319 #endif
320 }
321
322 if (atoi(p) && !ldapfailflag)
323 {
324 time(&ldapfailflag);
325 ldapfailflag += 60;
326 }
327 }
328
329 static int ldapconncheck()
330 {
331 time_t t;
332
333 if (!ldapfailflag)
334 return (0);
335
336 time(&t);
337
338 if (t >= ldapfailflag)
339 exit(0);
340 return (1);
341 }
342
343 static int read_env(const char *env, const char **copy,
344 const char *errstr, int needit, const char *value_default);
345 static void copy_value(LDAP *ld, LDAPMessage *entry, const char *attribut,
346 char **copy, const char *username);
347
348 /*
349 * Function: read_env
350 * Copy the environnement $env and copy to $copy if not null
351 * if needit is false, and env doesn't exist, copy $value_default to $copy
352 * INPUT:
353 * $env: pointer to the environnement name
354 * $copy: where the value go
355 * $err: print a nice message when $env not_found and $needit is true
356 * $needit: if $needit is true and $value not found, return a error
357 * $value_default: the default value when $needit is false and $env doesn't exists
358 * OUTPUT:
359 * boolean
360 */
361 static int read_env(const char *env, const char **copy,
362 const char *errstr, int needit, const char *value_default)
363 {
364 static char *ldapauth=0;
365 static size_t ldapauth_size=0;
366 size_t i;
367 char *p=0;
368 int l=strlen(env);
369
370 if (!ldapauth)
371 {
372 FILE *f=fopen(AUTHLDAPRC, "r");
373 struct stat buf;
374
375 if (!f) return (0);
376 if (fstat(fileno(f), &buf) ||
377 (ldapauth=malloc(buf.st_size+2)) == 0)
378 {
379 fclose(f);
380 return (0);
381 }
382 if (fread(ldapauth, buf.st_size, 1, f) != 1)
383 {
384 free(ldapauth);
385 ldapauth=0;
386 fclose(f);
387 return (0);
388 }
389 ldapauth[ldapauth_size=buf.st_size]=0;
390
391 for (i=0; i<ldapauth_size; i++)
392 if (ldapauth[i] == '\n')
393 ldapauth[i]=0;
394 fclose(f);
395 }
396
397 for (i=0; i<ldapauth_size; )
398 {
399 p=ldapauth+i;
400 if (memcmp(p, env, l) == 0 &&
401 isspace((int)(unsigned char)p[l]))
402 {
403 p += l;
404 while (*p && *p != '\n' &&
405 isspace((int)(unsigned char)*p))
406 ++p;
407 break;
408 }
409
410 while (i < ldapauth_size)
411 if (ldapauth[i++] == 0) break;
412 }
413
414 if (i < ldapauth_size)
415 {
416 *copy= p;
417 return (1);
418 }
419
420 if (needit)
421 {
422 err("%s", errstr);
423 return 0;
424 }
425
426 *copy=0;
427 if (value_default)
428 *copy=value_default;
429
430 return 1;
431 }
432
433 /*
434 * Function: authldap_read_config
435 * Read Configuration from the environnement table
436 * INPUT:
437 * $ldap: a structure where we place information
438 * OUTPUT:
439 * boolean
440 */
441 static int authldap_read_config(struct ldap_info *ldap)
442 {
443 struct passwd *pwent;
444 struct group *grent;
445 const char *p;
446 size_t i, pass;
447
448 for (i=0; ldap->auxoptions && ldap->auxoptions[i]; i++)
449 free(ldap->auxoptions[i]);
450 for (i=0; ldap->auxnames && ldap->auxnames[i]; i++)
451 free(ldap->auxnames[i]);
452
453 if (ldap->attrlist)
454 free(ldap->attrlist);
455 if (ldap->auxnames)
456 free(ldap->auxnames);
457 if (ldap->auxoptions)
458 free(ldap->auxoptions);
459
460 memset(ldap,0,sizeof(struct ldap_info));
461
462 if (!read_env("LDAP_URI",&ldap->uri,
463 "You need to specify LDAP_URI in config file",1,NULL))
464 return 0;
465
466 if (!read_env("LDAP_AUTHBIND", &p, "", 0, ""))
467 return (0);
468
469 if (p)
470 sscanf(p,"%d",&ldap->authbind);
471
472 if (!read_env("LDAP_BASEDN",&ldap->basedn,
473 "You need to specify a basedn in config file",1,NULL))
474 return 0;
475 if (!read_env("LDAP_BINDDN",&ldap->binddn,
476 "You need to specify a BINDDN in config file",0,NULL))
477 return 0;
478 if (!read_env("LDAP_BINDPW",&ldap->bindpw,
479 "You need to specify a password for the BINDDN in config file",0,NULL))
480 return 0;
481 if (!read_env("LDAP_MAIL",&ldap->mail,
482 "You need to specify a attribute for mail in config file",0,"mail"))
483 return 0;
484 if (!read_env("LDAP_DOMAIN",&ldap->domain,
485 "You need to specify a domain for mail in config file",0,""))
486 return 0;
487
488 p=0;
489 ldap->uid=0;
490 if (!read_env("LDAP_GLOB_UID", &p, "", 0, ""))
491 return (0);
492
493 if (p && *p)
494 {
495 unsigned long n;
496
497 if (sscanf(p, "%lu", &n) == 1)
498 ldap->uid=(uid_t)n;
499 else
500 {
501 pwent=getpwnam(p);
502 if (!pwent)
503 {
504 err("authldap: INVALID LDAP_GLOB_UID");
505 return (0);
506 }
507 ldap->uid=pwent->pw_uid;
508 }
509 }
510
511 ldap->gid=0;
512 p=0;
513 if (!read_env("LDAP_GLOB_GID", &p, "", 0, ""))
514 return (0);
515
516 if (p && *p)
517 {
518 unsigned long n;
519
520 if (sscanf(p, "%lu", &n) == 1)
521 ldap->gid=(gid_t)n;
522 else
523 {
524 grent=getgrnam(p);
525 if (!grent)
526 {
527 err("authldap: INVALID LDAP_GLOB_GID");
528 return (0);
529 }
530 ldap->gid=grent->gr_gid;
531 }
532 }
533
534 ldap->timeout=5;
535 p=0;
536 if (read_env("LDAP_TIMEOUT", &p, "", 0, "") && p)
537 {
538 sscanf(p,"%d",&ldap->timeout);
539 }
540
541 ldap->tls=0;
542 p=0;
543 if (read_env("LDAP_TLS", &p, "", 0, "") && p)
544 {
545 ldap->tls=atoi(p);
546 }
547
548 ldap->filter=0;
549 p=0;
550 if (read_env("LDAP_FILTER", &p, "", 0, "") && p && strlen (p))
551 {
552 ldap->filter=p;
553 }
554
555 ldap->enumerate_filter=0;
556 p=0;
557 if (read_env("LDAP_ENUMERATE_FILTER", &p, "", 0, "") && p && strlen (p))
558 {
559 ldap->enumerate_filter=p;
560 }
561 else if (ldap->filter)
562 {
563 ldap->enumerate_filter=ldap->filter;
564 }
565 else
566 {
567 ldap->enumerate_filter = malloc(strlen(ldap->mail)+3);
568 if (!ldap->enumerate_filter)
569 {
570 perror("CRIT: authldap: malloc failed");
571 return 0;
572 }
573 sprintf((char *)ldap->enumerate_filter, "%s=*", ldap->mail);
574 }
575
576 ldap->deref = LDAP_DEREF_NEVER;
577 ldap->protocol_version = 0; /* use API default */
578 p=0;
579 if (!read_env("LDAP_DEREF", &p, "", 0, ""))
580 return (0);
581 if (p)
582 {
583 #ifndef LDAP_OPT_DEREF
584 err("authldaplib: LDAP_OPT_DEREF not available, ignored");
585 #endif
586 if (!strcasecmp (p, "never"))
587 ldap->deref = LDAP_DEREF_NEVER;
588 else if (!strcasecmp (p, "searching"))
589 ldap->deref = LDAP_DEREF_SEARCHING;
590 else if (!strcasecmp (p, "finding"))
591 ldap->deref = LDAP_DEREF_FINDING;
592 else if (!strcasecmp (p, "always"))
593 ldap->deref = LDAP_DEREF_ALWAYS;
594 }
595
596 if (!read_env("LDAP_PROTOCOL_VERSION", &p, 0, 0, 0))
597 return (0);
598 if (p)
599 {
600 int lpv = atoi(p);
601 #ifndef LDAP_OPT_PROTOCOL_VERSION
602 err("authldaplib: LDAP_OPT_PROTOCOL_VERSION not available, ignored");
603 #endif
604 if (lpv == 0
605 #ifdef LDAP_VERSION_MIN
606 || lpv < LDAP_VERSION_MIN
607 #endif
608 #ifdef LDAP_VERSION_MAX
609 || lpv > LDAP_VERSION_MAX
610 #endif
611 )
612 err("authldaplib: illegal protocol version ignored");
613 else
614 ldap->protocol_version = lpv;
615 }
616
617 if (!read_env("LDAP_MAILROOT",&ldap->mailroot,"",0,NULL)
618 || ldap->mailroot == NULL || ldap->mailroot[0] == 0)
619 ldap->mailroot=NULL;
620
621 if (!read_env("LDAP_EMAILMAP", &ldap->emailmap, "", 0, "") ||
622 !read_env("LDAP_EMAILMAP_BASEDN", &ldap->emailmap_basedn, "", 0, "") ||
623 !read_env("LDAP_EMAILMAP_ATTRIBUTE", &ldap->emailmap_handle, "", 0, "")||
624 !read_env("LDAP_EMAILMAP_MAIL",
625 &ldap->emailmap_handle_lookup, "", 0, ""))
626 return (0);
627
628
629 for (pass=0; pass<2; pass++)
630 {
631 if (pass)
632 {
633 if ((ldap->auxnames=malloc((i+1)*sizeof(char *)))
634 == NULL ||
635 (ldap->auxoptions=malloc((i+1)*sizeof(char *)))
636 == NULL)
637 {
638 perror("CRIT: authldap: malloc failed");
639 if (ldap->auxnames)
640 ldap->auxnames[0]=0;
641 return 0;
642 }
643 }
644 i=0;
645
646 if (pass)
647 {
648 ldap->auxnames[0]=NULL;
649 ldap->auxoptions[0]=NULL;
650 }
651
652 if (!read_env("LDAP_AUXOPTIONS", &p, "", 0, NULL)
653 || p == NULL || *p == 0)
654 p=NULL;
655
656 while (p && *p)
657 {
658 size_t n;
659
660 if (*p == ',')
661 {
662 ++p;
663 continue;
664 }
665
666 for (n=0; p[n] && p[n] != ',' && p[n] != '='; n++)
667 ;
668
669 if (pass)
670 {
671 if ((ldap->auxoptions[i]=malloc(n+1)) == NULL)
672 {
673 perror("CRIT: authldap: malloc failed");
674 return 0;
675 }
676
677 memcpy(ldap->auxoptions[i], p, n);
678 ldap->auxoptions[i][n]=0;
679 ldap->auxoptions[i+1]=NULL;
680 }
681
682 p += n;
683
684 if (*p == '=') ++p;
685
686 for (n=0; p[n] && p[n] != ','; n++)
687 ;
688
689 if (pass)
690 {
691 if (n == 0)
692 {
693 if ((ldap->auxnames[i]=
694 strdup(ldap->auxoptions[i]))
695 == NULL)
696 {
697 perror("CRIT: authldap: malloc failed");
698 return 0;
699 }
700 }
701 else if ((ldap->auxnames[i]=malloc(n+1)) == NULL)
702 {
703 perror("CRIT: authldap: malloc failed");
704 return 0;
705 }
706 else
707 {
708 memcpy(ldap->auxnames[i], p, n);
709 ldap->auxnames[i][n]=0;
710 ldap->auxnames[i+1]=NULL;
711 }
712 }
713 p += n;
714 ++i;
715 }
716 }
717
718 if ((ldap->attrlist=malloc((i+20)*sizeof(const char *))) == NULL)
719 {
720 perror("CRIT: authldap: malloc failed");
721 return 0;
722 }
723
724 return 1;
725 }
726
727 static void get_error(LDAP *ld, LDAPMessage *entry,
728 const char *func,
729 const char *attribut)
730 {
731 #if HAVE_LDAP_PARSE_RESULT
732
733 int errcode;
734 char *nmatched;
735 char *errmsg;
736
737
738 if (ldap_parse_result(ld, entry, &errcode, &nmatched,
739 &errmsg, NULL, NULL, 0)
740 != LDAP_SUCCESS)
741 {
742 DPRINTF("ldap_parseresult failed");
743 }
744 else
745 {
746 if (errcode && errcode != LDAP_DECODING_ERROR &&
747 errcode != LDAP_NO_RESULTS_RETURNED)
748 {
749 DPRINTF("get_values attribute %s: %s",
750 attribut,
751 errmsg ? errmsg:"unknown error");
752 }
753
754 if (errmsg)
755 ldap_memfree(errmsg);
756 if (nmatched)
757 ldap_memfree(nmatched);
758 }
759 #else
760 #if HAVE_LDAP_RESULT2ERROR
761 int ld_errno = ldap_result2error(ld,entry,0);
762 if (ld_errno && ld_errno != LDAP_DECODING_ERROR
763 && ld_errno != LDAP_NO_RESULTS_RETURNED)
764 {
765 DPRINTF("get_values attribute %s: %s", attribut,
766 ldap_err2string(ld_errno));
767 }
768 #else
769 if (ld->ld_errno != LDAP_DECODING_ERROR
770 && ld->ld_errno != LDAP_NO_RESULTS_RETURNED)
771 {
772 DPRINTF("get_values attribute %s: %s", attribut,
773 ldap_err2string(ld->ld_errno));
774 }
775 #endif
776 #endif
777 }
778
779 static char **get_values(LDAP *ld, LDAPMessage *entry, const char *attribut)
780 {
781 char ** values;
782 values=l_get_values(ld,entry, (char *)attribut);
783
784 if (values==NULL)
785 {
786 get_error(ld, entry, "get_values", attribut);
787 }
788
789 return values;
790 }
791
792
793
794 /*
795 * Function: copy_value
796 * Copy value from a LDAP attribute to $copy
797 * INPUT:
798 * $ld: the connection with the LDAP server
799 * $entry: the entry who contains attributes
800 * $attribut: this attribut
801 * $copy: where data can go
802 * OUTPUT:
803 * void
804 */
805 static void copy_value(LDAP *ld, LDAPMessage *entry, const char *attribut,
806 char **copy, const char *username)
807 {
808 char ** values;
809 values=l_get_values(ld,entry, attribut);
810
811 if (values==NULL)
812 {
813 get_error(ld, entry, "copy_value ", attribut);
814 *copy=NULL;
815 return;
816 }
817 /* We accept only attribute with one value */
818 else if (l_count_values(values)>1)
819 {
820 *copy=strdup(values[0]);
821 fprintf(stderr, "WARN: authldaplib: duplicate attribute %s for %s\n",
822 attribut,
823 username);
824 *copy=NULL;
825 }
826 /* We accept only attribute with one value */
827 else if (l_count_values(values)!=1)
828 {
829 *copy=NULL;
830 }
831 else
832 {
833 *copy=strdup(values[0]);
834 }
835 #if DEBUG_LDAP
836 DPRINTF("copy_value %s: %s",attribut,values[0]);
837 #endif
838 l_value_free(values);
839 }
840
841 static struct ldap_info my_ldap;
842 static LDAP *my_ldap_fp=0;
843 static LDAP *bindp=0; /* for checking passwords with AUTHBIND */
844
845 void authldapclose()
846 {
847 if (my_ldap_fp)
848 {
849 l_unbind(my_ldap_fp);
850 my_ldap_fp=0;
851 }
852 if (bindp)
853 {
854 l_unbind(bindp);
855 bindp=0;
856 }
857 }
858
859 static int ldaperror(int rc)
860 {
861 #ifdef OPENLDAPV2
862 if (rc && !LDAP_NAME_ERROR(rc))
863 #else
864 if (rc && !NAME_ERROR(rc))
865 #endif
866 {
867 /* If there was a protocol error, close the connection */
868 authldapclose();
869 ldapconnfailure();
870 }
871 return (rc);
872 }
873
874 /* This function takes a ldap connection and
875 * tries to enable TLS on it.
876 */
877 static int enable_tls_on(LDAP *conn) {
878 #if HAVE_LDAP_TLS
879 int version;
880 int ldrc;
881
882 if (ldaperror(ldrc=ldap_get_option (conn,
883 LDAP_OPT_PROTOCOL_VERSION,
884 &version))
885 != LDAP_SUCCESS)
886 {
887 const char *s=ldap_err2string(ldrc);
888
889 err("ldap_get_option failed: %s", s);
890 return (-1);
891 }
892
893 if (version < LDAP_VERSION3)
894 {
895 version = LDAP_VERSION3;
896 (void)ldap_set_option (conn,
897 LDAP_OPT_PROTOCOL_VERSION,
898 &version);
899 }
900
901 if (ldaperror(ldrc=ldap_start_tls_s(conn, NULL, NULL))
902 != LDAP_SUCCESS)
903 {
904 const char *s=ldap_err2string(ldrc);
905
906 err("ldap_start_tls_s failed: %s", s);
907 return (-1);
908 }
909 return 0;
910 #else
911 err("authldaplib: TLS not available");
912 return (-1);
913 #endif
914 }
915
916 static LDAP *ldapconnect()
917 {
918 LDAP *p=NULL;
919
920 #if DEBUG_LDAP
921 DPRINTF("URI: %s",my_ldap.uri);
922 DPRINTF("UID: %d",my_ldap.uid);
923 DPRINTF("GID: %d",my_ldap.gid);
924 #endif
925
926 if (ldapconncheck())
927 {
928 DPRINTF("authldaplib: timing out after failed connection");
929 return (NULL);
930 }
931
932 ldap_initialize(&p, my_ldap.uri);
933
934 if (p==NULL)
935 {
936 err("cannot connect to LDAP server (%s): %s",
937 my_ldap.uri, strerror(errno));
938 ldapconnfailure();
939 }
940 #ifdef LDAP_OPT_NETWORK_TIMEOUT
941 if (my_ldap.timeout > 0)
942 ldap_set_option (p, LDAP_OPT_NETWORK_TIMEOUT, &my_ldap.timeout);
943 #endif
944 #if DEBUG_LDAP
945 DPRINTF("ldapconnect end");
946 #endif
947 return (p);
948 }
949
950 static int ldapopen()
951 {
952 int ldrc;
953
954 if (my_ldap_fp) return (0);
955
956 if (authldap_read_config(&my_ldap) == 0)
957 {
958 err("authldaplib: error in LDAP configuration file, aborting");
959 return (1);
960 }
961
962 my_ldap_fp=ldapconnect();
963
964 if (!my_ldap_fp)
965 {
966 return (1);
967 }
968
969 #ifdef LDAP_OPT_PROTOCOL_VERSION
970
971 /* Set protocol version if selected */
972 if (my_ldap.protocol_version &&
973 ldaperror(ldrc = ldap_set_option(my_ldap_fp, LDAP_OPT_PROTOCOL_VERSION,
974 (void *) & my_ldap.protocol_version)) != LDAP_SUCCESS)
975 {
976 const char *s=ldap_err2string(ldrc);
977
978 err("ldap_set_option(PROTOCOL_VERSION %d) failed: %s",
979 my_ldap.protocol_version, s);
980 authldapclose();
981 ldapconnfailure();
982 return (-1);
983 }
984 if (my_ldap.protocol_version)
985 {
986 DPRINTF("selected ldap protocol version %d", my_ldap.protocol_version);
987 }
988 #endif
989
990 if (my_ldap.tls && enable_tls_on(my_ldap_fp))
991 {
992 authldapclose();
993 ldapconnfailure();
994 return (-1);
995 }
996
997 #ifdef LDAP_OPT_DEREF
998
999 /* Set dereferencing mode */
1000 if (ldaperror(ldrc = ldap_set_option(my_ldap_fp, LDAP_OPT_DEREF,
1001 (void *) & my_ldap.deref)) != LDAP_SUCCESS)
1002 {
1003 const char *s=ldap_err2string(ldrc);
1004
1005 err("ldap_set_option(DEREF) failed: %s", s);
1006 authldapclose();
1007 ldapconnfailure();
1008 return (-1);
1009 }
1010 #endif
1011
1012 /* Bind to server */
1013 if (courier_authdebug_login_level >= 2)
1014 {
1015 DPRINTF("binding to LDAP server as DN '%s', password '%s'",
1016 my_ldap.binddn ? my_ldap.binddn : "<null>",
1017 my_ldap.bindpw ? my_ldap.bindpw : "<null>");
1018 }
1019 else
1020 {
1021 DPRINTF("binding to LDAP server as DN '%s'",
1022 my_ldap.binddn ? my_ldap.binddn : "<null>");
1023 }
1024
1025 if (ldaperror(ldrc = l_simple_bind_s(my_ldap_fp,
1026 my_ldap.binddn,
1027 my_ldap.bindpw)) != LDAP_SUCCESS)
1028 {
1029 const char *s=ldap_err2string(ldrc);
1030
1031 err("ldap_simple_bind_s failed: %s", s);
1032 authldapclose();
1033 ldapconnfailure();
1034 return (-1);
1035 }
1036 return (0);
1037 }
1038
1039 static int auth_ldap_do(const char *, const char *, const char *,
1040 int (*)(struct authinfo *, void *),
1041 void *arg, const char *);
1042
1043 int auth_ldap_changepw(const char *dummy, const char *user,
1044 const char *pass,
1045 const char *newpass)
1046 {
1047 return auth_ldap_do("authlib", user, pass, NULL, NULL, newpass);
1048 }
1049
1050 /*
1051 * Function: authldapcommon
1052 * Get information from the LDAP server ($ldap) for this $user
1053 * INPUT:
1054 * $user: the login name
1055 * $pass: the login password (NULL if we don't want to check the pw)
1056 * callback - callback function with filled in authentication info
1057 * arg - extra argument for the callback function.
1058 * OUTPUT:
1059 * < 0 - authentication failure
1060 * > 0 - temporary failure
1061 * else return code from the callback function.
1062 */
1063
1064 int authldapcommon(const char *service,
1065 const char *user, const char *pass,
1066 int (*callback)(struct authinfo *, void *),
1067 void *arg)
1068 {
1069 return (auth_ldap_do(service, user, pass, callback, arg, NULL));
1070 }
1071
1072 static int auth_ldap_do2(const char *service,
1073 const char *user, const char *pass,
1074 int (*callback)(struct authinfo *, void *),
1075 void *arg, const char *newpass);
1076
1077 static int auth_ldap_retry(const char *service,
1078 const char *user, const char *pass,
1079 int (*callback)(struct authinfo *, void *),
1080 void *arg, const char *newpass);
1081
1082 static int auth_ldap_do(const char *service,
1083 const char *user, const char *pass,
1084 int (*callback)(struct authinfo *, void *),
1085 void *arg, const char *newpass)
1086 {
1087 int rc=auth_ldap_retry(service, user, pass, callback, arg, newpass);
1088
1089 if (rc > 0)
1090 rc=auth_ldap_retry(service, user, pass, callback, arg,
1091 newpass);
1092
1093 return rc;
1094 }
1095
1096 static int auth_ldap_retry(const char *service,
1097 const char *user, const char *pass,
1098 int (*callback)(struct authinfo *, void *),
1099 void *arg, const char *newpass)
1100 {
1101 char *q;
1102 int i;
1103
1104 q=courier_auth_ldap_escape(user);
1105
1106 if (!q)
1107 {
1108 perror("malloc");
1109 return 1;
1110 }
1111
1112 i=auth_ldap_do2(service, q, pass, callback, arg, newpass);
1113 free(q);
1114 return (i);
1115 }
1116
1117
1118 static int auth_ldap_do3(const char *service,
1119 const char *attrname,
1120 const char *user, const char *pass,
1121 int (*callback)(struct authinfo *, void *),
1122 void *arg, const char *newpass, const char *authaddr);
1123
1124 static char *emailmap_get_search_string(const char *str, const char *email);
1125
1126 static int auth_ldap_do2(const char *service,
1127 const char *user, const char *pass,
1128 int (*callback)(struct authinfo *, void *),
1129 void *arg, const char *newpass)
1130 {
1131 char *srch;
1132 struct timeval tv;
1133 const char *attributes[2];
1134 LDAPMessage *result, *entry;
1135 int cnt;
1136 char *v;
1137 const char *aname;
1138
1139 if (ldapopen()) return (1);
1140
1141 if (my_ldap.emailmap[0] == 0 || strchr(user, '@') == NULL)
1142 return (auth_ldap_do3(service, my_ldap.mail,
1143 user, pass, callback, arg, newpass,
1144 user));
1145 /* Mapping is not enabled */
1146
1147 srch=emailmap_get_search_string(my_ldap.emailmap, user);
1148
1149 if (!srch)
1150 {
1151 perror("CRIT: authldaplib: malloc");
1152 exit(1);
1153 }
1154 DPRINTF("using emailmap search: %s", srch);
1155
1156 tv.tv_sec=my_ldap.timeout;
1157 tv.tv_usec=0;
1158
1159 attributes[0]=my_ldap.emailmap_handle;
1160
1161 if (!attributes[0][0])
1162 attributes[0]="handle";
1163 attributes[1]=NULL;
1164
1165 if (ldaperror(l_search_st(my_ldap_fp,
1166 (char *)(my_ldap.emailmap_basedn[0] ?
1167 my_ldap.emailmap_basedn
1168 :my_ldap.basedn),
1169 LDAP_SCOPE_SUBTREE,
1170 srch, (char **)attributes, 0,
1171 &tv, &result))
1172 != LDAP_SUCCESS)
1173 {
1174 free(srch);
1175
1176 DPRINTF("ldap_search_st failed");
1177 if (my_ldap_fp) return (-1);
1178 return (1);
1179 }
1180
1181 if ((cnt=ldap_count_entries(my_ldap_fp, result)) != 1)
1182 {
1183 if (cnt)
1184 err("emailmap: %d entries returned from search %s (but we need exactly 1)",
1185 cnt, srch);
1186 free(srch);
1187 ldap_msgfree(result);
1188 return -1;
1189 }
1190 free(srch);
1191
1192 entry=ldap_first_entry(my_ldap_fp, result);
1193
1194 if (!entry)
1195 {
1196 ldap_msgfree(result);
1197
1198 err("authldap: unexpected NULL from ldap_first_entry");
1199 return -1;
1200 }
1201
1202 copy_value(my_ldap_fp, entry, attributes[0], &v, user);
1203
1204 if (!v)
1205 {
1206 DPRINTF("emailmap: empty attribute");
1207 ldap_msgfree(result);
1208 return (-1);
1209 }
1210
1211 aname=my_ldap.emailmap_handle_lookup;
1212 if (aname[0] == 0)
1213 aname=my_ldap.mail;
1214
1215 DPRINTF("emailmap results: aname=%s, handle=%s", aname, v);
1216
1217 cnt=auth_ldap_do3(service,
1218 aname, v, pass, callback, arg, newpass, user);
1219
1220 ldap_msgfree(result);
1221 free(v);
1222 return (cnt);
1223 }
1224
1225 static int auth_ldap_do3(const char *service,
1226 const char *attrname,
1227 const char *user, const char *pass,
1228 int (*callback)(struct authinfo *, void *),
1229 void *arg, const char *newpass,
1230 const char *authaddr)
1231 {
1232 char *newpass_crypt=0;
1233 const char *attributes[10];
1234 struct timeval timeout;
1235
1236 LDAPMessage *result;
1237 LDAPMessage *entry;
1238 char *filter, *dn;
1239 int i, j;
1240
1241 struct authinfo auth;
1242 char *homeDir=0;
1243 char *mailDir=0;
1244 char *userPassword=0;
1245 char *cryptPassword=0;
1246 char *options=0;
1247 char *cn=0;
1248 uid_t au;
1249 gid_t ag;
1250 int rc;
1251 char *quota=0;
1252 int additionalFilter = 0;
1253 int hasAdditionalFilter = 0;
1254
1255 hasAdditionalFilter = my_ldap.filter != 0;
1256
1257 memset(&auth, 0, sizeof(auth));
1258
1259 if (hasAdditionalFilter)
1260 {
1261 /* To add the additional filter, we need to add on the
1262 * additional size for "(&)" and the other filter. So
1263 * filter+3
1264 */
1265 additionalFilter = strlen(my_ldap.filter) + 3;
1266 }
1267
1268 if ((filter=malloc(additionalFilter+strlen(attrname)+strlen(user)+
1269 (my_ldap.domain ? strlen(my_ldap.domain):0)+
1270 sizeof ("(=@)"))) == 0)
1271 {
1272 perror("malloc");
1273 return 1;
1274 }
1275 strcpy(filter, "\0");
1276
1277 if (hasAdditionalFilter)
1278 {
1279 strcat(filter, "(&");
1280 strcat(filter, my_ldap.filter);
1281 }
1282
1283 strcat(strcat(strcat(strcat(filter, "("), attrname), "="), user);
1284 if ( my_ldap.domain && my_ldap.domain[0] && strchr(user, '@') == 0 )
1285 strcat(strcat(filter, "@"), my_ldap.domain);
1286 strcat(filter, ")");
1287
1288 if (hasAdditionalFilter)
1289 {
1290 strcat(filter, ")");
1291 }
1292
1293 DPRINTF("using search filter: %s", filter);
1294
1295 timeout.tv_sec=my_ldap.timeout;
1296 timeout.tv_usec=0;
1297
1298 read_env("LDAP_HOMEDIR", &attributes[0], "", 0, "homeDir");
1299 read_env(service && strcmp(service, "courier") == 0
1300 ? "LDAP_DEFAULTDELIVERY":"LDAP_MAILDIR",
1301 &attributes[1], "", 0, 0);
1302 read_env("LDAP_FULLNAME", &attributes[2], "", 0, "cn");
1303 read_env("LDAP_CLEARPW", &attributes[3], "", 0, 0);
1304 read_env("LDAP_CRYPTPW", &attributes[4], "", 0, 0);
1305 read_env("LDAP_UID", &attributes[5], "", 0, 0);
1306 read_env("LDAP_GID", &attributes[6], "", 0, 0);
1307 attributes[7]=my_ldap.mail;
1308 read_env("LDAP_MAILDIRQUOTA", &attributes[8], "", 0, 0);
1309
1310 j=0;
1311 for (i=0; i<9; i++)
1312 {
1313 if (attributes[i])
1314 my_ldap.attrlist[j++]=attributes[i];
1315 }
1316
1317 for (i=0; my_ldap.auxoptions[i]; i++)
1318 my_ldap.attrlist[j++]=my_ldap.auxoptions[i];
1319
1320 my_ldap.attrlist[j]=0;
1321
1322 if (ldaperror(l_search_st(my_ldap_fp,
1323 (char *)my_ldap.basedn,LDAP_SCOPE_SUBTREE,
1324 filter, (char **)my_ldap.attrlist, 0,
1325 &timeout, &result))
1326 != LDAP_SUCCESS)
1327 {
1328 DPRINTF("ldap_search_st() failed");
1329 free(filter);
1330
1331 if (my_ldap_fp) return (-1);
1332 return (1);
1333 }
1334
1335 free(filter);
1336
1337 /* If we are more than one result, reject */
1338 if (ldap_count_entries(my_ldap_fp,result)!=1)
1339 {
1340 DPRINTF("number of entries returned: %d (but we need exactly 1)",
1341 ldap_count_entries(my_ldap_fp,result));
1342 ldap_msgfree(result);
1343 return -1;
1344 }
1345
1346 dn = ldap_get_dn(my_ldap_fp, result);
1347
1348 DPRINTF("one entry returned, DN: %s", dn ? dn : "<null>");
1349
1350 if (dn == NULL)
1351 {
1352 DPRINTF("ldap_get_dn failed");
1353 return -1;
1354 }
1355
1356 /* Get the pointer on this result */
1357 entry=ldap_first_entry(my_ldap_fp,result);
1358 if (entry==NULL)
1359 {
1360 DPRINTF("ldap_first_entry failed");
1361 free(dn);
1362 return -1;
1363 }
1364
1365 #if DEBUG_LDAP
1366 DPRINTF("after ldap_first_entry");
1367 #endif
1368
1369 /* print all the raw attributes */
1370 if (courier_authdebug_login_level >= 2)
1371 {
1372 char *attr;
1373 BerElement *berptr = 0;
1374
1375 attr = ldap_first_attribute(my_ldap_fp, entry, &berptr);
1376 if (attr)
1377 {
1378 DPRINTF("raw ldap entry returned:");
1379 }
1380
1381 while (attr)
1382 {
1383 char **av, **ap;
1384
1385 av = l_get_values(my_ldap_fp, entry, attr);
1386 ap = av;
1387 if (av)
1388 {
1389 while(*ap)
1390 {
1391 DPRINTF("| %s: %s", attr, *ap);
1392 ap++;
1393 }
1394 l_value_free(av);
1395 }
1396 ldap_memfree(attr);
1397 attr = ldap_next_attribute(my_ldap_fp, entry, berptr);
1398 }
1399
1400 ber_free(berptr, 0);
1401 }
1402
1403 /* Copy the directory and the password into struct */
1404 copy_value(my_ldap_fp,entry,attributes[0],&homeDir, user);
1405 if (attributes[1])
1406 copy_value(my_ldap_fp,entry,attributes[1],&mailDir, user);
1407 copy_value(my_ldap_fp,entry,attributes[2],&cn, user);
1408 if (attributes[3])
1409 copy_value(my_ldap_fp,entry,attributes[3],&userPassword, user);
1410 if (attributes[4])
1411 copy_value(my_ldap_fp,entry,attributes[4],&cryptPassword, user);
1412
1413 au=my_ldap.uid;
1414 ag=my_ldap.gid;
1415 if (attributes[5])
1416 {
1417 char *p=0;
1418 unsigned long n;
1419
1420 copy_value(my_ldap_fp, entry, attributes[5], &p, user);
1421 if (p) {
1422 if (sscanf(p, "%lu", &n) > 0)
1423 au= (uid_t)n;
1424 free(p);
1425 }
1426 #if DEBUG_LDAP
1427 DPRINTF("au= %d",au);
1428 #endif
1429 }
1430
1431 if (attributes[6])
1432 {
1433 char *p=0;
1434 unsigned long n;
1435
1436 copy_value(my_ldap_fp, entry, attributes[6], &p, user);
1437 if (p) {
1438 if (sscanf(p, "%lu", &n) > 0)
1439 ag= (gid_t)n;
1440 free(p);
1441 }
1442 #if DEBUG_LDAP
1443 DPRINTF("ag= %d",ag);
1444 #endif
1445 }
1446
1447 if (attributes[8])
1448 copy_value(my_ldap_fp,entry,attributes[8],&quota, user);
1449
1450 if (homeDir != 0 && my_ldap.mailroot != 0 && *my_ldap.mailroot)
1451 {
1452 char *new_mailroot=malloc(strlen(homeDir)+
1453 strlen(my_ldap.mailroot)+2);
1454
1455 if (!new_mailroot)
1456 {
1457 perror("CRIT: authldap: malloc failed");
1458 rc= -1;
1459 }
1460 else
1461 {
1462 strcat(strcat(strcpy(new_mailroot, my_ldap.mailroot),
1463 "/"), homeDir);
1464 free(homeDir);
1465 homeDir=new_mailroot;
1466 }
1467 }
1468
1469 j=1;
1470
1471 for (i=0; my_ldap.auxoptions[i]; i++)
1472 {
1473 char *val;
1474
1475 copy_value(my_ldap_fp, entry, my_ldap.auxoptions[i], &val,
1476 user);
1477
1478 if (!val)
1479 continue;
1480
1481 j += 2 + strlen(my_ldap.auxnames[i]) +
1482 strlen(val);
1483 free(val);
1484 }
1485
1486 options=malloc(j);
1487
1488 if (!options)
1489 {
1490 perror("CRIT: authldap: malloc failed");
1491 rc= -1;
1492 }
1493 else
1494 {
1495 *options=0;
1496
1497 for (i=0; my_ldap.auxoptions[i]; i++)
1498 {
1499 char *val;
1500
1501 copy_value(my_ldap_fp, entry, my_ldap.auxoptions[i],
1502 &val,
1503 user);
1504
1505 if (!val)
1506 continue;
1507
1508 if (*options)
1509 strcat(options, ",");
1510 strcat(options, my_ldap.auxnames[i]);
1511 strcat(options, "=");
1512 strcat(options, val);
1513 free(val);
1514 }
1515 }
1516
1517
1518 auth.sysuserid= &au;
1519 auth.sysgroupid= ag;
1520 auth.homedir=homeDir;
1521 auth.address=authaddr;
1522 auth.fullname=cn;
1523 auth.maildir=mailDir;
1524 auth.clearpasswd=userPassword;
1525 auth.passwd=cryptPassword;
1526 auth.quota=quota;
1527 auth.options=options && *options ? options:NULL;
1528
1529 if (homeDir == 0)
1530 auth.homedir="";
1531
1532 rc=0;
1533
1534 if (au == 0 || ag == 0)
1535 {
1536 err("authldaplib: refuse to authenticate %s: uid=%d, gid=%d (zero uid or gid not permitted)",
1537 user, au, ag);
1538 rc= 1;
1539 }
1540
1541 courier_authdebug_authinfo("DEBUG: authldaplib: ", &auth,
1542 userPassword, cryptPassword);
1543
1544 if (pass)
1545 {
1546 if (my_ldap.authbind)
1547 {
1548 if (!bindp)
1549 {
1550 bindp=ldapconnect();
1551
1552 if (!bindp)
1553 {
1554 DPRINTF("ldapconnect failed");
1555 rc=1;
1556 }
1557 else
1558 #ifdef LDAP_OPT_PROTOCOL_VERSION
1559 /* Set protocol version */
1560 if (my_ldap.protocol_version &&
1561 ldap_set_option(bindp, LDAP_OPT_PROTOCOL_VERSION,
1562 (void *) & my_ldap.protocol_version) != LDAP_OPT_SUCCESS)
1563 {
1564 err("ldap_set_option(PROTOCOL_VERSION %d) failed",
1565 my_ldap.protocol_version);
1566 rc = 1;
1567 }
1568 else
1569 #endif
1570 if(my_ldap.tls && enable_tls_on(bindp)) {
1571 err("authldaplib: LDAP_TLS enabled but I'm unable to start tls, check your config");
1572 rc = 1;
1573 }
1574 }
1575
1576 if (bindp)
1577 {
1578 if (rc == 0)
1579 {
1580 int ldrc;
1581 DPRINTF("rebinding with DN '%s' to validate password", dn);
1582 ldrc = l_simple_bind_s(bindp, dn, pass);
1583 switch (ldrc)
1584 {
1585 case LDAP_SUCCESS:
1586 DPRINTF("authentication bind successful");
1587 break;
1588 case LDAP_INVALID_CREDENTIALS:
1589 DPRINTF("authentication bind failed, invalid credentials");
1590 rc = -1;
1591 break;
1592 default:
1593 DPRINTF("authentication bind failed, some other problem: %s",
1594 ldap_err2string(ldrc));
1595 rc = 1;
1596 break;
1597 }
1598 }
1599 /* Drop the connection if there was a fatal
1600 error or if we are using historic LDAP v2,
1601 which didn't support rebinding on same conn */
1602 if (rc > 0 || my_ldap.protocol_version == 2)
1603 {
1604 l_unbind(bindp);
1605 bindp=0;
1606 }
1607 }
1608
1609 if (rc == 0 && newpass)
1610 {
1611 if ((newpass_crypt=authcryptpasswd(newpass,
1612 auth.passwd)
1613 ) == 0)
1614 rc= -1;
1615 }
1616 }
1617 else
1618 {
1619 if (auth.clearpasswd)
1620 {
1621 if (strcmp(pass,auth.clearpasswd))
1622 {
1623 if (courier_authdebug_login_level >= 2)
1624 {
1625 DPRINTF("supplied password '%s' does not match clearpasswd '%s'",
1626 pass, auth.clearpasswd);
1627 }
1628 else
1629 {
1630 DPRINTF("supplied password does not match clearpasswd");
1631 }
1632 rc= -1;
1633 }
1634 }
1635 else
1636 {
1637 const char *p=auth.passwd;
1638
1639 if (!p)
1640 {
1641 DPRINTF("no password to compare against!");
1642 rc= -1;
1643 }
1644 else if (authcheckpassword(pass, p))
1645 rc= -1;
1646 }
1647
1648 if (rc == 0 && newpass && auth.passwd)
1649 {
1650 if ((newpass_crypt=authcryptpasswd(newpass,
1651 auth.passwd)
1652 ) == 0)
1653 rc= -1;
1654 }
1655 }
1656 }
1657
1658 if (rc == 0 && newpass)
1659 {
1660 LDAPMod *mods[3];
1661 int mod_index=0;
1662
1663 LDAPMod mod_clear, mod_crypt;
1664 char *mod_clear_vals[2], *mod_crypt_vals[2];
1665
1666 if (attributes[3])
1667 {
1668 mods[mod_index]= &mod_clear;
1669 mod_clear.mod_op=LDAP_MOD_REPLACE;
1670 mod_clear.mod_type=(char *)attributes[3];
1671 mod_clear.mod_values=mod_clear_vals;
1672
1673 mod_clear_vals[0]=(char *)newpass;
1674 mod_clear_vals[1]=NULL;
1675 ++mod_index;
1676 }
1677
1678 if (attributes[4] && newpass_crypt)
1679 {
1680 mods[mod_index]= &mod_crypt;
1681 mod_crypt.mod_op=LDAP_MOD_REPLACE;
1682 mod_crypt.mod_type=(char *)attributes[4];
1683 mod_crypt.mod_values=mod_crypt_vals;
1684
1685 mod_crypt_vals[0]=newpass_crypt;
1686 mod_crypt_vals[1]=NULL;
1687 ++mod_index;
1688 }
1689 if (mod_index == 0)
1690 rc= -1;
1691 else
1692 {
1693 int ld_errno;
1694 mods[mod_index]=0;
1695
1696 /* On a system which uses LDAP_AUTHBIND, we probably
1697 want to use the user's credentials (bindp) rather
1698 than the search credentials (my_ldap_fp) for
1699 performing the password update. (May not always be
1700 true, ideally it would be configurable) */
1701 ld_errno = l_modify_s(bindp? bindp:my_ldap_fp, dn, mods);
1702 if (ld_errno != LDAP_SUCCESS)
1703 {
1704 rc= -1;
1705 DPRINTF("LDAP modify failed: %s",
1706 ldap_err2string(ld_errno));
1707 }
1708 }
1709 }
1710
1711 if (newpass_crypt)
1712 free(newpass_crypt);
1713 free (dn);
1714 #if DEBUG_LDAP
1715 DPRINTF("before callback rc=%d",rc);
1716 #endif
1717
1718 if (rc == 0 && callback)
1719 {
1720 if (!auth.clearpasswd)
1721 auth.clearpasswd=pass;
1722 rc= (*callback)(&auth, arg);
1723 #if DEBUG_LDAP
1724 DPRINTF("after callback rc=%d",rc);
1725 #endif
1726 }
1727
1728 ldap_msgfree(result);
1729 if (options) free(options);
1730 if (homeDir) free(homeDir);
1731 if (mailDir) free(mailDir);
1732 if (userPassword) free(userPassword);
1733 if (cryptPassword) free(cryptPassword);
1734 if (cn) free(cn);
1735 if (quota) free(quota);
1736 return (rc);
1737 }
1738
1739 /**
1740 ** Create an emailmap search string. I'm going to wrap this into an external
1741 ** variable, so I'll use generic coding here.
1742 */
1743
1744 struct varlist {
1745 const char *varname;
1746 int varname_len;
1747 const char *varvalue;
1748 int varvalue_len;
1749 } ;
1750
1751 static char *var_expand(const char *, const struct varlist *);
1752
1753 static char *emailmap_get_search_string(const char *str, const char *email)
1754 {
1755 struct varlist vl[3];
1756 const char *realmptr=strrchr(email, '@');/* Guaranteed nonNULL */
1757
1758 static const char userid[]="user";
1759 static const char realm[]="realm";
1760
1761 vl[0].varname=userid;
1762 vl[0].varname_len=sizeof(userid)-1;
1763 vl[0].varvalue=email;
1764 vl[0].varvalue_len=realmptr - email;
1765 vl[1].varname=realm;
1766 vl[1].varname_len=sizeof(realm)-1;
1767 vl[1].varvalue=realmptr+1;
1768 vl[1].varvalue_len=strlen(vl[1].varvalue);
1769 vl[2].varname=NULL;
1770
1771 return (var_expand(str, vl));
1772 }
1773
1774 static char *var_expand(const char *str, const struct varlist *vl)
1775 {
1776 const char *p;
1777 int cnt;
1778 int pass;
1779 char *q, *r;
1780
1781 cnt=0;
1782 q=NULL;
1783
1784 /*
1785 ** Pass 1 - count expanded string length, allocate buffer,
1786 ** Pass 2 - generate the string.
1787 */
1788
1789 for (pass=0; pass<2; pass++)
1790 {
1791 if (pass)
1792 {
1793 if ((q=malloc(cnt)) == NULL)
1794 return (NULL);
1795 }
1796 r=q;
1797 cnt=1;
1798
1799 p=str;
1800
1801 while (*p)
1802 {
1803 if (*p == '@')
1804 {
1805 int j;
1806
1807 for (j=0; vl[j].varname; j++)
1808 {
1809 if (memcmp(vl[j].varname, p+1,
1810 vl[j].varname_len) == 0
1811 && p[vl[j].varname_len+1] == '@')
1812 break;
1813 }
1814
1815 if (vl[j].varname)
1816 {
1817 p += vl[j].varname_len+2;
1818
1819 if (r)
1820 {
1821 memcpy(r, vl[j].varvalue,
1822 vl[j].varvalue_len);
1823 r += vl[j].varvalue_len;
1824 }
1825 cnt += vl[j].varvalue_len;
1826 continue;
1827 }
1828 }
1829
1830 if (r)
1831 *r++ = *p;
1832 ++p;
1833 ++cnt;
1834 }
1835 if (r)
1836 *r=0;
1837 }
1838
1839 return (q);
1840 }
1841
1842 void auth_ldap_enumerate( void(*cb_func)(const char *name,
1843 uid_t uid,
1844 gid_t gid,
1845 const char *homedir,
1846 const char *maildir,
1847 const char *options,
1848 void *void_arg),
1849 void *void_arg)
1850 {
1851 const char *attributes[5];
1852
1853 int i, j;
1854 int msgid;
1855
1856 if (ldapopen()) return;
1857
1858 read_env("LDAP_MAIL", &attributes[0], "", 0, "mail");
1859 read_env("LDAP_UID", &attributes[1], "", 0, 0);
1860 read_env("LDAP_GID", &attributes[2], "", 0, 0);
1861 read_env("LDAP_HOMEDIR", &attributes[3], "", 0, "homeDir");
1862 read_env("LDAP_MAILDIR", &attributes[4], "", 0, 0);
1863
1864 j=0;
1865 for (i=0; i<5; i++)
1866 {
1867 if (attributes[i])
1868 my_ldap.attrlist[j++]=attributes[i];
1869 }
1870
1871 for (i=0; my_ldap.auxoptions[i]; i++)
1872 my_ldap.attrlist[j++]=my_ldap.auxoptions[i];
1873
1874 my_ldap.attrlist[j]=0;
1875
1876 DPRINTF("ldap_search: basedn='%s', filter='%s'",
1877 my_ldap.basedn, my_ldap.enumerate_filter);
1878 if ((msgid = l_search(my_ldap_fp, (char *)my_ldap.basedn,LDAP_SCOPE_SUBTREE,
1879 my_ldap.enumerate_filter,
1880 (char **)my_ldap.attrlist, 0)) < 0)
1881 {
1882 DPRINTF("ldap_search failed");
1883 return;
1884 }
1885
1886 while(1) /* process results as they come in */
1887 {
1888 struct timeval timeout;
1889 LDAPMessage *result;
1890 LDAPMessage *entry;
1891 int ldrc;
1892
1893 timeout.tv_sec=my_ldap.timeout;
1894 timeout.tv_usec=0;
1895 ldrc = ldap_result(my_ldap_fp, msgid, 0, &timeout, &result);
1896 switch (ldrc)
1897 {
1898 case -1:
1899 DPRINTF("error in ldap_result");
1900 ldap_msgfree(result);
1901 return;
1902 case 0:
1903 DPRINTF("timeout waiting for search result");
1904 ldap_msgfree(result);
1905 return;
1906 case LDAP_RES_SEARCH_ENTRY:
1907 break; /* deal with below */
1908 case LDAP_RES_SEARCH_RESULT:
1909 if (ldap_parse_result(my_ldap_fp, result, &ldrc,
1910 NULL, NULL, NULL, NULL, 0) != LDAP_SUCCESS)
1911 {
1912 DPRINTF("ldap_parse_result failed");
1913 ldap_msgfree(result);
1914 return;
1915 }
1916 ldap_msgfree(result);
1917 if (ldrc != LDAP_SUCCESS)
1918 {
1919 DPRINTF("ldap search failure result: %s",
1920 ldap_err2string(ldrc));
1921 return;
1922 }
1923 /* Search successfully completed */
1924 (*cb_func)(NULL, 0, 0, NULL, NULL, NULL, void_arg);
1925 return;
1926 default:
1927 DPRINTF("ldap result type 0x%02X ignored", ldrc);
1928 ldap_msgfree(result);
1929 continue;
1930 }
1931
1932 entry = ldap_first_entry(my_ldap_fp, result);
1933 while (entry)
1934 {
1935 char **names = get_values(my_ldap_fp, entry, attributes[0]);
1936 int n;
1937
1938 if (names == NULL)
1939 {
1940 entry = ldap_next_entry(my_ldap_fp, entry);
1941 continue;
1942 }
1943
1944 n=l_count_values(names);
1945 if (n > 0)
1946 {
1947 const char *name = names[0] ? names[0] : "<null>";
1948 int i,j;
1949 char *uid_s=NULL;
1950 char *gid_s=NULL;
1951 char *homedir;
1952 char *maildir;
1953 char *options;
1954 uid_t uid=my_ldap.uid;
1955 gid_t gid=my_ldap.gid;
1956
1957 if (attributes[1])
1958 {
1959 copy_value(my_ldap_fp, entry, attributes[1],
1960 &uid_s,
1961 name);
1962 }
1963
1964 if (attributes[2])
1965 {
1966 copy_value(my_ldap_fp, entry, attributes[2],
1967 &gid_s, name);
1968 }
1969
1970 copy_value(my_ldap_fp, entry, attributes[3],
1971 &homedir, name);
1972 copy_value(my_ldap_fp, entry, attributes[4],
1973 &maildir, name);
1974
1975 if (uid_s)
1976 uid=atol(uid_s);
1977 if (gid_s)
1978 gid=atol(gid_s);
1979
1980 j=1;
1981
1982 for (i=0; my_ldap.auxoptions[i]; i++)
1983 {
1984 char *val;
1985
1986 copy_value(my_ldap_fp, entry, my_ldap.auxoptions[i],
1987 &val, name);
1988
1989 if (!val)
1990 continue;
1991
1992 j += 2 + strlen(my_ldap.auxnames[i]) +
1993 strlen(val);
1994 free(val);
1995 }
1996
1997 options=malloc(j);
1998
1999 if (!options)
2000 {
2001 l_value_free(names);
2002 perror("CRIT: auth_ldap_enumerate: malloc failed");
2003 return;
2004 }
2005 *options=0;
2006
2007 for (i=0; my_ldap.auxoptions[i]; i++)
2008 {
2009 char *val;
2010
2011 copy_value(my_ldap_fp, entry, my_ldap.auxoptions[i],
2012 &val, name);
2013
2014 if (!val)
2015 continue;
2016
2017 if (*options)
2018 strcat(options, ",");
2019 strcat(options, my_ldap.auxnames[i]);
2020 strcat(options, "=");
2021 strcat(options, val);
2022 free(val);
2023 }
2024
2025 for (j = 0; j < n; j++)
2026 {
2027 name=names[j];
2028
2029 if (name && homedir)
2030 (*cb_func)(name, uid, gid, homedir,
2031 maildir, options, void_arg);
2032 }
2033
2034 if (uid_s)
2035 free(uid_s);
2036 if (gid_s)
2037 free(gid_s);
2038 if (homedir)
2039 free(homedir);
2040 if (maildir)
2041 free(maildir);
2042 if (options)
2043 free(options);
2044 }
2045 l_value_free(names);
2046
2047 entry = ldap_next_entry(my_ldap_fp, entry);
2048 }
2049
2050 ldap_msgfree(result);
2051 }
2052 }