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