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