]> git.sur5r.net Git - openldap/blob - clients/fax500/main.c
struct ldap is now opaque to clients.
[openldap] / clients / fax500 / main.c
1 /*
2  * Copyright (c) 1990 Regents of the University of Michigan.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that this notice is preserved and that due credit is given
7  * to the University of Michigan at Ann Arbor. The name of the University
8  * may not be used to endorse or promote products derived from this
9  * software without specific prior written permission. This software
10  * is provided ``as is'' without express or implied warranty.
11  */
12
13 #include "portable.h"
14
15 #include <stdio.h>
16 #include <ctype.h>
17
18 #include <ac/socket.h>
19 #include <ac/string.h>
20 #include <ac/syslog.h>
21 #include <ac/time.h>
22 #include <ac/wait.h>
23
24 #ifdef HAVE_SYS_PARAM_H
25 #include <sys/param.h>
26 #endif
27
28 #include <sys/resource.h>
29 #include <sysexits.h>
30
31 #include "lber.h"
32 #include "ldap.h"
33
34 #include <ldapconfig.h>
35
36 #define USER            0
37 #define GROUP_ERRORS    1
38 #define GROUP_REQUEST   2
39 #define GROUP_MEMBERS   3
40
41 #define ERRORS  "errors"
42 #define REQUEST "request"
43 #define MEMBERS "members"
44
45 LDAP    *ld;
46 char    *errorsfrom = NULL;
47 char    *mailfrom = NULL;
48 char    *host = NULL;
49 int     hostlen = 0;
50 char    *faxtotpc();
51
52 int     identity;
53 #define MAIL500 1       
54 #define FAX500  2
55
56 typedef struct errs {
57         int             e_code;
58 #define E_USERUNKNOWN           1
59 #define E_AMBIGUOUS             2
60 #define E_NOEMAIL               3
61 #define E_NOREQUEST             4
62 #define E_NOERRORS              5
63 #define E_BADMEMBER             6
64 #define E_JOINMEMBERNOEMAIL     7
65 #define E_MEMBERNOEMAIL         8
66 #define E_NOFAXNUM              9
67 #define E_JOINMEMBERNOFAXNUM    10
68 #define E_MEMBERNOFAXNUM        11
69 #define E_FAXTOEMAILMBR         12
70
71         char            *e_addr;
72         LDAPMessage     *e_msg;
73 } Error;
74
75 typedef struct groupto {
76         char    *g_dn;
77         char    *g_errorsto;
78         char    **g_members;
79 } Group;
80
81 typedef struct baseinfo {
82         char    *b_dn;          /* dn to start searching at */
83         char    b_rdnpref;      /* give rdn's preference when searching? */
84         char    *b_filter[3];   /* filter to apply - name substituted for %s */
85                                 /* (up to three of them) */
86 } Base;
87
88 Base    base[] = 
89         { "ou=People, o=University of Michigan, c=US", 0,
90                 "uid=%s", "cn=%s", NULL,
91           "ou=System Groups, ou=Groups, o=University of Michigan, c=US", 1,
92                 "(&(cn=%s)(associatedDomain=%h))", NULL, NULL,
93           "ou=User Groups, ou=Groups, o=University of Michigan, c=US", 1,
94                 "(&(cn=%s)(associatedDomain=%h))", NULL, NULL,
95           NULL
96         };
97
98 char    *sendmailargs[] = { FAX_SENDMAIL, "-oMrX.500", "-odi", "-oi", "-f", NULL, NULL };
99
100 static char     *attrs[] = { "objectClass", "title", "postaladdress",
101                         "telephoneNumber", "mail", "description",
102                         "errorsTo", "rfc822ErrorsTo", "requestsTo",
103                         "rfc822RequestsTo", "joinable", "cn", "member",
104                         "facsimileTelephoneNumber", NULL };
105
106 static do_address();
107 static do_group();
108 static do_group_members();
109 static send_message();
110 static send_errors();
111 static do_noemailorfax();
112 static do_ambiguous();
113 static add_to();
114 static isgroup();
115 static add_error();
116 static add_group();
117 static unbind_and_exit();
118 static group_loop();
119 static send_group();
120 static has_attributes();
121 static char **get_attributes_mail_dn();
122 static char *canonical();
123
124 main (argc, argv)
125 int     argc;
126 char    **argv;
127 {
128         char            *myname;
129         char            **tolist;
130         Error           *errlist;
131         Group           *togroups;
132         int             numto, ngroups, numerr, nargs;
133         int             i, j;
134         FILE            *fp;
135         extern int      optind, errno;
136         extern char     *optarg;
137
138         while ( (i = getopt( argc, argv, "f:h:m:" )) != EOF ) {
139                 switch( i ) {
140                 case 'f':       /* who it's from & where errors should go */
141                         mailfrom = strdup( optarg );
142                         for ( j = 0; sendmailargs[j] != NULL; j++ ) {
143                                 if ( strcmp( sendmailargs[j], "-f" ) == 0 ) {
144                                         sendmailargs[j+1] = mailfrom;
145                                         break;
146                                 }
147                         }
148                         break;
149
150                 case 'h':       /* hostname */
151                         host = strdup( optarg );
152                         hostlen = strlen(host);
153                         break;
154
155                                 /* mailer-daemon address - who we should */
156                 case 'm':       /* say errors come from */
157                         errorsfrom = strdup( optarg );
158                         break;
159
160                 default:
161                         syslog( LOG_ALERT, "unknown option" );
162                         break;
163                 }
164         }
165
166         if ( (myname = strrchr( argv[0], '/' )) == NULL )
167                 myname = strdup( argv[0] );
168         else
169                 myname = strdup( myname + 1 );
170         if (!strcmp(myname, "mail500")) {
171                 identity = MAIL500;
172         } else if (!strcmp(myname, "fax500")) {
173                 identity = FAX500;
174         } else {
175                 /* I give up, I must be mail500 */
176                 identity = MAIL500;
177         }
178
179 #ifdef LOG_MAIL
180         openlog( myname, OPENLOG_OPTIONS, LOG_MAIL );
181 #else
182         openlog( myname, OPENLOG_OPTIONS );
183 #endif
184
185         if ( mailfrom == NULL ) {
186                 syslog( LOG_ALERT, "required argument -f not present" );
187                 exit( EX_TEMPFAIL );
188         }
189         if ( errorsfrom == NULL ) {
190                 syslog( LOG_ALERT, "required argument -m not present" );
191                 exit( EX_TEMPFAIL );
192         }
193         if ( host == NULL ) {
194                 syslog( LOG_ALERT, "required argument -h not present" );
195                 exit( EX_TEMPFAIL );
196         }
197
198         if ( connect_to_x500() != 0 )
199                 exit( EX_TEMPFAIL );
200
201         setuid( geteuid() );
202 /*
203 {
204         char    buf[1024];
205         int     i;
206
207         strcpy( buf, argv[0] );
208         for ( i = 1; i < argc; i++ ) {
209                 strcat( buf, " " );
210                 strcat( buf, argv[i] );
211         }
212
213         syslog( LOG_ALERT, "args: (%s)", buf );
214 }
215 */
216         numto = 0;
217         add_to( &tolist, &numto, sendmailargs );
218         nargs = numto;
219         ngroups = numerr = 0;
220         togroups = NULL;
221         errlist = NULL;
222         for ( i = optind; i < argc; i++ ) {
223                 char    *s;
224                 int     type;
225
226                 for ( j = 0; argv[i][j] != '\0'; j++ ) {
227                         if ( argv[i][j] == '.' || argv[i][j] == '_' )
228                                 argv[i][j] = ' ';
229                 }
230
231                 type = USER;
232                 if ( (s = strrchr( argv[i], '-' )) != NULL ) {
233                         s++;
234
235                         if ( strcmp( s, ERRORS ) == 0 ) {
236                                 type = GROUP_ERRORS;
237                                 *(--s) = '\0';
238                         } else if ( strcmp( s, REQUEST ) == 0 ) {
239                                 type = GROUP_REQUEST;
240                                 *(--s) = '\0';
241                         } else if ( strcmp( s, MEMBERS ) == 0 ) {
242                                 type = GROUP_MEMBERS;
243                                 *(--s) = '\0';
244                         }
245                 }
246
247                 do_address( argv[i], &tolist, &numto, &togroups, &ngroups,
248                     &errlist, &numerr, type );
249         }
250
251         /*
252          * If we have both errors and successful deliveries to make or if
253          * if there are any groups to deliver to, we basically need to read
254          * the message twice.  So, we have to put it in a tmp file.
255          */
256
257         if ( numerr > 0 && numto > nargs || ngroups > 0 ) {
258                 int     fd;
259                 char    buf[BUFSIZ];
260
261                 umask( 077 );
262                 if ( (fp = tmpfile()) == NULL ) {
263                         syslog( LOG_ALERT, "could not open tmp file" );
264                         unbind_and_exit( EX_TEMPFAIL );
265                 }
266
267                 /* copy the message to a temp file */
268                 while ( fgets( buf, sizeof(buf), stdin ) != NULL ) {
269                         if ( fputs( buf, fp ) == EOF ) {
270                                 syslog( LOG_ALERT, "error writing tmpfile" );
271                                 unbind_and_exit( EX_TEMPFAIL );
272                         }
273                 }
274
275                 if ( dup2( fileno( fp ), 0 ) == -1 ) {
276                         syslog( LOG_ALERT, "could not dup2 tmpfile" );
277                         unbind_and_exit( EX_TEMPFAIL );
278                 }
279
280                 fclose( fp );
281         }
282
283         /* deal with errors */
284         if ( numerr > 0 ) {
285                 (void) rewind( stdin );
286                 send_errors( errlist, numerr );
287         }
288
289         (void) ldap_unbind( ld );
290
291         /* send to groups with errorsTo */
292         if ( ngroups > 0 ) {
293                 (void) rewind( stdin );
294                 send_group( togroups, ngroups );
295         }
296
297         /* send to expanded aliases and groups w/o errorsTo */
298         if ( numto > nargs ) {
299                 (void) rewind( stdin );
300                 send_message( tolist );
301         }
302
303         return( EX_OK );
304 }
305
306 connect_to_x500()
307 {
308         int sizelimit = FAX_MAXAMBIGUOUS;
309         int deref = LDAP_DEREF_ALWAYS;
310
311         if ( (ld = ldap_open( LDAPHOST, LDAP_PORT )) == NULL ) {
312                 syslog( LOG_ALERT, "ldap_open failed" );
313                 return( -1 );
314         }
315
316         ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &sizelimit);
317         ldap_set_option(ld, LDAP_OPT_DEREF, &deref);
318
319         if ( ldap_simple_bind_s( ld, FAX_BINDDN, FAX_BIND_CRED ) != LDAP_SUCCESS ) {
320                 syslog( LOG_ALERT, "ldap_simple_bind_s failed" );
321                 return( -1 );
322         }
323
324         return( 0 );
325 }
326
327
328 static
329 do_address( name, to, nto, togroups, ngroups, err, nerr, type )
330     char        *name;
331     char        ***to;
332     int         *nto;
333     Group       **togroups;
334     int         *ngroups;
335     Error       **err;
336     int         *nerr;
337     int         type;
338 {
339         int             rc, b, f, match;
340         LDAPMessage     *e, *res;
341         struct timeval  timeout;
342         char            *dn;
343         char            filter[1024];
344         char            **mail;
345         char            **fax;
346
347         /*
348          * Look up the name in X.500, add the appropriate addresses found
349          * to the to list, or to the err list in case of error.  Groups are
350          * handled by the do_group routine, individuals are handled here.
351          * When looking up name, we follow the bases hierarchy, looking
352          * in base[0] first, then base[1], etc.  For each base, there is
353          * a set of search filters to try, in order.  If something goes
354          * wrong here trying to contact X.500, we exit with EX_TEMPFAIL.
355          * If the b_rdnpref flag is set, then we give preference to entries
356          * that matched name because it's their rdn, otherwise not.
357          */
358
359         timeout.tv_sec = FAX_TIMEOUT;
360         timeout.tv_usec = 0;
361         for ( b = 0, match = 0; !match && base[b].b_dn != NULL; b++ ) {
362                 for ( f = 0; base[b].b_filter[f] != NULL; f++ ) {
363                         char    *format, *p, *argv[3];
364                         int     argc;
365
366                         for ( argc = 0; argc < 3; argc++ ) {
367                                 argv[argc] = NULL;
368                         }
369
370                         format = strdup( base[b].b_filter[f] );
371                         for ( argc = 0, p = format; *p; p++ ) {
372                                 if ( *p == '%' ) {
373                                         switch ( *++p ) {
374                                         case 's':       /* %s is the name */
375                                                 argv[argc] = name;
376                                                 break;
377
378                                         case 'h':       /* %h is the host */
379                                                 *p = 's';
380                                                 argv[argc] = host;
381                                                 break;
382
383                                         default:
384                                                 syslog( LOG_ALERT,
385                                                     "unknown format %c", *p );
386                                                 break;
387                                         }
388
389                                         argc++;
390                                 }
391                         }
392
393                         /* three names ought to do... */
394                         sprintf( filter, format, argv[0], argv[1], argv[2] );
395                         free( format );
396
397                         res = NULL;
398                         rc = ldap_search_st( ld, base[b].b_dn,
399                             LDAP_SCOPE_SUBTREE, filter, attrs, 0, &timeout,
400                             &res );
401
402                         /* some other trouble - try again later */
403                         if ( rc != LDAP_SUCCESS &&
404                             rc != LDAP_SIZELIMIT_EXCEEDED ) {
405                                 syslog( LOG_ALERT, "return %d from X.500", rc );
406                                 unbind_and_exit( EX_TEMPFAIL );
407                         }
408
409                         if ( (match = ldap_count_entries( ld, res )) != 0 )
410                                 break;
411
412                         ldap_msgfree( res );
413                 }
414
415                 if ( match )
416                         break;
417         }
418
419         /* trouble - try again later */
420         if ( match == -1 ) {
421                 syslog( LOG_ALERT, "error parsing result from X.500" );
422                 unbind_and_exit( EX_TEMPFAIL );
423         }
424
425         /* no matches - bounce with user unknown */
426         if ( match == 0 ) {
427                 add_error( err, nerr, E_USERUNKNOWN, name, NULLMSG );
428                 return;
429         }
430
431         /* more than one match - bounce with ambiguous user? */
432         if ( match > 1 ) {
433                 LDAPMessage     *next, *tmpres = NULL;
434                 char            *dn;
435                 char            **xdn;
436
437                 /* not giving rdn preference - bounce with ambiguous user */
438                 if ( base[b].b_rdnpref == 0 ) {
439                         add_error( err, nerr, E_AMBIGUOUS, name, res );
440                         return;
441                 }
442
443                 /*
444                  * giving rdn preference - see if any entries were matched
445                  * because of their rdn.  If so, collect them to deal with
446                  * later (== 1 we deliver, > 1 we bounce).
447                  */
448
449                 for ( e = ldap_first_entry( ld, res ); e != NULL; e = next ) {
450                         next = ldap_next_entry( ld, e );
451                         dn = ldap_get_dn( ld, e );
452                         xdn = ldap_explode_dn( dn, 1 );
453
454                         /* XXX bad, but how else can we do it? XXX */
455                         if ( strcasecmp( xdn[0], name ) == 0 ) {
456                                 ldap_delete_result_entry( &res, e );
457                                 ldap_add_result_entry( &tmpres, e );
458                         }
459
460                         ldap_value_free( xdn );
461                         free( dn );
462                 }
463
464                 /* nothing matched by rdn - go ahead and bounce */
465                 if ( tmpres == NULL ) {
466                         add_error( err, nerr, E_AMBIGUOUS, name, res );
467                         return;
468
469                 /* more than one matched by rdn - bounce with rdn matches */
470                 } else if ( (match = ldap_count_entries( ld, tmpres )) > 1 ) {
471                         add_error( err, nerr, E_AMBIGUOUS, name, tmpres );
472                         return;
473
474                 /* trouble... */
475                 } else if ( match < 0 ) {
476                         syslog( LOG_ALERT, "error parsing result from X.500" );
477                         unbind_and_exit( EX_TEMPFAIL );
478                 }
479
480                 /* otherwise one matched by rdn - send to it */
481                 ldap_msgfree( res );
482                 res = tmpres;
483         }
484
485         /*
486          * if we get this far, it means that we found a single match for
487          * name.  for a user, we deliver to the mail attribute or bounce
488          * with address and phone if no mail attr.  for a group, we
489          * deliver to all members or bounce to rfc822ErrorsTo if no members.
490          */
491
492         /* trouble */
493         if ( (e = ldap_first_entry( ld, res )) == NULL ) {
494                 syslog( LOG_ALERT, "error parsing entry from X.500" );
495                 unbind_and_exit( EX_TEMPFAIL );
496         }
497
498         dn = ldap_get_dn( ld, e );
499
500         if ( type == GROUP_ERRORS ) {
501                 /* sent to group-errors - resend to [rfc822]ErrorsTo attr */
502                 do_group_errors( e, dn, to, nto, err, nerr );
503
504         } else if ( type == GROUP_REQUEST ) {
505                 /* sent to group-request - resend to [rfc822]RequestsTo attr */
506                 do_group_request( e, dn, to, nto, err, nerr );
507
508         } else if ( type == GROUP_MEMBERS ) {
509                 /* sent to group-members - expand */
510                 do_group_members( e, dn, to, nto, togroups, ngroups, err,
511                     nerr );
512
513         } else if ( isgroup( e ) ) {
514                 /* 
515                  * sent to group - resend from [rfc822]ErrorsTo if it's there,
516                  * otherwise, expand the group
517                  */
518
519                 do_group( e, dn, to, nto, togroups, ngroups, err, nerr );
520
521                 ldap_msgfree( res );
522
523         } else {
524                 /*
525                  * sent to user - mail attribute => add it to the to list,
526                  * otherwise bounce
527                  */
528                 switch (identity) {
529                 case FAX500 :   
530                         if ( (mail = ldap_get_values( ld, e, 
531                              "facsimileTelephoneNumber" )) != NULL ) {
532                                 char *fdn;
533                                 char **ufn;
534                                 int i;
535
536                                 fdn = ldap_get_dn( ld, e );
537                                 ufn = ldap_explode_dn( fdn, 1 );
538                                 /* Convert spaces to underscores for rp */
539                                 for (i = 0; ufn[0][i] != '\0'; i++) {
540                                         if (ufn[0][i] == ' ') {
541                                                 ufn[0][i] = '_';
542                                         }
543                                 }
544                                 *mail = faxtotpc(*mail, ufn[0]);
545                                 
546                                 add_to(to, nto, mail);
547
548                                 if (fdn != NULL) {
549                                         free(fdn);
550                                 }
551                                 ldap_value_free( ufn );
552                                 ldap_value_free( mail );
553                                 ldap_msgfree( res );
554                         } else {
555                                 add_error( err, nerr, E_NOFAXNUM, 
556                                            name, res );
557                         }
558                         break;
559                 case MAIL500 :
560                         if ( (mail = ldap_get_values( ld, e, "mail" ))
561                              != NULL ) {
562                                 add_to( to, nto, mail );
563
564                                 ldap_value_free( mail );
565                                 ldap_msgfree( res );
566                         } else {
567                                 add_error( err, nerr, E_NOEMAIL, 
568                                            name, res );
569                         }
570                         break;
571                 }
572         }
573
574         free( dn );
575
576         return;
577 }
578
579 static
580 do_group( e, dn, to, nto, togroups, ngroups, err, nerr )
581     LDAPMessage *e;
582     char        *dn;
583     char        ***to;
584     int         *nto;
585     Group       **togroups;
586     int         *ngroups;
587     Error       **err;
588     int         *nerr;
589 {
590         /*
591          * If this group has an rfc822ErrorsTo attribute, we need to
592          * arrange for errors involving this group to go there, not
593          * to the sender.  Since sendmail only has the concept of a
594          * single sender, we arrange for errors to go to groupname-errors,
595          * which we then handle specially when (if) it comes back to us
596          * by expanding to all the rfc822ErrorsTo addresses.  If it has no
597          * rfc822ErrorsTo attribute, we call do_group_members() to expand
598          * the group.
599          */
600
601         if ( group_loop( dn ) ) {
602                 return( -1 );
603         }
604
605         if ( has_attributes( e, "rfc822ErrorsTo", "errorsTo" ) ) {
606                 add_group( dn, togroups, ngroups );
607
608                 return( 0 );
609         }
610
611         do_group_members( e, dn, to, nto, togroups, ngroups, err, nerr );
612
613         return( 0 );
614 }
615
616 /* ARGSUSED */
617 static
618 do_group_members( e, dn, to, nto, togroups, ngroups, err, nerr )
619     LDAPMessage *e;
620     char        *dn;
621     char        ***to;
622     int         *nto;
623     Group       **togroups;
624     int         *ngroups;
625     Error       **err;
626     int         *nerr;
627 {
628         int             i, rc;
629         char            *ndn;
630         char            **mail, **member, **joinable;
631         char            filter[256];
632         LDAPMessage     *ee, *res;
633         struct timeval  timeout;
634
635         /*
636          * if all has gone according to plan, we've already arranged for
637          * errors to go to the [rfc822]ErrorsTo attributes (if they exist),
638          * so all we have to do here is arrange to send to the
639          * rfc822Mailbox attribute, the member attribute, and anyone who
640          * has joined the group by setting memberOfGroup equal to the
641          * group dn.
642          */
643
644         /* add members in the group itself - mail attribute */
645         if ( (mail = ldap_get_values( ld, e, "mail" )) != NULL ) {
646                 /* 
647                  * These are only email addresses - impossible 
648                  * to have a fax number
649                  */
650                 switch (identity) {
651                 case FAX500 :
652                         /* XXX How do we want to inform sender that the */
653                         /* group they sent to has email-only members? */
654                         break;
655                 case MAIL500 :
656                         add_to( to, nto, mail );
657                         break;
658                 }
659
660                 ldap_value_free( mail ); 
661         }
662
663         /* add members in the group itself - member attribute */
664         if ( (member = ldap_get_values( ld, e, "member" )) != NULL ) {
665                 for ( i = 0; member[i] != NULL; i++ ) {
666                         add_member( dn, member[i], to, nto, togroups,
667                             ngroups, err, nerr );
668                 }
669
670                 ldap_value_free( member );
671         }
672
673         /* add members who have joined by setting memberOfGroup */
674         if ( (joinable = ldap_get_values( ld, e, "joinable" )) != NULL ) {
675                 if ( strcasecmp( joinable[0], "FALSE" ) == 0 ) {
676                         ldap_value_free( joinable );
677                         return;
678                 }
679                 ldap_value_free( joinable );
680
681                 sprintf( filter, "(memberOfGroup=%s)", dn );
682
683                 timeout.tv_sec = FAX_TIMEOUT;
684                 timeout.tv_usec = 0;
685
686                 /* for each subtree to look in... */
687                 {
688                         int sizelimit = FAX_MAXMEMBERS;
689                         ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &sizelimit);
690                 }       
691                 for ( i = 0; base[i].b_dn != NULL; i++ ) {
692                         /* find entries that have joined this group... */
693                         rc = ldap_search_st( ld, base[i].b_dn,
694                             LDAP_SCOPE_SUBTREE, filter, attrs, 0, &timeout,
695                             &res );
696
697                         if ( rc == LDAP_SIZELIMIT_EXCEEDED ||
698                             rc == LDAP_TIMELIMIT_EXCEEDED ) {
699                                 syslog( LOG_ALERT,
700                                     "group search limit exceeded %d", rc );
701                                 unbind_and_exit( EX_TEMPFAIL );
702                         }
703
704                         if ( rc != LDAP_SUCCESS ) {
705                                 syslog( LOG_ALERT, "group search bad return %d",
706                                     rc );
707                                 unbind_and_exit( EX_TEMPFAIL );
708                         }
709
710                         /* for each entry that has joined... */
711                         for ( ee = ldap_first_entry( ld, res ); ee != NULL;
712                             ee = ldap_next_entry( ld, ee ) ) {
713                                 if ( isgroup( ee ) ) {
714                                         ndn = ldap_get_dn( ld, ee );
715
716                                         if ( do_group( e, ndn, to, nto,
717                                             togroups, ngroups, err, nerr )
718                                             == -1 ) {
719                                                 syslog( LOG_ALERT,
720                                                     "group loop (%s) (%s)",
721                                                     dn, ndn );
722                                         }
723
724                                         free( ndn );
725
726                                         continue;
727                                 }
728
729                                 /* add them to the to list */
730                                 switch (identity) {
731                                 case FAX500 :   
732                                         if ( (mail = ldap_get_values( ld, ee, 
733                                               "facsimileTelephoneNumber" )) 
734                                               != NULL ) {
735                                                 char *fdn;
736                                                 char **ufn;
737                                                 int i;
738
739                                                 fdn = ldap_get_dn( ld, ee );
740                                                 ufn = ldap_explode_dn( fdn, 1 );
741                                                 /* 
742                                                  * Convert spaces to 
743                                                  * underscores for rp
744                                                  */
745                                                 for (i = 0; ufn[0][i] != '\0'; 
746                                                      i++) {
747                                                         if (ufn[0][i] == ' ') {
748                                                                 ufn[0][i] = '_';
749                                                         }
750                                                 }
751                                                 *mail = faxtotpc(*mail, ufn[0]);
752                                                 add_to(to, nto, mail);
753
754                                                 ldap_value_free( mail );
755                                                 ldap_msgfree( res );
756                                         } else {
757                                                 ndn = ldap_get_dn( ld, ee );
758
759                                                 add_error( err, nerr,
760                                                     E_JOINMEMBERNOFAXNUM, ndn, 
761                                                     NULLMSG );
762
763                                                 free( ndn );
764                                         }
765                                         break;
766                                 case MAIL500 :
767                                         if ( (mail = ldap_get_values( ld, ee, 
768                                              "mail" )) != NULL ) {
769                                                 add_to( to, nto, mail );
770
771                                                 ldap_value_free( mail );
772
773                                         /* else generate a bounce */
774                                         } else {
775                                                 ndn = ldap_get_dn( ld, ee );
776
777                                                 add_error( err, nerr,
778                                                     E_JOINMEMBERNOEMAIL, ndn, 
779                                                     NULLMSG );
780
781                                                 free( ndn );
782                                         }
783                                         break;
784                                 }
785                         }
786
787                         ldap_msgfree( res );
788                 }
789                 {
790                         int sizelimit = FAX_MAXAMBIGUOUS;
791                         ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &sizelimit);
792                 }       
793         }
794
795         return;
796 }
797
798 add_member( gdn, dn, to, nto, togroups, ngroups, err, nerr )
799     char        *gdn;
800     char        *dn;
801     char        ***to;
802     int         *nto;
803     Group       **togroups;
804     int         *ngroups;
805     Error       **err;
806     int         *nerr;
807 {
808         char            *ndn;
809         char            **mail;
810         int             rc;
811         LDAPMessage     *res, *e;
812         struct timeval  timeout;
813
814         timeout.tv_sec = FAX_TIMEOUT;
815         timeout.tv_usec = 0;
816         if ( (rc = ldap_search_st( ld, dn, LDAP_SCOPE_BASE, "(objectclass=*)",
817             attrs, 0, &timeout, &res )) != LDAP_SUCCESS ) {
818                 if ( rc == LDAP_NO_SUCH_OBJECT ) {
819                         add_error( err, nerr, E_BADMEMBER, dn, NULLMSG );
820
821                         return;
822                 } else {
823                         syslog( LOG_ALERT, "member search bad return %d", rc );
824
825                         unbind_and_exit( EX_TEMPFAIL );
826                 }
827         }
828
829         if ( (e = ldap_first_entry( ld, res )) == NULL ) {
830                 syslog( LOG_ALERT, "member search error parsing entry" );
831
832                 unbind_and_exit( EX_TEMPFAIL );
833         }
834         ndn = ldap_get_dn( ld, e );
835
836         /* allow groups within groups */
837         if ( isgroup( e ) ) {
838                 if ( do_group( e, ndn, to, nto, togroups, ngroups, err, nerr )
839                     == -1 ) {
840                         syslog( LOG_ALERT, "group loop (%s) (%s)", gdn, ndn );
841                 }
842
843                 free( ndn );
844
845                 return;
846         }
847
848         switch (identity) {
849         case FAX500 :   
850                 if ( (mail = ldap_get_values( ld, e, 
851                      "facsimileTelephoneNumber" )) != NULL ) {
852                         char *fdn;
853                         char **ufn;
854                         int i;
855                         fdn = ldap_get_dn( ld, e );
856                         ufn = ldap_explode_dn( fdn, 1 );
857                         /* Convert spaces to underscores for rp */
858                         for (i = 0; ufn[0][i] != '\0'; i++) {
859                                 if (ufn[0][i] == ' ') {
860                                         ufn[0][i] = '_';
861                                 }
862                         }
863                         *mail = faxtotpc(*mail, ufn[0]);
864                         add_to(to, nto, mail);
865
866                         ldap_value_free( mail );
867                         ldap_msgfree( res );
868                 } else {
869                         add_error( err, nerr, E_MEMBERNOFAXNUM, ndn, NULLMSG );
870                 }
871                 break;
872         case MAIL500 :
873                 /* send to the member's mail attribute */
874                 if ( (mail = ldap_get_values( ld, e, "mail" )) != NULL ) {
875                         add_to( to, nto, mail );
876
877                         ldap_value_free( mail );
878
879                 /* else generate a bounce */
880                 } else {
881                         add_error( err, nerr, E_MEMBERNOEMAIL, ndn, NULLMSG );
882                 }
883
884                 free( ndn );
885         }
886         return;
887 }
888
889 do_group_request( e, dn, to, nto, err, nerr )
890     LDAPMessage *e;
891     char        *dn;
892     char        ***to;
893     int         *nto;
894     Error       **err;
895     int         *nerr;
896 {
897         char            **requeststo;
898
899         if ( (requeststo = get_attributes_mail_dn( e, "rfc822RequestsTo",
900             "requestsTo" )) != NULL ) {
901                 add_to( to, nto, requeststo );
902
903                 ldap_value_free( requeststo );
904         } else {
905                 add_error( err, nerr, E_NOREQUEST, dn, NULLMSG );
906         }
907
908         return;
909 }
910
911 do_group_errors( e, dn, to, nto, err, nerr )
912     LDAPMessage *e;
913     char        *dn;
914     char        ***to;
915     int         *nto;
916     Error       **err;
917     int         *nerr;
918 {
919         char            **errorsto;
920
921         if ( (errorsto = get_attributes_mail_dn( e, "rfc822ErrorsTo",
922             "errorsTo" )) != NULL ) {
923                 add_to( to, nto, errorsto );
924
925                 ldap_value_free( errorsto );
926         } else {
927                 add_error( err, nerr, E_NOERRORS, dn, NULLMSG );
928         }
929
930         return;
931 }
932
933 static
934 send_message( to )
935     char        **to;
936 {
937         int     pid;
938 #ifndef HAVE_WAITPID
939         WAITSTATUSTYPE  status;
940 #endif
941
942
943         /* parent */
944         if ( pid = fork() ) {
945 #ifdef HAVE_WAITPID
946                 waitpid( pid, (int *) NULL, 0 );
947 #else
948                 wait4( pid, &status, WAIT_FLAGS, 0 );
949 #endif
950         /* child */
951         } else {
952                 /* to includes sendmailargs */
953                 execv( FAX_SENDMAIL, to );
954
955                 syslog( LOG_ALERT, "execv failed" );
956
957                 exit( EX_TEMPFAIL );
958         }
959 }
960
961 static
962 send_group( group, ngroup )
963     Group       *group;
964     int         ngroup;
965 {
966         int     i, pid;
967         char    **argv;
968         int     argc;
969         char    *iargv[7];
970 #ifndef HAVE_WAITPID
971         WAITSTATUSTYPE  status;
972 #endif
973
974         for ( i = 0; i < ngroup; i++ ) {
975                 (void) rewind( stdin );
976
977                 iargv[0] = FAX_SENDMAIL;
978                 iargv[1] = "-f";
979                 iargv[2] = group[i].g_errorsto;
980                 iargv[3] = "-oMrX.500";
981                 iargv[4] = "-odi";
982                 iargv[5] = "-oi";
983                 iargv[6] = NULL;
984
985                 argv = NULL;
986                 argc = 0;
987                 add_to( &argv, &argc, iargv );
988                 add_to( &argv, &argc, group[i].g_members );
989
990
991                 /* parent */
992                 if ( pid = fork() ) {
993 #ifdef HAVE_WAITPID
994                         waitpid( pid, (int *) NULL, 0 );
995 #else
996                         wait4( pid, &status, WAIT_FLAGS, 0 );
997 #endif
998                 /* child */
999                 } else {
1000                         execv( FAX_SENDMAIL, argv );
1001
1002                         syslog( LOG_ALERT, "execv failed" );
1003
1004                         exit( EX_TEMPFAIL );
1005                 }
1006         }
1007
1008         return;
1009 }
1010
1011 static
1012 send_errors( err, nerr )
1013     Error       *err;
1014     int         nerr;
1015 {
1016         int             i, namelen;
1017         FILE            *fp;
1018         char            buf[1024];
1019
1020         sprintf( buf, "%s -oMrX.500 -odi -oi -f %s %s", FAX_SENDMAIL, errorsfrom,
1021             mailfrom );
1022         if ( (fp = popen( buf, "w" )) == NULL ) {
1023                 syslog( LOG_ALERT, "could not popen sendmail for errs" );
1024                 return;
1025         }
1026
1027         fprintf( fp, "To: %s\n", mailfrom );
1028         fprintf( fp, "From: %s\n", errorsfrom );
1029         fprintf( fp, "Subject: undeliverable mail\n" );
1030         fprintf( fp, "\n" );
1031         fprintf( fp, "The following errors occurred when trying to deliver the attached mail:\n" );
1032         for ( i = 0; i < nerr; i++ ) {
1033                 namelen = strlen( err[i].e_addr );
1034                 fprintf( fp, "\n" );
1035
1036                 switch ( err[i].e_code ) {
1037                 case E_USERUNKNOWN:
1038                         fprintf( fp, "%s: User unknown\n", err[i].e_addr );
1039                         break;
1040
1041                 case E_BADMEMBER:
1042                         fprintf( fp, "%s: Group member does not exist\n",
1043                             err[i].e_addr );
1044                         break;
1045
1046                 case E_NOREQUEST:
1047                         fprintf( fp, "%s: Group exists but has no request address\n",
1048                             err[i].e_addr );
1049                         break;
1050
1051                 case E_NOERRORS:
1052                         fprintf( fp, "%s: Group exists but has no errors-to address\n",
1053                             err[i].e_addr );
1054                         break;
1055
1056                 case E_AMBIGUOUS:
1057                         do_ambiguous( fp, &err[i], namelen );
1058                         break;
1059
1060                 case E_NOEMAIL:
1061                         do_noemailorfax( fp, &err[i], namelen, E_NOEMAIL );
1062                         break;
1063
1064                 case E_MEMBERNOEMAIL:
1065                         fprintf( fp, "%s: Group member exists but does not have an email address\n",
1066                             err[i].e_addr );
1067                         break;
1068
1069                 case E_JOINMEMBERNOEMAIL:
1070                         fprintf( fp, "%s: User has joined group but does not have an email address\n",
1071                             err[i].e_addr );
1072                         break;
1073
1074                 case E_NOFAXNUM:
1075                         do_noemailorfax( fp, &err[i], namelen, E_NOFAXNUM );
1076                         break;
1077
1078                 case E_MEMBERNOFAXNUM:
1079                         fprintf( fp, "%s: Group member exists but does not have a fax number\n",
1080                             err[i].e_addr );
1081                         break;
1082
1083                 case E_JOINMEMBERNOFAXNUM:
1084                         fprintf( fp, "%s: User has joined group but does not have a fax number\n",
1085                             err[i].e_addr );
1086                         break;
1087
1088                 default:
1089                         syslog( LOG_ALERT, "unknown error %d", err[i].e_code );
1090                         unbind_and_exit( EX_TEMPFAIL );
1091                         break;
1092                 }
1093         }
1094
1095         fprintf( fp, "\n------- The original message sent:\n\n" );
1096
1097         while ( fgets( buf, sizeof(buf), stdin ) != NULL ) {
1098                 fputs( buf, fp );
1099         }
1100
1101         if ( pclose( fp ) == -1 ) {
1102                 syslog( LOG_ALERT, "pclose failed" );
1103                 unbind_and_exit( EX_TEMPFAIL );
1104         }
1105
1106         return;
1107 }
1108
1109
1110 static
1111 do_noemailorfax( fp, err, namelen, errtype )
1112     FILE        *fp;
1113     Error       *err;
1114     int         namelen;
1115     int         errtype;
1116 {
1117         int             i, last;
1118         char            *dn, *rdn;
1119         char            **ufn, **vals;
1120
1121         if (errtype == E_NOFAXNUM) {
1122                 fprintf(fp, "%s: User has no facsimile number registered.\n",
1123                         err->e_addr );
1124         } else if (errtype == E_NOEMAIL) {
1125                 fprintf(fp, "%s: User has no email address registered.\n",
1126                         err->e_addr );
1127         }
1128         fprintf( fp, "%*s  Name, title, postal address and phone for '%s':\n\n",
1129             namelen, " ", err->e_addr );
1130
1131         /* name */
1132         dn = ldap_get_dn( ld, err->e_msg );
1133         ufn = ldap_explode_dn( dn, 1 );
1134         rdn = strdup( ufn[0] );
1135         if ( strcasecmp( rdn, err->e_addr ) == 0 ) {
1136                 if ( (vals = ldap_get_values( ld, err->e_msg, "cn" ))
1137                     != NULL ) {
1138                         for ( i = 0; vals[i]; i++ ) {
1139                                 last = strlen( vals[i] ) - 1;
1140                                 if ( isdigit( vals[i][last] ) ) {
1141                                         rdn = strdup( vals[i] );
1142                                         break;
1143                                 }
1144                         }
1145
1146                         ldap_value_free( vals );
1147                 }
1148         }
1149         fprintf( fp, "%*s  %s\n", namelen, " ", rdn );
1150         free( dn );
1151         free( rdn );
1152         ldap_value_free( ufn );
1153
1154         /* titles or descriptions */
1155         if ( (vals = ldap_get_values( ld, err->e_msg, "title" )) == NULL &&
1156             (vals = ldap_get_values( ld, err->e_msg, "description" ))
1157             == NULL ) {
1158                 fprintf( fp, "%*s  No title or description registered\n",
1159                     namelen, " " );
1160         } else {
1161                 for ( i = 0; vals[i] != NULL; i++ ) {
1162                         fprintf( fp, "%*s  %s\n", namelen, " ", vals[i] );
1163                 }
1164
1165                 ldap_value_free( vals );
1166         }
1167
1168         /* postal address */
1169         if ( (vals = ldap_get_values( ld, err->e_msg, "postalAddress" ))
1170             == NULL ) {
1171                 fprintf( fp, "%*s  No postal address registered\n", namelen,
1172                     " " );
1173         } else {
1174                 fprintf( fp, "%*s  ", namelen, " " );
1175                 for ( i = 0; vals[0][i] != '\0'; i++ ) {
1176                         if ( vals[0][i] == '$' ) {
1177                                 fprintf( fp, "\n%*s  ", namelen, " " );
1178                                 while ( isspace( vals[0][i+1] ) )
1179                                         i++;
1180                         } else {
1181                                 fprintf( fp, "%c", vals[0][i] );
1182                         }
1183                 }
1184                 fprintf( fp, "\n" );
1185
1186                 ldap_value_free( vals );
1187         }
1188
1189         /* telephone number */
1190         if ( (vals = ldap_get_values( ld, err->e_msg, "telephoneNumber" ))
1191             == NULL ) {
1192                 fprintf( fp, "%*s  No phone number registered\n", namelen,
1193                     " " );
1194         } else {
1195                 for ( i = 0; vals[i] != NULL; i++ ) {
1196                         fprintf( fp, "%*s  %s\n", namelen, " ", vals[i] );
1197                 }
1198
1199                 ldap_value_free( vals );
1200         }
1201 }
1202
1203 /* ARGSUSED */
1204 static
1205 do_ambiguous( fp, err, namelen )
1206     FILE        *fp;
1207     Error       *err;
1208     int         namelen;
1209 {
1210         int             i, last;
1211         char            *dn, *rdn;
1212         char            **ufn, **vals;
1213         LDAPMessage     *e;
1214
1215         i = ldap_result2error( ld, err->e_msg, 0 );
1216
1217         fprintf( fp, "%s: Ambiguous user.  %s%d matches found:\n\n",
1218             err->e_addr, i == LDAP_SIZELIMIT_EXCEEDED ? "First " : "",
1219             ldap_count_entries( ld, err->e_msg ) );
1220
1221         for ( e = ldap_first_entry( ld, err->e_msg ); e != NULL;
1222             e = ldap_next_entry( ld, e ) ) {
1223                 dn = ldap_get_dn( ld, e );
1224                 ufn = ldap_explode_dn( dn, 1 );
1225                 rdn = strdup( ufn[0] );
1226                 if ( strcasecmp( rdn, err->e_addr ) == 0 ) {
1227                         if ( (vals = ldap_get_values( ld, e, "cn" )) != NULL ) {
1228                                 for ( i = 0; vals[i]; i++ ) {
1229                                         last = strlen( vals[i] ) - 1;
1230                                         if ( isdigit( vals[i][last] ) ) {
1231                                                 rdn = strdup( vals[i] );
1232                                                 break;
1233                                         }
1234                                 }
1235
1236                                 ldap_value_free( vals );
1237                         }
1238                 }
1239
1240                 if ( isgroup( e ) ) {
1241                         vals = ldap_get_values( ld, e, "description" );
1242                 } else {
1243                         vals = ldap_get_values( ld, e, "title" );
1244                 }
1245
1246                 fprintf( fp, "    %-20s %s\n", rdn, vals ? vals[0] : "" );
1247                 for ( i = 1; vals && vals[i] != NULL; i++ ) {
1248                         fprintf( fp, "                         %s\n", vals[i] );
1249                 }
1250
1251                 free( dn );
1252                 free( rdn );
1253                 ldap_value_free( ufn );
1254                 if ( vals != NULL )
1255                         ldap_value_free( vals );
1256         }
1257 }
1258
1259 static
1260 count_values( list )
1261     char        **list;
1262 {
1263         int     i;
1264
1265         for ( i = 0; list && list[i] != NULL; i++ )
1266                 ;       /* NULL */
1267
1268         return( i );
1269 }
1270
1271 static
1272 add_to( list, nlist, new )
1273     char        ***list;
1274     int         *nlist;
1275     char        **new;
1276 {
1277         int     i, nnew, oldnlist;
1278
1279         nnew = count_values( new );
1280
1281         oldnlist = *nlist;
1282         if ( *list == NULL || *nlist == 0 ) {
1283                 *list = (char **) malloc( (nnew + 1) * sizeof(char *) );
1284                 *nlist = nnew;
1285         } else {
1286                 *list = (char **) realloc( *list, *nlist * sizeof(char *) +
1287                     nnew * sizeof(char *) + sizeof(char *) );
1288                 *nlist += nnew;
1289         }
1290
1291         for ( i = 0; i < nnew; i++ ) {
1292                 (*list)[i + oldnlist] = strdup( new[i] );
1293         }
1294         (*list)[*nlist] = NULL;
1295
1296         return;
1297 }
1298
1299 static
1300 isgroup( e )
1301     LDAPMessage *e;
1302 {
1303         int     i;
1304         char    **oclist;
1305
1306         oclist = ldap_get_values( ld, e, "objectClass" );
1307
1308         for ( i = 0; oclist[i] != NULL; i++ ) {
1309                 if ( strcasecmp( oclist[i], "rfc822MailGroup" ) == 0 ) {
1310                         ldap_value_free( oclist );
1311                         return( 1 );
1312                 }
1313         }
1314         ldap_value_free( oclist );
1315
1316         return( 0 );
1317 }
1318
1319 static
1320 add_error( err, nerr, code, addr, msg )
1321     Error       **err;
1322     int         *nerr;
1323     int         code;
1324     char        *addr;
1325     LDAPMessage *msg;
1326 {
1327         if ( *nerr == 0 ) {
1328                 *err = (Error *) malloc( sizeof(Error) );
1329         } else {
1330                 *err = (Error *) realloc( *err, (*nerr + 1) * sizeof(Error) );
1331         }
1332
1333         (*err)[*nerr].e_code = code;
1334         (*err)[*nerr].e_addr = strdup( addr );
1335         (*err)[*nerr].e_msg = msg;
1336         (*nerr)++;
1337
1338         return;
1339 }
1340
1341 static
1342 add_group( dn, list, nlist )
1343     char        *dn;
1344     Group       **list;
1345     int         *nlist;
1346 {
1347         int     i, namelen;
1348         char    **ufn;
1349
1350         for ( i = 0; i < *nlist; i++ ) {
1351                 if ( strcmp( dn, (*list)[i].g_dn ) == 0 ) {
1352                         syslog( LOG_ALERT, "group loop 2 detected (%s)", dn );
1353                         return;
1354                 }
1355         }
1356
1357         ufn = ldap_explode_dn( dn, 1 );
1358         namelen = strlen( ufn[0] );
1359
1360         if ( *nlist == 0 ) {
1361                 *list = (Group *) malloc( sizeof(Group) );
1362         } else {
1363                 *list = (Group *) realloc( *list, (*nlist + 1) *
1364                     sizeof(Group) );
1365         }
1366
1367         /* send errors to groupname-errors@host */
1368         (*list)[*nlist].g_errorsto = (char *) malloc( namelen + sizeof(ERRORS)
1369             + hostlen + 2 );
1370         sprintf( (*list)[*nlist].g_errorsto, "%s-%s@%s", ufn[0], ERRORS, host );
1371         (void) canonical( (*list)[*nlist].g_errorsto );
1372
1373         /* send to groupname-members@host - make it a list for send_group */
1374         (*list)[*nlist].g_members = (char **) malloc( 2 * sizeof(char *) );
1375         (*list)[*nlist].g_members[0] = (char *) malloc( namelen +
1376             sizeof(MEMBERS) + hostlen + 2 );
1377         sprintf( (*list)[*nlist].g_members[0], "%s-%s@%s", ufn[0], MEMBERS,
1378             host );
1379         (void) canonical( (*list)[*nlist].g_members[0] );
1380         (*list)[*nlist].g_members[1] = NULL;
1381
1382         /* save the group's dn so we can check for loops above */
1383         (*list)[*nlist].g_dn = strdup( dn );
1384
1385         (*nlist)++;
1386
1387         ldap_value_free( ufn );
1388
1389         return;
1390 }
1391
1392 static
1393 unbind_and_exit( rc )
1394     int rc;
1395 {
1396         int     i;
1397
1398         if ( (i = ldap_unbind( ld )) != LDAP_SUCCESS )
1399                 syslog( LOG_ALERT, "ldap_unbind failed %d\n", i );
1400
1401         exit( rc );
1402 }
1403
1404 static char *
1405 canonical( s )
1406     char        *s;
1407 {
1408         char    *saves = s;
1409
1410         for ( ; *s != '\0'; s++ ) {
1411                 if ( *s == ' ' )
1412                         *s = '.';
1413         }
1414
1415         return( saves );
1416 }
1417
1418 static
1419 group_loop( dn )
1420     char        *dn;
1421 {
1422         int             i;
1423         static char     **groups;
1424         static int      ngroups;
1425
1426         for ( i = 0; i < ngroups; i++ ) {
1427                 if ( strcmp( dn, groups[i] ) == 0 )
1428                         return( 1 );
1429         }
1430
1431         if ( ngroups == 0 )
1432                 groups = (char **) malloc( sizeof(char *) );
1433         else
1434                 groups = (char **) realloc( groups,
1435                     (ngroups + 1) * sizeof(char *) );
1436
1437         groups[ngroups++] = strdup( dn );
1438
1439         return( 0 );
1440 }
1441
1442 static
1443 has_attributes( e, attr1, attr2 )
1444     LDAPMessage *e;
1445     char        *attr1;
1446     char        *attr2;
1447 {
1448         char    **attr;
1449
1450         if ( (attr = ldap_get_values( ld, e, attr1 )) != NULL ) {
1451                 ldap_value_free( attr );
1452                 return( 1 );
1453         }
1454
1455         if ( (attr = ldap_get_values( ld, e, attr2 )) != NULL ) {
1456                 ldap_value_free( attr );
1457                 return( 1 );
1458         }
1459
1460         return( 0 );
1461 }
1462
1463 static char **
1464 get_attributes_mail_dn( e, attr1, attr2 )
1465     LDAPMessage *e;
1466     char        *attr1;
1467     char        *attr2;         /* this one is dn-valued */
1468 {
1469         LDAPMessage     *ee, *res;
1470         char            **vals, **dnlist, **mail;
1471         int             nto, i, rc;
1472         struct timeval  timeout;
1473
1474         vals = ldap_get_values( ld, e, attr1 );
1475         for ( nto = 0; vals != NULL && vals[nto] != NULL; nto++ )
1476                 ;       /* NULL */
1477
1478         if ( (dnlist = ldap_get_values( ld, e, attr2 )) != NULL ) {
1479                 timeout.tv_sec = FAX_TIMEOUT;
1480                 timeout.tv_usec = 0;
1481
1482                 for ( i = 0; dnlist[i] != NULL; i++ ) {
1483                         if ( (rc = ldap_search_st( ld, dnlist[i],
1484                             LDAP_SCOPE_BASE, "(objectclass=*)", attrs, 0,
1485                             &timeout, &res )) != LDAP_SUCCESS ) {
1486                                 if ( rc != LDAP_NO_SUCH_OBJECT ) {
1487                                         unbind_and_exit( EX_TEMPFAIL );
1488                                 }
1489
1490                                 syslog( LOG_ALERT, "bad (%s) dn (%s)", attr2,
1491                                     dnlist[i] );
1492
1493                                 continue;
1494                         }
1495
1496                         if ( (ee = ldap_first_entry( ld, res )) == NULL ) {
1497                                 syslog( LOG_ALERT, "error parsing x500 entry" );
1498                                 continue;
1499                         }
1500
1501                         if ( (mail = ldap_get_values( ld, ee, "mail" ))
1502                             != NULL ) {
1503                                 add_to( &vals, &nto, mail );
1504
1505                                 ldap_value_free( mail );
1506                         }
1507
1508                         ldap_msgfree( res );
1509                 }
1510         }
1511
1512         return( vals );
1513 }