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