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