2 * Copyright (c) 1990 Regents of the University of Michigan.
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.
17 #include <ac/stdlib.h>
21 #include <ac/signal.h>
22 #include <ac/socket.h>
23 #include <ac/string.h>
24 #include <ac/sysexits.h>
25 #include <ac/syslog.h>
27 #include <ac/unistd.h>
30 #ifdef HAVE_SYS_PARAM_H
31 #include <sys/param.h>
33 #ifdef HAVE_SYS_RESOURCE_H
34 #include <sys/resource.h>
40 #include "ldap_defaults.h"
43 #define GROUP_ERRORS 1
44 #define GROUP_REQUEST 2
45 #define GROUP_MEMBERS 3
47 #define ERRORS "errors"
48 #define REQUEST "request"
49 #define MEMBERS "members"
52 char *errorsfrom = NULL;
53 char *mailfrom = NULL;
63 #define E_USERUNKNOWN 1
69 #define E_JOINMEMBERNOEMAIL 7
70 #define E_MEMBERNOEMAIL 8
72 #define E_JOINMEMBERNOFAXNUM 10
73 #define E_MEMBERNOFAXNUM 11
74 #define E_FAXTOEMAILMBR 12
80 typedef struct groupto {
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) */
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,
103 char *sendmailargs[] = { FAX_SENDMAIL, "-oMrX.500", "-odi", "-oi", "-f", NULL, NULL };
105 static char *attrs[] = { "objectClass", "title", "postaladdress",
106 "telephoneNumber", "mail", "description",
107 "errorsTo", "rfc822ErrorsTo", "requestsTo",
108 "rfc822RequestsTo", "joinable", "cn", "member",
109 "facsimileTelephoneNumber", NULL };
112 static void do_address(char *name, char ***to, int *nto, Group **togroups, int *ngroups, Error **err, int *nerr, int type);
113 static int do_group(LDAPMessage *e, char *dn, char ***to, int *nto, Group **togroups, int *ngroups, Error **err, int *nerr);
114 static void do_group_members(LDAPMessage *e, char *dn, char ***to, int *nto, Group **togroups, int *ngroups, Error **err, int *nerr);
115 static void send_message(char **to);
116 static void send_errors(Error *err, int nerr);
117 static void do_noemailorfax(FILE *fp, Error *err, int namelen, int errtype);
118 static void do_ambiguous(FILE *fp, Error *err, int namelen);
119 static int count_values(char **list);
120 static void add_to(char ***list, int *nlist, char **new);
121 static int isgroup(LDAPMessage *e);
122 static void add_error(Error **err, int *nerr, int code, char *addr, LDAPMessage *msg);
123 static void add_group(char *dn, Group **list, int *nlist);
124 static void unbind_and_exit(int rc) LDAP_GCCATTR((noreturn));
125 static int group_loop(char *dn);
126 static void send_group(Group *group, int ngroup);
127 static int has_attributes(LDAPMessage *e, char *attr1, char *attr2);
128 static char **get_attributes_mail_dn(LDAPMessage *e, char *attr1, char *attr2);
129 static char *canonical(char *s);
130 static int connect_to_x500 (void);
131 static void do_group_errors (LDAPMessage *e, char *dn, char ***to, int *nto, Error **err, int *nerr);
132 static void do_group_request (LDAPMessage *e, char *dn, char ***to, int *nto, Error **err, int *nerr);
133 static void add_member (char *gdn, char *dn, char ***to, int *nto, Group **togroups, int *ngroups, Error **err, int *nerr);
137 main ( int argc, char **argv )
143 int numto, ngroups, numerr, nargs;
146 while ( (i = getopt( argc, argv, "f:h:m:" )) != EOF ) {
148 case 'f': /* who it's from & where errors should go */
149 mailfrom = strdup( optarg );
150 for ( j = 0; sendmailargs[j] != NULL; j++ ) {
151 if ( strcmp( sendmailargs[j], "-f" ) == 0 ) {
152 sendmailargs[j+1] = mailfrom;
158 case 'h': /* hostname */
159 host = strdup( optarg );
160 hostlen = strlen(host);
163 /* mailer-daemon address - who we should */
164 case 'm': /* say errors come from */
165 errorsfrom = strdup( optarg );
169 syslog( LOG_ALERT, "unknown option" );
174 if ( (myname = strrchr( argv[0], '/' )) == NULL )
175 myname = strdup( argv[0] );
177 myname = strdup( myname + 1 );
178 if (!strcmp(myname, "mail500")) {
180 } else if (!strcmp(myname, "fax500")) {
183 /* I give up, I must be mail500 */
188 (void) SIGNAL( SIGPIPE, SIG_IGN );
192 openlog( myname, OPENLOG_OPTIONS, LOG_MAIL );
194 openlog( myname, OPENLOG_OPTIONS );
197 if ( mailfrom == NULL ) {
198 syslog( LOG_ALERT, "required argument -f not present" );
201 if ( errorsfrom == NULL ) {
202 syslog( LOG_ALERT, "required argument -m not present" );
205 if ( host == NULL ) {
206 syslog( LOG_ALERT, "required argument -h not present" );
210 if ( connect_to_x500() != 0 )
219 strcpy( buf, argv[0] );
220 for ( i = 1; i < argc; i++ ) {
222 strcat( buf, argv[i] );
225 syslog( LOG_ALERT, "args: (%s)", buf );
229 add_to( &tolist, &numto, sendmailargs );
231 ngroups = numerr = 0;
234 for ( i = optind; i < argc; i++ ) {
238 for ( j = 0; argv[i][j] != '\0'; j++ ) {
239 if ( argv[i][j] == '.' || argv[i][j] == '_' )
244 if ( (s = strrchr( argv[i], '-' )) != NULL ) {
247 if ( strcmp( s, ERRORS ) == 0 ) {
250 } else if ( strcmp( s, REQUEST ) == 0 ) {
251 type = GROUP_REQUEST;
253 } else if ( strcmp( s, MEMBERS ) == 0 ) {
254 type = GROUP_MEMBERS;
259 do_address( argv[i], &tolist, &numto, &togroups, &ngroups,
260 &errlist, &numerr, type );
264 * If we have both errors and successful deliveries to make or if
265 * if there are any groups to deliver to, we basically need to read
266 * the message twice. So, we have to put it in a tmp file.
269 if ( numerr > 0 && numto > nargs || ngroups > 0 ) {
274 if ( (fp = tmpfile()) == NULL ) {
275 syslog( LOG_ALERT, "could not open tmp file" );
276 unbind_and_exit( EX_TEMPFAIL );
279 /* copy the message to a temp file */
280 while ( fgets( buf, sizeof(buf), stdin ) != NULL ) {
281 if ( fputs( buf, fp ) == EOF ) {
282 syslog( LOG_ALERT, "error writing tmpfile" );
283 unbind_and_exit( EX_TEMPFAIL );
287 if ( dup2( fileno( fp ), 0 ) == -1 ) {
288 syslog( LOG_ALERT, "could not dup2 tmpfile" );
289 unbind_and_exit( EX_TEMPFAIL );
295 /* deal with errors */
297 (void) rewind( stdin );
298 send_errors( errlist, numerr );
301 (void) ldap_unbind( ld );
303 /* send to groups with errorsTo */
305 (void) rewind( stdin );
306 send_group( togroups, ngroups );
309 /* send to expanded aliases and groups w/o errorsTo */
310 if ( numto > nargs ) {
311 (void) rewind( stdin );
312 send_message( tolist );
319 connect_to_x500( void )
321 int sizelimit = FAX_MAXAMBIGUOUS;
322 int deref = LDAP_DEREF_ALWAYS;
324 if ( (ld = ldap_init( NULL, 0 )) == NULL ) {
325 syslog( LOG_ALERT, "ldap_init failed" );
329 ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &sizelimit);
330 ldap_set_option(ld, LDAP_OPT_DEREF, &deref);
332 if ( ldap_simple_bind_s( ld, NULL, NULL ) != LDAP_SUCCESS ) {
333 syslog( LOG_ALERT, "ldap_simple_bind_s failed" );
354 LDAPMessage *e, *res;
355 struct timeval timeout;
362 * Look up the name in X.500, add the appropriate addresses found
363 * to the to list, or to the err list in case of error. Groups are
364 * handled by the do_group routine, individuals are handled here.
365 * When looking up name, we follow the bases hierarchy, looking
366 * in base[0] first, then base[1], etc. For each base, there is
367 * a set of search filters to try, in order. If something goes
368 * wrong here trying to contact X.500, we exit with EX_TEMPFAIL.
369 * If the b_rdnpref flag is set, then we give preference to entries
370 * that matched name because it's their rdn, otherwise not.
373 timeout.tv_sec = FAX_TIMEOUT;
375 for ( b = 0, match = 0; !match && base[b].b_dn != NULL; b++ ) {
376 for ( f = 0; base[b].b_filter[f] != NULL; f++ ) {
377 char *format, *p, *argv[3];
380 for ( argc = 0; argc < 3; argc++ ) {
384 format = strdup( base[b].b_filter[f] );
385 for ( argc = 0, p = format; *p; p++ ) {
388 case 's': /* %s is the name */
392 case 'h': /* %h is the host */
399 "unknown format %c", *p );
407 /* three names ought to do... */
408 sprintf( filter, format, argv[0], argv[1], argv[2] );
412 rc = ldap_search_st( ld, base[b].b_dn,
413 LDAP_SCOPE_SUBTREE, filter, attrs, 0, &timeout,
416 /* some other trouble - try again later */
417 if ( rc != LDAP_SUCCESS &&
418 rc != LDAP_SIZELIMIT_EXCEEDED ) {
419 syslog( LOG_ALERT, "return %d from X.500", rc );
420 unbind_and_exit( EX_TEMPFAIL );
423 if ( (match = ldap_count_entries( ld, res )) != 0 )
433 /* trouble - try again later */
435 syslog( LOG_ALERT, "error parsing result from X.500" );
436 unbind_and_exit( EX_TEMPFAIL );
439 /* no matches - bounce with user unknown */
441 add_error( err, nerr, E_USERUNKNOWN, name, NULL );
445 /* more than one match - bounce with ambiguous user? */
447 LDAPMessage *next, *tmpres = NULL;
451 /* not giving rdn preference - bounce with ambiguous user */
452 if ( base[b].b_rdnpref == 0 ) {
453 add_error( err, nerr, E_AMBIGUOUS, name, res );
458 * giving rdn preference - see if any entries were matched
459 * because of their rdn. If so, collect them to deal with
460 * later (== 1 we deliver, > 1 we bounce).
463 for ( e = ldap_first_entry( ld, res ); e != NULL; e = next ) {
464 next = ldap_next_entry( ld, e );
465 dn = ldap_get_dn( ld, e );
466 xdn = ldap_explode_dn( dn, 1 );
468 /* XXX bad, but how else can we do it? XXX */
469 if ( strcasecmp( xdn[0], name ) == 0 ) {
470 ldap_delete_result_entry( &res, e );
471 ldap_add_result_entry( &tmpres, e );
474 ldap_value_free( xdn );
478 /* nothing matched by rdn - go ahead and bounce */
479 if ( tmpres == NULL ) {
480 add_error( err, nerr, E_AMBIGUOUS, name, res );
483 /* more than one matched by rdn - bounce with rdn matches */
484 } else if ( (match = ldap_count_entries( ld, tmpres )) > 1 ) {
485 add_error( err, nerr, E_AMBIGUOUS, name, tmpres );
489 } else if ( match < 0 ) {
490 syslog( LOG_ALERT, "error parsing result from X.500" );
491 unbind_and_exit( EX_TEMPFAIL );
494 /* otherwise one matched by rdn - send to it */
500 * if we get this far, it means that we found a single match for
501 * name. for a user, we deliver to the mail attribute or bounce
502 * with address and phone if no mail attr. for a group, we
503 * deliver to all members or bounce to rfc822ErrorsTo if no members.
507 if ( (e = ldap_first_entry( ld, res )) == NULL ) {
508 syslog( LOG_ALERT, "error parsing entry from X.500" );
509 unbind_and_exit( EX_TEMPFAIL );
512 dn = ldap_get_dn( ld, e );
514 if ( type == GROUP_ERRORS ) {
515 /* sent to group-errors - resend to [rfc822]ErrorsTo attr */
516 do_group_errors( e, dn, to, nto, err, nerr );
518 } else if ( type == GROUP_REQUEST ) {
519 /* sent to group-request - resend to [rfc822]RequestsTo attr */
520 do_group_request( e, dn, to, nto, err, nerr );
522 } else if ( type == GROUP_MEMBERS ) {
523 /* sent to group-members - expand */
524 do_group_members( e, dn, to, nto, togroups, ngroups, err,
527 } else if ( isgroup( e ) ) {
529 * sent to group - resend from [rfc822]ErrorsTo if it's there,
530 * otherwise, expand the group
533 do_group( e, dn, to, nto, togroups, ngroups, err, nerr );
539 * sent to user - mail attribute => add it to the to list,
544 if ( (mail = ldap_get_values( ld, e,
545 "facsimileTelephoneNumber" )) != NULL ) {
550 fdn = ldap_get_dn( ld, e );
551 ufn = ldap_explode_dn( fdn, 1 );
552 /* Convert spaces to underscores for rp */
553 for (i = 0; ufn[0][i] != '\0'; i++) {
554 if (ufn[0][i] == ' ') {
558 *mail = faxtotpc(*mail, ufn[0]);
560 add_to(to, nto, mail);
565 ldap_value_free( ufn );
566 ldap_value_free( mail );
569 add_error( err, nerr, E_NOFAXNUM,
574 if ( (mail = ldap_get_values( ld, e, "mail" ))
576 add_to( to, nto, mail );
578 ldap_value_free( mail );
581 add_error( err, nerr, E_NOEMAIL,
606 * If this group has an rfc822ErrorsTo attribute, we need to
607 * arrange for errors involving this group to go there, not
608 * to the sender. Since sendmail only has the concept of a
609 * single sender, we arrange for errors to go to groupname-errors,
610 * which we then handle specially when (if) it comes back to us
611 * by expanding to all the rfc822ErrorsTo addresses. If it has no
612 * rfc822ErrorsTo attribute, we call do_group_members() to expand
616 if ( group_loop( dn ) ) {
620 if ( has_attributes( e, "rfc822ErrorsTo", "errorsTo" ) ) {
621 add_group( dn, togroups, ngroups );
626 do_group_members( e, dn, to, nto, togroups, ngroups, err, nerr );
646 char **mail, **member, **joinable;
648 LDAPMessage *ee, *res;
649 struct timeval timeout;
652 * if all has gone according to plan, we've already arranged for
653 * errors to go to the [rfc822]ErrorsTo attributes (if they exist),
654 * so all we have to do here is arrange to send to the
655 * rfc822Mailbox attribute, the member attribute, and anyone who
656 * has joined the group by setting memberOfGroup equal to the
660 /* add members in the group itself - mail attribute */
661 if ( (mail = ldap_get_values( ld, e, "mail" )) != NULL ) {
663 * These are only email addresses - impossible
664 * to have a fax number
668 /* XXX How do we want to inform sender that the */
669 /* group they sent to has email-only members? */
672 add_to( to, nto, mail );
676 ldap_value_free( mail );
679 /* add members in the group itself - member attribute */
680 if ( (member = ldap_get_values( ld, e, "member" )) != NULL ) {
681 for ( i = 0; member[i] != NULL; i++ ) {
682 add_member( dn, member[i], to, nto, togroups,
683 ngroups, err, nerr );
686 ldap_value_free( member );
689 /* add members who have joined by setting memberOfGroup */
690 if ( (joinable = ldap_get_values( ld, e, "joinable" )) != NULL ) {
691 if ( strcasecmp( joinable[0], "FALSE" ) == 0 ) {
692 ldap_value_free( joinable );
695 ldap_value_free( joinable );
697 sprintf( filter, "(memberOfGroup=%s)", dn );
699 timeout.tv_sec = FAX_TIMEOUT;
702 /* for each subtree to look in... */
704 int sizelimit = FAX_MAXMEMBERS;
705 ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &sizelimit);
707 for ( i = 0; base[i].b_dn != NULL; i++ ) {
708 /* find entries that have joined this group... */
709 rc = ldap_search_st( ld, base[i].b_dn,
710 LDAP_SCOPE_SUBTREE, filter, attrs, 0, &timeout,
713 if ( rc == LDAP_SIZELIMIT_EXCEEDED ||
714 rc == LDAP_TIMELIMIT_EXCEEDED ) {
716 "group search limit exceeded %d", rc );
717 unbind_and_exit( EX_TEMPFAIL );
720 if ( rc != LDAP_SUCCESS ) {
721 syslog( LOG_ALERT, "group search bad return %d",
723 unbind_and_exit( EX_TEMPFAIL );
726 /* for each entry that has joined... */
727 for ( ee = ldap_first_entry( ld, res ); ee != NULL;
728 ee = ldap_next_entry( ld, ee ) ) {
729 if ( isgroup( ee ) ) {
730 ndn = ldap_get_dn( ld, ee );
732 if ( do_group( e, ndn, to, nto,
733 togroups, ngroups, err, nerr )
736 "group loop (%s) (%s)",
745 /* add them to the to list */
748 if ( (mail = ldap_get_values( ld, ee,
749 "facsimileTelephoneNumber" ))
755 fdn = ldap_get_dn( ld, ee );
756 ufn = ldap_explode_dn( fdn, 1 );
761 for (i = 0; ufn[0][i] != '\0';
763 if (ufn[0][i] == ' ') {
767 *mail = faxtotpc(*mail, ufn[0]);
768 add_to(to, nto, mail);
770 ldap_value_free( mail );
773 ndn = ldap_get_dn( ld, ee );
775 add_error( err, nerr,
776 E_JOINMEMBERNOFAXNUM, ndn,
783 if ( (mail = ldap_get_values( ld, ee,
784 "mail" )) != NULL ) {
785 add_to( to, nto, mail );
787 ldap_value_free( mail );
789 /* else generate a bounce */
791 ndn = ldap_get_dn( ld, ee );
793 add_error( err, nerr,
794 E_JOINMEMBERNOEMAIL, ndn,
806 int sizelimit = FAX_MAXAMBIGUOUS;
807 ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &sizelimit);
829 LDAPMessage *res, *e;
830 struct timeval timeout;
832 timeout.tv_sec = FAX_TIMEOUT;
834 if ( (rc = ldap_search_st( ld, dn, LDAP_SCOPE_BASE, "(objectclass=*)",
835 attrs, 0, &timeout, &res )) != LDAP_SUCCESS ) {
836 if ( rc == LDAP_NO_SUCH_OBJECT ) {
837 add_error( err, nerr, E_BADMEMBER, dn, NULL );
841 syslog( LOG_ALERT, "member search bad return %d", rc );
843 unbind_and_exit( EX_TEMPFAIL );
847 if ( (e = ldap_first_entry( ld, res )) == NULL ) {
848 syslog( LOG_ALERT, "member search error parsing entry" );
850 unbind_and_exit( EX_TEMPFAIL );
852 ndn = ldap_get_dn( ld, e );
854 /* allow groups within groups */
855 if ( isgroup( e ) ) {
856 if ( do_group( e, ndn, to, nto, togroups, ngroups, err, nerr )
858 syslog( LOG_ALERT, "group loop (%s) (%s)", gdn, ndn );
868 if ( (mail = ldap_get_values( ld, e,
869 "facsimileTelephoneNumber" )) != NULL ) {
873 fdn = ldap_get_dn( ld, e );
874 ufn = ldap_explode_dn( fdn, 1 );
875 /* Convert spaces to underscores for rp */
876 for (i = 0; ufn[0][i] != '\0'; i++) {
877 if (ufn[0][i] == ' ') {
881 *mail = faxtotpc(*mail, ufn[0]);
882 add_to(to, nto, mail);
884 ldap_value_free( mail );
887 add_error( err, nerr, E_MEMBERNOFAXNUM, ndn, NULL );
891 /* send to the member's mail attribute */
892 if ( (mail = ldap_get_values( ld, e, "mail" )) != NULL ) {
893 add_to( to, nto, mail );
895 ldap_value_free( mail );
897 /* else generate a bounce */
899 add_error( err, nerr, E_MEMBERNOEMAIL, ndn, NULL );
919 if ( (requeststo = get_attributes_mail_dn( e, "rfc822RequestsTo",
920 "requestsTo" )) != NULL ) {
921 add_to( to, nto, requeststo );
923 ldap_value_free( requeststo );
925 add_error( err, nerr, E_NOREQUEST, dn, NULL );
941 if ( (errorsto = get_attributes_mail_dn( e, "rfc822ErrorsTo",
942 "errorsTo" )) != NULL ) {
943 add_to( to, nto, errorsto );
945 ldap_value_free( errorsto );
947 add_error( err, nerr, E_NOERRORS, dn, NULL );
952 send_message( char **to )
956 WAITSTATUSTYPE status;
961 if ( (pid = fork()) != 0 ) {
963 waitpid( pid, (int *) NULL, 0 );
965 wait4( pid, &status, WAIT_FLAGS, 0 );
969 /* to includes sendmailargs */
970 execv( FAX_SENDMAIL, to );
972 syslog( LOG_ALERT, "execv failed" );
979 send_group( Group *group, int ngroup )
986 WAITSTATUSTYPE status;
989 for ( i = 0; i < ngroup; i++ ) {
990 (void) rewind( stdin );
992 iargv[0] = FAX_SENDMAIL;
994 iargv[2] = group[i].g_errorsto;
995 iargv[3] = "-oMrX.500";
1002 add_to( &argv, &argc, iargv );
1003 add_to( &argv, &argc, group[i].g_members );
1007 if ( (pid = fork()) != 0 ) {
1009 waitpid( pid, (int *) NULL, 0 );
1011 wait4( pid, &status, WAIT_FLAGS, 0 );
1015 execv( FAX_SENDMAIL, argv );
1017 syslog( LOG_ALERT, "execv failed" );
1019 exit( EX_TEMPFAIL );
1027 send_errors( Error *err, int nerr )
1033 sprintf( buf, "%s -oMrX.500 -odi -oi -f %s %s", FAX_SENDMAIL, errorsfrom,
1035 if ( (fp = popen( buf, "w" )) == NULL ) {
1036 syslog( LOG_ALERT, "could not popen sendmail for errs" );
1040 fprintf( fp, "To: %s\n", mailfrom );
1041 fprintf( fp, "From: %s\n", errorsfrom );
1042 fprintf( fp, "Subject: undeliverable mail\n" );
1043 fprintf( fp, "\n" );
1044 fprintf( fp, "The following errors occurred when trying to deliver the attached mail:\n" );
1045 for ( i = 0; i < nerr; i++ ) {
1046 namelen = strlen( err[i].e_addr );
1047 fprintf( fp, "\n" );
1049 switch ( err[i].e_code ) {
1051 fprintf( fp, "%s: User unknown\n", err[i].e_addr );
1055 fprintf( fp, "%s: Group member does not exist\n",
1060 fprintf( fp, "%s: Group exists but has no request address\n",
1065 fprintf( fp, "%s: Group exists but has no errors-to address\n",
1070 do_ambiguous( fp, &err[i], namelen );
1074 do_noemailorfax( fp, &err[i], namelen, E_NOEMAIL );
1077 case E_MEMBERNOEMAIL:
1078 fprintf( fp, "%s: Group member exists but does not have an email address\n",
1082 case E_JOINMEMBERNOEMAIL:
1083 fprintf( fp, "%s: User has joined group but does not have an email address\n",
1088 do_noemailorfax( fp, &err[i], namelen, E_NOFAXNUM );
1091 case E_MEMBERNOFAXNUM:
1092 fprintf( fp, "%s: Group member exists but does not have a fax number\n",
1096 case E_JOINMEMBERNOFAXNUM:
1097 fprintf( fp, "%s: User has joined group but does not have a fax number\n",
1102 syslog( LOG_ALERT, "unknown error %d", err[i].e_code );
1103 unbind_and_exit( EX_TEMPFAIL );
1108 fprintf( fp, "\n------- The original message sent:\n\n" );
1110 while ( fgets( buf, sizeof(buf), stdin ) != NULL ) {
1114 if ( pclose( fp ) == -1 ) {
1115 syslog( LOG_ALERT, "pclose failed" );
1116 unbind_and_exit( EX_TEMPFAIL );
1124 do_noemailorfax( FILE *fp, Error *err, int namelen, int errtype )
1130 if (errtype == E_NOFAXNUM) {
1131 fprintf(fp, "%s: User has no facsimile number registered.\n",
1133 } else if (errtype == E_NOEMAIL) {
1134 fprintf(fp, "%s: User has no email address registered.\n",
1137 fprintf( fp, "%*s Name, title, postal address and phone for '%s':\n\n",
1138 namelen, " ", err->e_addr );
1141 dn = ldap_get_dn( ld, err->e_msg );
1142 ufn = ldap_explode_dn( dn, 1 );
1143 rdn = strdup( ufn[0] );
1144 if ( strcasecmp( rdn, err->e_addr ) == 0 ) {
1145 if ( (vals = ldap_get_values( ld, err->e_msg, "cn" ))
1147 for ( i = 0; vals[i]; i++ ) {
1148 last = strlen( vals[i] ) - 1;
1149 if ( isdigit((unsigned char) vals[i][last]) ) {
1150 rdn = strdup( vals[i] );
1155 ldap_value_free( vals );
1158 fprintf( fp, "%*s %s\n", namelen, " ", rdn );
1161 ldap_value_free( ufn );
1163 /* titles or descriptions */
1164 if ( (vals = ldap_get_values( ld, err->e_msg, "title" )) == NULL &&
1165 (vals = ldap_get_values( ld, err->e_msg, "description" ))
1167 fprintf( fp, "%*s No title or description registered\n",
1170 for ( i = 0; vals[i] != NULL; i++ ) {
1171 fprintf( fp, "%*s %s\n", namelen, " ", vals[i] );
1174 ldap_value_free( vals );
1177 /* postal address */
1178 if ( (vals = ldap_get_values( ld, err->e_msg, "postalAddress" ))
1180 fprintf( fp, "%*s No postal address registered\n", namelen,
1183 fprintf( fp, "%*s ", namelen, " " );
1184 for ( i = 0; vals[0][i] != '\0'; i++ ) {
1185 if ( vals[0][i] == '$' ) {
1186 fprintf( fp, "\n%*s ", namelen, " " );
1187 while ( isspace((unsigned char) vals[0][i+1]) )
1190 fprintf( fp, "%c", vals[0][i] );
1193 fprintf( fp, "\n" );
1195 ldap_value_free( vals );
1198 /* telephone number */
1199 if ( (vals = ldap_get_values( ld, err->e_msg, "telephoneNumber" ))
1201 fprintf( fp, "%*s No phone number registered\n", namelen,
1204 for ( i = 0; vals[i] != NULL; i++ ) {
1205 fprintf( fp, "%*s %s\n", namelen, " ", vals[i] );
1208 ldap_value_free( vals );
1214 do_ambiguous( FILE *fp, Error *err, int namelen )
1221 i = ldap_result2error( ld, err->e_msg, 0 );
1223 fprintf( fp, "%s: Ambiguous user. %s%d matches found:\n\n",
1224 err->e_addr, i == LDAP_SIZELIMIT_EXCEEDED ? "First " : "",
1225 ldap_count_entries( ld, err->e_msg ) );
1227 for ( e = ldap_first_entry( ld, err->e_msg ); e != NULL;
1228 e = ldap_next_entry( ld, e ) ) {
1229 dn = ldap_get_dn( ld, e );
1230 ufn = ldap_explode_dn( dn, 1 );
1231 rdn = strdup( ufn[0] );
1232 if ( strcasecmp( rdn, err->e_addr ) == 0 ) {
1233 if ( (vals = ldap_get_values( ld, e, "cn" )) != NULL ) {
1234 for ( i = 0; vals[i]; i++ ) {
1235 last = strlen( vals[i] ) - 1;
1236 if ( isdigit((unsigned char) vals[i][last]) ) {
1237 rdn = strdup( vals[i] );
1242 ldap_value_free( vals );
1246 if ( isgroup( e ) ) {
1247 vals = ldap_get_values( ld, e, "description" );
1249 vals = ldap_get_values( ld, e, "title" );
1252 fprintf( fp, " %-20s %s\n", rdn, vals ? vals[0] : "" );
1253 for ( i = 1; vals && vals[i] != NULL; i++ ) {
1254 fprintf( fp, " %s\n", vals[i] );
1259 ldap_value_free( ufn );
1261 ldap_value_free( vals );
1266 count_values( char **list )
1270 for ( i = 0; list && list[i] != NULL; i++ )
1277 add_to( char ***list, int *nlist, char **new )
1279 int i, nnew, oldnlist;
1281 nnew = count_values( new );
1284 if ( *list == NULL || *nlist == 0 ) {
1285 *list = (char **) malloc( (nnew + 1) * sizeof(char *) );
1288 *list = (char **) realloc( *list, *nlist * sizeof(char *) +
1289 nnew * sizeof(char *) + sizeof(char *) );
1293 for ( i = 0; i < nnew; i++ ) {
1294 (*list)[i + oldnlist] = strdup( new[i] );
1296 (*list)[*nlist] = NULL;
1302 isgroup( LDAPMessage *e )
1307 oclist = ldap_get_values( ld, e, "objectClass" );
1309 for ( i = 0; oclist[i] != NULL; i++ ) {
1310 if ( strcasecmp( oclist[i], "rfc822MailGroup" ) == 0 ) {
1311 ldap_value_free( oclist );
1315 ldap_value_free( oclist );
1321 add_error( Error **err, int *nerr, int code, char *addr, LDAPMessage *msg )
1324 *err = (Error *) malloc( sizeof(Error) );
1326 *err = (Error *) realloc( *err, (*nerr + 1) * sizeof(Error) );
1329 (*err)[*nerr].e_code = code;
1330 (*err)[*nerr].e_addr = strdup( addr );
1331 (*err)[*nerr].e_msg = msg;
1338 add_group( char *dn, Group **list, int *nlist )
1343 for ( i = 0; i < *nlist; i++ ) {
1344 if ( strcmp( dn, (*list)[i].g_dn ) == 0 ) {
1345 syslog( LOG_ALERT, "group loop 2 detected (%s)", dn );
1350 ufn = ldap_explode_dn( dn, 1 );
1351 namelen = strlen( ufn[0] );
1353 if ( *nlist == 0 ) {
1354 *list = (Group *) malloc( sizeof(Group) );
1356 *list = (Group *) realloc( *list, (*nlist + 1) *
1360 /* send errors to groupname-errors@host */
1361 (*list)[*nlist].g_errorsto = (char *) malloc( namelen + sizeof(ERRORS)
1363 sprintf( (*list)[*nlist].g_errorsto, "%s-%s@%s", ufn[0], ERRORS, host );
1364 (void) canonical( (*list)[*nlist].g_errorsto );
1366 /* send to groupname-members@host - make it a list for send_group */
1367 (*list)[*nlist].g_members = (char **) malloc( 2 * sizeof(char *) );
1368 (*list)[*nlist].g_members[0] = (char *) malloc( namelen +
1369 sizeof(MEMBERS) + hostlen + 2 );
1370 sprintf( (*list)[*nlist].g_members[0], "%s-%s@%s", ufn[0], MEMBERS,
1372 (void) canonical( (*list)[*nlist].g_members[0] );
1373 (*list)[*nlist].g_members[1] = NULL;
1375 /* save the group's dn so we can check for loops above */
1376 (*list)[*nlist].g_dn = strdup( dn );
1380 ldap_value_free( ufn );
1386 unbind_and_exit( int rc )
1390 if ( (i = ldap_unbind( ld )) != LDAP_SUCCESS )
1391 syslog( LOG_ALERT, "ldap_unbind failed %d\n", i );
1397 canonical( char *s )
1401 for ( ; *s != '\0'; s++ ) {
1410 group_loop( char *dn )
1413 static char **groups;
1416 for ( i = 0; i < ngroups; i++ ) {
1417 if ( strcmp( dn, groups[i] ) == 0 )
1422 groups = (char **) malloc( sizeof(char *) );
1424 groups = (char **) realloc( groups,
1425 (ngroups + 1) * sizeof(char *) );
1427 groups[ngroups++] = strdup( dn );
1433 has_attributes( LDAPMessage *e, char *attr1, char *attr2 )
1437 if ( (attr = ldap_get_values( ld, e, attr1 )) != NULL ) {
1438 ldap_value_free( attr );
1442 if ( (attr = ldap_get_values( ld, e, attr2 )) != NULL ) {
1443 ldap_value_free( attr );
1451 get_attributes_mail_dn( LDAPMessage *e, char *attr1, char *attr2 )
1453 LDAPMessage *ee, *res;
1454 char **vals, **dnlist, **mail;
1456 struct timeval timeout;
1458 vals = ldap_get_values( ld, e, attr1 );
1459 for ( nto = 0; vals != NULL && vals[nto] != NULL; nto++ )
1462 if ( (dnlist = ldap_get_values( ld, e, attr2 )) != NULL ) {
1463 timeout.tv_sec = FAX_TIMEOUT;
1464 timeout.tv_usec = 0;
1466 for ( i = 0; dnlist[i] != NULL; i++ ) {
1467 if ( (rc = ldap_search_st( ld, dnlist[i],
1468 LDAP_SCOPE_BASE, "(objectclass=*)", attrs, 0,
1469 &timeout, &res )) != LDAP_SUCCESS ) {
1470 if ( rc != LDAP_NO_SUCH_OBJECT ) {
1471 unbind_and_exit( EX_TEMPFAIL );
1474 syslog( LOG_ALERT, "bad (%s) dn (%s)", attr2,
1480 if ( (ee = ldap_first_entry( ld, res )) == NULL ) {
1481 syslog( LOG_ALERT, "error parsing x500 entry" );
1485 if ( (mail = ldap_get_values( ld, ee, "mail" ))
1487 add_to( &vals, &nto, mail );
1489 ldap_value_free( mail );
1492 ldap_msgfree( res );