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.
18 #include <ac/socket.h>
19 #include <ac/string.h>
20 #include <ac/syslog.h>
24 #ifdef HAVE_SYS_PARAM_H
25 #include <sys/param.h>
28 #include <sys/resource.h>
34 #include <ldapconfig.h>
37 #define GROUP_ERRORS 1
38 #define GROUP_REQUEST 2
39 #define GROUP_MEMBERS 3
41 #define ERRORS "errors"
42 #define REQUEST "request"
43 #define MEMBERS "members"
46 char *errorsfrom = NULL;
47 char *mailfrom = NULL;
58 #define E_USERUNKNOWN 1
64 #define E_JOINMEMBERNOEMAIL 7
65 #define E_MEMBERNOEMAIL 8
67 #define E_JOINMEMBERNOFAXNUM 10
68 #define E_MEMBERNOFAXNUM 11
69 #define E_FAXTOEMAILMBR 12
75 typedef struct groupto {
81 typedef struct baseinfo {
82 char *b_dn; /* dn to start searching at */
83 char b_rdnpref; /* give rdn's preference when searching? */
84 char *b_filter[3]; /* filter to apply - name substituted for %s */
85 /* (up to three of them) */
89 { "ou=People, o=University of Michigan, c=US", 0,
90 "uid=%s", "cn=%s", NULL,
91 "ou=System Groups, ou=Groups, o=University of Michigan, c=US", 1,
92 "(&(cn=%s)(associatedDomain=%h))", NULL, NULL,
93 "ou=User Groups, ou=Groups, o=University of Michigan, c=US", 1,
94 "(&(cn=%s)(associatedDomain=%h))", NULL, NULL,
98 char *sendmailargs[] = { FAX_SENDMAIL, "-oMrX.500", "-odi", "-oi", "-f", NULL, NULL };
100 static char *attrs[] = { "objectClass", "title", "postaladdress",
101 "telephoneNumber", "mail", "description",
102 "errorsTo", "rfc822ErrorsTo", "requestsTo",
103 "rfc822RequestsTo", "joinable", "cn", "member",
104 "facsimileTelephoneNumber", NULL };
108 static do_group_members();
109 static send_message();
110 static send_errors();
111 static do_noemailorfax();
112 static do_ambiguous();
117 static unbind_and_exit();
120 static has_attributes();
121 static char **get_attributes_mail_dn();
122 static char *canonical();
132 int numto, ngroups, numerr, nargs;
135 extern int optind, errno;
138 while ( (i = getopt( argc, argv, "f:h:m:" )) != EOF ) {
140 case 'f': /* who it's from & where errors should go */
141 mailfrom = strdup( optarg );
142 for ( j = 0; sendmailargs[j] != NULL; j++ ) {
143 if ( strcmp( sendmailargs[j], "-f" ) == 0 ) {
144 sendmailargs[j+1] = mailfrom;
150 case 'h': /* hostname */
151 host = strdup( optarg );
152 hostlen = strlen(host);
155 /* mailer-daemon address - who we should */
156 case 'm': /* say errors come from */
157 errorsfrom = strdup( optarg );
161 syslog( LOG_ALERT, "unknown option" );
166 if ( (myname = strrchr( argv[0], '/' )) == NULL )
167 myname = strdup( argv[0] );
169 myname = strdup( myname + 1 );
170 if (!strcmp(myname, "mail500")) {
172 } else if (!strcmp(myname, "fax500")) {
175 /* I give up, I must be mail500 */
180 openlog( myname, OPENLOG_OPTIONS, LOG_MAIL );
182 openlog( myname, OPENLOG_OPTIONS );
185 if ( mailfrom == NULL ) {
186 syslog( LOG_ALERT, "required argument -f not present" );
189 if ( errorsfrom == NULL ) {
190 syslog( LOG_ALERT, "required argument -m not present" );
193 if ( host == NULL ) {
194 syslog( LOG_ALERT, "required argument -h not present" );
198 if ( connect_to_x500() != 0 )
207 strcpy( buf, argv[0] );
208 for ( i = 1; i < argc; i++ ) {
210 strcat( buf, argv[i] );
213 syslog( LOG_ALERT, "args: (%s)", buf );
217 add_to( &tolist, &numto, sendmailargs );
219 ngroups = numerr = 0;
222 for ( i = optind; i < argc; i++ ) {
226 for ( j = 0; argv[i][j] != '\0'; j++ ) {
227 if ( argv[i][j] == '.' || argv[i][j] == '_' )
232 if ( (s = strrchr( argv[i], '-' )) != NULL ) {
235 if ( strcmp( s, ERRORS ) == 0 ) {
238 } else if ( strcmp( s, REQUEST ) == 0 ) {
239 type = GROUP_REQUEST;
241 } else if ( strcmp( s, MEMBERS ) == 0 ) {
242 type = GROUP_MEMBERS;
247 do_address( argv[i], &tolist, &numto, &togroups, &ngroups,
248 &errlist, &numerr, type );
252 * If we have both errors and successful deliveries to make or if
253 * if there are any groups to deliver to, we basically need to read
254 * the message twice. So, we have to put it in a tmp file.
257 if ( numerr > 0 && numto > nargs || ngroups > 0 ) {
262 if ( (fp = tmpfile()) == NULL ) {
263 syslog( LOG_ALERT, "could not open tmp file" );
264 unbind_and_exit( EX_TEMPFAIL );
267 /* copy the message to a temp file */
268 while ( fgets( buf, sizeof(buf), stdin ) != NULL ) {
269 if ( fputs( buf, fp ) == EOF ) {
270 syslog( LOG_ALERT, "error writing tmpfile" );
271 unbind_and_exit( EX_TEMPFAIL );
275 if ( dup2( fileno( fp ), 0 ) == -1 ) {
276 syslog( LOG_ALERT, "could not dup2 tmpfile" );
277 unbind_and_exit( EX_TEMPFAIL );
283 /* deal with errors */
285 (void) rewind( stdin );
286 send_errors( errlist, numerr );
289 (void) ldap_unbind( ld );
291 /* send to groups with errorsTo */
293 (void) rewind( stdin );
294 send_group( togroups, ngroups );
297 /* send to expanded aliases and groups w/o errorsTo */
298 if ( numto > nargs ) {
299 (void) rewind( stdin );
300 send_message( tolist );
308 int sizelimit = FAX_MAXAMBIGUOUS;
309 int deref = LDAP_DEREF_ALWAYS;
311 if ( (ld = ldap_open( NULL, 0 )) == NULL ) {
312 syslog( LOG_ALERT, "ldap_open failed" );
316 ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &sizelimit);
317 ldap_set_option(ld, LDAP_OPT_DEREF, &deref);
319 if ( ldap_simple_bind_s( ld, NULL, NULL ) != LDAP_SUCCESS ) {
320 syslog( LOG_ALERT, "ldap_simple_bind_s failed" );
329 do_address( name, to, nto, togroups, ngroups, err, nerr, type )
340 LDAPMessage *e, *res;
341 struct timeval timeout;
348 * Look up the name in X.500, add the appropriate addresses found
349 * to the to list, or to the err list in case of error. Groups are
350 * handled by the do_group routine, individuals are handled here.
351 * When looking up name, we follow the bases hierarchy, looking
352 * in base[0] first, then base[1], etc. For each base, there is
353 * a set of search filters to try, in order. If something goes
354 * wrong here trying to contact X.500, we exit with EX_TEMPFAIL.
355 * If the b_rdnpref flag is set, then we give preference to entries
356 * that matched name because it's their rdn, otherwise not.
359 timeout.tv_sec = FAX_TIMEOUT;
361 for ( b = 0, match = 0; !match && base[b].b_dn != NULL; b++ ) {
362 for ( f = 0; base[b].b_filter[f] != NULL; f++ ) {
363 char *format, *p, *argv[3];
366 for ( argc = 0; argc < 3; argc++ ) {
370 format = strdup( base[b].b_filter[f] );
371 for ( argc = 0, p = format; *p; p++ ) {
374 case 's': /* %s is the name */
378 case 'h': /* %h is the host */
385 "unknown format %c", *p );
393 /* three names ought to do... */
394 sprintf( filter, format, argv[0], argv[1], argv[2] );
398 rc = ldap_search_st( ld, base[b].b_dn,
399 LDAP_SCOPE_SUBTREE, filter, attrs, 0, &timeout,
402 /* some other trouble - try again later */
403 if ( rc != LDAP_SUCCESS &&
404 rc != LDAP_SIZELIMIT_EXCEEDED ) {
405 syslog( LOG_ALERT, "return %d from X.500", rc );
406 unbind_and_exit( EX_TEMPFAIL );
409 if ( (match = ldap_count_entries( ld, res )) != 0 )
419 /* trouble - try again later */
421 syslog( LOG_ALERT, "error parsing result from X.500" );
422 unbind_and_exit( EX_TEMPFAIL );
425 /* no matches - bounce with user unknown */
427 add_error( err, nerr, E_USERUNKNOWN, name, NULLMSG );
431 /* more than one match - bounce with ambiguous user? */
433 LDAPMessage *next, *tmpres = NULL;
437 /* not giving rdn preference - bounce with ambiguous user */
438 if ( base[b].b_rdnpref == 0 ) {
439 add_error( err, nerr, E_AMBIGUOUS, name, res );
444 * giving rdn preference - see if any entries were matched
445 * because of their rdn. If so, collect them to deal with
446 * later (== 1 we deliver, > 1 we bounce).
449 for ( e = ldap_first_entry( ld, res ); e != NULL; e = next ) {
450 next = ldap_next_entry( ld, e );
451 dn = ldap_get_dn( ld, e );
452 xdn = ldap_explode_dn( dn, 1 );
454 /* XXX bad, but how else can we do it? XXX */
455 if ( strcasecmp( xdn[0], name ) == 0 ) {
456 ldap_delete_result_entry( &res, e );
457 ldap_add_result_entry( &tmpres, e );
460 ldap_value_free( xdn );
464 /* nothing matched by rdn - go ahead and bounce */
465 if ( tmpres == NULL ) {
466 add_error( err, nerr, E_AMBIGUOUS, name, res );
469 /* more than one matched by rdn - bounce with rdn matches */
470 } else if ( (match = ldap_count_entries( ld, tmpres )) > 1 ) {
471 add_error( err, nerr, E_AMBIGUOUS, name, tmpres );
475 } else if ( match < 0 ) {
476 syslog( LOG_ALERT, "error parsing result from X.500" );
477 unbind_and_exit( EX_TEMPFAIL );
480 /* otherwise one matched by rdn - send to it */
486 * if we get this far, it means that we found a single match for
487 * name. for a user, we deliver to the mail attribute or bounce
488 * with address and phone if no mail attr. for a group, we
489 * deliver to all members or bounce to rfc822ErrorsTo if no members.
493 if ( (e = ldap_first_entry( ld, res )) == NULL ) {
494 syslog( LOG_ALERT, "error parsing entry from X.500" );
495 unbind_and_exit( EX_TEMPFAIL );
498 dn = ldap_get_dn( ld, e );
500 if ( type == GROUP_ERRORS ) {
501 /* sent to group-errors - resend to [rfc822]ErrorsTo attr */
502 do_group_errors( e, dn, to, nto, err, nerr );
504 } else if ( type == GROUP_REQUEST ) {
505 /* sent to group-request - resend to [rfc822]RequestsTo attr */
506 do_group_request( e, dn, to, nto, err, nerr );
508 } else if ( type == GROUP_MEMBERS ) {
509 /* sent to group-members - expand */
510 do_group_members( e, dn, to, nto, togroups, ngroups, err,
513 } else if ( isgroup( e ) ) {
515 * sent to group - resend from [rfc822]ErrorsTo if it's there,
516 * otherwise, expand the group
519 do_group( e, dn, to, nto, togroups, ngroups, err, nerr );
525 * sent to user - mail attribute => add it to the to list,
530 if ( (mail = ldap_get_values( ld, e,
531 "facsimileTelephoneNumber" )) != NULL ) {
536 fdn = ldap_get_dn( ld, e );
537 ufn = ldap_explode_dn( fdn, 1 );
538 /* Convert spaces to underscores for rp */
539 for (i = 0; ufn[0][i] != '\0'; i++) {
540 if (ufn[0][i] == ' ') {
544 *mail = faxtotpc(*mail, ufn[0]);
546 add_to(to, nto, mail);
551 ldap_value_free( ufn );
552 ldap_value_free( mail );
555 add_error( err, nerr, E_NOFAXNUM,
560 if ( (mail = ldap_get_values( ld, e, "mail" ))
562 add_to( to, nto, mail );
564 ldap_value_free( mail );
567 add_error( err, nerr, E_NOEMAIL,
580 do_group( e, dn, to, nto, togroups, ngroups, err, nerr )
591 * If this group has an rfc822ErrorsTo attribute, we need to
592 * arrange for errors involving this group to go there, not
593 * to the sender. Since sendmail only has the concept of a
594 * single sender, we arrange for errors to go to groupname-errors,
595 * which we then handle specially when (if) it comes back to us
596 * by expanding to all the rfc822ErrorsTo addresses. If it has no
597 * rfc822ErrorsTo attribute, we call do_group_members() to expand
601 if ( group_loop( dn ) ) {
605 if ( has_attributes( e, "rfc822ErrorsTo", "errorsTo" ) ) {
606 add_group( dn, togroups, ngroups );
611 do_group_members( e, dn, to, nto, togroups, ngroups, err, nerr );
618 do_group_members( e, dn, to, nto, togroups, ngroups, err, nerr )
630 char **mail, **member, **joinable;
632 LDAPMessage *ee, *res;
633 struct timeval timeout;
636 * if all has gone according to plan, we've already arranged for
637 * errors to go to the [rfc822]ErrorsTo attributes (if they exist),
638 * so all we have to do here is arrange to send to the
639 * rfc822Mailbox attribute, the member attribute, and anyone who
640 * has joined the group by setting memberOfGroup equal to the
644 /* add members in the group itself - mail attribute */
645 if ( (mail = ldap_get_values( ld, e, "mail" )) != NULL ) {
647 * These are only email addresses - impossible
648 * to have a fax number
652 /* XXX How do we want to inform sender that the */
653 /* group they sent to has email-only members? */
656 add_to( to, nto, mail );
660 ldap_value_free( mail );
663 /* add members in the group itself - member attribute */
664 if ( (member = ldap_get_values( ld, e, "member" )) != NULL ) {
665 for ( i = 0; member[i] != NULL; i++ ) {
666 add_member( dn, member[i], to, nto, togroups,
667 ngroups, err, nerr );
670 ldap_value_free( member );
673 /* add members who have joined by setting memberOfGroup */
674 if ( (joinable = ldap_get_values( ld, e, "joinable" )) != NULL ) {
675 if ( strcasecmp( joinable[0], "FALSE" ) == 0 ) {
676 ldap_value_free( joinable );
679 ldap_value_free( joinable );
681 sprintf( filter, "(memberOfGroup=%s)", dn );
683 timeout.tv_sec = FAX_TIMEOUT;
686 /* for each subtree to look in... */
688 int sizelimit = FAX_MAXMEMBERS;
689 ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &sizelimit);
691 for ( i = 0; base[i].b_dn != NULL; i++ ) {
692 /* find entries that have joined this group... */
693 rc = ldap_search_st( ld, base[i].b_dn,
694 LDAP_SCOPE_SUBTREE, filter, attrs, 0, &timeout,
697 if ( rc == LDAP_SIZELIMIT_EXCEEDED ||
698 rc == LDAP_TIMELIMIT_EXCEEDED ) {
700 "group search limit exceeded %d", rc );
701 unbind_and_exit( EX_TEMPFAIL );
704 if ( rc != LDAP_SUCCESS ) {
705 syslog( LOG_ALERT, "group search bad return %d",
707 unbind_and_exit( EX_TEMPFAIL );
710 /* for each entry that has joined... */
711 for ( ee = ldap_first_entry( ld, res ); ee != NULL;
712 ee = ldap_next_entry( ld, ee ) ) {
713 if ( isgroup( ee ) ) {
714 ndn = ldap_get_dn( ld, ee );
716 if ( do_group( e, ndn, to, nto,
717 togroups, ngroups, err, nerr )
720 "group loop (%s) (%s)",
729 /* add them to the to list */
732 if ( (mail = ldap_get_values( ld, ee,
733 "facsimileTelephoneNumber" ))
739 fdn = ldap_get_dn( ld, ee );
740 ufn = ldap_explode_dn( fdn, 1 );
745 for (i = 0; ufn[0][i] != '\0';
747 if (ufn[0][i] == ' ') {
751 *mail = faxtotpc(*mail, ufn[0]);
752 add_to(to, nto, mail);
754 ldap_value_free( mail );
757 ndn = ldap_get_dn( ld, ee );
759 add_error( err, nerr,
760 E_JOINMEMBERNOFAXNUM, ndn,
767 if ( (mail = ldap_get_values( ld, ee,
768 "mail" )) != NULL ) {
769 add_to( to, nto, mail );
771 ldap_value_free( mail );
773 /* else generate a bounce */
775 ndn = ldap_get_dn( ld, ee );
777 add_error( err, nerr,
778 E_JOINMEMBERNOEMAIL, ndn,
790 int sizelimit = FAX_MAXAMBIGUOUS;
791 ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &sizelimit);
798 add_member( gdn, dn, to, nto, togroups, ngroups, err, nerr )
811 LDAPMessage *res, *e;
812 struct timeval timeout;
814 timeout.tv_sec = FAX_TIMEOUT;
816 if ( (rc = ldap_search_st( ld, dn, LDAP_SCOPE_BASE, "(objectclass=*)",
817 attrs, 0, &timeout, &res )) != LDAP_SUCCESS ) {
818 if ( rc == LDAP_NO_SUCH_OBJECT ) {
819 add_error( err, nerr, E_BADMEMBER, dn, NULLMSG );
823 syslog( LOG_ALERT, "member search bad return %d", rc );
825 unbind_and_exit( EX_TEMPFAIL );
829 if ( (e = ldap_first_entry( ld, res )) == NULL ) {
830 syslog( LOG_ALERT, "member search error parsing entry" );
832 unbind_and_exit( EX_TEMPFAIL );
834 ndn = ldap_get_dn( ld, e );
836 /* allow groups within groups */
837 if ( isgroup( e ) ) {
838 if ( do_group( e, ndn, to, nto, togroups, ngroups, err, nerr )
840 syslog( LOG_ALERT, "group loop (%s) (%s)", gdn, ndn );
850 if ( (mail = ldap_get_values( ld, e,
851 "facsimileTelephoneNumber" )) != NULL ) {
855 fdn = ldap_get_dn( ld, e );
856 ufn = ldap_explode_dn( fdn, 1 );
857 /* Convert spaces to underscores for rp */
858 for (i = 0; ufn[0][i] != '\0'; i++) {
859 if (ufn[0][i] == ' ') {
863 *mail = faxtotpc(*mail, ufn[0]);
864 add_to(to, nto, mail);
866 ldap_value_free( mail );
869 add_error( err, nerr, E_MEMBERNOFAXNUM, ndn, NULLMSG );
873 /* send to the member's mail attribute */
874 if ( (mail = ldap_get_values( ld, e, "mail" )) != NULL ) {
875 add_to( to, nto, mail );
877 ldap_value_free( mail );
879 /* else generate a bounce */
881 add_error( err, nerr, E_MEMBERNOEMAIL, ndn, NULLMSG );
889 do_group_request( e, dn, to, nto, err, nerr )
899 if ( (requeststo = get_attributes_mail_dn( e, "rfc822RequestsTo",
900 "requestsTo" )) != NULL ) {
901 add_to( to, nto, requeststo );
903 ldap_value_free( requeststo );
905 add_error( err, nerr, E_NOREQUEST, dn, NULLMSG );
911 do_group_errors( e, dn, to, nto, err, nerr )
921 if ( (errorsto = get_attributes_mail_dn( e, "rfc822ErrorsTo",
922 "errorsTo" )) != NULL ) {
923 add_to( to, nto, errorsto );
925 ldap_value_free( errorsto );
927 add_error( err, nerr, E_NOERRORS, dn, NULLMSG );
939 WAITSTATUSTYPE status;
944 if ( pid = fork() ) {
946 waitpid( pid, (int *) NULL, 0 );
948 wait4( pid, &status, WAIT_FLAGS, 0 );
952 /* to includes sendmailargs */
953 execv( FAX_SENDMAIL, to );
955 syslog( LOG_ALERT, "execv failed" );
962 send_group( group, ngroup )
971 WAITSTATUSTYPE status;
974 for ( i = 0; i < ngroup; i++ ) {
975 (void) rewind( stdin );
977 iargv[0] = FAX_SENDMAIL;
979 iargv[2] = group[i].g_errorsto;
980 iargv[3] = "-oMrX.500";
987 add_to( &argv, &argc, iargv );
988 add_to( &argv, &argc, group[i].g_members );
992 if ( pid = fork() ) {
994 waitpid( pid, (int *) NULL, 0 );
996 wait4( pid, &status, WAIT_FLAGS, 0 );
1000 execv( FAX_SENDMAIL, argv );
1002 syslog( LOG_ALERT, "execv failed" );
1004 exit( EX_TEMPFAIL );
1012 send_errors( err, nerr )
1020 sprintf( buf, "%s -oMrX.500 -odi -oi -f %s %s", FAX_SENDMAIL, errorsfrom,
1022 if ( (fp = popen( buf, "w" )) == NULL ) {
1023 syslog( LOG_ALERT, "could not popen sendmail for errs" );
1027 fprintf( fp, "To: %s\n", mailfrom );
1028 fprintf( fp, "From: %s\n", errorsfrom );
1029 fprintf( fp, "Subject: undeliverable mail\n" );
1030 fprintf( fp, "\n" );
1031 fprintf( fp, "The following errors occurred when trying to deliver the attached mail:\n" );
1032 for ( i = 0; i < nerr; i++ ) {
1033 namelen = strlen( err[i].e_addr );
1034 fprintf( fp, "\n" );
1036 switch ( err[i].e_code ) {
1038 fprintf( fp, "%s: User unknown\n", err[i].e_addr );
1042 fprintf( fp, "%s: Group member does not exist\n",
1047 fprintf( fp, "%s: Group exists but has no request address\n",
1052 fprintf( fp, "%s: Group exists but has no errors-to address\n",
1057 do_ambiguous( fp, &err[i], namelen );
1061 do_noemailorfax( fp, &err[i], namelen, E_NOEMAIL );
1064 case E_MEMBERNOEMAIL:
1065 fprintf( fp, "%s: Group member exists but does not have an email address\n",
1069 case E_JOINMEMBERNOEMAIL:
1070 fprintf( fp, "%s: User has joined group but does not have an email address\n",
1075 do_noemailorfax( fp, &err[i], namelen, E_NOFAXNUM );
1078 case E_MEMBERNOFAXNUM:
1079 fprintf( fp, "%s: Group member exists but does not have a fax number\n",
1083 case E_JOINMEMBERNOFAXNUM:
1084 fprintf( fp, "%s: User has joined group but does not have a fax number\n",
1089 syslog( LOG_ALERT, "unknown error %d", err[i].e_code );
1090 unbind_and_exit( EX_TEMPFAIL );
1095 fprintf( fp, "\n------- The original message sent:\n\n" );
1097 while ( fgets( buf, sizeof(buf), stdin ) != NULL ) {
1101 if ( pclose( fp ) == -1 ) {
1102 syslog( LOG_ALERT, "pclose failed" );
1103 unbind_and_exit( EX_TEMPFAIL );
1111 do_noemailorfax( fp, err, namelen, errtype )
1121 if (errtype == E_NOFAXNUM) {
1122 fprintf(fp, "%s: User has no facsimile number registered.\n",
1124 } else if (errtype == E_NOEMAIL) {
1125 fprintf(fp, "%s: User has no email address registered.\n",
1128 fprintf( fp, "%*s Name, title, postal address and phone for '%s':\n\n",
1129 namelen, " ", err->e_addr );
1132 dn = ldap_get_dn( ld, err->e_msg );
1133 ufn = ldap_explode_dn( dn, 1 );
1134 rdn = strdup( ufn[0] );
1135 if ( strcasecmp( rdn, err->e_addr ) == 0 ) {
1136 if ( (vals = ldap_get_values( ld, err->e_msg, "cn" ))
1138 for ( i = 0; vals[i]; i++ ) {
1139 last = strlen( vals[i] ) - 1;
1140 if ( isdigit( vals[i][last] ) ) {
1141 rdn = strdup( vals[i] );
1146 ldap_value_free( vals );
1149 fprintf( fp, "%*s %s\n", namelen, " ", rdn );
1152 ldap_value_free( ufn );
1154 /* titles or descriptions */
1155 if ( (vals = ldap_get_values( ld, err->e_msg, "title" )) == NULL &&
1156 (vals = ldap_get_values( ld, err->e_msg, "description" ))
1158 fprintf( fp, "%*s No title or description registered\n",
1161 for ( i = 0; vals[i] != NULL; i++ ) {
1162 fprintf( fp, "%*s %s\n", namelen, " ", vals[i] );
1165 ldap_value_free( vals );
1168 /* postal address */
1169 if ( (vals = ldap_get_values( ld, err->e_msg, "postalAddress" ))
1171 fprintf( fp, "%*s No postal address registered\n", namelen,
1174 fprintf( fp, "%*s ", namelen, " " );
1175 for ( i = 0; vals[0][i] != '\0'; i++ ) {
1176 if ( vals[0][i] == '$' ) {
1177 fprintf( fp, "\n%*s ", namelen, " " );
1178 while ( isspace( vals[0][i+1] ) )
1181 fprintf( fp, "%c", vals[0][i] );
1184 fprintf( fp, "\n" );
1186 ldap_value_free( vals );
1189 /* telephone number */
1190 if ( (vals = ldap_get_values( ld, err->e_msg, "telephoneNumber" ))
1192 fprintf( fp, "%*s No phone number registered\n", namelen,
1195 for ( i = 0; vals[i] != NULL; i++ ) {
1196 fprintf( fp, "%*s %s\n", namelen, " ", vals[i] );
1199 ldap_value_free( vals );
1205 do_ambiguous( fp, err, namelen )
1215 i = ldap_result2error( ld, err->e_msg, 0 );
1217 fprintf( fp, "%s: Ambiguous user. %s%d matches found:\n\n",
1218 err->e_addr, i == LDAP_SIZELIMIT_EXCEEDED ? "First " : "",
1219 ldap_count_entries( ld, err->e_msg ) );
1221 for ( e = ldap_first_entry( ld, err->e_msg ); e != NULL;
1222 e = ldap_next_entry( ld, e ) ) {
1223 dn = ldap_get_dn( ld, e );
1224 ufn = ldap_explode_dn( dn, 1 );
1225 rdn = strdup( ufn[0] );
1226 if ( strcasecmp( rdn, err->e_addr ) == 0 ) {
1227 if ( (vals = ldap_get_values( ld, e, "cn" )) != NULL ) {
1228 for ( i = 0; vals[i]; i++ ) {
1229 last = strlen( vals[i] ) - 1;
1230 if ( isdigit( vals[i][last] ) ) {
1231 rdn = strdup( vals[i] );
1236 ldap_value_free( vals );
1240 if ( isgroup( e ) ) {
1241 vals = ldap_get_values( ld, e, "description" );
1243 vals = ldap_get_values( ld, e, "title" );
1246 fprintf( fp, " %-20s %s\n", rdn, vals ? vals[0] : "" );
1247 for ( i = 1; vals && vals[i] != NULL; i++ ) {
1248 fprintf( fp, " %s\n", vals[i] );
1253 ldap_value_free( ufn );
1255 ldap_value_free( vals );
1260 count_values( list )
1265 for ( i = 0; list && list[i] != NULL; i++ )
1272 add_to( list, nlist, new )
1277 int i, nnew, oldnlist;
1279 nnew = count_values( new );
1282 if ( *list == NULL || *nlist == 0 ) {
1283 *list = (char **) malloc( (nnew + 1) * sizeof(char *) );
1286 *list = (char **) realloc( *list, *nlist * sizeof(char *) +
1287 nnew * sizeof(char *) + sizeof(char *) );
1291 for ( i = 0; i < nnew; i++ ) {
1292 (*list)[i + oldnlist] = strdup( new[i] );
1294 (*list)[*nlist] = NULL;
1306 oclist = ldap_get_values( ld, e, "objectClass" );
1308 for ( i = 0; oclist[i] != NULL; i++ ) {
1309 if ( strcasecmp( oclist[i], "rfc822MailGroup" ) == 0 ) {
1310 ldap_value_free( oclist );
1314 ldap_value_free( oclist );
1320 add_error( err, nerr, code, addr, msg )
1328 *err = (Error *) malloc( sizeof(Error) );
1330 *err = (Error *) realloc( *err, (*nerr + 1) * sizeof(Error) );
1333 (*err)[*nerr].e_code = code;
1334 (*err)[*nerr].e_addr = strdup( addr );
1335 (*err)[*nerr].e_msg = msg;
1342 add_group( dn, list, nlist )
1350 for ( i = 0; i < *nlist; i++ ) {
1351 if ( strcmp( dn, (*list)[i].g_dn ) == 0 ) {
1352 syslog( LOG_ALERT, "group loop 2 detected (%s)", dn );
1357 ufn = ldap_explode_dn( dn, 1 );
1358 namelen = strlen( ufn[0] );
1360 if ( *nlist == 0 ) {
1361 *list = (Group *) malloc( sizeof(Group) );
1363 *list = (Group *) realloc( *list, (*nlist + 1) *
1367 /* send errors to groupname-errors@host */
1368 (*list)[*nlist].g_errorsto = (char *) malloc( namelen + sizeof(ERRORS)
1370 sprintf( (*list)[*nlist].g_errorsto, "%s-%s@%s", ufn[0], ERRORS, host );
1371 (void) canonical( (*list)[*nlist].g_errorsto );
1373 /* send to groupname-members@host - make it a list for send_group */
1374 (*list)[*nlist].g_members = (char **) malloc( 2 * sizeof(char *) );
1375 (*list)[*nlist].g_members[0] = (char *) malloc( namelen +
1376 sizeof(MEMBERS) + hostlen + 2 );
1377 sprintf( (*list)[*nlist].g_members[0], "%s-%s@%s", ufn[0], MEMBERS,
1379 (void) canonical( (*list)[*nlist].g_members[0] );
1380 (*list)[*nlist].g_members[1] = NULL;
1382 /* save the group's dn so we can check for loops above */
1383 (*list)[*nlist].g_dn = strdup( dn );
1387 ldap_value_free( ufn );
1393 unbind_and_exit( rc )
1398 if ( (i = ldap_unbind( ld )) != LDAP_SUCCESS )
1399 syslog( LOG_ALERT, "ldap_unbind failed %d\n", i );
1410 for ( ; *s != '\0'; s++ ) {
1423 static char **groups;
1426 for ( i = 0; i < ngroups; i++ ) {
1427 if ( strcmp( dn, groups[i] ) == 0 )
1432 groups = (char **) malloc( sizeof(char *) );
1434 groups = (char **) realloc( groups,
1435 (ngroups + 1) * sizeof(char *) );
1437 groups[ngroups++] = strdup( dn );
1443 has_attributes( e, attr1, attr2 )
1450 if ( (attr = ldap_get_values( ld, e, attr1 )) != NULL ) {
1451 ldap_value_free( attr );
1455 if ( (attr = ldap_get_values( ld, e, attr2 )) != NULL ) {
1456 ldap_value_free( attr );
1464 get_attributes_mail_dn( e, attr1, attr2 )
1467 char *attr2; /* this one is dn-valued */
1469 LDAPMessage *ee, *res;
1470 char **vals, **dnlist, **mail;
1472 struct timeval timeout;
1474 vals = ldap_get_values( ld, e, attr1 );
1475 for ( nto = 0; vals != NULL && vals[nto] != NULL; nto++ )
1478 if ( (dnlist = ldap_get_values( ld, e, attr2 )) != NULL ) {
1479 timeout.tv_sec = FAX_TIMEOUT;
1480 timeout.tv_usec = 0;
1482 for ( i = 0; dnlist[i] != NULL; i++ ) {
1483 if ( (rc = ldap_search_st( ld, dnlist[i],
1484 LDAP_SCOPE_BASE, "(objectclass=*)", attrs, 0,
1485 &timeout, &res )) != LDAP_SUCCESS ) {
1486 if ( rc != LDAP_NO_SUCH_OBJECT ) {
1487 unbind_and_exit( EX_TEMPFAIL );
1490 syslog( LOG_ALERT, "bad (%s) dn (%s)", attr2,
1496 if ( (ee = ldap_first_entry( ld, res )) == NULL ) {
1497 syslog( LOG_ALERT, "error parsing x500 entry" );
1501 if ( (mail = ldap_get_values( ld, ee, "mail" ))
1503 add_to( &vals, &nto, mail );
1505 ldap_value_free( mail );
1508 ldap_msgfree( res );