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