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