3 * Copyright (c) 1990 Regents of the University of Michigan.
6 * Redistribution and use in source and binary forms are permitted
7 * provided that this notice is preserved and that due credit is given
8 * to the University of Michigan at Ann Arbor. The name of the University
9 * may not be used to endorse or promote products derived from this
10 * software without specific prior written permission. This software
11 * is provided ``as is'' without express or implied warranty.
13 * Copyright 1998-2002 The OpenLDAP Foundation
14 * COPYING RESTRICTIONS APPLY. See COPYRIGHT File in top level directory
15 * of this package for details.
22 #include <ac/stdlib.h>
26 #include <ac/signal.h>
27 #include <ac/string.h>
28 #include <ac/sysexits.h>
29 #include <ac/syslog.h>
31 #include <ac/unistd.h>
36 #ifdef HAVE_SYS_RESOURCE_H
37 #include <sys/resource.h>
42 #include "ldap_defaults.h"
44 #ifndef MAIL500_BOUNCEFROM
45 #define MAIL500_BOUNCEFROM "<>"
49 #define GROUP_ERRORS 0x02
50 #define GROUP_REQUEST 0x04
51 #define GROUP_MEMBERS 0x08
52 #define GROUP_OWNER 0x10
55 #define ERRORS "errors"
56 #define REQUEST "request"
57 #define REQUESTS "requests"
58 #define MEMBERS "members"
60 #define OWNERS "owners"
63 char *vacationhost = NULL;
64 char *errorsfrom = NULL;
65 char *mailfrom = NULL;
67 char *ldaphost = NULL;
73 #define E_USERUNKNOWN 1
79 #define E_JOINMEMBERNOEMAIL 7
80 #define E_MEMBERNOEMAIL 8
82 #define E_NOMEMBERS 10
84 #define E_GROUPUNKNOWN 12
90 #define e_msg e_union.e_u_msg
91 #define e_loop e_union.e_u_loop
94 typedef struct groupto {
100 typedef struct baseinfo {
101 char *b_dn; /* dn to start searching at */
102 char b_rdnpref; /* give rdn's preference when searching? */
103 int b_search; /* ORed with the type of thing the address */
104 /* looks like (USER, GROUP_ERRORS, etc.) */
105 /* to see if this should be searched */
106 char *b_filter[3]; /* filter to apply - name substituted for %s */
107 /* (up to three of them) */
111 {"ou=People, dc=example, dc=com",
113 {"uid=%s", "cn=%s", NULL}},
114 {"ou=System Groups, ou=Groups, dc=example, dc=com",
116 {"(&(cn=%s)(associatedDomain=%h))", NULL, NULL}},
117 {"ou=User Groups, ou=Groups, dc=example, dc=com",
119 {"(&(cn=%s)(associatedDomain=%h))", NULL, NULL}},
123 char *sendmailargs[] = { MAIL500_SENDMAIL, "-oMrLDAP", "-odi", "-oi", "-f", NULL, NULL };
125 static char *attrs[] = { "objectClass", "title", "postaladdress",
126 "telephoneNumber", "mail", "description", "owner",
127 "errorsTo", "rfc822ErrorsTo", "requestsTo",
128 "rfc822RequestsTo", "joinable", "cn", "member",
129 "moderator", "onVacation", "uid",
130 "suppressNoEmailError", NULL };
132 static void do_address( char *name, char ***to, int *nto, Group **togroups, int *ngroups, Error **err, int *nerr, int type );
133 static int do_group( LDAPMessage *e, char *dn, char ***to, int *nto, Group **togroups, int *ngroups, Error **err, int *nerr );
134 static void do_group_members( LDAPMessage *e, char *dn, char ***to, int *nto, Group **togroups, int *ngroups, Error **err, int *nerr );
135 static void send_message( char **to );
136 static void send_errors( Error *err, int nerr );
137 static void do_noemail( FILE *fp, Error *err, int namelen );
138 static void do_ambiguous( FILE *fp, Error *err, int namelen );
139 static void add_to( char ***list, int *nlist, char **new );
140 static int isgroup( LDAPMessage *e );
141 static void add_error( Error **err, int *nerr, int code, char *addr, LDAPMessage *msg );
142 static void add_group( char *dn, Group **list, int *nlist );
143 static void unbind_and_exit( int rc );
144 static int group_loop( char *dn );
145 static void send_group( Group *group, int ngroup );
146 static int has_attributes( LDAPMessage *e, char *attr1, char *attr2 );
147 static char **get_attributes_mail_dn( LDAPMessage *e, char *attr1, char *attr2 );
148 static char *canonical( char *s );
149 static int connect_to_x500( void );
151 static void do_group_errors( LDAPMessage *e, char *dn, char ***to, int *nto, Error **err, int *nerr );
152 static void do_group_request( LDAPMessage *e, char *dn, char ***to, int *nto, Error **err, int *nerr );
153 static void do_group_owner( LDAPMessage *e, char *dn, char ***to, int *nto, Error **err, int *nerr );
154 static void add_member( char *gdn, char *dn, char ***to, int *nto, Group **togroups, int *ngroups, Error **err, int *nerr, char **suppress );
157 main ( int argc, char **argv )
163 int numto, ngroups, numerr, nargs;
166 if ( (myname = strrchr( argv[0], *LDAP_DIRSEP )) == NULL )
167 myname = strdup( argv[0] );
169 myname = strdup( myname + 1 );
172 (void) SIGNAL( SIGPIPE, SIG_IGN );
176 openlog( myname, OPENLOG_OPTIONS, LOG_MAIL );
178 openlog( myname, OPENLOG_OPTIONS );
181 while ( (i = getopt( argc, argv, "d:f:h:l:m:v:" )) != EOF ) {
183 case 'd': /* turn on debugging */
184 debug = atoi( optarg );
187 case 'f': /* who it's from & where errors should go */
188 mailfrom = strdup( optarg );
189 for ( j = 0; sendmailargs[j] != NULL; j++ ) {
190 if ( strcmp( sendmailargs[j], "-f" ) == 0 ) {
191 sendmailargs[j+1] = mailfrom;
197 case 'h': /* hostname */
198 host = strdup( optarg );
199 hostlen = strlen(host);
202 case 'l': /* ldap host */
203 ldaphost = strdup( optarg );
206 /* mailer-daemon address - who we should */
207 case 'm': /* say errors come from */
208 errorsfrom = strdup( optarg );
211 case 'v': /* vacation host */
212 vacationhost = strdup( optarg );
216 syslog( LOG_ALERT, "unknown option" );
221 if ( mailfrom == NULL ) {
222 syslog( LOG_ALERT, "required argument -f not present" );
225 if ( errorsfrom == NULL ) {
226 syslog( LOG_ALERT, "required argument -m not present" );
229 if ( host == NULL ) {
230 syslog( LOG_ALERT, "required argument -h not present" );
234 if ( connect_to_x500() != 0 )
243 syslog( LOG_ALERT, "running as %d", geteuid() );
244 strcpy( buf, argv[0] );
245 for ( i = 1; i < argc; i++ ) {
247 strcat( buf, argv[i] );
250 syslog( LOG_ALERT, "args: (%s)", buf );
255 add_to( &tolist, &numto, sendmailargs );
257 ngroups = numerr = 0;
260 for ( i = optind; i < argc; i++ ) {
264 for ( j = 0; argv[i][j] != '\0'; j++ ) {
265 if ( argv[i][j] == '.' || argv[i][j] == '_' )
270 if ( (s = strrchr( argv[i], '-' )) != NULL ) {
273 if ((strcasecmp(s, ERROR) == 0) ||
274 (strcasecmp(s, ERRORS) == 0)) {
277 } else if ((strcasecmp(s, REQUEST) == 0) ||
278 (strcasecmp(s, REQUESTS) == 0)) {
279 type = GROUP_REQUEST;
281 } else if ( strcasecmp( s, MEMBERS ) == 0 ) {
282 type = GROUP_MEMBERS;
284 } else if ((strcasecmp(s, OWNER) == 0) ||
285 (strcasecmp(s, OWNERS) == 0)) {
291 do_address( argv[i], &tolist, &numto, &togroups, &ngroups,
292 &errlist, &numerr, type );
296 * If we have both errors and successful deliveries to make or if
297 * if there are any groups to deliver to, we basically need to read
298 * the message twice. So, we have to put it in a tmp file.
301 if ( numerr > 0 && numto > nargs || ngroups > 0 ) {
306 if ( (fp = tmpfile()) == NULL ) {
307 syslog( LOG_ALERT, "could not open tmp file" );
308 unbind_and_exit( EX_TEMPFAIL );
311 /* copy the message to a temp file */
312 while ( fgets( buf, sizeof(buf), stdin ) != NULL ) {
313 if ( fputs( buf, fp ) == EOF ) {
314 syslog( LOG_ALERT, "error writing tmpfile" );
315 unbind_and_exit( EX_TEMPFAIL );
319 if ( dup2( fileno( fp ), 0 ) == -1 ) {
320 syslog( LOG_ALERT, "could not dup2 tmpfile" );
321 unbind_and_exit( EX_TEMPFAIL );
327 /* deal with errors */
330 syslog( LOG_ALERT, "sending errors" );
332 (void) rewind( stdin );
333 send_errors( errlist, numerr );
336 (void) ldap_unbind( ld );
338 /* send to groups with errorsTo */
341 syslog( LOG_ALERT, "sending to groups with errorsto" );
343 (void) rewind( stdin );
344 send_group( togroups, ngroups );
347 /* send to expanded aliases and groups w/o errorsTo */
348 if ( numto > nargs ) {
350 syslog( LOG_ALERT, "sending to aliases and groups" );
352 (void) rewind( stdin );
353 send_message( tolist );
360 connect_to_x500( void )
364 if ( (ld = ldap_init( ldaphost, 0 )) == NULL ) {
365 syslog( LOG_ALERT, "ldap_init failed" );
369 opt = MAIL500_MAXAMBIGUOUS;
370 ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &opt);
371 opt = LDAP_DEREF_ALWAYS;
372 ldap_set_option(ld, LDAP_OPT_DEREF, &opt);
374 if ( ldap_simple_bind_s( ld, NULL, NULL ) != LDAP_SUCCESS ) {
375 syslog( LOG_ALERT, "ldap_simple_bind_s failed" );
383 mailcmp( char *a, char *b )
387 for ( i = 0; a[i] != '\0'; i++ ) {
388 if ( a[i] != b[i] ) {
393 if ( b[i] == ' ' || b[i] == '.' || b[i] == '_' )
419 LDAPMessage *e, *res;
420 struct timeval timeout;
423 char realfilter[1024];
424 char **mail, **onvacation = NULL, **uid = NULL;
427 * Look up the name in X.500, add the appropriate addresses found
428 * to the to list, or to the err list in case of error. Groups are
429 * handled by the do_group routine, individuals are handled here.
430 * When looking up name, we follow the bases hierarchy, looking
431 * in base[0] first, then base[1], etc. For each base, there is
432 * a set of search filters to try, in order. If something goes
433 * wrong here trying to contact X.500, we exit with EX_TEMPFAIL.
434 * If the b_rdnpref flag is set, then we give preference to entries
435 * that matched name because it's their rdn, otherwise not.
438 timeout.tv_sec = MAIL500_TIMEOUT;
440 for ( b = 0, match = 0; !match && base[b].b_dn != NULL; b++ ) {
441 if ( ! (base[b].b_search & type) ) {
444 for ( f = 0; base[b].b_filter[f] != NULL; f++ ) {
445 char *format, *p, *s, *d;
449 for ( argc = 0; argc < 3; argc++ ) {
453 format = strdup( base[b].b_filter[f] );
454 for ( argc = 0, p = format; *p; p++ ) {
457 case 's': /* %s is the name */
461 case 'h': /* %h is the host */
468 "unknown format %c", *p );
476 /* three names ought to do... */
477 sprintf( filter, format, argv[0], argv[1], argv[2] );
479 for ( s = filter, d = realfilter; *s; s++, d++ ) {
488 rc = ldap_search_st( ld, base[b].b_dn,
489 LDAP_SCOPE_SUBTREE, realfilter, attrs, 0, &timeout,
492 /* some other trouble - try again later */
493 if ( rc != LDAP_SUCCESS &&
494 rc != LDAP_SIZELIMIT_EXCEEDED ) {
495 syslog( LOG_ALERT, "return 0x%x from X.500",
497 unbind_and_exit( EX_TEMPFAIL );
500 if ( (match = ldap_count_entries( ld, res )) != 0 )
510 /* trouble - try again later */
512 syslog( LOG_ALERT, "error parsing result from X.500" );
513 unbind_and_exit( EX_TEMPFAIL );
516 /* no matches - bounce with user unknown */
518 if ( type == USER ) {
519 add_error( err, nerr, E_USERUNKNOWN, name, NULL );
521 add_error( err, nerr, E_GROUPUNKNOWN, name, NULL );
526 /* more than one match - bounce with ambiguous user? */
528 LDAPMessage *next, *tmpres = NULL;
532 /* not giving rdn preference - bounce with ambiguous user */
533 if ( base[b].b_rdnpref == 0 ) {
534 add_error( err, nerr, E_AMBIGUOUS, name, res );
539 * giving rdn preference - see if any entries were matched
540 * because of their rdn. If so, collect them to deal with
541 * later (== 1 we deliver, > 1 we bounce).
544 for ( e = ldap_first_entry( ld, res ); e != NULL; e = next ) {
545 next = ldap_next_entry( ld, e );
546 dn = ldap_get_dn( ld, e );
547 xdn = ldap_explode_dn( dn, 1 );
549 /* XXX bad, but how else can we do it? XXX */
550 if ( strcasecmp( xdn[0], name ) == 0 ) {
551 ldap_delete_result_entry( &res, e );
552 ldap_add_result_entry( &tmpres, e );
555 ldap_value_free( xdn );
559 /* nothing matched by rdn - go ahead and bounce */
560 if ( tmpres == NULL ) {
561 add_error( err, nerr, E_AMBIGUOUS, name, res );
564 /* more than one matched by rdn - bounce with rdn matches */
565 } else if ( (match = ldap_count_entries( ld, tmpres )) > 1 ) {
566 add_error( err, nerr, E_AMBIGUOUS, name, tmpres );
570 } else if ( match < 0 ) {
571 syslog( LOG_ALERT, "error parsing result from X.500" );
572 unbind_and_exit( EX_TEMPFAIL );
575 /* otherwise one matched by rdn - send to it */
581 * if we get this far, it means that we found a single match for
582 * name. for a user, we deliver to the mail attribute or bounce
583 * with address and phone if no mail attr. for a group, we
584 * deliver to all members or bounce to rfc822ErrorsTo if no members.
588 if ( (e = ldap_first_entry( ld, res )) == NULL ) {
589 syslog( LOG_ALERT, "error parsing entry from X.500" );
590 unbind_and_exit( EX_TEMPFAIL );
593 dn = ldap_get_dn( ld, e );
595 if ( type == GROUP_ERRORS ) {
596 /* sent to group-errors - resend to [rfc822]ErrorsTo attr */
597 do_group_errors( e, dn, to, nto, err, nerr );
599 } else if ( type == GROUP_REQUEST ) {
600 /* sent to group-request - resend to [rfc822]RequestsTo attr */
601 do_group_request( e, dn, to, nto, err, nerr );
603 } else if ( type == GROUP_MEMBERS ) {
604 /* sent to group-members - expand */
605 do_group_members( e, dn, to, nto, togroups, ngroups, err,
608 } else if ( type == GROUP_OWNER ) {
609 /* sent to group-owner - resend to owner attr */
610 do_group_owner( e, dn, to, nto, err, nerr );
612 } else if ( isgroup( e ) ) {
614 * sent to group - resend from [rfc822]ErrorsTo if it's there,
615 * otherwise, expand the group
618 do_group( e, dn, to, nto, togroups, ngroups, err, nerr );
624 * sent to user - mail attribute => add it to the to list,
627 if ( (mail = ldap_get_values( ld, e, "mail" )) != NULL ) {
632 /* try to detect simple mail loops */
633 sprintf( buf, "%s@%s", name, host );
634 for ( i = 0; mail[i] != NULL; i++ ) {
636 * address is the same as the one we're
637 * sending to - mail loop. syslog the
638 * problem, bounce a message back to the
639 * sender (who else?), and delete the bogus
640 * addr from the list.
643 if ( (h = strchr( mail[i], '@' )) != NULL ) {
645 if ( strcasecmp( h, host ) == 0 ) {
647 "potential loop detected (%s)",
652 if ( mailcmp( buf, mail[i] ) == 0 ) {
654 "loop detected (%s)", mail[i] );
656 /* remove the bogus address */
657 for ( j = i; mail[j] != NULL; j++ ) {
662 if ( mail[0] != NULL ) {
663 add_to( to, nto, mail );
665 add_error( err, nerr, E_NOEMAIL, name, res );
668 ldap_value_free( mail );
670 add_error( err, nerr, E_NOEMAIL, name, res );
674 * If the user is on vacation, send a copy of the mail to
675 * the vacation server. The address is constructed from
676 * the vacationhost (set in a command line argument) and
677 * the uid (XXX this should be more general XXX).
680 if ( vacationhost != NULL && (onvacation = ldap_get_values( ld,
681 e, "onVacation" )) != NULL && strcasecmp( onvacation[0],
686 if ( (uid = ldap_get_values( ld, e, "uid" )) != NULL ) {
687 sprintf( buf, "%s@%s", uid[0], vacationhost );
692 add_to( to, nto, vaddr );
695 "user without a uid on vacation (%s)",
701 if ( onvacation != NULL ) {
702 ldap_value_free( onvacation );
705 ldap_value_free( uid );
726 * If this group has an rfc822ErrorsTo attribute, we need to
727 * arrange for errors involving this group to go there, not
728 * to the sender. Since sendmail only has the concept of a
729 * single sender, we arrange for errors to go to groupname-errors,
730 * which we then handle specially when (if) it comes back to us
731 * by expanding to all the rfc822ErrorsTo addresses. If it has no
732 * rfc822ErrorsTo attribute, we call do_group_members() to expand
736 if ( group_loop( dn ) ) {
741 * check for moderated groups - if the group has a moderator
742 * attribute, we check to see if the from address is one of
743 * the moderator values. if so, continue on. if not, arrange
744 * to send the mail to the moderator(s). need to do this before
745 * we change the from below.
748 if ( (moderator = ldap_get_values( ld, e, "moderator" )) != NULL ) {
749 /* check if it came from any of the group's moderators */
750 for ( i = 0; moderator[i] != NULL; i++ ) {
751 if ( strcasecmp( moderator[i], mailfrom ) == 0 )
755 /* not from the moderator? */
756 if ( moderator[i] == NULL ) {
757 add_to( to, nto, moderator );
758 ldap_value_free( moderator );
762 /* else from the moderator - fall through and deliver it */
765 if (strcmp(MAIL500_BOUNCEFROM, mailfrom) != 0 &&
766 has_attributes( e, "rfc822ErrorsTo", "errorsTo" ) ) {
767 add_group( dn, togroups, ngroups );
772 do_group_members( e, dn, to, nto, togroups, ngroups, err, nerr );
790 int i, rc, anymembers;
792 char **mail, **member, **joinable, **suppress;
794 LDAPMessage *ee, *res;
795 struct timeval timeout;
799 * if all has gone according to plan, we've already arranged for
800 * errors to go to the [rfc822]ErrorsTo attributes (if they exist),
801 * so all we have to do here is arrange to send to the
802 * rfc822Mailbox attribute, the member attribute, and anyone who
803 * has joined the group by setting memberOfGroup equal to the
807 /* add members in the group itself - mail attribute */
809 if ( (mail = ldap_get_values( ld, e, "mail" )) != NULL ) {
811 add_to( to, nto, mail );
813 ldap_value_free( mail );
816 /* add members in the group itself - member attribute */
817 if ( (member = ldap_get_values( ld, e, "member" )) != NULL ) {
818 suppress = ldap_get_values( ld, e, "suppressNoEmailError" );
820 for ( i = 0; member[i] != NULL; i++ ) {
821 if ( strcasecmp( dn, member[i] ) == 0 ) {
822 syslog( LOG_ALERT, "group (%s) contains itself",
826 add_member( dn, member[i], to, nto, togroups,
827 ngroups, err, nerr, suppress );
831 ldap_value_free( suppress );
833 ldap_value_free( member );
836 /* add members who have joined by setting memberOfGroup */
837 if ( (joinable = ldap_get_values( ld, e, "joinable" )) != NULL ) {
838 if ( strcasecmp( joinable[0], "FALSE" ) == 0 ) {
839 if ( ! anymembers ) {
840 add_error( err, nerr, E_NOMEMBERS, dn,
844 ldap_value_free( joinable );
847 ldap_value_free( joinable );
849 sprintf( filter, "(memberOfGroup=%s)", dn );
851 timeout.tv_sec = MAIL500_TIMEOUT;
854 /* for each subtree to look in... */
855 opt = MAIL500_MAXAMBIGUOUS;
856 ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &opt);
857 for ( i = 0; base[i].b_dn != NULL; i++ ) {
858 /* find entries that have joined this group... */
859 rc = ldap_search_st( ld, base[i].b_dn,
860 LDAP_SCOPE_SUBTREE, filter, attrs, 0, &timeout,
863 if ( rc == LDAP_SIZELIMIT_EXCEEDED ||
864 rc == LDAP_TIMELIMIT_EXCEEDED ) {
866 "group search limit exceeded %d", rc );
867 unbind_and_exit( EX_TEMPFAIL );
870 if ( rc != LDAP_SUCCESS ) {
871 syslog( LOG_ALERT, "group search return 0x%x",
873 unbind_and_exit( EX_TEMPFAIL );
876 /* for each entry that has joined... */
877 for ( ee = ldap_first_entry( ld, res ); ee != NULL;
878 ee = ldap_next_entry( ld, ee ) ) {
880 if ( isgroup( ee ) ) {
881 ndn = ldap_get_dn( ld, ee );
883 if ( do_group( e, ndn, to, nto,
884 togroups, ngroups, err, nerr )
887 "group loop (%s) (%s)",
896 /* add them to the to list */
897 if ( (mail = ldap_get_values( ld, ee, "mail" ))
899 add_to( to, nto, mail );
901 ldap_value_free( mail );
903 /* else generate a bounce */
905 ndn = ldap_get_dn( ld, ee );
907 add_error( err, nerr,
908 E_JOINMEMBERNOEMAIL, ndn, NULL );
916 opt = MAIL500_MAXAMBIGUOUS;
917 ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &opt);
920 if ( ! anymembers ) {
921 add_error( err, nerr, E_NOMEMBERS, dn, NULL );
941 LDAPMessage *res, *e;
942 struct timeval timeout;
944 timeout.tv_sec = MAIL500_TIMEOUT;
946 if ( (rc = ldap_search_st( ld, dn, LDAP_SCOPE_BASE, "(objectclass=*)",
947 attrs, 0, &timeout, &res )) != LDAP_SUCCESS ) {
948 if ( rc == LDAP_NO_SUCH_OBJECT ) {
949 add_error( err, nerr, E_BADMEMBER, dn, NULL );
953 syslog( LOG_ALERT, "member search return 0x%x", rc );
955 unbind_and_exit( EX_TEMPFAIL );
959 if ( (e = ldap_first_entry( ld, res )) == NULL ) {
960 syslog( LOG_ALERT, "member search error parsing entry" );
962 unbind_and_exit( EX_TEMPFAIL );
964 ndn = ldap_get_dn( ld, e );
966 /* allow groups within groups */
967 if ( isgroup( e ) ) {
968 if ( do_group( e, ndn, to, nto, togroups, ngroups, err, nerr )
970 syslog( LOG_ALERT, "group loop (%s) (%s)", gdn, ndn );
978 /* send to the member's mail attribute */
979 if ( (mail = ldap_get_values( ld, e, "mail" )) != NULL ) {
980 add_to( to, nto, mail );
982 ldap_value_free( mail );
984 /* else generate a bounce */
986 if ( suppress == NULL || strcasecmp( suppress[0], "FALSE" )
988 add_error( err, nerr, E_MEMBERNOEMAIL, ndn, NULL );
1007 if ( (requeststo = get_attributes_mail_dn( e, "rfc822RequestsTo",
1008 "requestsTo" )) != NULL ) {
1009 add_to( to, nto, requeststo );
1011 ldap_value_free( requeststo );
1013 add_error( err, nerr, E_NOREQUEST, dn, NULL );
1029 if ( (errorsto = get_attributes_mail_dn( e, "rfc822ErrorsTo",
1030 "errorsTo" )) != NULL ) {
1031 add_to( to, nto, errorsto );
1033 ldap_value_free( errorsto );
1035 add_error( err, nerr, E_NOERRORS, dn, NULL );
1051 if ( (owner = get_attributes_mail_dn( e, "", "owner" )) != NULL ) {
1052 add_to( to, nto, owner );
1053 ldap_value_free( owner );
1055 add_error( err, nerr, E_NOOWNER, dn, NULL );
1060 send_message( char **to )
1063 #ifndef HAVE_WAITPID
1064 WAITSTATUSTYPE status;
1071 strcpy( buf, to[0] );
1072 for ( i = 1; to[i] != NULL; i++ ) {
1074 strcat( buf, to[i] );
1077 syslog( LOG_ALERT, "send_message execing sendmail: (%s)", buf );
1081 if ( (pid = fork()) != 0 ) {
1083 waitpid( pid, (int *) NULL, 0 );
1085 wait4( pid, &status, WAIT_FLAGS, 0 );
1089 /* to includes sendmailargs */
1090 execv( MAIL500_SENDMAIL, to );
1092 syslog( LOG_ALERT, "execv failed" );
1094 exit( EX_TEMPFAIL );
1099 send_group( Group *group, int ngroup )
1105 #ifndef HAVE_WAITPID
1106 WAITSTATUSTYPE status;
1109 for ( i = 0; i < ngroup; i++ ) {
1110 (void) rewind( stdin );
1112 iargv[0] = MAIL500_SENDMAIL;
1114 iargv[2] = group[i].g_errorsto;
1115 iargv[3] = "-oMrX.500";
1122 add_to( &argv, &argc, iargv );
1123 add_to( &argv, &argc, group[i].g_members );
1129 strcpy( buf, argv[0] );
1130 for ( i = 1; i < argc; i++ ) {
1132 strcat( buf, argv[i] );
1135 syslog( LOG_ALERT, "execing sendmail: (%s)", buf );
1139 if ( (pid = fork()) != 0 ) {
1141 waitpid( pid, (int *) NULL, 0 );
1143 wait4( pid, &status, WAIT_FLAGS, 0 );
1147 execv( MAIL500_SENDMAIL, argv );
1149 syslog( LOG_ALERT, "execv failed" );
1151 exit( EX_TEMPFAIL );
1157 send_errors( Error *err, int nerr )
1159 int pid, i, namelen;
1164 #ifndef HAVE_WAITPID
1165 WAITSTATUSTYPE status;
1168 if ( strcmp( MAIL500_BOUNCEFROM, mailfrom ) == 0 ) {
1169 mailfrom = errorsfrom;
1172 argv[0] = MAIL500_SENDMAIL;
1173 argv[1] = "-oMrX.500";
1177 argv[5] = MAIL500_BOUNCEFROM;
1184 strcpy( buf, argv[0] );
1185 for ( i = 1; argv[i] != NULL; i++ ) {
1187 strcat( buf, argv[i] );
1190 syslog( LOG_ALERT, "execing sendmail: (%s)", buf );
1193 if ( pipe( fd ) == -1 ) {
1194 syslog( LOG_ALERT, "cannot create pipe" );
1195 exit( EX_TEMPFAIL );
1198 if ( (pid = fork()) != 0 ) {
1199 if ( (fp = fdopen( fd[1], "w" )) == NULL ) {
1200 syslog( LOG_ALERT, "cannot fdopen pipe" );
1201 exit( EX_TEMPFAIL );
1204 fprintf( fp, "To: %s\n", mailfrom );
1205 fprintf( fp, "From: %s\n", errorsfrom );
1206 fprintf( fp, "Subject: undeliverable mail\n" );
1207 fprintf( fp, "\n" );
1208 fprintf( fp, "The following errors occurred when trying to deliver the attached mail:\n" );
1209 for ( i = 0; i < nerr; i++ ) {
1210 namelen = strlen( err[i].e_addr );
1211 fprintf( fp, "\n" );
1213 switch ( err[i].e_code ) {
1215 fprintf( fp, "%s: User unknown\n", err[i].e_addr );
1218 case E_GROUPUNKNOWN:
1219 fprintf( fp, "%s: Group unknown\n", err[i].e_addr );
1223 fprintf( fp, "%s: Group member does not exist\n",
1225 fprintf( fp, "This could be because the distinguished name of the person has changed\n" );
1226 fprintf( fp, "If this is the case, the problem can be solved by removing and\n" );
1227 fprintf( fp, "then re-adding the person to the group.\n" );
1231 fprintf( fp, "%s: Group exists but has no request address\n",
1236 fprintf( fp, "%s: Group exists but has no errors-to address\n",
1241 fprintf( fp, "%s: Group exists but has no owner\n",
1246 do_ambiguous( fp, &err[i], namelen );
1250 do_noemail( fp, &err[i], namelen );
1253 case E_MEMBERNOEMAIL:
1254 fprintf( fp, "%s: Group member exists but does not have an email address\n",
1258 case E_JOINMEMBERNOEMAIL:
1259 fprintf( fp, "%s: User has joined group but does not have an email address\n",
1264 fprintf( fp, "%s: User has created a mail loop by adding address %s to their X.500 entry\n",
1265 err[i].e_addr, err[i].e_loop );
1269 fprintf( fp, "%s: Group has no members\n",
1274 syslog( LOG_ALERT, "unknown error %d", err[i].e_code );
1275 unbind_and_exit( EX_TEMPFAIL );
1280 fprintf( fp, "\n------- The original message sent:\n\n" );
1282 while ( fgets( buf, sizeof(buf), stdin ) != NULL ) {
1288 waitpid( pid, (int *) NULL, 0 );
1290 wait4( pid, &status, WAIT_FLAGS, 0 );
1295 execv( MAIL500_SENDMAIL, argv );
1297 syslog( LOG_ALERT, "execv failed" );
1299 exit( EX_TEMPFAIL );
1304 do_noemail( FILE *fp, Error *err, int namelen )
1310 fprintf(fp, "%s: User has no email address registered.\n",
1312 fprintf( fp, "%*s Name, title, postal address and phone for '%s':\n\n",
1313 namelen, " ", err->e_addr );
1316 dn = ldap_get_dn( ld, err->e_msg );
1317 ufn = ldap_explode_dn( dn, 1 );
1318 rdn = strdup( ufn[0] );
1319 if ( strcasecmp( rdn, err->e_addr ) == 0 ) {
1320 if ( (vals = ldap_get_values( ld, err->e_msg, "cn" ))
1322 for ( i = 0; vals[i]; i++ ) {
1323 last = strlen( vals[i] ) - 1;
1324 if ( isdigit((unsigned char) vals[i][last]) ) {
1325 rdn = strdup( vals[i] );
1330 ldap_value_free( vals );
1333 fprintf( fp, "%*s %s\n", namelen, " ", rdn );
1336 ldap_value_free( ufn );
1338 /* titles or descriptions */
1339 if ( (vals = ldap_get_values( ld, err->e_msg, "title" )) == NULL &&
1340 (vals = ldap_get_values( ld, err->e_msg, "description" ))
1342 fprintf( fp, "%*s No title or description registered\n",
1345 for ( i = 0; vals[i] != NULL; i++ ) {
1346 fprintf( fp, "%*s %s\n", namelen, " ", vals[i] );
1349 ldap_value_free( vals );
1352 /* postal address */
1353 if ( (vals = ldap_get_values( ld, err->e_msg, "postalAddress" ))
1355 fprintf( fp, "%*s No postal address registered\n", namelen,
1358 fprintf( fp, "%*s ", namelen, " " );
1359 for ( i = 0; vals[0][i] != '\0'; i++ ) {
1360 if ( vals[0][i] == '$' ) {
1361 fprintf( fp, "\n%*s ", namelen, " " );
1362 while ( isspace((unsigned char) vals[0][i+1]) )
1365 fprintf( fp, "%c", vals[0][i] );
1368 fprintf( fp, "\n" );
1370 ldap_value_free( vals );
1373 /* telephone number */
1374 if ( (vals = ldap_get_values( ld, err->e_msg, "telephoneNumber" ))
1376 fprintf( fp, "%*s No phone number registered\n", namelen,
1379 for ( i = 0; vals[i] != NULL; i++ ) {
1380 fprintf( fp, "%*s %s\n", namelen, " ", vals[i] );
1383 ldap_value_free( vals );
1389 do_ambiguous( FILE *fp, Error *err, int namelen )
1396 i = ldap_result2error( ld, err->e_msg, 0 );
1398 fprintf( fp, "%s: Ambiguous user. %s%d matches found:\n\n",
1399 err->e_addr, i == LDAP_SIZELIMIT_EXCEEDED ? "First " : "",
1400 ldap_count_entries( ld, err->e_msg ) );
1402 for ( e = ldap_first_entry( ld, err->e_msg ); e != NULL;
1403 e = ldap_next_entry( ld, e ) ) {
1404 dn = ldap_get_dn( ld, e );
1405 ufn = ldap_explode_dn( dn, 1 );
1406 rdn = strdup( ufn[0] );
1407 if ( strcasecmp( rdn, err->e_addr ) == 0 ) {
1408 if ( (vals = ldap_get_values( ld, e, "cn" )) != NULL ) {
1409 for ( i = 0; vals[i]; i++ ) {
1410 last = strlen( vals[i] ) - 1;
1411 if (isdigit((unsigned char) vals[i][last])) {
1412 rdn = strdup( vals[i] );
1417 ldap_value_free( vals );
1421 if ( isgroup( e ) ) {
1422 vals = ldap_get_values( ld, e, "description" );
1424 vals = ldap_get_values( ld, e, "title" );
1427 fprintf( fp, " %-20s %s\n", rdn, vals ? vals[0] : "" );
1428 for ( i = 1; vals && vals[i] != NULL; i++ ) {
1429 fprintf( fp, " %s\n", vals[i] );
1434 ldap_value_free( ufn );
1436 ldap_value_free( vals );
1441 count_values( char **list )
1445 for ( i = 0; list && list[i] != NULL; i++ )
1452 add_to( char ***list, int *nlist, char **new )
1454 int i, nnew, oldnlist;
1456 nnew = count_values( new );
1459 if ( *list == NULL || *nlist == 0 ) {
1460 *list = (char **) malloc( (nnew + 1) * sizeof(char *) );
1463 *list = (char **) realloc( *list, *nlist * sizeof(char *) +
1464 nnew * sizeof(char *) + sizeof(char *) );
1468 for ( i = 0; i < nnew; i++ )
1469 (*list)[i + oldnlist] = strdup( new[i] );
1470 (*list)[*nlist] = NULL;
1474 isgroup( LDAPMessage *e )
1479 oclist = ldap_get_values( ld, e, "objectClass" );
1481 for ( i = 0; oclist[i] != NULL; i++ ) {
1482 if ( strcasecmp( oclist[i], "rfc822MailGroup" ) == 0 ) {
1483 ldap_value_free( oclist );
1487 ldap_value_free( oclist );
1493 add_error( Error **err, int *nerr, int code, char *addr, LDAPMessage *msg )
1496 *err = (Error *) malloc( sizeof(Error) );
1498 *err = (Error *) realloc( *err, (*nerr + 1) * sizeof(Error) );
1501 (*err)[*nerr].e_code = code;
1502 (*err)[*nerr].e_addr = strdup( addr );
1503 (*err)[*nerr].e_msg = msg;
1508 add_group( char *dn, Group **list, int *nlist )
1513 for ( i = 0; i < *nlist; i++ ) {
1514 if ( strcmp( dn, (*list)[i].g_dn ) == 0 ) {
1515 syslog( LOG_ALERT, "group loop 2 detected (%s)", dn );
1520 ufn = ldap_explode_dn( dn, 1 );
1521 namelen = strlen( ufn[0] );
1523 if ( *nlist == 0 ) {
1524 *list = (Group *) malloc( sizeof(Group) );
1526 *list = (Group *) realloc( *list, (*nlist + 1) *
1530 /* send errors to groupname-errors@host */
1531 (*list)[*nlist].g_errorsto = (char *) malloc( namelen + sizeof(ERRORS)
1533 sprintf( (*list)[*nlist].g_errorsto, "%s-%s@%s", ufn[0], ERRORS, host );
1534 (void) canonical( (*list)[*nlist].g_errorsto );
1536 /* send to groupname-members@host - make it a list for send_group */
1537 (*list)[*nlist].g_members = (char **) malloc( 2 * sizeof(char *) );
1538 (*list)[*nlist].g_members[0] = (char *) malloc( namelen +
1539 sizeof(MEMBERS) + hostlen + 2 );
1540 sprintf( (*list)[*nlist].g_members[0], "%s-%s@%s", ufn[0], MEMBERS,
1542 (void) canonical( (*list)[*nlist].g_members[0] );
1543 (*list)[*nlist].g_members[1] = NULL;
1545 /* save the group's dn so we can check for loops above */
1546 (*list)[*nlist].g_dn = strdup( dn );
1550 ldap_value_free( ufn );
1554 unbind_and_exit( int rc )
1558 if ( (i = ldap_unbind( ld )) != LDAP_SUCCESS )
1559 syslog( LOG_ALERT, "ldap_unbind failed %d\n", i );
1565 canonical( char *s )
1569 for ( ; *s != '\0'; s++ ) {
1578 group_loop( char *dn )
1581 static char **groups;
1584 for ( i = 0; i < ngroups; i++ ) {
1585 if ( strcmp( dn, groups[i] ) == 0 )
1590 groups = (char **) malloc( sizeof(char *) );
1592 groups = (char **) realloc( groups,
1593 (ngroups + 1) * sizeof(char *) );
1595 groups[ngroups++] = strdup( dn );
1601 has_attributes( LDAPMessage *e, char *attr1, char *attr2 )
1605 if ( (attr = ldap_get_values( ld, e, attr1 )) != NULL ) {
1606 ldap_value_free( attr );
1610 if ( (attr = ldap_get_values( ld, e, attr2 )) != NULL ) {
1611 ldap_value_free( attr );
1619 get_attributes_mail_dn(
1622 char *attr2 /* this one is dn-valued */
1625 LDAPMessage *ee, *res;
1626 char **vals, **dnlist, **mail, **grname;
1629 struct timeval timeout;
1631 dn = ldap_get_dn( ld, e );
1633 vals = ldap_get_values( ld, e, attr1 );
1634 for ( nto = 0; vals != NULL && vals[nto] != NULL; nto++ )
1637 if ( (dnlist = ldap_get_values( ld, e, attr2 )) != NULL ) {
1638 timeout.tv_sec = MAIL500_TIMEOUT;
1639 timeout.tv_usec = 0;
1641 for ( i = 0; dnlist[i] != NULL; i++ ) {
1642 if ( (rc = ldap_search_st( ld, dnlist[i],
1643 LDAP_SCOPE_BASE, "(objectclass=*)", attrs, 0,
1644 &timeout, &res )) != LDAP_SUCCESS ) {
1645 if ( rc != LDAP_NO_SUCH_OBJECT ) {
1646 unbind_and_exit( EX_TEMPFAIL );
1649 syslog( LOG_ALERT, "bad (%s) dn (%s)", attr2,
1655 if ( (ee = ldap_first_entry( ld, res )) == NULL ) {
1656 syslog( LOG_ALERT, "error parsing x500 entry" );
1660 if ( isgroup(ee) ) {
1663 grname = ldap_explode_dn( dnlist[i], 1 );
1665 /* groupname + host + @ + null */
1666 graddr[0] = (char *) malloc( strlen( grname[0] )
1667 + strlen( host ) + 2 );
1669 sprintf( graddr[0], "%s@%s", grname[0], host);
1670 (void) canonical( graddr[0] );
1672 add_to( &vals, &nto, graddr );
1675 ldap_value_free( grname );
1676 } else if ( (mail = ldap_get_values( ld, ee, "mail" ))
1678 add_to( &vals, &nto, mail );
1680 ldap_value_free( mail );
1683 ldap_msgfree( res );