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