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