From: Kurt Zeilenga Date: Sat, 10 Aug 2002 00:20:45 +0000 (+0000) Subject: Zap ldapv2-only stuff X-Git-Tag: OPENLDAP_REL_ENG_2_1_4~42 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=c6d5a774dfdaeb1ff0fff83208a468eaaca5c4ce;p=openldap Zap ldapv2-only stuff --- diff --git a/clients/Makefile.in b/clients/Makefile.in index ad081a9510..e9deeb06e7 100644 --- a/clients/Makefile.in +++ b/clients/Makefile.in @@ -4,6 +4,5 @@ ## ## Clients Makefile.in for OpenLDAP -SUBDIRS = tools ud -CLEANDIRS = mail500 maildap +SUBDIRS = tools diff --git a/clients/mail500/README b/clients/mail500/README deleted file mode 100644 index 57e7dd1cf8..0000000000 --- a/clients/mail500/README +++ /dev/null @@ -1,186 +0,0 @@ -This is the README file for mail500, a mailer that does X.500 lookups -via LDAP. - -If you are planning to run mail500 at your site, there are several -things you will have to tailor in main.c: - - LDAPHOST - The host running an LDAP server - - base[] - The array telling mail500 where/how to search for - things. See the explanation below. - -*** WHAT mail500 DOES: *** - -mail500 is designed to be invoked as a mailer (e.g., from sendmail), -similar to the way /bin/mail works. It takes a few required arguments -and then a list of addresses to deliver to. It expects to find the -message to deliver on its standard input. It looks up the addresses in -X.500 to figure out where to route the mail, and then execs sendmail to -do the actual delivery. It supports simple aliases, groups, and -mailing lists, the details of which are given below. - -*** HOW IT WORKS (from the sendmail side): *** - -The idea is that you might have a rule like this in your sendmail.cf -file somewhere in rule set 0: - -R$*<@umich.edu>$* $#mail500$@umich.edu$:<$1> - -This rule says that any address that ends in @umich.edu will cause -the mail500 mailer to be called to deliver the mail. You probably -also want to do something to prevent addresses like terminator!tim@umich.edu -or tim%terminator.rs.itd.umich.edu@umich.edu from being passed to mail500. -At U-M, we do this by adding rules like this to rule set 9 where we -strip off our local names: - -R<@umich.edu>$*:$* $>10<@>$1:$2 -R$+%$+<@umich.edu> $>10$1%$2<@> -R$+!$+<@umich.edu> $>10$1!$2<@> - -See the sample sendmail.cf in this directory for more details. - -The mail500 mailer should be defined similar to this in the -sendmail.cf file: - -Mmail500, P=/usr/local/etc/mail500, F=DFMSmnXuh, A=mail500 -f $f -h $h -m $n@$w $u - -This defines how mail500 will be treated by sendmail and what -arguments it will have when it's called. The various flags specified -by the F=... parameter are explained in your local sendmail book (with -any luck). The arguments to mail500 are as follows: - - -f Who the mail is from. This will be used as the address - to which any errors should be sent (unless the address - specifies a mailing list - see below). Normally, sendmail - defines the $f macro to be the sender. - - -h The domain for which the mail is destined. This is passed - in to mail500 via the $h macro, which is set by the - $@ metasymbol in the rule added to rule set 0 above. - It's normally used when searching for groups. - - -m The mailer-daemon address. If errors have to be sent, - this is the address they will come from. $n is normally - set to mailer-daemon and $w is normally the local host - name. - -The final argument $u is used to stand for the addresses to which to -deliver the mail. - -*** HOW IT WORKS (from the mail500 side): *** - -When mail500 gets invoked with one or more names to which to -deliver mail, it searches for each name in X.500. Where it searches, -and what kind(s) of search(es) it does are compile-time configurable -by changing the base array in main.c. For example, the configuration -we use at U-M is like this: - - Base base[] = - { "ou=People, o=University of Michigan, c=US", 0 - "uid=%s", "cn=%s", NULL, - "ou=System Groups, ou=Groups, o=University of Michigan, c=US", 1 - "(&(cn=%s)(associatedDomain=%h))", NULL, NULL, - "ou=User Groups, ou=Groups, o=University of Michigan, c=US", 1 - "(&(cn=%s)(associatedDomain=%h))", NULL, NULL, - NULL - }; - -which means that in delivering mail to "name" mail500 would do the -the following searches, stopping if it found anything at any step: - - Search (18) [2]: c=US@o=University of Michigan@ou=People - Search subtree (uid=name) - Search (18) [3]: c=US@o=University of Michigan@ou=People - Search subtree (cn=name) - - Search (18) [4]: c=US@o=University of Michigan@ou=Groups@ou=System Groups - Search subtree & ((cn=name)(associatedDomain=umich.edu)) - - Search (18) [5]: c=US@o=University of Michigan@ou=Groups@ou=User Groups - Search subtree & ((cn=name)(associatedDomain=umich.edu)) - -Notice that when specifying a filter %s is replaced by the name, -or user portion of the address while %h is replaced by whatever is -passed in to mail500 via the -h option (typically the host portion -of the address). - -You can also specify whether you want search results that matched -because the entry's RDN matched the search to be given preference -or not. At U-M, we only give such preference in the mail group -portion of the searches. Beware with this option: the algorithm -used to decide whether an entry's RDN matched the search is very -simple-minded, and may not always be correct. - -There is currently no limit on the number of areas searched (the base -array can be as large as you want), and an arbitrary limit of 2 filters -for each base. If you want more than that, simply changing the 3 in -the typedef for Base should do the trick. - -*** HOW IT WORKS (from the X.500 side): *** - -In X.500, there are several new attribute types and one new object -class defined that mail500 makes use of. At its most basic, for normal -entries mail500 will deliver to the value(s) listed in the -rfc822Mailbox attribute of the entry. For example, at U-M my entry has -the attribute - - mail= tim@terminator.rs.itd.umich.edu - -So mail sent to tim@umich.edu will be delivered via mail500 to that -address. If there were multiple values for the mail attribute, multiple -copies of the mail would be sent. - -A new object class, rfc822MailGroup, and several new attributes have -been defined to handle email groups/mailing lists. To use this, you -will need to add this to your local oidtable.oc: - - # object class for representing rfc 822 mailgroups - rfc822MailGroup: umichObjectClass.2 : \ - top : \ - cn : \ - rfc822Mailbox, member, memberOfGroup, owner, \ - errorsTo, rfc822ErrorsTo, requestsTo, rfc822RequestsTo, - joinable, associatedDomain, \ - description, multiLineDescription, \ - userPassword, krbName, \ - telecommunicationAttributeSet, postalAttributeSet - -And you will need to add these to your local oidtable.at: - - # attrs for rfc822mailgroups - multiLineDescription: umichAttributeType.2 : CaseIgnoreList - rfc822ErrorsTo: umichAttributeType.26 : CaseIgnoreIA5String - rfc822RequestsTo: umichAttributeType.27 : CaseIgnoreIA5String - joinable: umichAttributeType.28 : Boolean - memberOfGroup: umichAttributeType.29 : DN - errorsTo: umichAttributeType.30 : DN - requestsTo: umichAttributeType.31 : DN - -The idea was to define a kind of hybrid mail group that could handle -people who were in X.500 or not. So, for example, members of a group -can be specified via the member attribute (for X.500 members) or the -rfc822MailBox attribute (for non-X.500 members). Similarly for the -errorsTo and rfc822ErrorsTo, and the requestsTo and rfc822RequestsTo -attributes. - -To create a real mailing list, with a list maintainer, all you have to -do is create an rfc822MailGroup and fill in the errorsTo or -rfc822ErrorsTo attributes (or both). That will cause any errors -encountered when delivering mail to the group to go to the addresses -listed (or X.500 entry via it's mail attribute). - -If you fill in the requestsTo or rfc822RequestsTo (or both) attributes, -mail sent to groupname-request will be sent to the addresses listed -there. mail500 does this automatically, so you don't have to explicitly -add the groupname-request alias to your group. - -To allow users to join a group, there is the joinable flag. If TRUE, -mail500 will search for entries that have a memberOfGroup attribute -equal to the DN of the group, using the same algorithm it used to find -the group in the first place (i.e. the DNs and filters listed in the -base array). This allows people to join (or subscribe to) a group -without having to modify the group entry directly. If joinable is -FALSE, the search is not done. - -Finally, keep in mind that this is somewhat experimental at the moment. -We are using it in production at U-M, but your mileage may vary... diff --git a/clients/mail500/main.c b/clients/mail500/main.c deleted file mode 100644 index 5fdea96201..0000000000 --- a/clients/mail500/main.c +++ /dev/null @@ -1,1691 +0,0 @@ -/* - * Copyright (c) 1990 Regents of the University of Michigan. - * All rights reserved. - * - * Redistribution and use in source and binary forms are permitted - * provided that this notice is preserved and that due credit is given - * to the University of Michigan at Ann Arbor. The name of the University - * may not be used to endorse or promote products derived from this - * software without specific prior written permission. This software - * is provided ``as is'' without express or implied warranty. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "portable.h" - -#include "lber.h" -#include "ldap.h" -#include "ldapconfig.h" - -#define USER 0x01 -#define GROUP_ERRORS 0x02 -#define GROUP_REQUEST 0x04 -#define GROUP_MEMBERS 0x08 -#define GROUP_OWNER 0x10 - -#define ERROR "error" -#define ERRORS "errors" -#define REQUEST "request" -#define REQUESTS "requests" -#define MEMBERS "members" -#define OWNER "owner" -#define OWNERS "owners" - -LDAP *ld; -char *vacationhost = NULL; -char *errorsfrom = NULL; -char *mailfrom = NULL; -char *host = NULL; -char *ldaphost = LDAPHOST; -int hostlen = 0; -int debug; - -typedef struct errs { - int e_code; -#define E_USERUNKNOWN 1 -#define E_AMBIGUOUS 2 -#define E_NOEMAIL 3 -#define E_NOREQUEST 4 -#define E_NOERRORS 5 -#define E_BADMEMBER 6 -#define E_JOINMEMBERNOEMAIL 7 -#define E_MEMBERNOEMAIL 8 -#define E_LOOP 9 -#define E_NOMEMBERS 10 -#define E_NOOWNER 11 -#define E_GROUPUNKNOWN 12 - char *e_addr; - union { - char *e_u_loop; - LDAPMessage *e_u_msg; - } e_union; -#define e_msg e_union.e_u_msg -#define e_loop e_union.e_u_loop -} Error; - -typedef struct groupto { - char *g_dn; - char *g_errorsto; - char **g_members; -} Group; - -typedef struct baseinfo { - char *b_dn; /* dn to start searching at */ - char b_rdnpref; /* give rdn's preference when searching? */ - int b_search; /* ORed with the type of thing the address */ - /* looks like (USER, GROUP_ERRORS, etc.) */ - /* to see if this should be searched */ - char *b_filter[3]; /* filter to apply - name substituted for %s */ - /* (up to three of them) */ -} Base; - -Base base[] = - { "ou=People, o=University of Michigan, c=US", - 0, USER, - "uid=%s", "cn=%s", NULL, - "ou=System Groups, ou=Groups, o=University of Michigan, c=US", - 1, 0xff, - "(&(cn=%s)(associatedDomain=%h))", NULL, NULL, - "ou=User Groups, ou=Groups, o=University of Michigan, c=US", - 1, 0xff, - "(&(cn=%s)(associatedDomain=%h))", NULL, NULL, - NULL - }; - -char *sendmailargs[] = { MAIL500_SENDMAIL, "-oMrX.500", "-odi", "-oi", "-f", NULL, NULL }; - -static char *attrs[] = { "objectClass", "title", "postaladdress", - "telephoneNumber", "mail", "description", "owner", - "errorsTo", "rfc822ErrorsTo", "requestsTo", - "rfc822RequestsTo", "joinable", "cn", "member", - "moderator", "onVacation", "uid", - "suppressNoEmailError", NULL }; - -static do_address(); -static do_group(); -static do_group_members(); -static send_message(); -static send_errors(); -static do_noemail(); -static do_ambiguous(); -static add_to(); -static isgroup(); -static add_error(); -static add_group(); -static unbind_and_exit(); -static group_loop(); -static send_group(); -static has_attributes(); -static char **get_attributes_mail_dn(); -static char *canonical(); - -main (argc, argv) -int argc; -char **argv; -{ - char *myname; - char **tolist; - Error *errlist; - Group *togroups; - int numto, ngroups, numerr, nargs; - int i, j; - FILE *fp; - extern int optind, errno; - extern char *optarg; - - if ( (myname = strrchr( argv[0], '/' )) == NULL ) - myname = strdup( argv[0] ); - else - myname = strdup( myname + 1 ); - -#ifdef LOG_MAIL - openlog( myname, OPENLOG_OPTIONS, LOG_MAIL ); -#else - openlog( myname, OPENLOG_OPTIONS ); -#endif - - while ( (i = getopt( argc, argv, "d:f:h:l:m:v:" )) != EOF ) { - switch( i ) { - case 'd': /* turn on debugging */ - debug = atoi( optarg ); - break; - - case 'f': /* who it's from & where errors should go */ - mailfrom = strdup( optarg ); - for ( j = 0; sendmailargs[j] != NULL; j++ ) { - if ( strcmp( sendmailargs[j], "-f" ) == 0 ) { - sendmailargs[j+1] = mailfrom; - break; - } - } - break; - - case 'h': /* hostname */ - host = strdup( optarg ); - hostlen = strlen(host); - break; - - case 'l': /* ldap host */ - ldaphost = strdup( optarg ); - break; - - /* mailer-daemon address - who we should */ - case 'm': /* say errors come from */ - errorsfrom = strdup( optarg ); - break; - - case 'v': /* vacation host */ - vacationhost = strdup( optarg ); - break; - - default: - syslog( LOG_ALERT, "unknown option" ); - break; - } - } - - if ( mailfrom == NULL ) { - syslog( LOG_ALERT, "required argument -f not present" ); - exit( EX_TEMPFAIL ); - } - if ( errorsfrom == NULL ) { - syslog( LOG_ALERT, "required argument -m not present" ); - exit( EX_TEMPFAIL ); - } - if ( host == NULL ) { - syslog( LOG_ALERT, "required argument -h not present" ); - exit( EX_TEMPFAIL ); - } - - if ( connect_to_x500() != 0 ) - exit( EX_TEMPFAIL ); - - setuid( geteuid() ); - - if ( debug ) { - char buf[1024]; - int i; - - syslog( LOG_ALERT, "running as %d", geteuid() ); - strcpy( buf, argv[0] ); - for ( i = 1; i < argc; i++ ) { - strcat( buf, " " ); - strcat( buf, argv[i] ); - } - - syslog( LOG_ALERT, "args: (%s)", buf ); - } - - tolist = NULL; - numto = 0; - add_to( &tolist, &numto, sendmailargs ); - nargs = numto; - ngroups = numerr = 0; - togroups = NULL; - errlist = NULL; - for ( i = optind; i < argc; i++ ) { - char *s; - int type; - - for ( j = 0; argv[i][j] != '\0'; j++ ) { - if ( argv[i][j] == '.' || argv[i][j] == '_' ) - argv[i][j] = ' '; - } - - type = USER; - if ( (s = strrchr( argv[i], '-' )) != NULL ) { - s++; - - if ((strcasecmp(s, ERROR) == 0) || - (strcasecmp(s, ERRORS) == 0)) { - type = GROUP_ERRORS; - *(--s) = '\0'; - } else if ((strcasecmp(s, REQUEST) == 0) || - (strcasecmp(s, REQUESTS) == 0)) { - type = GROUP_REQUEST; - *(--s) = '\0'; - } else if ( strcasecmp( s, MEMBERS ) == 0 ) { - type = GROUP_MEMBERS; - *(--s) = '\0'; - } else if ((strcasecmp(s, OWNER) == 0) || - (strcasecmp(s, OWNERS) == 0)) { - type = GROUP_OWNER; - *(--s) = '\0'; - } - } - - do_address( argv[i], &tolist, &numto, &togroups, &ngroups, - &errlist, &numerr, type ); - } - - /* - * If we have both errors and successful deliveries to make or if - * if there are any groups to deliver to, we basically need to read - * the message twice. So, we have to put it in a tmp file. - */ - - if ( numerr > 0 && numto > nargs || ngroups > 0 ) { - int fd; - char buf[BUFSIZ]; - - umask( 077 ); - if ( (fp = tmpfile()) == NULL ) { - syslog( LOG_ALERT, "could not open tmp file" ); - unbind_and_exit( EX_TEMPFAIL ); - } - - /* copy the message to a temp file */ - while ( fgets( buf, sizeof(buf), stdin ) != NULL ) { - if ( fputs( buf, fp ) == EOF ) { - syslog( LOG_ALERT, "error writing tmpfile" ); - unbind_and_exit( EX_TEMPFAIL ); - } - } - - if ( dup2( fileno( fp ), 0 ) == -1 ) { - syslog( LOG_ALERT, "could not dup2 tmpfile" ); - unbind_and_exit( EX_TEMPFAIL ); - } - - fclose( fp ); - } - - /* deal with errors */ - if ( numerr > 0 ) { - if ( debug ) { - syslog( LOG_ALERT, "sending errors" ); - } - (void) rewind( stdin ); - send_errors( errlist, numerr ); - } - - (void) ldap_unbind( ld ); - - /* send to groups with errorsTo */ - if ( ngroups > 0 ) { - if ( debug ) { - syslog( LOG_ALERT, "sending to groups with errorsto" ); - } - (void) rewind( stdin ); - send_group( togroups, ngroups ); - } - - /* send to expanded aliases and groups w/o errorsTo */ - if ( numto > nargs ) { - if ( debug ) { - syslog( LOG_ALERT, "sending to aliases and groups" ); - } - (void) rewind( stdin ); - send_message( tolist ); - } - - return( EX_OK ); -} - -connect_to_x500() -{ - if ( (ld = ldap_open( ldaphost, LDAP_PORT )) == NULL ) { - syslog( LOG_ALERT, "ldap_open failed" ); - return( -1 ); - } - ld->ld_sizelimit = MAIL500_MAXAMBIGUOUS; - ld->ld_deref = LDAP_DEREF_ALWAYS; - - if ( ldap_simple_bind_s( ld, MAIL500_BINDDN, NULL ) != LDAP_SUCCESS ) { - syslog( LOG_ALERT, "ldap_simple_bind_s failed" ); - return( -1 ); - } - - return( 0 ); -} - -static -mailcmp( a, b ) - char *a; - char *b; -{ - int i; - - for ( i = 0; a[i] != '\0'; i++ ) { - if ( a[i] != b[i] ) { - switch ( a[i] ) { - case ' ': - case '.': - case '_': - if ( b[i] == ' ' || b[i] == '.' || b[i] == '_' ) - break; - return( 1 ); - - default: - return( 1 ); - } - } - } - - return( 0 ); -} - -static -do_address( name, to, nto, togroups, ngroups, err, nerr, type ) - char *name; - char ***to; - int *nto; - Group **togroups; - int *ngroups; - Error **err; - int *nerr; - int type; -{ - int rc, b, f, match; - LDAPMessage *e, *res; - struct timeval timeout; - char *dn; - char filter[1024]; - char realfilter[1024]; - char **mail, **onvacation = NULL, **uid = NULL; - - /* - * Look up the name in X.500, add the appropriate addresses found - * to the to list, or to the err list in case of error. Groups are - * handled by the do_group routine, individuals are handled here. - * When looking up name, we follow the bases hierarchy, looking - * in base[0] first, then base[1], etc. For each base, there is - * a set of search filters to try, in order. If something goes - * wrong here trying to contact X.500, we exit with EX_TEMPFAIL. - * If the b_rdnpref flag is set, then we give preference to entries - * that matched name because it's their rdn, otherwise not. - */ - - timeout.tv_sec = MAIL500_TIMEOUT; - timeout.tv_usec = 0; - for ( b = 0, match = 0; !match && base[b].b_dn != NULL; b++ ) { - if ( ! (base[b].b_search & type) ) { - continue; - } - for ( f = 0; base[b].b_filter[f] != NULL; f++ ) { - char *format, *p, *s, *d; - char *argv[3]; - int argc; - - for ( argc = 0; argc < 3; argc++ ) { - argv[argc] = NULL; - } - - format = strdup( base[b].b_filter[f] ); - for ( argc = 0, p = format; *p; p++ ) { - if ( *p == '%' ) { - switch ( *++p ) { - case 's': /* %s is the name */ - argv[argc] = name; - break; - - case 'h': /* %h is the host */ - *p = 's'; - argv[argc] = host; - break; - - default: - syslog( LOG_ALERT, - "unknown format %c", *p ); - break; - } - - argc++; - } - } - - /* three names ought to do... */ - sprintf( filter, format, argv[0], argv[1], argv[2] ); - free( format ); - for ( s = filter, d = realfilter; *s; s++, d++ ) { - if ( *s == '*' ) { - *d++ = '\\'; - } - *d = *s; - } - *d = '\0'; - - res = NULL; - rc = ldap_search_st( ld, base[b].b_dn, - LDAP_SCOPE_SUBTREE, realfilter, attrs, 0, &timeout, - &res ); - - /* some other trouble - try again later */ - if ( rc != LDAP_SUCCESS && - rc != LDAP_SIZELIMIT_EXCEEDED ) { - syslog( LOG_ALERT, "return 0x%x from X.500", - rc ); - unbind_and_exit( EX_TEMPFAIL ); - } - - if ( (match = ldap_count_entries( ld, res )) != 0 ) - break; - - ldap_msgfree( res ); - } - - if ( match ) - break; - } - - /* trouble - try again later */ - if ( match == -1 ) { - syslog( LOG_ALERT, "error parsing result from X.500" ); - unbind_and_exit( EX_TEMPFAIL ); - } - - /* no matches - bounce with user unknown */ - if ( match == 0 ) { - if ( type == USER ) { - add_error( err, nerr, E_USERUNKNOWN, name, NULLMSG ); - } else { - add_error( err, nerr, E_GROUPUNKNOWN, name, NULLMSG ); - } - return; - } - - /* more than one match - bounce with ambiguous user? */ - if ( match > 1 ) { - LDAPMessage *next, *tmpres = NULL; - char *dn; - char **xdn; - - /* not giving rdn preference - bounce with ambiguous user */ - if ( base[b].b_rdnpref == 0 ) { - add_error( err, nerr, E_AMBIGUOUS, name, res ); - return; - } - - /* - * giving rdn preference - see if any entries were matched - * because of their rdn. If so, collect them to deal with - * later (== 1 we deliver, > 1 we bounce). - */ - - for ( e = ldap_first_entry( ld, res ); e != NULL; e = next ) { - next = ldap_next_entry( ld, e ); - dn = ldap_get_dn( ld, e ); - xdn = ldap_explode_dn( dn, 1 ); - - /* XXX bad, but how else can we do it? XXX */ - if ( strcasecmp( xdn[0], name ) == 0 ) { - ldap_delete_result_entry( &res, e ); - ldap_add_result_entry( &tmpres, e ); - } - - ldap_value_free( xdn ); - free( dn ); - } - - /* nothing matched by rdn - go ahead and bounce */ - if ( tmpres == NULL ) { - add_error( err, nerr, E_AMBIGUOUS, name, res ); - return; - - /* more than one matched by rdn - bounce with rdn matches */ - } else if ( (match = ldap_count_entries( ld, tmpres )) > 1 ) { - add_error( err, nerr, E_AMBIGUOUS, name, tmpres ); - return; - - /* trouble... */ - } else if ( match < 0 ) { - syslog( LOG_ALERT, "error parsing result from X.500" ); - unbind_and_exit( EX_TEMPFAIL ); - } - - /* otherwise one matched by rdn - send to it */ - ldap_msgfree( res ); - res = tmpres; - } - - /* - * if we get this far, it means that we found a single match for - * name. for a user, we deliver to the mail attribute or bounce - * with address and phone if no mail attr. for a group, we - * deliver to all members or bounce to rfc822ErrorsTo if no members. - */ - - /* trouble */ - if ( (e = ldap_first_entry( ld, res )) == NULL ) { - syslog( LOG_ALERT, "error parsing entry from X.500" ); - unbind_and_exit( EX_TEMPFAIL ); - } - - dn = ldap_get_dn( ld, e ); - - if ( type == GROUP_ERRORS ) { - /* sent to group-errors - resend to [rfc822]ErrorsTo attr */ - do_group_errors( e, dn, to, nto, err, nerr ); - - } else if ( type == GROUP_REQUEST ) { - /* sent to group-request - resend to [rfc822]RequestsTo attr */ - do_group_request( e, dn, to, nto, err, nerr ); - - } else if ( type == GROUP_MEMBERS ) { - /* sent to group-members - expand */ - do_group_members( e, dn, to, nto, togroups, ngroups, err, - nerr ); - - } else if ( type == GROUP_OWNER ) { - /* sent to group-owner - resend to owner attr */ - do_group_owner( e, dn, to, nto, err, nerr ); - - } else if ( isgroup( e ) ) { - /* - * sent to group - resend from [rfc822]ErrorsTo if it's there, - * otherwise, expand the group - */ - - do_group( e, dn, to, nto, togroups, ngroups, err, nerr ); - - ldap_msgfree( res ); - - } else { - /* - * sent to user - mail attribute => add it to the to list, - * otherwise bounce - */ - if ( (mail = ldap_get_values( ld, e, "mail" )) != NULL ) { - char buf[1024]; - char *h; - int i, j; - - /* try to detect simple mail loops */ - sprintf( buf, "%s@%s", name, host ); - for ( i = 0; mail[i] != NULL; i++ ) { - /* - * address is the same as the one we're - * sending to - mail loop. syslog the - * problem, bounce a message back to the - * sender (who else?), and delete the bogus - * addr from the list. - */ - - if ( (h = strchr( mail[i], '@' )) != NULL ) { - h++; - if ( strcasecmp( h, host ) == 0 ) { - syslog( LOG_ALERT, - "potential loop detected (%s)", - mail[i] ); - } - } - - if ( mailcmp( buf, mail[i] ) == 0 ) { - syslog( LOG_ALERT, - "loop detected (%s)", mail[i] ); - - /* remove the bogus address */ - for ( j = i; mail[j] != NULL; j++ ) { - mail[j] = mail[j+1]; - } - } - } - if ( mail[0] != NULL ) { - add_to( to, nto, mail ); - } else { - add_error( err, nerr, E_NOEMAIL, name, res ); - } - - ldap_value_free( mail ); - } else { - add_error( err, nerr, E_NOEMAIL, name, res ); - } - - /* - * If the user is on vacation, send a copy of the mail to - * the vacation server. The address is constructed from - * the vacationhost (set in a command line argument) and - * the uid (XXX this should be more general XXX). - */ - - if ( vacationhost != NULL && (onvacation = ldap_get_values( ld, - e, "onVacation" )) != NULL && strcasecmp( onvacation[0], - "TRUE" ) == 0 ) { - char buf[1024]; - char *vaddr[2]; - - if ( (uid = ldap_get_values( ld, e, "uid" )) != NULL ) { - sprintf( buf, "%s@%s", uid[0], vacationhost ); - - vaddr[0] = buf; - vaddr[1] = NULL; - - add_to( to, nto, vaddr ); - } else { - syslog( LOG_ALERT, - "user without a uid on vacation (%s)", - name ); - } - } - } - - if ( onvacation != NULL ) { - ldap_value_free( onvacation ); - } - if ( uid != NULL ) { - ldap_value_free( uid ); - } - free( dn ); - - return; -} - -static -do_group( e, dn, to, nto, togroups, ngroups, err, nerr ) - LDAPMessage *e; - char *dn; - char ***to; - int *nto; - Group **togroups; - int *ngroups; - Error **err; - int *nerr; -{ - int i; - char **moderator; - - /* - * If this group has an rfc822ErrorsTo attribute, we need to - * arrange for errors involving this group to go there, not - * to the sender. Since sendmail only has the concept of a - * single sender, we arrange for errors to go to groupname-errors, - * which we then handle specially when (if) it comes back to us - * by expanding to all the rfc822ErrorsTo addresses. If it has no - * rfc822ErrorsTo attribute, we call do_group_members() to expand - * the group. - */ - - if ( group_loop( dn ) ) { - return( -1 ); - } - - /* - * check for moderated groups - if the group has a moderator - * attribute, we check to see if the from address is one of - * the moderator values. if so, continue on. if not, arrange - * to send the mail to the moderator(s). need to do this before - * we change the from below. - */ - - if ( (moderator = ldap_get_values( ld, e, "moderator" )) != NULL ) { - /* check if it came from any of the group's moderators */ - for ( i = 0; moderator[i] != NULL; i++ ) { - if ( strcasecmp( moderator[i], mailfrom ) == 0 ) - break; - } - - /* not from the moderator? */ - if ( moderator[i] == NULL ) { - add_to( to, nto, moderator ); - ldap_value_free( moderator ); - - return( 0 ); - } - /* else from the moderator - fall through and deliver it */ - } - - if ( has_attributes( e, "rfc822ErrorsTo", "errorsTo" ) ) { - add_group( dn, togroups, ngroups ); - - return( 0 ); - } - - do_group_members( e, dn, to, nto, togroups, ngroups, err, nerr ); - - return( 0 ); -} - -/* ARGSUSED */ -static -do_group_members( e, dn, to, nto, togroups, ngroups, err, nerr ) - LDAPMessage *e; - char *dn; - char ***to; - int *nto; - Group **togroups; - int *ngroups; - Error **err; - int *nerr; -{ - int i, rc, anymembers; - char *ndn; - char **mail, **member, **joinable, **suppress; - char filter[1024]; - LDAPMessage *ee, *res; - struct timeval timeout; - - /* - * if all has gone according to plan, we've already arranged for - * errors to go to the [rfc822]ErrorsTo attributes (if they exist), - * so all we have to do here is arrange to send to the - * rfc822Mailbox attribute, the member attribute, and anyone who - * has joined the group by setting memberOfGroup equal to the - * group dn. - */ - - /* add members in the group itself - mail attribute */ - anymembers = 0; - if ( (mail = ldap_get_values( ld, e, "mail" )) != NULL ) { - anymembers = 1; - add_to( to, nto, mail ); - - ldap_value_free( mail ); - } - - /* add members in the group itself - member attribute */ - if ( (member = ldap_get_values( ld, e, "member" )) != NULL ) { - suppress = ldap_get_values( ld, e, "suppressNoEmailError" ); - anymembers = 1; - for ( i = 0; member[i] != NULL; i++ ) { - if ( strcasecmp( dn, member[i] ) == 0 ) { - syslog( LOG_ALERT, "group (%s) contains itself", - dn ); - continue; - } - add_member( dn, member[i], to, nto, togroups, - ngroups, err, nerr, suppress ); - } - - if ( suppress ) { - ldap_value_free( suppress ); - } - ldap_value_free( member ); - } - - /* add members who have joined by setting memberOfGroup */ - if ( (joinable = ldap_get_values( ld, e, "joinable" )) != NULL ) { - if ( strcasecmp( joinable[0], "FALSE" ) == 0 ) { - if ( ! anymembers ) { - add_error( err, nerr, E_NOMEMBERS, dn, - NULLMSG ); - } - - ldap_value_free( joinable ); - return; - } - ldap_value_free( joinable ); - - sprintf( filter, "(memberOfGroup=%s)", dn ); - - timeout.tv_sec = MAIL500_TIMEOUT; - timeout.tv_usec = 0; - - /* for each subtree to look in... */ - ld->ld_sizelimit = MAIL500_MAXGROUPMEMBERS; - for ( i = 0; base[i].b_dn != NULL; i++ ) { - /* find entries that have joined this group... */ - rc = ldap_search_st( ld, base[i].b_dn, - LDAP_SCOPE_SUBTREE, filter, attrs, 0, &timeout, - &res ); - - if ( rc == LDAP_SIZELIMIT_EXCEEDED || - rc == LDAP_TIMELIMIT_EXCEEDED ) { - syslog( LOG_ALERT, - "group search limit exceeded %d", rc ); - unbind_and_exit( EX_TEMPFAIL ); - } - - if ( rc != LDAP_SUCCESS ) { - syslog( LOG_ALERT, "group search return 0x%x", - rc ); - unbind_and_exit( EX_TEMPFAIL ); - } - - /* for each entry that has joined... */ - for ( ee = ldap_first_entry( ld, res ); ee != NULL; - ee = ldap_next_entry( ld, ee ) ) { - anymembers = 1; - if ( isgroup( ee ) ) { - ndn = ldap_get_dn( ld, ee ); - - if ( do_group( e, ndn, to, nto, - togroups, ngroups, err, nerr ) - == -1 ) { - syslog( LOG_ALERT, - "group loop (%s) (%s)", - dn, ndn ); - } - - free( ndn ); - - continue; - } - - /* add them to the to list */ - if ( (mail = ldap_get_values( ld, ee, "mail" )) - != NULL ) { - add_to( to, nto, mail ); - - ldap_value_free( mail ); - - /* else generate a bounce */ - } else { - ndn = ldap_get_dn( ld, ee ); - - add_error( err, nerr, - E_JOINMEMBERNOEMAIL, ndn, NULLMSG ); - - free( ndn ); - } - } - - ldap_msgfree( res ); - } - ld->ld_sizelimit = MAIL500_MAXAMBIGUOUS; - } - - if ( ! anymembers ) { - add_error( err, nerr, E_NOMEMBERS, dn, NULLMSG ); - } - - return; -} - -add_member( gdn, dn, to, nto, togroups, ngroups, err, nerr, suppress ) - char *gdn; - char *dn; - char ***to; - int *nto; - Group **togroups; - int *ngroups; - Error **err; - int *nerr; - char **suppress; -{ - char *ndn; - char **mail; - int i, rc; - LDAPMessage *res, *e; - struct timeval timeout; - - timeout.tv_sec = MAIL500_TIMEOUT; - timeout.tv_usec = 0; - if ( (rc = ldap_search_st( ld, dn, LDAP_SCOPE_BASE, "(objectclass=*)", - attrs, 0, &timeout, &res )) != LDAP_SUCCESS ) { - if ( rc == LDAP_NO_SUCH_OBJECT ) { - add_error( err, nerr, E_BADMEMBER, dn, NULLMSG ); - - return; - } else { - syslog( LOG_ALERT, "member search return 0x%x", rc ); - - unbind_and_exit( EX_TEMPFAIL ); - } - } - - if ( (e = ldap_first_entry( ld, res )) == NULL ) { - syslog( LOG_ALERT, "member search error parsing entry" ); - - unbind_and_exit( EX_TEMPFAIL ); - } - ndn = ldap_get_dn( ld, e ); - - /* allow groups within groups */ - if ( isgroup( e ) ) { - if ( do_group( e, ndn, to, nto, togroups, ngroups, err, nerr ) - == -1 ) { - syslog( LOG_ALERT, "group loop (%s) (%s)", gdn, ndn ); - } - - free( ndn ); - - return; - } - - /* send to the member's mail attribute */ - if ( (mail = ldap_get_values( ld, e, "mail" )) != NULL ) { - add_to( to, nto, mail ); - - ldap_value_free( mail ); - - /* else generate a bounce */ - } else { - if ( suppress == NULL || strcasecmp( suppress[0], "FALSE" ) - == 0 ) { - add_error( err, nerr, E_MEMBERNOEMAIL, ndn, NULLMSG ); - } - } - - free( ndn ); - - return; -} - -do_group_request( e, dn, to, nto, err, nerr ) - LDAPMessage *e; - char *dn; - char ***to; - int *nto; - Error **err; - int *nerr; -{ - char **requeststo; - - if ( (requeststo = get_attributes_mail_dn( e, "rfc822RequestsTo", - "requestsTo" )) != NULL ) { - add_to( to, nto, requeststo ); - - ldap_value_free( requeststo ); - } else { - add_error( err, nerr, E_NOREQUEST, dn, NULLMSG ); - } - - return; -} - -do_group_errors( e, dn, to, nto, err, nerr ) - LDAPMessage *e; - char *dn; - char ***to; - int *nto; - Error **err; - int *nerr; -{ - char **errorsto; - - if ( (errorsto = get_attributes_mail_dn( e, "rfc822ErrorsTo", - "errorsTo" )) != NULL ) { - add_to( to, nto, errorsto ); - - ldap_value_free( errorsto ); - } else { - add_error( err, nerr, E_NOERRORS, dn, NULLMSG ); - } - - return; -} - -do_group_owner( e, dn, to, nto, err, nerr ) - LDAPMessage *e; - char *dn; - char ***to; - int *nto; - Error **err; - int *nerr; -{ - char **owner; - - if ( (owner = get_attributes_mail_dn( e, "", "owner" )) != NULL ) { - add_to( to, nto, owner ); - ldap_value_free( owner ); - } else { - add_error( err, nerr, E_NOOWNER, dn, NULLMSG ); - } - return; -} - -static -send_message( to ) - char **to; -{ - int pid; -#ifndef USE_WAITPID - WAITSTATUSTYPE status; -#endif - - if ( debug ) { - char buf[1024]; - int i; - - strcpy( buf, to[0] ); - for ( i = 1; to[i] != NULL; i++ ) { - strcat( buf, " " ); - strcat( buf, to[i] ); - } - - syslog( LOG_ALERT, "send_message execing sendmail: (%s)", buf ); - } - - /* parent */ - if ( pid = fork() ) { -#ifdef USE_WAITPID - waitpid( pid, (int *) NULL, 0 ); -#else - wait4( pid, &status, WAIT_FLAGS, 0 ); -#endif - /* child */ - } else { - /* to includes sendmailargs */ - execv( MAIL500_SENDMAIL, to ); - - syslog( LOG_ALERT, "execv failed" ); - - exit( EX_TEMPFAIL ); - } -} - -static -send_group( group, ngroup ) - Group *group; - int ngroup; -{ - int i, pid; - char **argv; - int argc; - char *iargv[7]; -#ifndef USE_WAITPID - WAITSTATUSTYPE status; -#endif - - for ( i = 0; i < ngroup; i++ ) { - (void) rewind( stdin ); - - iargv[0] = MAIL500_SENDMAIL; - iargv[1] = "-f"; - iargv[2] = group[i].g_errorsto; - iargv[3] = "-oMrX.500"; - iargv[4] = "-odi"; - iargv[5] = "-oi"; - iargv[6] = NULL; - - argv = NULL; - argc = 0; - add_to( &argv, &argc, iargv ); - add_to( &argv, &argc, group[i].g_members ); - - if ( debug ) { - char buf[1024]; - int i; - - strcpy( buf, argv[0] ); - for ( i = 1; i < argc; i++ ) { - strcat( buf, " " ); - strcat( buf, argv[i] ); - } - - syslog( LOG_ALERT, "execing sendmail: (%s)", buf ); - } - - /* parent */ - if ( pid = fork() ) { -#ifdef USE_WAITPID - waitpid( pid, (int *) NULL, 0 ); -#else - wait4( pid, &status, WAIT_FLAGS, 0 ); -#endif - /* child */ - } else { - execv( MAIL500_SENDMAIL, argv ); - - syslog( LOG_ALERT, "execv failed" ); - - exit( EX_TEMPFAIL ); - } - } - - return; -} - -static -send_errors( err, nerr ) - Error *err; - int nerr; -{ - int pid, i, namelen; - FILE *fp; - int fd[2]; - char *argv[8]; - char buf[1024]; -#ifndef USE_WAITPID - WAITSTATUSTYPE status; -#endif - - argv[0] = MAIL500_SENDMAIL; - argv[1] = "-oMrX.500"; - argv[2] = "-odi"; - argv[3] = "-oi"; - argv[4] = "-f"; - argv[5] = errorsfrom; - argv[6] = mailfrom; - argv[7] = NULL; - - if ( debug ) { - int i; - - strcpy( buf, argv[0] ); - for ( i = 1; argv[i] != NULL; i++ ) { - strcat( buf, " " ); - strcat( buf, argv[i] ); - } - - syslog( LOG_ALERT, "execing sendmail: (%s)", buf ); - } - - if ( pipe( fd ) == -1 ) { - syslog( LOG_ALERT, "cannot create pipe" ); - exit( EX_TEMPFAIL ); - } - - if ( pid = fork() ) { - if ( (fp = fdopen( fd[1], "w" )) == NULL ) { - syslog( LOG_ALERT, "cannot fdopen pipe" ); - exit( EX_TEMPFAIL ); - } - - fprintf( fp, "To: %s\n", mailfrom ); - fprintf( fp, "From: %s\n", errorsfrom ); - fprintf( fp, "Subject: undeliverable mail\n" ); - fprintf( fp, "\n" ); - fprintf( fp, "The following errors occurred when trying to deliver the attached mail:\n" ); - for ( i = 0; i < nerr; i++ ) { - namelen = strlen( err[i].e_addr ); - fprintf( fp, "\n" ); - - switch ( err[i].e_code ) { - case E_USERUNKNOWN: - fprintf( fp, "%s: User unknown\n", err[i].e_addr ); - break; - - case E_GROUPUNKNOWN: - fprintf( fp, "%s: Group unknown\n", err[i].e_addr ); - break; - - case E_BADMEMBER: - fprintf( fp, "%s: Group member does not exist\n", - err[i].e_addr ); - fprintf( fp, "This could be because the distinguished name of the person has changed\n" ); - fprintf( fp, "If this is the case, the problem can be solved by removing and\n" ); - fprintf( fp, "then re-adding the person to the group.\n" ); - break; - - case E_NOREQUEST: - fprintf( fp, "%s: Group exists but has no request address\n", - err[i].e_addr ); - break; - - case E_NOERRORS: - fprintf( fp, "%s: Group exists but has no errors-to address\n", - err[i].e_addr ); - break; - - case E_NOOWNER: - fprintf( fp, "%s: Group exists but has no owner\n", - err[i].e_addr ); - break; - - case E_AMBIGUOUS: - do_ambiguous( fp, &err[i], namelen ); - break; - - case E_NOEMAIL: - do_noemail( fp, &err[i], namelen ); - break; - - case E_MEMBERNOEMAIL: - fprintf( fp, "%s: Group member exists but does not have an email address\n", - err[i].e_addr ); - break; - - case E_JOINMEMBERNOEMAIL: - fprintf( fp, "%s: User has joined group but does not have an email address\n", - err[i].e_addr ); - break; - - case E_LOOP: - fprintf( fp, "%s: User has created a mail loop by adding address %s to their X.500 entry\n", - err[i].e_addr, err[i].e_loop ); - break; - - case E_NOMEMBERS: - fprintf( fp, "%s: Group has no members\n", - err[i].e_addr ); - break; - - default: - syslog( LOG_ALERT, "unknown error %d", err[i].e_code ); - unbind_and_exit( EX_TEMPFAIL ); - break; - } - } - - fprintf( fp, "\n------- The original message sent:\n\n" ); - - while ( fgets( buf, sizeof(buf), stdin ) != NULL ) { - fputs( buf, fp ); - } - fclose( fp ); - -#ifdef USE_WAITPID - waitpid( pid, (int *) NULL, 0 ); -#else - wait4( pid, &status, WAIT_FLAGS, 0 ); -#endif - } else { - dup2( fd[0], 0 ); - - execv( MAIL500_SENDMAIL, argv ); - - syslog( LOG_ALERT, "execv failed" ); - - exit( EX_TEMPFAIL ); - } - - return; -} - -static -do_noemail( fp, err, namelen ) - FILE *fp; - Error *err; - int namelen; -{ - int i, last; - char *dn, *rdn; - char **ufn, **vals; - - fprintf(fp, "%s: User has no email address registered.\n", - err->e_addr ); - fprintf( fp, "%*s Name, title, postal address and phone for '%s':\n\n", - namelen, " ", err->e_addr ); - - /* name */ - dn = ldap_get_dn( ld, err->e_msg ); - ufn = ldap_explode_dn( dn, 1 ); - rdn = strdup( ufn[0] ); - if ( strcasecmp( rdn, err->e_addr ) == 0 ) { - if ( (vals = ldap_get_values( ld, err->e_msg, "cn" )) - != NULL ) { - for ( i = 0; vals[i]; i++ ) { - last = strlen( vals[i] ) - 1; - if ( isdigit( vals[i][last] ) ) { - rdn = strdup( vals[i] ); - break; - } - } - - ldap_value_free( vals ); - } - } - fprintf( fp, "%*s %s\n", namelen, " ", rdn ); - free( dn ); - free( rdn ); - ldap_value_free( ufn ); - - /* titles or descriptions */ - if ( (vals = ldap_get_values( ld, err->e_msg, "title" )) == NULL && - (vals = ldap_get_values( ld, err->e_msg, "description" )) - == NULL ) { - fprintf( fp, "%*s No title or description registered\n", - namelen, " " ); - } else { - for ( i = 0; vals[i] != NULL; i++ ) { - fprintf( fp, "%*s %s\n", namelen, " ", vals[i] ); - } - - ldap_value_free( vals ); - } - - /* postal address */ - if ( (vals = ldap_get_values( ld, err->e_msg, "postalAddress" )) - == NULL ) { - fprintf( fp, "%*s No postal address registered\n", namelen, - " " ); - } else { - fprintf( fp, "%*s ", namelen, " " ); - for ( i = 0; vals[0][i] != '\0'; i++ ) { - if ( vals[0][i] == '$' ) { - fprintf( fp, "\n%*s ", namelen, " " ); - while ( isspace( vals[0][i+1] ) ) - i++; - } else { - fprintf( fp, "%c", vals[0][i] ); - } - } - fprintf( fp, "\n" ); - - ldap_value_free( vals ); - } - - /* telephone number */ - if ( (vals = ldap_get_values( ld, err->e_msg, "telephoneNumber" )) - == NULL ) { - fprintf( fp, "%*s No phone number registered\n", namelen, - " " ); - } else { - for ( i = 0; vals[i] != NULL; i++ ) { - fprintf( fp, "%*s %s\n", namelen, " ", vals[i] ); - } - - ldap_value_free( vals ); - } -} - -/* ARGSUSED */ -static -do_ambiguous( fp, err, namelen ) - FILE *fp; - Error *err; - int namelen; -{ - int i, last; - char *dn, *rdn; - char **ufn, **vals; - LDAPMessage *e; - - i = ldap_result2error( ld, err->e_msg, 0 ); - - fprintf( fp, "%s: Ambiguous user. %s%d matches found:\n\n", - err->e_addr, i == LDAP_SIZELIMIT_EXCEEDED ? "First " : "", - ldap_count_entries( ld, err->e_msg ) ); - - for ( e = ldap_first_entry( ld, err->e_msg ); e != NULL; - e = ldap_next_entry( ld, e ) ) { - dn = ldap_get_dn( ld, e ); - ufn = ldap_explode_dn( dn, 1 ); - rdn = strdup( ufn[0] ); - if ( strcasecmp( rdn, err->e_addr ) == 0 ) { - if ( (vals = ldap_get_values( ld, e, "cn" )) != NULL ) { - for ( i = 0; vals[i]; i++ ) { - last = strlen( vals[i] ) - 1; - if ( isdigit( vals[i][last] ) ) { - rdn = strdup( vals[i] ); - break; - } - } - - ldap_value_free( vals ); - } - } - - if ( isgroup( e ) ) { - vals = ldap_get_values( ld, e, "description" ); - } else { - vals = ldap_get_values( ld, e, "title" ); - } - - fprintf( fp, " %-20s %s\n", rdn, vals ? vals[0] : "" ); - for ( i = 1; vals && vals[i] != NULL; i++ ) { - fprintf( fp, " %s\n", vals[i] ); - } - - free( dn ); - free( rdn ); - ldap_value_free( ufn ); - if ( vals != NULL ) - ldap_value_free( vals ); - } -} - -static -count_values( list ) - char **list; -{ - int i; - - for ( i = 0; list && list[i] != NULL; i++ ) - ; /* NULL */ - - return( i ); -} - -static -add_to( list, nlist, new ) - char ***list; - int *nlist; - char **new; -{ - int i, nnew, oldnlist; - - nnew = count_values( new ); - - oldnlist = *nlist; - if ( *list == NULL || *nlist == 0 ) { - *list = (char **) malloc( (nnew + 1) * sizeof(char *) ); - *nlist = nnew; - } else { - *list = (char **) realloc( *list, *nlist * sizeof(char *) + - nnew * sizeof(char *) + sizeof(char *) ); - *nlist += nnew; - } - - for ( i = 0; i < nnew; i++ ) - (*list)[i + oldnlist] = strdup( new[i] ); - (*list)[*nlist] = NULL; - - return; -} - -static -isgroup( e ) - LDAPMessage *e; -{ - int i; - char **oclist; - - oclist = ldap_get_values( ld, e, "objectClass" ); - - for ( i = 0; oclist[i] != NULL; i++ ) { - if ( strcasecmp( oclist[i], "rfc822MailGroup" ) == 0 ) { - ldap_value_free( oclist ); - return( 1 ); - } - } - ldap_value_free( oclist ); - - return( 0 ); -} - -static -add_error( err, nerr, code, addr, msg ) - Error **err; - int *nerr; - int code; - char *addr; - LDAPMessage *msg; -{ - if ( *nerr == 0 ) { - *err = (Error *) malloc( sizeof(Error) ); - } else { - *err = (Error *) realloc( *err, (*nerr + 1) * sizeof(Error) ); - } - - (*err)[*nerr].e_code = code; - (*err)[*nerr].e_addr = strdup( addr ); - (*err)[*nerr].e_msg = msg; - (*nerr)++; - - return; -} - -static -add_group( dn, list, nlist ) - char *dn; - Group **list; - int *nlist; -{ - int i, namelen; - char **ufn; - - for ( i = 0; i < *nlist; i++ ) { - if ( strcmp( dn, (*list)[i].g_dn ) == 0 ) { - syslog( LOG_ALERT, "group loop 2 detected (%s)", dn ); - return; - } - } - - ufn = ldap_explode_dn( dn, 1 ); - namelen = strlen( ufn[0] ); - - if ( *nlist == 0 ) { - *list = (Group *) malloc( sizeof(Group) ); - } else { - *list = (Group *) realloc( *list, (*nlist + 1) * - sizeof(Group) ); - } - - /* send errors to groupname-errors@host */ - (*list)[*nlist].g_errorsto = (char *) malloc( namelen + sizeof(ERRORS) - + hostlen + 2 ); - sprintf( (*list)[*nlist].g_errorsto, "%s-%s@%s", ufn[0], ERRORS, host ); - (void) canonical( (*list)[*nlist].g_errorsto ); - - /* send to groupname-members@host - make it a list for send_group */ - (*list)[*nlist].g_members = (char **) malloc( 2 * sizeof(char *) ); - (*list)[*nlist].g_members[0] = (char *) malloc( namelen + - sizeof(MEMBERS) + hostlen + 2 ); - sprintf( (*list)[*nlist].g_members[0], "%s-%s@%s", ufn[0], MEMBERS, - host ); - (void) canonical( (*list)[*nlist].g_members[0] ); - (*list)[*nlist].g_members[1] = NULL; - - /* save the group's dn so we can check for loops above */ - (*list)[*nlist].g_dn = strdup( dn ); - - (*nlist)++; - - ldap_value_free( ufn ); - - return; -} - -static -unbind_and_exit( rc ) - int rc; -{ - int i; - - if ( (i = ldap_unbind( ld )) != LDAP_SUCCESS ) - syslog( LOG_ALERT, "ldap_unbind failed %d\n", i ); - - exit( rc ); -} - -static char * -canonical( s ) - char *s; -{ - char *saves = s; - - for ( ; *s != '\0'; s++ ) { - if ( *s == ' ' ) - *s = '.'; - } - - return( saves ); -} - -static -group_loop( dn ) - char *dn; -{ - int i; - static char **groups; - static int ngroups; - - for ( i = 0; i < ngroups; i++ ) { - if ( strcmp( dn, groups[i] ) == 0 ) - return( 1 ); - } - - if ( ngroups == 0 ) - groups = (char **) malloc( sizeof(char *) ); - else - groups = (char **) realloc( groups, - (ngroups + 1) * sizeof(char *) ); - - groups[ngroups++] = strdup( dn ); - - return( 0 ); -} - -static -has_attributes( e, attr1, attr2 ) - LDAPMessage *e; - char *attr1; - char *attr2; -{ - char **attr; - - if ( (attr = ldap_get_values( ld, e, attr1 )) != NULL ) { - ldap_value_free( attr ); - return( 1 ); - } - - if ( (attr = ldap_get_values( ld, e, attr2 )) != NULL ) { - ldap_value_free( attr ); - return( 1 ); - } - - return( 0 ); -} - -static char ** -get_attributes_mail_dn( e, attr1, attr2 ) - LDAPMessage *e; - char *attr1; - char *attr2; /* this one is dn-valued */ -{ - LDAPMessage *ee, *res; - char **vals, **dnlist, **mail, **grname, **graddr; - char *dn; - int nto = 0, i, rc; - struct timeval timeout; - - dn = ldap_get_dn( ld, e ); - - vals = ldap_get_values( ld, e, attr1 ); - for ( nto = 0; vals != NULL && vals[nto] != NULL; nto++ ) - ; /* NULL */ - - if ( (dnlist = ldap_get_values( ld, e, attr2 )) != NULL ) { - timeout.tv_sec = MAIL500_TIMEOUT; - timeout.tv_usec = 0; - - for ( i = 0; dnlist[i] != NULL; i++ ) { - if ( (rc = ldap_search_st( ld, dnlist[i], - LDAP_SCOPE_BASE, "(objectclass=*)", attrs, 0, - &timeout, &res )) != LDAP_SUCCESS ) { - if ( rc != LDAP_NO_SUCH_OBJECT ) { - unbind_and_exit( EX_TEMPFAIL ); - } - - syslog( LOG_ALERT, "bad (%s) dn (%s)", attr2, - dnlist[i] ); - - continue; - } - - if ( (ee = ldap_first_entry( ld, res )) == NULL ) { - syslog( LOG_ALERT, "error parsing x500 entry" ); - continue; - } - - if ( isgroup(ee) ) { - char *graddr[2]; - - grname = ldap_explode_dn( dnlist[i], 1 ); - - /* groupname + host + @ + null */ - graddr[0] = (char *) malloc( strlen( grname[0] ) - + strlen( host ) + 2 ); - graddr[1] = NULL; - sprintf( graddr[0], "%s@%s", grname[0], host); - (void) canonical( graddr[0] ); - - add_to( &vals, &nto, graddr ); - - free( graddr[0] ); - ldap_value_free( grname ); - } else if ( (mail = ldap_get_values( ld, ee, "mail" )) - != NULL ) { - add_to( &vals, &nto, mail ); - - ldap_value_free( mail ); - } - - ldap_msgfree( res ); - } - } - - return( vals ); -} diff --git a/clients/mail500/sendmail.cf b/clients/mail500/sendmail.cf deleted file mode 100644 index b7ec14d1ce..0000000000 --- a/clients/mail500/sendmail.cf +++ /dev/null @@ -1,203 +0,0 @@ -# Mostly rfc1123 compliant sendmail.cf -# -# Mail sendmail-admins-request@itd.umich.edu to join -# sendmail-admins@itd.umich.edu. sendmail-admins carries information -# regarding this sendmail.cf, including announcements of changes -# and discussions of interest to admins. -# -DWtotalrecall -Dw$W.rs.itd.umich.edu - -DBcunyvm.cuny.edu -DUdestroyer.rs.itd.umich.edu - -DV2.2 -De$j sendmail ($v/$V) ready at $b -Dj$w -DlFrom $g $d -Dnmailer-daemon -Do.:%@!^=/[] -Dq$?x\"$x\" <$g>$|$g$. - -OA/etc/aliases -OQ/var/spool/mqueue -OH/usr/lib/sendmail.hf -OS/usr/lib/sendmail.st -OP -OD -OX10 -Ox5 -Ou1 -Og1 -Odb -OF0600 -OL9 -Oo -Or15m -Os -OT3d - -H?P?Return-Path: <$g> -HReceived: $?sfrom $s $.by $j ($v/$V) - $?rwith $r $.id $i; $b -H?D?Resent-Date: $a -H?F?Resent-From: $q -H?M?Resent-Message-Id: <$t.$i@$j> -H?M?Message-Id: <$t.$i@$j> -H?D?Date: $a -H?x?Full-Name: $x -H?F?From: $q - -Troot uucp daemon - -Pspecial-delivery=100 -Pfirst-class=0 -Pjunk=-100 - -# Organization: -# -# ruleset 3 and friends -# focus addresses, don't screw with them -# ruleset 0 and friends -# beat the hell out of addresses, convert them to -# their deliverable form -# mailers and associated rulesets -# * focused addresses are body addresses, and should be -# left as they are -# * unfocused addresses are envelope addresses, and should -# be converted to the mailers format -# ruleset 4 -# remove focus on all addresses - -# All addresses are passed through this rule. It functions by finding -# the host to delivery to, and marking it with <> -S3 -R$*<$+>$* $2 remove comments -R$+:$*; $@ $1:$2; done if list -R$*@$+ $: $>5$1@$2 focus rfc822 addresses -R$+!$+ $: $>6$1!$2 focus uucp -R$*<@$+>$* $: $1<@$[$2$]>$3 canonicalize -R$*<$+>$* $@ $1<$2>$3 done if focused -R$+%$+ $: $1@$2 a%b -> a@b -R$+@$+%$+ $1%$2@$3 a@b%c -> a%b@c -R$+@$+ $: $>3$1@$2 try again... - -# Find the "next hop" in normal rfc822 syntax. These rules -# all return upon marking the next hop with <> -S5 -R@$+,@$+:$+ $@ <@$1>,@$2:$3 @a,@b:@c -> <@a>,@b:c -R@$+:$+ $@ <@$1>:$2 @a:b -> <@a>:b -R$+@$+ $@ $1<@$2> a@b -> a<@b> - -# Focus bang style addresses. Won't change already focused addresses. -# Strips .uucp in bang paths, and converts domain syntax to rfc822 adresses. -S6 -R$*<$+>$* $@ $1<$2>$3 already focused -R$+!$+ $: <$1!>$2 a!b -> b -R<$+.uucp!>$+ <$1!>$2 b -> b - -# Find a mailer. This involves finding the "real" host to deliver to, -# by removing our local name, and/or doing a "domain forward" -S0 -R$+ $: $>7$1 deliverable format -R$*<$+>$* $: $>11$1<$2>$3 domain forward -R<$+!>$+ $: $>12<$1!>$2 route uucp -R$*<@$+.bitnet>$* $#inet$@$B$:$1<@$2.bitnet>$3 -R$*<@umich.edu>$* $#mail500$@umich.edu$:<$1> -R$*<@itd.umich.edu>$* $#mail500$@itd.umich.edu$:<$1> -#R<$+!>$+ $#uux$@$U$:<$1!>$2 -R<$+!>$+ $#unet$@$U$:<$1!>$2 -R$*<@$+>$* $#inet$@$2$:$1<@$2>$3 -R$+ $#local$:$1 - -# Find the delivery address. Convert to standard-internal form, -# remove local name. -S7 -R<$-.$+!>$+ $3<@$1.$2> c -> c<@a.b> -R$*<@$-.uucp>$* $>8$1@$2.uucp$3 *.uucp to ! -R$*<$+>$* $: $>9$1<$2>$3 strip local name - -# Convert rfc822 syntax to a uucp "bang path". This works well -# on normal a@b address and route-addrs. It will also do something -# to list syntax address, but it's not clear how correct it is. -S8 -R@$+,@$+:$+ @$1!$2:$3 @a,@b:c -> @a!b:c -R@$+:$+@$+ $1!$3!$2 @a:b@c -> a!c!b -R@$+:$+!$+ $1!$2!$3 @a:b!c -> a!b!c -R$+@$+ $2!$1 a@b -> b!c -R$+ $: $>3$1 refocus - -# Remove local names. You won't see things like a.b!u or u@b.uucp. -# Add new rules here to accept more than just the default locally. -S9 -R$*<@$w>$* $>10$1<@>$2 remove local name -R<$W!>$+ $>10$1 -R<@umich.edu>$*:$* $>10<@>$1:$2 -R$+%$+<@umich.edu> $>10$1%$2<@> -R$+!$+<@umich.edu> $>10$1!$2<@> - -# Called only from above. Refocus and loop. -S10 -R<@>,$+ $>3$1 -R<@>:$+ $>3$1 -R$+<@> $>3$1 -R$+ $>3$1 -R$*<$+>$* $: $>7$1<$2>$3 - -# Convert domain names to uucp names, and refocus -S11 -#R$*<@inquiry.org>$* $: $>8$1@inquiry$2 - -# Route uucp addresses, if we're not connected to them. We rely on the -# domain-path operator to down case addresses. -S12 -R<$+!>$+ $: <${$1$}!>$2 pathalias route -R<$+!$+!>$+ <$1!>$2!$3 c -> b!c - -Muux, P=/usr/bin/uux, F=DFMhu, S=13, R=14, - A=uux - -gC -b -r -a$f $h!rmail ($u) -Munet, P=[IPC], F=mDFMhuX, S=13, R=14, A=IPC $h, E=\r\n -Minet, P=[IPC], F=mDFMuX, S=15, R=15, A=IPC $h, E=\r\n -Mlocal, P=/bin/mail, F=rlsDFMmn, S=16, R=16, A=mail -d $u -Mprog, P=/bin/sh, F=lsDFMe, S=16, R=16, A=sh -c $u -Mmail500, P=/usr/local/etc/mail500, F=DFMSmnXuh, - A=mail500 -f $f -h $h -m $n@$w $u - -# UUCP mailers require that the sender be in ! format. -# XXX Do we add our name to other people's paths? -S13 -R$*<@$+>$* $: $>8$1@$2$3 -#R<$w!>$+ $@ <$W!>$1 -R<$+!>$+ $@ <$1!>$2 -R$+:$*; $@ $1:$2; -R<> $@ -#R$+ $@ <$W!>$1 -R$+ $@ <$w!>$1 - -# Only add our name to local mail. Anything that's focused, leave alone. -S14 -R$*<$+>$* $@ $1<$2>$3 -R$+:$*; $@ $1:$2; -#R$+ $@ <$W!>$1 -R$+ $@ <$w!>$1 - -# SMTP mailers require that addresses be in rfc822 format. If there's no -# @ in the address, add one. -S15 -R<$W!>$+ $1<@$w> -R<$-.$+!>$+ $3<@$1.$2> -R$*<@$+>$* $@ $1<@$2>$3 -R<$+!>$+ $@ $1!$2<@$w> -R$+:$*; $@ $1:$2; -R<> $@ -R$+ $@ $1<@$w> - -# Local and prog mailer -S16 -R$+ $@ $1 - -# -# Called on all outgoing addresses. Used to remove the <> focus -# -S4 -R$*<$+>$* $@ $1$2$3 defocus diff --git a/clients/maildap/main.c b/clients/maildap/main.c deleted file mode 100644 index 345c8f4256..0000000000 --- a/clients/maildap/main.c +++ /dev/null @@ -1,2074 +0,0 @@ -/* $OpenLDAP$ */ -/* - * Copyright (c) 1990 Regents of the University of Michigan. - * All rights reserved. - * - * Redistribution and use in source and binary forms are permitted - * provided that this notice is preserved and that due credit is given - * to the University of Michigan at Ann Arbor. The name of the University - * may not be used to endorse or promote products derived from this - * software without specific prior written permission. This software - * is provided ``as is'' without express or implied warranty. - * - * Copyright 1998-2002 The OpenLDAP Foundation - * COPYING RESTRICTIONS APPLY. See COPYRIGHT File in top level directory - * of this package for details. - */ - -#include "portable.h" - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#ifdef HAVE_SYS_RESOURCE_H -#include -#endif - -#include - -#include "ldap_defaults.h" - -#ifndef MAIL500_BOUNCEFROM -#define MAIL500_BOUNCEFROM "<>" -#endif - -#define USER 0x01 -#define GROUP_ERRORS 0x02 -#define GROUP_REQUEST 0x04 -#define GROUP_MEMBERS 0x08 -#define GROUP_OWNER 0x10 - -#define ERROR "error" -#define ERRORS "errors" -#define REQUEST "request" -#define REQUESTS "requests" -#define MEMBERS "members" -#define OWNER "owner" -#define OWNERS "owners" - -LDAP *ld; -char *vacationhost = NULL; -char *errorsfrom = MAIL500_BOUNCEFROM; -char *mailfrom = NULL; -char *host = NULL; -char *ldaphost = NULL; -int hostlen = 0; -int debug; - -typedef struct errs { - int e_code; -#define E_USERUNKNOWN 1 -#define E_AMBIGUOUS 2 -#define E_NOEMAIL 3 -#define E_NOREQUEST 4 -#define E_NOERRORS 5 -#define E_BADMEMBER 6 -#define E_JOINMEMBERNOEMAIL 7 -#define E_MEMBERNOEMAIL 8 -#define E_LOOP 9 -#define E_NOMEMBERS 10 -#define E_NOOWNER 11 -#define E_GROUPUNKNOWN 12 -#define E_NOOWNADDRESS 13 - char *e_addr; - union e_union_u { - char *e_u_loop; - LDAPMessage *e_u_msg; - } e_union; -#define e_msg e_union.e_u_msg -#define e_loop e_union.e_u_loop -} Error; - -typedef struct groupto { - char *g_dn; - char *g_errorsto; - char **g_members; - int g_nmembers; -} Group; - -typedef struct baseinfo { - char *b_url; - int b_m_entries; - char b_rdnpref; /* give rdn's preference when searching? */ - int b_search; /* ORed with the type of thing the address */ - /* looks like (USER, GROUP_ERRORS, etc.) */ - /* to see if this should be searched */ -} Base; - -Base **base = NULL; - -char *sendmailargs[] = { MAIL500_SENDMAIL, "-oMrLDAP", "-odi", "-oi", "-f", NULL, NULL }; - -typedef struct attr_semantics { - char *as_name; - int as_m_valued; /* Is multivalued? */ - int as_priority; /* Priority level of this attribut type */ - int as_syntax; /* How to interpret values */ - int as_m_entries; /* Can resolve to several entries? */ - int as_kind; /* Recipient, sender, etc. */ - char *as_param; /* Extra info for filters and things alike */ -} AttrSemantics; - -#define AS_SYNTAX_UNKNOWN 0 -#define AS_SYNTAX_NATIVE_MB 1 /* Unqualified mailbox name */ -#define AS_SYNTAX_RFC822 2 /* RFC822 mail address */ -#define AS_SYNTAX_HOST 3 -#define AS_SYNTAX_DN 4 /* A directory entry */ -#define AS_SYNTAX_RFC822_EXT 5 -#define AS_SYNTAX_URL 6 /* mailto: or ldap: URL */ -#define AS_SYNTAX_BOOL_FILTER 7 /* For joinable, filter in as_param */ -#define AS_SYNTAX_PRESENT 8 /* Value irrelevant, only presence is - * considered. */ - -#define AS_KIND_UNKNOWN 0 -#define AS_KIND_RECIPIENT 1 -#define AS_KIND_ERRORS 2 /* For ErrorsTo and similar */ -#define AS_KIND_REQUEST 3 -#define AS_KIND_OWNER 4 -#define AS_KIND_ROUTE_TO_HOST 5 /* Expand at some other host */ -#define AS_KIND_ALLOWED_SENDER 6 /* Can send to group */ -#define AS_KIND_MODERATOR 7 -#define AS_KIND_ROUTE_TO_ADDR 8 /* Rewrite recipient address as */ -#define AS_KIND_OWN_ADDR 9 /* RFC822 name of this entry */ -#define AS_KIND_DELIVERY_TYPE 10 /* How to deliver mail to this entry */ - -AttrSemantics **attr_semantics = NULL; -int current_priority = 0; - -typedef struct subst { - char sub_char; - char *sub_value; -} Subst; - -char **groupclasses = NULL; -char **def_attr = NULL; -char **myhosts = NULL; /* FQDNs not to route elsewhere */ -char **mydomains = NULL; /* If an RFC822 address points to one - of these domains, search it in the - directory instead of returning it - to hte MTA */ - -static void load_config( char *filespec ); -static void split_address( char *address, char **localpart, char **domainpart); -static int entry_engine( LDAPMessage *e, char *dn, char *address, char ***to, int *nto, Group ***togroups, int *ngroups, Error **err, int *nerr, int type ); -static void do_address( char *name, char ***to, int *nto, Group ***togroups, int *ngroups, Error **err, int *nerr, int type ); -static void send_message( char **to ); -static void send_errors( Error *err, int nerr ); -static void do_noemail( FILE *fp, Error *err, int namelen ); -static void do_ambiguous( FILE *fp, Error *err, int namelen ); -static int count_values( char **list ); -static void add_to( char ***list, int *nlist, char **new ); -static void add_single_to( char ***list, char *new ); -static int isgroup( LDAPMessage *e ); -static void add_error( Error **err, int *nerr, int code, char *addr, LDAPMessage *msg ); -static void unbind_and_exit( int rc ) LDAP_GCCATTR((noreturn)); -static void send_group( Group **group, int ngroup ); - -static int connect_to_x500( void ); - - -int -main ( int argc, char **argv ) -{ - char *myname; - char **tolist; - Error *errlist; - Group **togroups; - int numto, ngroups, numerr, nargs; - int i, j; - char *conffile = NULL; - - if ( (myname = strrchr( argv[0], *LDAP_DIRSEP )) == NULL ) - myname = strdup( argv[0] ); - else - myname = strdup( myname + 1 ); - -#ifdef SIGPIPE - (void) SIGNAL( SIGPIPE, SIG_IGN ); -#endif - -#ifdef LOG_MAIL - openlog( myname, OPENLOG_OPTIONS, LOG_MAIL ); -#elif LOG_DEBUG - openlog( myname, OPENLOG_OPTIONS ); -#endif - - while ( (i = getopt( argc, argv, "d:C:f:h:l:m:v:" )) != EOF ) { - switch( i ) { - case 'd': /* turn on debugging */ - debug |= atoi( optarg ); - break; - - case 'C': /* path to configuration file */ - conffile = strdup( optarg ); - break; - - case 'f': /* who it's from & where errors should go */ - mailfrom = strdup( optarg ); - /* Deal with <> */ - if ( mailfrom[0] == '\0' ) { - free( mailfrom ); - mailfrom = strdup( "<>" ); - } - for ( j = 0; sendmailargs[j] != NULL; j++ ) { - if ( strcmp( sendmailargs[j], "-f" ) == 0 ) { - sendmailargs[j+1] = mailfrom; - break; - } - } - break; - - case 'h': /* hostname */ - host = strdup( optarg ); - hostlen = strlen(host); - break; - - case 'l': /* ldap host */ - ldaphost = strdup( optarg ); - break; - - /* mailer-daemon address - who we should */ - case 'm': /* say errors come from */ - errorsfrom = strdup( optarg ); - break; - - case 'v': /* vacation host */ - vacationhost = strdup( optarg ); - break; - - default: - syslog( LOG_ALERT, "unknown option" ); - break; - } - } - - if ( mailfrom == NULL ) { - syslog( LOG_ALERT, "required argument -f not present" ); - exit( EX_TEMPFAIL ); - } - if ( errorsfrom == NULL ) { - syslog( LOG_ALERT, "required argument -m not present" ); - exit( EX_TEMPFAIL ); - } -/* if ( host == NULL ) { */ -/* syslog( LOG_ALERT, "required argument -h not present" ); */ -/* exit( EX_TEMPFAIL ); */ -/* } */ - if ( conffile == NULL ) { - syslog( LOG_ALERT, "required argument -C not present" ); - exit( EX_TEMPFAIL ); - } - - load_config( conffile ); - - if ( connect_to_x500() != 0 ) - exit( EX_TEMPFAIL ); - - setuid( geteuid() ); - - if ( debug ) { - char buf[1024]; - int i; - - syslog( LOG_ALERT, "running as %d", geteuid() ); - strcpy( buf, argv[0] ); - for ( i = 1; i < argc; i++ ) { - strcat( buf, " " ); - strcat( buf, argv[i] ); - } - - syslog( LOG_ALERT, "args: (%s)", buf ); - } - - tolist = NULL; - numto = 0; - add_to( &tolist, &numto, sendmailargs ); - nargs = numto; - ngroups = numerr = 0; - togroups = NULL; - errlist = NULL; - for ( i = optind; i < argc; i++ ) { - char *s; - int type; - char *localpart = NULL, *domainpart = NULL; - char address[1024]; - - type = USER; - split_address( argv[i], &localpart, &domainpart ); - if ( (s = strrchr( localpart, '-' )) != NULL ) { - s++; - - if ((strcasecmp(s, ERROR) == 0) || - (strcasecmp(s, ERRORS) == 0)) { - type = GROUP_ERRORS; - *(--s) = '\0'; - } else if ((strcasecmp(s, REQUEST) == 0) || - (strcasecmp(s, REQUESTS) == 0)) { - type = GROUP_REQUEST; - *(--s) = '\0'; - } else if ( strcasecmp( s, MEMBERS ) == 0 ) { - type = GROUP_MEMBERS; - *(--s) = '\0'; - } else if ((strcasecmp(s, OWNER) == 0) || - (strcasecmp(s, OWNERS) == 0)) { - type = GROUP_OWNER; - *(--s) = '\0'; - } - } - - if ( domainpart ) { - sprintf( address, "%s@%s", localpart, domainpart ); - free( localpart ); - free( domainpart ); - } else { - sprintf( address, "%s", localpart ); - free( localpart ); - } - do_address( address, &tolist, &numto, &togroups, &ngroups, - &errlist, &numerr, type ); - } - - /* - * If we have both errors and successful deliveries to make or if - * if there are any groups to deliver to, we basically need to read - * the message twice. So, we have to put it in a tmp file. - */ - - if ( numerr > 0 && numto > nargs || ngroups > 0 ) { - FILE *fp; - char buf[BUFSIZ]; - - umask( 077 ); - if ( (fp = tmpfile()) == NULL ) { - syslog( LOG_ALERT, "could not open tmp file" ); - unbind_and_exit( EX_TEMPFAIL ); - } - - /* copy the message to a temp file */ - while ( fgets( buf, sizeof(buf), stdin ) != NULL ) { - if ( fputs( buf, fp ) == EOF ) { - syslog( LOG_ALERT, "error writing tmpfile" ); - unbind_and_exit( EX_TEMPFAIL ); - } - } - - if ( dup2( fileno( fp ), 0 ) == -1 ) { - syslog( LOG_ALERT, "could not dup2 tmpfile" ); - unbind_and_exit( EX_TEMPFAIL ); - } - - fclose( fp ); - } - - /* deal with errors */ - if ( numerr > 0 ) { - if ( debug ) { - syslog( LOG_ALERT, "sending errors" ); - } - (void) rewind( stdin ); - send_errors( errlist, numerr ); - } - - (void) ldap_unbind( ld ); - - /* send to groups with errorsTo */ - if ( ngroups > 0 ) { - if ( debug ) { - syslog( LOG_ALERT, "sending to groups with errorsto" ); - } - (void) rewind( stdin ); - send_group( togroups, ngroups ); - } - - /* send to expanded aliases and groups w/o errorsTo */ - if ( numto > nargs ) { - if ( debug ) { - syslog( LOG_ALERT, "sending to aliases and groups" ); - } - (void) rewind( stdin ); - send_message( tolist ); - } - - return( EX_OK ); -} - -static char * -get_config_line( FILE *cf, int *lineno) -{ - static char buf[2048]; - int len; - int pos; - int room; - - pos = 0; - room = sizeof( buf ); - while ( fgets( &buf[pos], room, cf ) ) { - (*lineno)++; - if ( pos > 0 ) { - /* Delete whitespace at the beginning of new data */ - if ( isspace( (unsigned char) buf[pos] ) ) { - char *s, *d; - for ( s = buf+pos; isspace((unsigned char) *s); s++ ) - ; - for ( d = buf+pos; *s; s++, d++ ) { - *d = *s; - } - *d = *s; - } - } - len = strlen( buf ); - if ( buf[len-1] != '\n' ) { - syslog( LOG_ALERT, "Definition too long at line %d", - *lineno ); - exit( EX_TEMPFAIL ); - } - if ( buf[0] == '#' ) - continue; - if ( strspn( buf, " \t\n" ) == len ) - continue; - if ( len >= 2 && buf[len-2] == '\\' ) { - pos = len - 2; - room = sizeof(buf) - pos; - continue; - } - /* We have a real line, we will exit the loop */ - buf[len-1] = '\0'; - return( buf ); - } - return( NULL ); -} - -static void -add_url ( char *url, int rdnpref, int typemask ) -{ - Base **list_temp; - int size; - Base *b; - - b = calloc(1, sizeof(Base)); - if ( !b ) { - syslog( LOG_ALERT, "Out of memory" ); - exit( EX_TEMPFAIL ); - } - b->b_url = strdup( url ); - b->b_rdnpref = rdnpref; - b->b_search = typemask; - - if ( base == NULL ) { - base = calloc(2, sizeof(LDAPURLDesc *)); - if ( !base ) { - syslog( LOG_ALERT, "Out of memory" ); - exit( EX_TEMPFAIL ); - } - base[0] = b; - } else { - for ( size = 0; base[size]; size++ ) - ; - size += 2; - list_temp = realloc( base, size*sizeof(LDAPURLDesc *) ); - if ( !list_temp ) { - syslog( LOG_ALERT, "Out of memory" ); - exit( EX_TEMPFAIL ); - } - base = list_temp; - base[size-2] = b; - base[size-1] = NULL; - } -} - -static void -add_def_attr( char *s ) -{ - char *p, *q; - - p = s; - while ( *p ) { - p += strspn( p, "\t," ); - q = strpbrk( p, " \t," ); - if ( q ) { - *q = '\0'; - add_single_to( &def_attr, p ); - } else { - add_single_to( &def_attr, p ); - break; - } - p = q + 1; - } -} - -static void -add_attr_semantics( char *s ) -{ - char *p, *q; - AttrSemantics *as; - - as = calloc( 1, sizeof( AttrSemantics ) ); - as->as_priority = current_priority; - p = s; - while ( isspace ( (unsigned char) *p ) ) - p++; - q = p; - while ( !isspace ( (unsigned char) *q ) && *q != '\0' ) - q++; - *q = '\0'; - as->as_name = strdup( p ); - p = q + 1; - - while ( *p ) { - while ( isspace ( (unsigned char) *p ) ) - p++; - q = p; - while ( !isspace ( (unsigned char) *q ) && *q != '\0' ) - q++; - *q = '\0'; - if ( !strcasecmp( p, "multivalued" ) ) { - as->as_m_valued = 1; - } else if ( !strcasecmp( p, "multiple-entries" ) ) { - as->as_m_entries = 1; - } else if ( !strcasecmp( p, "local-native-mailbox" ) ) { - as->as_syntax = AS_SYNTAX_NATIVE_MB; - } else if ( !strcasecmp( p, "rfc822" ) ) { - as->as_syntax = AS_SYNTAX_RFC822; - } else if ( !strcasecmp( p, "rfc822-extended" ) ) { - as->as_syntax = AS_SYNTAX_RFC822_EXT; - } else if ( !strcasecmp( p, "dn" ) ) { - as->as_syntax = AS_SYNTAX_DN; - } else if ( !strcasecmp( p, "url" ) ) { - as->as_syntax = AS_SYNTAX_URL; - } else if ( !strcasecmp( p, "search-with-filter" ) ) { - as->as_syntax = AS_SYNTAX_BOOL_FILTER; - } else if ( !strncasecmp( p, "param=", 6 ) ) { - q = strchr( p, '=' ); - if ( q ) { - p = q + 1; - while ( *q && !isspace( (unsigned char) *q ) ) { - q++; - } - if ( *q ) { - *q = '\0'; - as->as_param = strdup( p ); - p = q + 1; - } else { - as->as_param = strdup( p ); - p = q; - } - } - } else if ( !strcasecmp( p, "host" ) ) { - as->as_kind = AS_SYNTAX_HOST; - } else if ( !strcasecmp( p, "present" ) ) { - as->as_kind = AS_SYNTAX_PRESENT; - } else if ( !strcasecmp( p, "route-to-host" ) ) { - as->as_kind = AS_KIND_ROUTE_TO_HOST; - } else if ( !strcasecmp( p, "route-to-address" ) ) { - as->as_kind = AS_KIND_ROUTE_TO_ADDR; - } else if ( !strcasecmp( p, "own-address" ) ) { - as->as_kind = AS_KIND_OWN_ADDR; - } else if ( !strcasecmp( p, "recipient" ) ) { - as->as_kind = AS_KIND_RECIPIENT; - } else if ( !strcasecmp( p, "errors" ) ) { - as->as_kind = AS_KIND_ERRORS; - } else if ( !strcasecmp( p, "request" ) ) { - as->as_kind = AS_KIND_REQUEST; - } else if ( !strcasecmp( p, "owner" ) ) { - as->as_kind = AS_KIND_OWNER; - } else if ( !strcasecmp( p, "delivery-type" ) ) { - as->as_kind = AS_KIND_DELIVERY_TYPE; - } else { - syslog( LOG_ALERT, - "Unknown semantics word %s", p ); - exit( EX_TEMPFAIL ); - } - p = q + 1; - } - if ( attr_semantics == NULL ) { - attr_semantics = calloc(2, sizeof(AttrSemantics *)); - if ( !attr_semantics ) { - syslog( LOG_ALERT, "Out of memory" ); - exit( EX_TEMPFAIL ); - } - attr_semantics[0] = as; - } else { - int size; - AttrSemantics **list_temp; - for ( size = 0; attr_semantics[size]; size++ ) - ; - size += 2; - list_temp = realloc( attr_semantics, - size*sizeof(AttrSemantics *) ); - if ( !list_temp ) { - syslog( LOG_ALERT, "Out of memory" ); - exit( EX_TEMPFAIL ); - } - attr_semantics = list_temp; - attr_semantics[size-2] = as; - attr_semantics[size-1] = NULL; - } -} - -static void -load_config( char *filespec ) -{ - FILE *cf; - char *line; - int lineno = 0; - char *p; - int rdnpref; - int typemask; - - cf = fopen( filespec, "r" ); - if ( !cf ) { - perror( "Opening config file" ); - exit( EX_TEMPFAIL ); - } - - while ( ( line = get_config_line( cf,&lineno ) ) ) { - p = strpbrk( line, " \t" ); - if ( !p ) { - syslog( LOG_ALERT, - "Missing space at line %d", lineno ); - exit( EX_TEMPFAIL ); - } - if ( !strncmp( line, "search", p-line ) ) { - p += strspn( p, " \t" ); - /* TBC, get these */ - rdnpref = 0; - typemask = 0xFF; - add_url( p, rdnpref, typemask ); - } else if ( !strncmp(line, "attribute", p-line) ) { - p += strspn(p, " \t"); - add_attr_semantics( p ); - } else if ( !strncmp(line, "default-attributes", p-line) ) { - p += strspn(p, " \t"); - add_def_attr( p ); - } else if ( !strncmp(line, "group-classes", p-line) ) { - p += strspn(p, " \t"); - add_single_to( &groupclasses, p ); - } else if ( !strncmp(line, "priority", p-line) ) { - p += strspn(p, " \t"); - current_priority = atoi(p); - } else if ( !strncmp(line, "domain", p-line) ) { - p += strspn(p, " \t"); - add_single_to( &mydomains, p ); - } else if ( !strncmp(line, "host", p-line) ) { - p += strspn(p, " \t"); - add_single_to( &myhosts, p ); - } else { - syslog( LOG_ALERT, - "Unparseable config definition at line %d", - lineno ); - exit( EX_TEMPFAIL ); - } - } - fclose( cf ); -} - -static int -connect_to_x500( void ) -{ - int opt; - - if ( (ld = ldap_init( ldaphost, 0 )) == NULL ) { - syslog( LOG_ALERT, "ldap_init failed" ); - return( -1 ); - } - - /* TBC: Set this only when it makes sense - opt = MAIL500_MAXAMBIGUOUS; - ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &opt); - */ - opt = LDAP_DEREF_ALWAYS; - ldap_set_option(ld, LDAP_OPT_DEREF, &opt); - - if ( ldap_simple_bind_s( ld, NULL, NULL ) != LDAP_SUCCESS ) { - syslog( LOG_ALERT, "ldap_simple_bind_s failed" ); - return( -1 ); - } - - return( 0 ); -} - -static Group * -new_group( char *dn, Group ***list, int *nlist ) -{ - int i; - Group *this_group; - - for ( i = 0; i < *nlist; i++ ) { - if ( strcasecmp( dn, (*list)[i]->g_dn ) == 0 ) { - syslog( LOG_ALERT, "group loop 2 detected (%s)", dn ); - return NULL; - } - } - - this_group = (Group *) malloc( sizeof(Group) ); - - if ( *nlist == 0 ) { - *list = (Group **) malloc( sizeof(Group *) ); - } else { - *list = (Group **) realloc( *list, (*nlist + 1) * - sizeof(Group *) ); - } - - this_group->g_errorsto = NULL; - this_group->g_members = NULL; - this_group->g_nmembers = 0; - /* save the group's dn so we can check for loops above */ - this_group->g_dn = strdup( dn ); - - (*list)[*nlist] = this_group; - (*nlist)++; - - return( this_group ); -} - -static void -split_address( - char *address, - char **localpart, - char **domainpart -) -{ - char *p; - - if ( ( p = strrchr( address, '@' ) ) == NULL ) { - *localpart = strdup( address ); - *domainpart = NULL; - } else { - *localpart = malloc( p - address + 1 ); - strncpy( *localpart, address, p - address ); - (*localpart)[p - address] = '\0'; - p++; - *domainpart = strdup( p ); - } -} - -static int -dn_search( - char **dnlist, - char *address, - char ***to, - int *nto, - Group ***togroups, - int *ngroups, - Error **err, - int *nerr -) -{ - int rc; - int i; - int resolved = 0; - LDAPMessage *res, *e; - struct timeval timeout; - - timeout.tv_sec = MAIL500_TIMEOUT; - timeout.tv_usec = 0; - for ( i = 0; dnlist[i]; i++ ) { - if ( (rc = ldap_search_st( ld, dnlist[i], LDAP_SCOPE_BASE, - NULL, def_attr, 0, - &timeout, &res )) != LDAP_SUCCESS ) { - if ( rc == LDAP_NO_SUCH_OBJECT ) { - add_error( err, nerr, E_BADMEMBER, dnlist[i], NULL ); - continue; - } else { - syslog( LOG_ALERT, "member search return 0x%x", rc ); - - unbind_and_exit( EX_TEMPFAIL ); - } - } else { - if ( (e = ldap_first_entry( ld, res )) == NULL ) { - syslog( LOG_ALERT, "member search error parsing entry" ); - unbind_and_exit( EX_TEMPFAIL ); - } - if ( entry_engine( e, dnlist[i], address, to, nto, - togroups, ngroups, err, nerr, - USER | GROUP_MEMBERS ) ) { - resolved = 1; - } - } - } - return( resolved ); -} - -static int -search_ldap_url( - char *url, - Subst *substs, - char *address, - int rdnpref, - int multi_entry, - char ***to, - int *nto, - Group ***togroups, - int *ngroups, - Error **err, - int *nerr, - int type -) -{ - LDAPURLDesc *ludp; - char *p, *s, *d; - int i; - char filter[1024]; - LDAPMessage *e, *res; - int rc; - char **attrlist; - struct timeval timeout; - int match; - int resolved = 0; - char *dn; - - timeout.tv_sec = MAIL500_TIMEOUT; - timeout.tv_usec = 0; - - rc = ldap_url_parse( url, &ludp ); - if ( rc ) { - switch ( rc ) { - case LDAP_URL_ERR_BADSCHEME: - syslog( LOG_ALERT, - "Not an LDAP URL: %s", url ); - break; - case LDAP_URL_ERR_BADENCLOSURE: - syslog( LOG_ALERT, - "Bad Enclosure in URL: %s", url ); - break; - case LDAP_URL_ERR_BADURL: - syslog( LOG_ALERT, - "Bad URL: %s", url ); - break; - case LDAP_URL_ERR_BADHOST: - syslog( LOG_ALERT, - "Host is invalid in URL: %s", url ); - break; - case LDAP_URL_ERR_BADATTRS: - syslog( LOG_ALERT, - "Attributes are invalid in URL: %s", url ); - break; - case LDAP_URL_ERR_BADSCOPE: - syslog( LOG_ALERT, - "Scope is invalid in URL: %s", url ); - break; - case LDAP_URL_ERR_BADFILTER: - syslog( LOG_ALERT, - "Filter is invalid in URL: %s", url ); - break; - case LDAP_URL_ERR_BADEXTS: - syslog( LOG_ALERT, - "Extensions are invalid in URL: %s", url ); - break; - case LDAP_URL_ERR_MEM: - syslog( LOG_ALERT, - "Out of memory parsing URL: %s", url ); - break; - case LDAP_URL_ERR_PARAM: - syslog( LOG_ALERT, - "bad parameter parsing URL: %s", url ); - break; - default: - syslog( LOG_ALERT, - "Unknown error %d parsing URL: %s", - rc, url ); - break; - } - add_error( err, nerr, E_BADMEMBER, - url, NULL ); - return 0; - } - - if ( substs ) { - for ( s = ludp->lud_filter, d = filter; *s; s++,d++ ) { - if ( *s == '%' ) { - s++; - if ( *s == '%' ) { - *d = '%'; - continue; - } - for ( i = 0; substs[i].sub_char != '\0'; - i++ ) { - if ( *s == substs[i].sub_char ) { - for ( p = substs[i].sub_value; - *p; p++,d++ ) { - *d = *p; - } - d--; - break; - } - } - if ( substs[i].sub_char == '\0' ) { - syslog( LOG_ALERT, - "unknown format %c", *s ); - } - } else { - *d = *s; - } - } - *d = *s; - } else { - strncpy( filter, ludp->lud_filter, sizeof( filter ) - 1 ); - filter[ sizeof( filter ) - 1 ] = '\0'; - } - - if ( ludp->lud_attrs ) { - attrlist = ludp->lud_attrs; - } else { - attrlist = def_attr; - } - res = NULL; - /* TBC: we don't read the host, dammit */ - rc = ldap_search_st( ld, ludp->lud_dn, ludp->lud_scope, - filter, attrlist, 0, - &timeout, &res ); - - /* some other trouble - try again later */ - if ( rc != LDAP_SUCCESS && - rc != LDAP_SIZELIMIT_EXCEEDED ) { - syslog( LOG_ALERT, "return 0x%x from X.500", - rc ); - unbind_and_exit( EX_TEMPFAIL ); - } - - match = ldap_count_entries( ld, res ); - - /* trouble - try again later */ - if ( match == -1 ) { - syslog( LOG_ALERT, "error parsing result from X.500" ); - unbind_and_exit( EX_TEMPFAIL ); - } - - if ( match == 1 || multi_entry ) { - for ( e = ldap_first_entry( ld, res ); e != NULL; - e = ldap_next_entry( ld, e ) ) { - dn = ldap_get_dn( ld, e ); - resolved = entry_engine( e, dn, address, to, nto, - togroups, ngroups, - err, nerr, type ); - if ( !resolved ) { - add_error( err, nerr, E_NOEMAIL, address, res ); - } - } - return ( resolved ); - } - - /* more than one match - bounce with ambiguous user? */ - if ( match > 1 ) { - LDAPMessage *next, *tmpres = NULL; - char *dn; - char **xdn; - - /* not giving rdn preference - bounce with ambiguous user */ - if ( rdnpref == 0 ) { - add_error( err, nerr, E_AMBIGUOUS, address, res ); - return 0; - } - - /* - * giving rdn preference - see if any entries were matched - * because of their rdn. If so, collect them to deal with - * later (== 1 we deliver, > 1 we bounce). - */ - - for ( e = ldap_first_entry( ld, res ); e != NULL; e = next ) { - next = ldap_next_entry( ld, e ); - dn = ldap_get_dn( ld, e ); - xdn = ldap_explode_dn( dn, 1 ); - - /* XXX bad, but how else can we do it? XXX */ - if ( strcasecmp( xdn[0], address ) == 0 ) { - ldap_delete_result_entry( &res, e ); - ldap_add_result_entry( &tmpres, e ); - } - - ldap_value_free( xdn ); - free( dn ); - } - - /* nothing matched by rdn - go ahead and bounce */ - if ( tmpres == NULL ) { - add_error( err, nerr, E_AMBIGUOUS, address, res ); - return 0; - - /* more than one matched by rdn - bounce with rdn matches */ - } else if ( (match = ldap_count_entries( ld, tmpres )) > 1 ) { - add_error( err, nerr, E_AMBIGUOUS, address, tmpres ); - return 0; - - /* trouble... */ - } else if ( match < 0 ) { - syslog( LOG_ALERT, "error parsing result from X.500" ); - unbind_and_exit( EX_TEMPFAIL ); - } - - /* otherwise one matched by rdn - send to it */ - ldap_msgfree( res ); - res = tmpres; - - /* trouble */ - if ( (e = ldap_first_entry( ld, res )) == NULL ) { - syslog( LOG_ALERT, "error parsing entry from X.500" ); - unbind_and_exit( EX_TEMPFAIL ); - } - - dn = ldap_get_dn( ld, e ); - - resolved = entry_engine( e, dn, address, to, nto, - togroups, ngroups, - err, nerr, type ); - if ( !resolved ) { - add_error( err, nerr, E_NOEMAIL, address, res ); - /* Don't free res if we passed it to add_error */ - } else { - ldap_msgfree( res ); - } - } - return( resolved ); -} - -static int -url_list_search( - char **urllist, - char *address, - int multi_entry, - char ***to, - int *nto, - Group ***togroups, - int *ngroups, - Error **err, - int *nerr, - int type -) -{ - int i; - int resolved = 0; - - for ( i = 0; urllist[i]; i++ ) { - - if ( !strncasecmp( urllist[i], "mail:", 5 ) ) { - char *vals[2]; - - vals[0] = urllist[i] + 5; - vals[1] = NULL; - add_to( to, nto, vals ); - resolved = 1; - - } else if ( ldap_is_ldap_url( urllist[i] ) ) { - - resolved = search_ldap_url( urllist[i], NULL, - address, 0, multi_entry, - to, nto, togroups, ngroups, - err, nerr, type ); - } else { - /* Produce some sensible error here */ - resolved = 0; - } - } - return( resolved ); -} - -/* - * We should probably take MX records into account to cover all bases, - * but really, routing belongs in the MTA. - */ -static int -is_my_host( - char * host -) -{ - char **d; - - if ( myhosts == NULL ) - return 0; - for ( d = myhosts; *d; d++ ) { - if ( !strcasecmp(*d,host) ) { - return 1; - } - } - return 0; -} - -static int -is_my_domain( - char * address -) -{ - char **d; - char *p; - - if ( mydomains == NULL ) - return 0; - p = strchr( address, '@' ); - if ( p == NULL) - return 0; - for ( d = mydomains; *d; d++ ) { - if ( !strcasecmp(*d,p+1) ) { - return 1; - } - } - return 0; -} - -static void -do_addresses( - char **addresses, - char ***to, - int *nto, - Group ***togroups, - int *ngroups, - Error **err, - int *nerr, - int type -) -{ - int i, j; - int n; - - /* - * Well, this is tricky, every address in my_addresses will be - * removed from the list while we shift the other values down - * and we do it in a single scan of the address list and - * without using additional memory. We are going to be - * modifying the value list in a way that the later - * ldap_value_free works. - */ - j = 0; - for ( i = 0; addresses[i]; i++ ) { - if ( is_my_domain(addresses[i]) ) { - do_address( addresses[i], to, nto, togroups, ngroups, - err, nerr, type ); - ldap_memfree( addresses[i] ); - } else { - if ( j < i ) { - addresses[j] = addresses[i]; - } - j++; - } - } - addresses[j] = NULL; - if ( addresses[0] ) { - add_to( to, nto, addresses ); - } -} - -/* - * The entry engine processes an entry. Normally, each entry will resolve - * to one or more values that will be added to the 'to' argument. This - * argument needs not be the global 'to' list, it may be the g_to field - * in a group. Groups have no special treatment, unless they require - * a special sender. - */ - -static int -entry_engine( - LDAPMessage *e, - char *dn, - char *address, - char ***to, - int *nto, - Group ***togroups, - int *ngroups, - Error **err, - int *nerr, - int type -) -{ - char **vals; - int i; - int resolved = 0; - char ***current_to = to; - int *current_nto = nto; - Group *current_group = NULL; - char buf[1024]; - char *localpart = NULL, *domainpart = NULL; - Subst substs[2]; - int cur_priority = 0; - char *route_to_host = NULL; - char *route_to_address = NULL; - int needs_mta_routing = 0; - char **own_addresses = NULL; - int own_addresses_total = 0; - char **delivery_types = NULL; - int delivery_types_total = 0; - char *nvals[2]; - - for ( i=0; attr_semantics[i] != NULL; i++ ) { - AttrSemantics *as = attr_semantics[i]; - int nent; - int j; - - if ( as->as_priority < cur_priority ) { - /* - * We already got higher priority information, - * so no further work to do, ignore the rest. - */ - break; - } - vals = ldap_get_values( ld, e, as->as_name ); - if ( !vals || vals[0] == NULL ) { - continue; - } - nent = count_values( vals ); - if ( nent > 1 && !as->as_m_valued ) { - add_error( err, nerr, E_AMBIGUOUS, address, e ); - return( 0 ); - } - switch ( as->as_kind ) { - case AS_KIND_RECIPIENT: - cur_priority = as->as_priority; - if ( ! ( type & ( USER | GROUP_MEMBERS ) ) ) - break; - switch ( as->as_syntax ) { - case AS_SYNTAX_RFC822: - do_addresses( vals, current_to, current_nto, - togroups, ngroups, err, nerr, - USER ); - resolved = 1; - break; - case AS_SYNTAX_RFC822_EXT: - do_addresses( vals, current_to, current_nto, - togroups, ngroups, err, nerr, - USER ); - resolved = 1; - break; - case AS_SYNTAX_NATIVE_MB: - /* We used to concatenate mailHost if set here */ - /* - * We used to send a copy to the vacation host - * if onVacation to uid@vacationhost - */ - if ( as->as_param ) { - for ( j=0; jas_param, delivery_types[j] ) ) { - add_to( current_to, current_nto, vals ); - resolved = 1; - break; - } - } - } else { - add_to( current_to, current_nto, vals ); - resolved = 1; - } - break; - - case AS_SYNTAX_DN: - if ( dn_search( vals, address, - current_to, current_nto, - togroups, ngroups, - err, nerr ) ) { - resolved = 1; - } - break; - - case AS_SYNTAX_URL: - if ( url_list_search( vals, address, - as->as_m_entries, - current_to, current_nto, - togroups, ngroups, - err, nerr, type ) ) { - resolved = 1; - } - break; - - case AS_SYNTAX_BOOL_FILTER: - if ( strcasecmp( vals[0], "true" ) ) { - break; - } - substs[0].sub_char = 'D'; - substs[0].sub_value = dn; - substs[1].sub_char = '\0'; - substs[1].sub_value = NULL; - if ( url_list_search( vals, address, - as->as_m_entries, - current_to, current_nto, - togroups, ngroups, - err, nerr, type ) ) { - resolved = 1; - } - break; - - default: - syslog( LOG_ALERT, - "Invalid syntax %d for kind %d", - as->as_syntax, as->as_kind ); - break; - } - break; - - case AS_KIND_ERRORS: - cur_priority = as->as_priority; - /* This is a group with special processing */ - if ( type & GROUP_ERRORS ) { - switch (as->as_kind) { - case AS_SYNTAX_RFC822: - add_to( current_to, current_nto, vals ); - resolved = 1; - break; - case AS_SYNTAX_URL: - default: - syslog( LOG_ALERT, - "Invalid syntax %d for kind %d", - as->as_syntax, as->as_kind ); - } - } else { - current_group = new_group( dn, togroups, - ngroups ); - if ( ! current_group ) - /* - * We have already considered - * this group, so we just - * return resolved. - */ - return 1; - current_to = ¤t_group->g_members; - current_nto = ¤t_group->g_nmembers; - split_address( address, - &localpart, &domainpart ); - if ( domainpart ) { - sprintf( buf, "%s-%s@%s", - localpart, ERRORS, - domainpart ); - free( localpart ); - free( domainpart ); - } else { - sprintf( buf, "%s-%s@%s", - localpart, ERRORS, - host ); - free( localpart ); - } - current_group->g_errorsto = strdup( buf ); - } - break; - - case AS_KIND_REQUEST: - cur_priority = as->as_priority; - /* This is a group with special processing */ - if ( type & GROUP_REQUEST ) { - add_to( current_to, current_nto, vals ); - resolved = 1; - } - break; - - case AS_KIND_OWNER: - cur_priority = as->as_priority; - /* This is a group with special processing */ - if ( type & GROUP_REQUEST ) { - add_to( current_to, current_nto, vals ); - resolved = 1; - } - break; - - case AS_KIND_ROUTE_TO_HOST: - if ( !is_my_host( vals[0] ) ) { - cur_priority = as->as_priority; - if ( as->as_syntax == AS_SYNTAX_PRESENT ) { - needs_mta_routing = 1; - } else { - route_to_host = strdup( vals[0] ); - } - } - break; - - case AS_KIND_ROUTE_TO_ADDR: - for ( j=0; jas_priority; - if ( as->as_syntax == AS_SYNTAX_PRESENT ) { - needs_mta_routing = 1; - } else { - route_to_address = strdup( vals[0] ); - } - } - break; - } - - case AS_KIND_OWN_ADDR: - add_to( &own_addresses, &own_addresses_total, vals ); - cur_priority = as->as_priority; - break; - - case AS_KIND_DELIVERY_TYPE: - add_to( &delivery_types, &delivery_types_total, vals ); - cur_priority = as->as_priority; - break; - - default: - syslog( LOG_ALERT, - "Invalid kind %d", as->as_kind ); - /* Error, TBC */ - } - ldap_value_free( vals ); - } - /* - * Now check if we are dealing with mail routing. We support - * two modes. - * - * The first mode and by far the most robust method is doing - * routing at the MTA. In this case, we just checked if the - * routing attributes were present and did not seem like - * pointing to ourselves. The only thing we have to do here - * is adding to the recipient list any of the RFC822 addresses - * of this entry. That means we needed to retrieve them from - * the entry itself because we might have arrived here through - * some directory search. The address received as argument is - * not the address of the entry we are processing, but rather - * the RFC822 address we are expanding now. Unfortunately, - * this requires an MTA that understands LDAP routing. - * Sendmail 8.10.0 does, if compiled properly. - * - * The second method, that is most emphatically not recommended - * is routing in maildap. This is going to require using the - * percent hack. Moreover, this may occasionally loop. - */ - if ( needs_mta_routing ) { - if ( !own_addresses ) { - add_error( err, nerr, E_NOOWNADDRESS, address, e ); - return( 0 ); - } - nvals[0] = own_addresses[0]; /* Anyone will do */ - nvals[1] = NULL; - add_to( current_to, current_nto, nvals ); - resolved = 1; - } else if ( route_to_host ) { - char *p; - if ( !route_to_address ) { - if ( !own_addresses ) { - add_error( err, nerr, E_NOOWNADDRESS, address, e ); - return( 0 ); - } - route_to_address = strdup( own_addresses[0] ); - } - /* This makes use of the percent hack, but there's no choice */ - p = strchr( route_to_address, '@' ); - if ( p ) { - *p = '%'; - } - sprintf( buf, "%s@%s", route_to_address, route_to_host ); - nvals[0] = buf; - nvals[1] = NULL; - add_to( current_to, current_nto, nvals ); - resolved = 1; - free( route_to_host ); - free( route_to_address ); - } else if ( route_to_address ) { - nvals[0] = route_to_address; - nvals[1] = NULL; - add_to( current_to, current_nto, nvals ); - resolved = 1; - free( route_to_address ); - } - if ( own_addresses ) { - ldap_value_free( own_addresses ); - } - if ( delivery_types ) { - ldap_value_free( delivery_types ); - } - - return( resolved ); -} - -static int -search_bases( - char *filter, - Subst *substs, - char *name, - char ***to, - int *nto, - Group ***togroups, - int *ngroups, - Error **err, - int *nerr, - int type -) -{ - int b, resolved = 0; - - for ( b = 0; base[b] != NULL; b++ ) { - - if ( ! (base[b]->b_search & type) ) { - continue; - } - - resolved = search_ldap_url( base[b]->b_url, substs, name, - base[b]->b_rdnpref, - base[b]->b_m_entries, - to, nto, togroups, ngroups, - err, nerr, type ); - if ( resolved ) - break; - } - return( resolved ); -} - -static void -do_address( - char *name, - char ***to, - int *nto, - Group ***togroups, - int *ngroups, - Error **err, - int *nerr, - int type -) -{ - char *localpart = NULL, *domainpart = NULL; - char *synthname = NULL; - int resolved; - int i; - Subst substs[6]; - - /* - * Look up the name in X.500, add the appropriate addresses found - * to the to list, or to the err list in case of error. Groups are - * handled by the do_group routine, individuals are handled here. - * When looking up name, we follow the bases hierarchy, looking - * in base[0] first, then base[1], etc. For each base, there is - * a set of search filters to try, in order. If something goes - * wrong here trying to contact X.500, we exit with EX_TEMPFAIL. - * If the b_rdnpref flag is set, then we give preference to entries - * that matched name because it's their rdn, otherwise not. - */ - - split_address( name, &localpart, &domainpart ); - synthname = strdup( localpart ); - for ( i = 0; synthname[i] != '\0'; i++ ) { - if ( synthname[i] == '.' || synthname[i] == '_' ) - synthname[i] = ' '; - } - substs[0].sub_char = 'm'; - substs[0].sub_value = name; - substs[1].sub_char = 'h'; - substs[1].sub_value = host; - substs[2].sub_char = 'l'; - substs[2].sub_value = localpart; - substs[3].sub_char = 'd'; - substs[3].sub_value = domainpart; - substs[4].sub_char = 's'; - substs[4].sub_value = synthname; - substs[5].sub_char = '\0'; - substs[5].sub_value = NULL; - - resolved = search_bases( NULL, substs, name, - to, nto, togroups, ngroups, - err, nerr, type ); - - if ( localpart ) { - free( localpart ); - } - if ( domainpart ) { - free( domainpart ); - } - if ( synthname ) { - free( synthname ); - } - - if ( !resolved ) { - /* not resolved - bounce with user unknown */ - if ( type == USER ) { - add_error( err, nerr, E_USERUNKNOWN, name, NULL ); - } else { - add_error( err, nerr, E_GROUPUNKNOWN, name, NULL ); - } - } -} - -static void -send_message( char **to ) -{ - int pid; -#ifndef HAVE_WAITPID - WAITSTATUSTYPE status; -#endif - - if ( debug ) { - char buf[1024]; - int i; - - strcpy( buf, to[0] ); - for ( i = 1; to[i] != NULL; i++ ) { - strcat( buf, " " ); - strcat( buf, to[i] ); - } - - syslog( LOG_ALERT, "send_message execing sendmail: (%s)", buf ); - } - - /* parent */ - if ( (pid = fork()) != 0 ) { -#ifdef HAVE_WAITPID - waitpid( pid, (int *) NULL, 0 ); -#else - wait4( pid, &status, WAIT_FLAGS, 0 ); -#endif - /* child */ - } else { - /* to includes sendmailargs */ - execv( MAIL500_SENDMAIL, to ); - - syslog( LOG_ALERT, "execv failed" ); - - exit( EX_TEMPFAIL ); - } -} - -static void -send_group( Group **group, int ngroup ) -{ - int i, pid; - char **argv; - int argc; - char *iargv[7]; -#ifndef HAVE_WAITPID - WAITSTATUSTYPE status; -#endif - - for ( i = 0; i < ngroup; i++ ) { - (void) rewind( stdin ); - - iargv[0] = MAIL500_SENDMAIL; - iargv[1] = "-f"; - iargv[2] = group[i]->g_errorsto; - iargv[3] = "-oMrX.500"; - iargv[4] = "-odi"; - iargv[5] = "-oi"; - iargv[6] = NULL; - - argv = NULL; - argc = 0; - add_to( &argv, &argc, iargv ); - add_to( &argv, &argc, group[i]->g_members ); - - if ( debug ) { - char buf[1024]; - int i; - - strcpy( buf, argv[0] ); - for ( i = 1; i < argc; i++ ) { - strcat( buf, " " ); - strcat( buf, argv[i] ); - } - - syslog( LOG_ALERT, "execing sendmail: (%s)", buf ); - } - - /* parent */ - if ( (pid = fork()) != 0 ) { -#ifdef HAVE_WAITPID - waitpid( pid, (int *) NULL, 0 ); -#else - wait4( pid, &status, WAIT_FLAGS, 0 ); -#endif - /* child */ - } else { - execv( MAIL500_SENDMAIL, argv ); - - syslog( LOG_ALERT, "execv failed" ); - - exit( EX_TEMPFAIL ); - } - } -} - -static void -send_errors( Error *err, int nerr ) -{ - int pid, i, namelen; - FILE *fp; - int fd[2]; - char *argv[8]; - char buf[1024]; -#ifndef HAVE_WAITPID - WAITSTATUSTYPE status; -#endif - - if ( strcmp( MAIL500_BOUNCEFROM, mailfrom ) == 0 ) { - mailfrom = errorsfrom; - } - - argv[0] = MAIL500_SENDMAIL; - argv[1] = "-oMrX.500"; - argv[2] = "-odi"; - argv[3] = "-oi"; - argv[4] = "-f"; - argv[5] = MAIL500_BOUNCEFROM; - argv[6] = mailfrom; - argv[7] = NULL; - - if ( debug ) { - int i; - - strcpy( buf, argv[0] ); - for ( i = 1; argv[i] != NULL; i++ ) { - strcat( buf, " " ); - strcat( buf, argv[i] ); - } - - syslog( LOG_ALERT, "execing sendmail: (%s)", buf ); - } - - if ( pipe( fd ) == -1 ) { - syslog( LOG_ALERT, "cannot create pipe" ); - exit( EX_TEMPFAIL ); - } - - if ( (pid = fork()) != 0 ) { - if ( (fp = fdopen( fd[1], "w" )) == NULL ) { - syslog( LOG_ALERT, "cannot fdopen pipe" ); - exit( EX_TEMPFAIL ); - } - - fprintf( fp, "To: %s\n", mailfrom ); - fprintf( fp, "From: %s\n", errorsfrom ); - fprintf( fp, "Subject: undeliverable mail\n" ); - fprintf( fp, "\n" ); - fprintf( fp, "The following errors occurred when trying to deliver the attached mail:\n" ); - for ( i = 0; i < nerr; i++ ) { - namelen = strlen( err[i].e_addr ); - fprintf( fp, "\n" ); - - switch ( err[i].e_code ) { - case E_USERUNKNOWN: - fprintf( fp, "%s: User unknown\n", err[i].e_addr ); - break; - - case E_GROUPUNKNOWN: - fprintf( fp, "%s: Group unknown\n", err[i].e_addr ); - break; - - case E_BADMEMBER: - fprintf( fp, "%s: Group member does not exist\n", - err[i].e_addr ); - fprintf( fp, "This could be because the distinguished name of the person has changed\n" ); - fprintf( fp, "If this is the case, the problem can be solved by removing and\n" ); - fprintf( fp, "then re-adding the person to the group.\n" ); - break; - - case E_NOREQUEST: - fprintf( fp, "%s: Group exists but has no request address\n", - err[i].e_addr ); - break; - - case E_NOERRORS: - fprintf( fp, "%s: Group exists but has no errors-to address\n", - err[i].e_addr ); - break; - - case E_NOOWNER: - fprintf( fp, "%s: Group exists but has no owner\n", - err[i].e_addr ); - break; - - case E_AMBIGUOUS: - do_ambiguous( fp, &err[i], namelen ); - break; - - case E_NOEMAIL: - do_noemail( fp, &err[i], namelen ); - break; - - case E_MEMBERNOEMAIL: - fprintf( fp, "%s: Group member exists but does not have an email address\n", - err[i].e_addr ); - break; - - case E_JOINMEMBERNOEMAIL: - fprintf( fp, "%s: User has joined group but does not have an email address\n", - err[i].e_addr ); - break; - - case E_LOOP: - fprintf( fp, "%s: User has created a mail loop by adding address %s to their X.500 entry\n", - err[i].e_addr, err[i].e_loop ); - break; - - case E_NOMEMBERS: - fprintf( fp, "%s: Group has no members\n", - err[i].e_addr ); - break; - - case E_NOOWNADDRESS: - fprintf( fp, "%s: Not enough information to perform required routing\n", - err[i].e_addr ); - break; - - default: - syslog( LOG_ALERT, "unknown error %d", err[i].e_code ); - unbind_and_exit( EX_TEMPFAIL ); - break; - } - } - - fprintf( fp, "\n------- The original message sent:\n\n" ); - - while ( fgets( buf, sizeof(buf), stdin ) != NULL ) { - fputs( buf, fp ); - } - fclose( fp ); - -#ifdef HAVE_WAITPID - waitpid( pid, (int *) NULL, 0 ); -#else - wait4( pid, &status, WAIT_FLAGS, 0 ); -#endif - } else { - dup2( fd[0], 0 ); - - execv( MAIL500_SENDMAIL, argv ); - - syslog( LOG_ALERT, "execv failed" ); - - exit( EX_TEMPFAIL ); - } -} - -static void -do_noemail( FILE *fp, Error *err, int namelen ) -{ - int i, last; - char *dn, *rdn; - char **ufn, **vals; - - fprintf(fp, "%s: User has no email address registered.\n", - err->e_addr ); - fprintf( fp, "%*s Name, title, postal address and phone for '%s':\n\n", - namelen, " ", err->e_addr ); - - /* name */ - dn = ldap_get_dn( ld, err->e_msg ); - ufn = ldap_explode_dn( dn, 1 ); - rdn = strdup( ufn[0] ); - if ( strcasecmp( rdn, err->e_addr ) == 0 ) { - if ( (vals = ldap_get_values( ld, err->e_msg, "cn" )) - != NULL ) { - for ( i = 0; vals[i]; i++ ) { - last = strlen( vals[i] ) - 1; - if ( isdigit((unsigned char) vals[i][last]) ) { - rdn = strdup( vals[i] ); - break; - } - } - - ldap_value_free( vals ); - } - } - fprintf( fp, "%*s %s\n", namelen, " ", rdn ); - free( dn ); - free( rdn ); - ldap_value_free( ufn ); - - /* titles or descriptions */ - if ( (vals = ldap_get_values( ld, err->e_msg, "title" )) == NULL && - (vals = ldap_get_values( ld, err->e_msg, "description" )) - == NULL ) { - fprintf( fp, "%*s No title or description registered\n", - namelen, " " ); - } else { - for ( i = 0; vals[i] != NULL; i++ ) { - fprintf( fp, "%*s %s\n", namelen, " ", vals[i] ); - } - - ldap_value_free( vals ); - } - - /* postal address */ - if ( (vals = ldap_get_values( ld, err->e_msg, "postalAddress" )) - == NULL ) { - fprintf( fp, "%*s No postal address registered\n", namelen, - " " ); - } else { - fprintf( fp, "%*s ", namelen, " " ); - for ( i = 0; vals[0][i] != '\0'; i++ ) { - if ( vals[0][i] == '$' ) { - fprintf( fp, "\n%*s ", namelen, " " ); - while ( isspace((unsigned char) vals[0][i+1]) ) - i++; - } else { - fprintf( fp, "%c", vals[0][i] ); - } - } - fprintf( fp, "\n" ); - - ldap_value_free( vals ); - } - - /* telephone number */ - if ( (vals = ldap_get_values( ld, err->e_msg, "telephoneNumber" )) - == NULL ) { - fprintf( fp, "%*s No phone number registered\n", namelen, - " " ); - } else { - for ( i = 0; vals[i] != NULL; i++ ) { - fprintf( fp, "%*s %s\n", namelen, " ", vals[i] ); - } - - ldap_value_free( vals ); - } -} - -/* ARGSUSED */ -static void -do_ambiguous( FILE *fp, Error *err, int namelen ) -{ - int i, last; - char *dn, *rdn; - char **ufn, **vals; - LDAPMessage *e; - - i = ldap_result2error( ld, err->e_msg, 0 ); - - fprintf( fp, "%s: Ambiguous user. %s%d matches found:\n\n", - err->e_addr, i == LDAP_SIZELIMIT_EXCEEDED ? "First " : "", - ldap_count_entries( ld, err->e_msg ) ); - - for ( e = ldap_first_entry( ld, err->e_msg ); e != NULL; - e = ldap_next_entry( ld, e ) ) { - dn = ldap_get_dn( ld, e ); - ufn = ldap_explode_dn( dn, 1 ); - rdn = strdup( ufn[0] ); - if ( strcasecmp( rdn, err->e_addr ) == 0 ) { - if ( (vals = ldap_get_values( ld, e, "cn" )) != NULL ) { - for ( i = 0; vals[i]; i++ ) { - last = strlen( vals[i] ) - 1; - if (isdigit((unsigned char) vals[i][last])) { - rdn = strdup( vals[i] ); - break; - } - } - - ldap_value_free( vals ); - } - } - - /* - if ( isgroup( e ) ) { - vals = ldap_get_values( ld, e, "description" ); - } else { - vals = ldap_get_values( ld, e, "title" ); - } - */ - vals = ldap_get_values( ld, e, "description" ); - - fprintf( fp, " %-20s %s\n", rdn, vals ? vals[0] : "" ); - for ( i = 1; vals && vals[i] != NULL; i++ ) { - fprintf( fp, " %s\n", vals[i] ); - } - - free( dn ); - free( rdn ); - ldap_value_free( ufn ); - if ( vals != NULL ) - ldap_value_free( vals ); - } -} - -static int -count_values( char **list ) -{ - int i; - - for ( i = 0; list && list[i] != NULL; i++ ) - ; /* NULL */ - - return( i ); -} - -static void -add_to( char ***list, int *nlist, char **new ) -{ - int i, nnew, oldnlist; - - nnew = count_values( new ); - - oldnlist = *nlist; - if ( *list == NULL || *nlist == 0 ) { - *list = (char **) malloc( (nnew + 1) * sizeof(char *) ); - *nlist = nnew; - } else { - *list = (char **) realloc( *list, *nlist * sizeof(char *) + - nnew * sizeof(char *) + sizeof(char *) ); - *nlist += nnew; - } - - for ( i = 0; i < nnew; i++ ) - (*list)[i + oldnlist] = strdup( new[i] ); - (*list)[*nlist] = NULL; -} - -static void -add_single_to( char ***list, char *new ) -{ - int nlist; - - if ( *list == NULL ) { - nlist = 0; - *list = (char **) malloc( 2 * sizeof(char *) ); - } else { - nlist = count_values( *list ); - *list = (char **) realloc( *list, - ( nlist + 2 ) * sizeof(char *) ); - } - - (*list)[nlist] = strdup( new ); - (*list)[nlist+1] = NULL; -} - -static int -isgroup( LDAPMessage *e ) -{ - int i, j; - char **oclist; - - if ( !groupclasses ) { - return( 0 ); - } - - oclist = ldap_get_values( ld, e, "objectClass" ); - - for ( i = 0; oclist[i] != NULL; i++ ) { - for ( j = 0; groupclasses[j] != NULL; j++ ) { - if ( strcasecmp( oclist[i], groupclasses[j] ) == 0 ) { - ldap_value_free( oclist ); - return( 1 ); - } - } - } - ldap_value_free( oclist ); - - return( 0 ); -} - -static void -add_error( Error **err, int *nerr, int code, char *addr, LDAPMessage *msg ) -{ - if ( *nerr == 0 ) { - *err = (Error *) malloc( sizeof(Error) ); - } else { - *err = (Error *) realloc( *err, (*nerr + 1) * sizeof(Error) ); - } - - (*err)[*nerr].e_code = code; - (*err)[*nerr].e_addr = strdup( addr ); - (*err)[*nerr].e_msg = msg; - (*nerr)++; -} - -static void -unbind_and_exit( int rc ) -{ - int i; - - if ( (i = ldap_unbind( ld )) != LDAP_SUCCESS ) - syslog( LOG_ALERT, "ldap_unbind failed %d\n", i ); - - exit( rc ); -} diff --git a/clients/ud/auth.c b/clients/ud/auth.c deleted file mode 100644 index be4727695b..0000000000 --- a/clients/ud/auth.c +++ /dev/null @@ -1,427 +0,0 @@ -/* - * Copyright (c) 1991, 1992 Regents of the University of Michigan. - * All rights reserved. - * - * Redistribution and use in source and binary forms are permitted - * provided that this notice is preserved and that due credit is given - * to the University of Michigan at Ann Arbor. The name of the University - * may not be used to endorse or promote products derived from this - * software without specific prior written permission. This software - * is provided ``as is'' without express or implied warranty. - */ - -#include -#include -#include -#include -#include -#include -#include -#include "ud.h" -#ifdef KERBEROS -#include -#include -#endif - -extern LDAP *ld; /* our LDAP descriptor */ -extern int verbose; /* verbosity indicator */ -extern char *mygetpass(); /* getpass() passwds are too short */ - -#ifdef DEBUG -extern int debug; /* debug flag */ -#endif - -#ifdef KERBEROS -static char tktpath[20]; /* ticket file path */ -static int kinit(); -static int valid_tgt(); -#endif - -auth(who, implicit) -char *who; -int implicit; -{ - int rc; /* return code from ldap_bind() */ - char *passwd = NULL; /* returned by mygetpass() */ - char **rdns; /* for fiddling with the DN */ - int authmethod; - int name_provided; /* was a name passed in? */ - struct passwd *pw; /* for getting user id */ - char uidname[20]; -#ifdef KERBEROS - char **krbnames; /* for kerberos names */ - int kinited, ikrb; - char buf[5]; - extern int krb_debug; -#endif - LDAPMessage *mp; /* returned from find() */ - static char prompt[MED_BUF_SIZE]; /* place for us to sprintf the prompt */ - static char name[MED_BUF_SIZE]; /* place to store the user's name */ - static char password[MED_BUF_SIZE]; /* password entered by user */ - extern struct entry Entry; /* look here for a name if needed */ - extern LDAPMessage *find(); /* for looking up 'name' */ - extern char *search_base; /* for printing later */ - extern char *default_bind_object; /* bind as this on failure */ - extern void printbase(); /* used to pretty-print a base */ - extern int bind_status; - extern void Free(); - static void set_bound_dn(); - -#ifdef DEBUG - if (debug & D_TRACE) - fprintf(stderr, "auth(%s, NULL)\n", who); -#endif - name_provided = ( who != NULL ); - - /* - * The user needs to bind. If is not specified, we - * assume that authenticating as user id is what user wants. - */ - if (who == NULL && implicit && (pw = getpwuid((uid_t)geteuid())) - != (struct passwd *) NULL) { - sprintf(uidname, "uid=%s", pw->pw_name); - /* who = pw->pw_name; /* */ - who = uidname; - } - - if ( who == NULL ) { - if ( implicit ) - printf( "You must first authenticate yourself to the Directory.\n" ); -#ifdef UOFM - printf(" What is your name or uniqname? "); -#else - printf(" What is your name or user id? "); -#endif - fflush(stdout); - fetch_buffer(name, sizeof(name), stdin); - if (name[0] == '\0') - return( -1 ); - who = name; - } - -#ifdef DEBUG - if (debug & D_AUTHENTICAT) - printf(" Authenticating as \"%s\"\n", who); -#endif - - /* - * Bail out if the name is bogus. If not, strip off the junk - * at the start of the DN, build a prompt, and get a password - * from the user. Then perform the ldap_bind(). - */ - if ((mp = find(who, TRUE)) == NULL) { - (void) ldap_msgfree(mp); - printf(" I could not find \"%s\" in the Directory.\n", who); - printf(" I used a search base of "); - printbase("", search_base); - printf("\n"); -#ifdef DEBUG - if (debug & D_AUTHENTICAT) - printf(" Could not find \"%s\"\n", who); -#endif - return(-1); - } - - /* - * Fill in the Entry structure. May be handy later. - */ - (void) parse_answer(mp); - - rdns = ldap_explode_dn(Entry.DN, TRUE); - printf(" Authenticating to the directory as \"%s\"...\n", *rdns ); - -#ifdef KERBEROS - /* - * First, if the user has a choice of auth methods, ask which - * one they want to use. if they want kerberos, ask which - * krbname they want to bind as. - */ - - if ( (krbnames = ldap_get_values( ld, mp, "krbName" )) != NULL ) { - int choice, hassimple; - - hassimple = (ldap_compare_s( ld, Entry.DN, - "userPassword", "x" ) == LDAP_COMPARE_FALSE); - (void) ldap_msgfree(mp); - - /* if we're running as a server (e.g., out of inetd) */ - if ( ! isatty( 1 ) ) { - strcpy( tktpath, "/tmp/ud_tktXXXXXX" ); - mktemp( tktpath ); - krb_set_tkt_string( tktpath ); - } - - kinited = valid_tgt( krbnames ); - - if ( hassimple && !kinited ) { - printf(" Which password would you like to use?\n"); - printf(" 1 -> X.500 password\n"); -#ifdef UOFM - printf(" 2 -> UMICH password (aka Uniqname or Kerberos password)\n"); -#else - printf(" 2 -> Kerberos password\n"); -#endif - - do { - printf(" Enter 1 or 2: "); - fflush(stdout); - - fetch_buffer(buf, sizeof(buf), stdin); - choice = atoi(buf); - } while (choice != 1 && choice != 2); - - authmethod = (choice == 1 ? LDAP_AUTH_SIMPLE : - LDAP_AUTH_KRBV4); - } else { - authmethod = LDAP_AUTH_KRBV4; - } - } else { - authmethod = LDAP_AUTH_SIMPLE; - (void) ldap_msgfree(mp); - } - - /* - * if they are already kinited, we don't need to ask for a - * password. - */ - - if ( authmethod == LDAP_AUTH_KRBV4 ) { - if ( ! kinited ) { - if ( krbnames[1] != NULL ) { - int i; - - /* ask which one to use */ -#ifdef UOFM - printf(" Which UMICH (aka Kerberos or uniqname) name would you like to use?\n"); -#else - printf(" Which Kerberos name would you like to use?\n"); -#endif - for ( i = 0; krbnames[i] != NULL; i++ ) { - printf( " %d -> %s\n", i + 1, - krbnames[i] ); - } - do { - printf(" Enter a number between 1 and %d: ", i ); - fflush( stdout ); - - fetch_buffer(buf, sizeof(buf), stdin); - ikrb = atoi(buf) - 1; - } while ( ikrb > i - 1 || ikrb < 0 ); - } else { - ikrb = 0; - } - - /* kinit */ - if ( kinit( krbnames[ikrb] ) != 0 ) { - (void) ldap_value_free(rdns); - (void) ldap_value_free(krbnames); - return(-1); - } - } - } else { -#endif - authmethod = LDAP_AUTH_SIMPLE; - sprintf(prompt, " Enter your X.500 password: "); - do { - passwd = mygetpass(prompt); - } while (passwd != NULL && *passwd == '\0'); - if (passwd == NULL) { - (void) ldap_value_free(rdns); - return(0); - } -#ifdef KERBEROS - } - (void) ldap_value_free(krbnames); -#endif - ldap_flush_cache( ld ); - rc = ldap_bind_s(ld, Entry.DN, passwd, authmethod); - if (rc != LDAP_SUCCESS) { - if (ld->ld_errno == LDAP_NO_SUCH_ATTRIBUTE) - fprintf(stderr, " Entry has no password\n"); - else if (ld->ld_errno == LDAP_INVALID_CREDENTIALS) -#ifdef KERBEROS - if ( authmethod == LDAP_AUTH_KRBV4 ) { - fprintf(stderr, " The Kerberos credentials are invalid.\n"); - } else { -#endif - fprintf(stderr, " The password you provided is incorrect.\n"); -#ifdef KERBEROS - } -#endif - else - ldap_perror(ld, "ldap_bind_s" ); - (void) ldap_bind_s(ld, default_bind_object, - (char *) UD_PASSWD, LDAP_AUTH_SIMPLE); - if (default_bind_object == NULL) - set_bound_dn(NULL); - else - set_bound_dn(default_bind_object); - bind_status = UD_NOT_BOUND; - if (verbose) - printf(" Authentication failed.\n\n"); - (void) ldap_value_free(rdns); - return(-1); - } - else if (verbose) - printf(" Authentication successful.\n\n"); - else - printf("\n"); - set_bound_dn(Entry.DN); - bind_status = UD_BOUND; - if (passwd != NULL) - (void) strcpy(password, passwd); - (void) ldap_value_free(rdns); - return(0); -} - -#ifdef KERBEROS - -#define FIVEMINS ( 5 * 60 ) -#define TGT "krbtgt" - -str2upper( s ) - char *s; -{ - char *p; - - for ( p = s; *p != '\0'; ++p ) { - if ( islower( *p )) { - *p = toupper( *p ); - } - } -} - - -static valid_tgt( names ) - char **names; -{ - int i; - char name[ ANAME_SZ ], inst[ INST_SZ ], realm[ REALM_SZ ]; - CREDENTIALS cred; - - for ( i = 0; names[i] != NULL; i++ ) { - if ( kname_parse( name, inst, realm, names[i] ) != KSUCCESS ) { - fprintf( stderr, "Bad format for krbName %s\n", - names[i] ); - fprintf( stderr, "Contact x500@umich.edu\n" ); - return( 0 ); - } - -#ifdef AFSKERBEROS - /* - * realm must be uppercase for krb_ routines - */ - str2upper( realm ); -#endif /* AFSKERBEROS */ - - /* - * check ticket file for a valid ticket granting ticket - * my check is: have ticket granting ticket and it is good for - * at least 5 more minutes - */ - if ( krb_get_cred( TGT, realm, realm, - &cred ) == KSUCCESS && time( 0 ) + FIVEMINS < - cred.issue_date + (u_char)cred.lifetime * FIVEMINS ) { - return( 1 ); - } - } - - return( 0 ); -} - -static char *kauth_name; - -/*ARGSUSED*/ -int -krbgetpass( user, inst, realm, pw, key ) - char *user, *inst, *realm, *pw; - C_Block key; -{ - char *p, lcrealm[ REALM_SZ ], prompt[256], *passwd; - -#ifdef UOFM - sprintf(prompt, " Enter the UMICH password (same as Uniqname or Kerberos password)\n for %s: ", kauth_name ); -#else - sprintf(prompt, " Enter Kerberos password for %s: ", kauth_name ); -#endif - do { - passwd = mygetpass(prompt); - } while (passwd != NULL && *passwd == '\0'); - if (passwd == NULL) { - return(-1); - } - -#ifdef AFSKERBEROS - strcpy( lcrealm, realm ); - for ( p = lcrealm; *p != '\0'; ++p ) { - if ( isupper( *p )) { - *p = tolower( *p ); - } - } - - ka_StringToKey( passwd, lcrealm, key ); -#else /* AFSKERBEROS */ - string_to_key( passwd, key ); -#endif /* AFSKERBEROS */ - - return( 0 ); -} - -static kinit( kname ) - char *kname; -{ - int rc; - char name[ ANAME_SZ ], inst[ INST_SZ ], realm[ REALM_SZ ]; - - kauth_name = kname; - - if ( kname_parse( name, inst, realm, kname ) != KSUCCESS ) { - fprintf( stderr, "Bad format for krbName %s\n", - kname ); - fprintf( stderr, "Contact x500@umich.edu\n" ); - return( -1 ); - } - -#ifdef AFSKERBEROS - /* - * realm must be uppercase for krb_ routines - */ - str2upper( realm ); -#endif /* AFSKERBEROS */ - - rc = krb_get_in_tkt( name, inst, realm, TGT, realm, - DEFAULT_TKT_LIFE, krbgetpass, NULL, NULL ); - - if ( rc != KSUCCESS ) { - switch ( rc ) { - case SKDC_CANT: - fprintf( stderr, "Can't contact Kerberos server for %s\n", realm ); - break; - default: - fprintf( stderr, "%s: %s\n", name, krb_err_txt[ rc ] ); - break; - } - return( -1 ); - } - - return( 0 ); -} - -destroy_tickets() -{ - if ( *tktpath != '\0' ) { - unlink( tktpath ); - } -} -#endif - -static void set_bound_dn(s) -char *s; -{ - extern void Free(); - extern char *bound_dn; - - if (bound_dn != NULL) - Free(bound_dn); - bound_dn = strdup(s); -} diff --git a/clients/ud/edit.c b/clients/ud/edit.c deleted file mode 100644 index eb8969c533..0000000000 --- a/clients/ud/edit.c +++ /dev/null @@ -1,453 +0,0 @@ -/* - * Copyright (c) 1994 Regents of the University of Michigan. - * All rights reserved. - * - * Redistribution and use in source and binary forms are permitted - * provided that this notice is preserved and that due credit is given - * to the University of Michigan at Ann Arbor. The name of the University - * may not be used to endorse or promote products derived from this - * software without specific prior written permission. This software - * is provided ``as is'' without express or implied warranty. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ud.h" - -extern struct entry Entry; -extern int verbose; -extern LDAP *ld; - -extern LDAPMessage *find(); - -static char *entry_temp_file; - -#ifdef DEBUG -extern int debug; -#endif - -edit(who) -char *who; -{ - LDAPMessage *mp; /* returned from find() */ - char *dn, **rdns; /* distinguished name */ - char name[MED_BUF_SIZE]; /* entry to modify */ - extern int bind_status; - static int load_editor(); - static int write_entry(); - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->edit(%s)\n", who); -#endif - /* - * One must be bound in order to edit an entry. - */ - if (bind_status == UD_NOT_BOUND) { - if (auth((char *) NULL, 1) < 0) - return; - } - - /* - * First, decide what entry we are going to modify. If the - * user has not included a name on the modify command line, - * we will use the person who was last looked up with a find - * command. If there is no value there either, we don't know - * who to modify. - * - * Once we know who to modify, be sure that they exist, and - * parse out their DN. - */ - if (who == NULL) { - if (verbose) { - printf(" Enter the name of the person or\n"); - printf(" group whose entry you want to edit: "); - } - else - printf(" Edit whose entry? "); - fflush(stdout); - fetch_buffer(name, sizeof(name), stdin); - if (name[0] != '\0') - who = name; - else - return; - } - if ((mp = find(who, TRUE)) == NULL) { - (void) ldap_msgfree(mp); - printf(" Could not locate \"%s\" in the Directory.\n", who); - return; - } - dn = ldap_get_dn(ld, ldap_first_entry(ld, mp)); - rdns = ldap_explode_dn(dn, TRUE); - Free(dn); - if (verbose) { - printf("\n Editing directory entry \"%s\"...\n", *rdns); - } - parse_answer(mp); - (void) ldap_msgfree(mp); - (void) ldap_value_free(rdns); - if (load_editor() < 0) - return; - (void) write_entry(); - (void) unlink(entry_temp_file); - ldap_uncache_entry(ld, Entry.DN); - return; -} - -static load_editor() -{ - FILE *fp; - char *cp, *editor = UD_DEFAULT_EDITOR; - static char template[MED_BUF_SIZE]; - extern char * mktemp(); - extern int isgroup(), fatal(); - static int print_attrs_and_values(); - int pid; - int status; - int rc; - void (*handler)(); - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->load_editor()\n"); -#endif - - /* write the entry into a temp file */ - (void) strcpy(template, "/tmp/udEdit.XXXXXX"); - if ((entry_temp_file = mktemp(template)) == NULL) { - perror("mktemp"); - return(-1); - } - if ((fp = fopen(entry_temp_file, "w")) == NULL) { - perror("fopen"); - return(-1); - } - fprintf(fp, "## Directory entry of %s\n", Entry.name); - fprintf(fp, "##\n"); - fprintf(fp, "## Syntax is:\n"); - fprintf(fp, "## \n"); - fprintf(fp, "## \n"); - fprintf(fp, "## : :\n"); - fprintf(fp, "## \n"); - fprintf(fp, "## Lines beginning with a hash mark are comments.\n"); - fprintf(fp, "##\n"); - fflush(fp); - if (isgroup()) - rc = print_attrs_and_values(fp, Entry.attrs, ATTR_FLAG_GROUP_MOD); - else - rc = print_attrs_and_values(fp, Entry.attrs, ATTR_FLAG_PERSON_MOD); - fclose(fp); - - if ( rc != 0 ) { - (void) unlink(entry_temp_file); - return( rc ); - } - - /* edit the temp file with the editor of choice */ - if ((cp = getenv("EDITOR")) != NULL) - editor = cp; - if (verbose) { - char *p; - - if (( p = strrchr( editor, '/' )) == NULL ) { - p = editor; - } else { - ++p; - } - printf(" Using %s as the editor...\n", p ); - sleep(2); - } - if ((pid = fork()) == 0) { - /* child - edit the Directory entry */ - (void) signal(SIGINT, SIG_IGN); - (void) execlp(editor, editor, entry_temp_file, NULL); - /*NOTREACHED*/ - (void) fatal(editor); - } - else if (pid > 0) { - /* parent - wait until the child proc is done editing */ - handler = signal(SIGINT, SIG_IGN); - (void) wait(&status); - (void) signal(SIGINT, handler); - } - else { - fatal("fork"); - /*NOTREACHED*/ - } - return(0); -} - -static int print_attrs_and_values(fp, attrs, flag) -FILE *fp; -struct attribute attrs[]; -short flag; -{ - static int modifiable(); - register int i, j; - - for (i = 0; attrs[i].quipu_name != NULL; i++) { - if (!modifiable(attrs[i].quipu_name, flag|ATTR_FLAG_MAY_EDIT)) - continue; - fprintf(fp, "%s\n", attrs[i].quipu_name); - if ( attrs[i].number_of_values > MAX_VALUES ) { - printf(" The %s attribute has more than %d values.\n", - attrs[i].quipu_name, MAX_VALUES ); - printf(" You cannot use the vedit command on this entry. Sorry!\n" ); - return( -1 ); - } - for (j = 0; j < attrs[i].number_of_values; j++) - fprintf(fp, "\t%s\n", attrs[i].values[j]); - } - return( 0 ); -} - -static modifiable(s, flag) -char *s; -short flag; -{ - register int i; - extern struct attribute attrlist[]; - - for (i = 0; attrlist[i].quipu_name != NULL; i++) { - if (strcasecmp(s, attrlist[i].quipu_name)) - continue; - if ((attrlist[i].flags & flag) == ATTR_FLAG_NONE) - return(FALSE); - return(TRUE); - } - /* should never be here */ - return(FALSE); -} - -static write_entry() -{ - int i = 0, j, number_of_values = -1; - - FILE *fp; - char *cp, line[LARGE_BUF_SIZE], *values[MAX_VALUES], **vp; - - LDAPMod *mods[MAX_ATTRS + 1]; - LDAPMod *modp = NULL; - - static int ovalues(); - extern char * code_to_str(); - extern void free_mod_struct(); - - /* parse the file and write the values to the Directory */ - if ((fp = fopen(entry_temp_file, "r")) == NULL) { - perror("fopen"); - return; - } - for (;;) { - (void) fgets(line, sizeof(line), fp); - if (feof(fp)) - break; - line[strlen(line) - 1] = '\0'; /* kill newline */ - cp = line; - if (*cp == '#') - continue; - if (isspace(*cp)) { /* value */ - while (isspace(*cp)) - cp++; - values[number_of_values++] = strdup(cp); - if ( number_of_values >= MAX_VALUES ) { - printf(" A maximum of %d values can be handled at one time. Sorry!\n", MAX_VALUES ); - return; - } - continue; - } - /* attribute */ - while (isspace(*cp)) - cp++; - /* - * If the number of values is greater than zero, then we - * know that this is not the first time through this - * loop, and we also know that we have a little bit - * of work to do: - * - * o The modify operation needs to be changed from - * a DELETE to a REPLACE - * - * o The list of values pointer needs to be changed - * from NULL, to a NULL-terminated list of char - * pointers. - */ - if (number_of_values > 0) { - modp->mod_op = LDAP_MOD_REPLACE; - if ((vp = (char **) Malloc(sizeof(char *) * (number_of_values + 2))) == (char **) NULL) { - fatal("Malloc"); - /*NOTREACHED*/ - } - modp->mod_values = vp; - for (j = 0; j < number_of_values; j++) { - *vp++ = strdup(values[j]); - (void) Free(values[j]); - } - *vp = NULL; - } - /* - * If there are no values, and there were no values to begin - * with, then there is nothing to do. - */ - if ((number_of_values == 0) && (ovalues(modp->mod_type) == 0)) { -#ifdef DEBUG - if (debug & D_MODIFY) - printf(" %s has zero values - skipping\n", - modp->mod_type); -#endif - (void) Free(modp->mod_type); - modp->mod_type = strdup(cp); - modp->mod_op = LDAP_MOD_DELETE; - modp->mod_values = NULL; - continue; - } - /* - * Fetch a new modify structure. - * - * Assume a DELETE operation with no values. - */ - if ((modp = (LDAPMod *) Malloc(sizeof(LDAPMod))) == NULL) { - fatal("Malloc"); - /*NOTREACHED*/ - } - modp->mod_values = NULL; - modp->mod_type = strdup(cp); - modp->mod_op = LDAP_MOD_DELETE; - mods[i++] = modp; - number_of_values = 0; - } - fclose(fp); - - /* check the last one too */ - if (number_of_values > 0) { - modp->mod_op = LDAP_MOD_REPLACE; - /* - * Fetch some value pointers. - * - * number_of_values To store the values - * 1 For the NULL terminator - * 1 In case we need it to store - * the RDN as on of the values - * of 'cn' in case it isn't there - */ - if ((vp = (char **) Malloc(sizeof(char *) * (number_of_values + - 2))) == (char **) NULL) { - fatal("Malloc"); - /*NOTREACHED*/ - } - modp->mod_values = vp; - for (j = 0; j < number_of_values; j++) { - *vp++ = strdup(values[j]); - (void) Free(values[j]); - } - *vp = NULL; - } - else if ((number_of_values == 0) && - (ovalues(mods[i - 1]->mod_type) == 0)) { -#ifdef DEBUG - if (debug & D_MODIFY) - printf(" %s has zero values - skipping\n", - mods[i - 1]->mod_type); -#endif - Free(mods[i - 1]->mod_type); - Free(mods[i - 1]); - i--; - } - mods[i] = (LDAPMod *) NULL; - - /* - * If one of the mods pointers is 'cn', be sure that the RDN is one - * of the values. - */ - for (j = 0; j < i; j++) { - if (strcasecmp("cn", mods[j]->mod_type)) - continue; - /* - * True only if there WERE values, but the person deleted - * them all. - */ - if (mods[j]->mod_values == NULL) { - mods[j]->mod_op = LDAP_MOD_REPLACE; - if ((vp = (char **) Malloc(sizeof(char *) * 2)) == (char **) NULL) { - fatal("Malloc"); - /*NOTREACHED*/ - } - mods[j]->mod_values = vp; - *vp++ = strdup(Entry.name); - *vp = NULL; - break; - } - /* - * Be sure that one of the values of 'cn' is the RDN. - */ - for (vp = mods[j]->mod_values; *vp != NULL; vp++) { - if (strcasecmp(*vp, Entry.DN)) - continue; - break; - } - if (*vp == NULL) { - *vp++ = strdup(Entry.name); - *vp = NULL; - break; - } - } -#ifdef DEBUG - if (debug & D_MODIFY) { - register int x, y; - - printf(" ld = 0x%x\n", ld); - printf(" dn = [%s]\n", Entry.DN); - for (x = 0; mods[x] != (LDAPMod *) NULL; x++) { - printf(" mods[%d]->mod_op = %s\n", - x, code_to_str(mods[x]->mod_op)); - printf(" mods[%d]->mod_type = %s\n", - x, mods[x]->mod_type); - if (mods[x]->mod_values == NULL) - printf(" mods[%d]->mod_values = NULL\n", x); - else { - for (y = 0; mods[x]->mod_values[y] != NULL; y++) - printf(" mods[%d]->mod_values[%1d] = %s\n", - x, y, mods[x]->mod_values[y]); - printf(" mods[%d]->mod_values[%1d] = NULL\n", - x, y); - } - printf("\n"); - } - } -#endif - if (ldap_modify_s(ld, Entry.DN, mods)) - mod_perror(ld); - else - printf(" Modification complete.\n" ); - - /* clean up */ - for (i = 0; mods[i] != NULL; i++) - free_mod_struct(mods[i]); - return; -} - -static ovalues(attr) -char *attr; -{ - struct attribute *ap; - - /* - * Lookup the attribute with quipu_name 'attr' in the Entry - * structure and return the number of values. - */ - for (ap = Entry.attrs; ap->quipu_name != NULL; ap++) { - if (!strcasecmp(ap->quipu_name, attr)) - return(ap->number_of_values); - } - /* should never get to this point unless 'attr' was something odd */ - return(0); -} diff --git a/clients/ud/etc.ud.conf b/clients/ud/etc.ud.conf deleted file mode 100644 index 4566d6ffa1..0000000000 --- a/clients/ud/etc.ud.conf +++ /dev/null @@ -1,2 +0,0 @@ -server -base diff --git a/clients/ud/find.c b/clients/ud/find.c deleted file mode 100644 index 3551c1af6d..0000000000 --- a/clients/ud/find.c +++ /dev/null @@ -1,496 +0,0 @@ -/* - * Copyright (c) 1991, 1992, 1993 - * Regents of the University of Michigan. All rights reserved. - * - * Redistribution and use in source and binary forms are permitted - * provided that this notice is preserved and that due credit is given - * to the University of Michigan at Ann Arbor. The name of the University - * may not be used to endorse or promote products derived from this - * software without specific prior written permission. This software - * is provided ``as is'' without express or implied warranty. - */ - -#include -#include -#include -#ifndef __STDC__ -#include -#endif -#include -#include -#include "ud.h" - -extern char *search_base; /* search base */ -extern int verbose; /* verbose mode flag */ -extern LDAP *ld; /* our ldap descriptor */ - -static int num_picked = 0; /* used when user picks entry at More prompt */ - -#ifdef DEBUG -extern int debug; /* debug flag */ -#endif - -vrfy(dn) -char *dn; -{ - LDAPMessage *results; - static char *attrs[2] = { "objectClass", NULL }; - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->vrfy(%s)\n", dn); -#endif - /* verify that this DN exists in the directory */ - (void) ldap_search_s(ld, dn, LDAP_SCOPE_BASE, "objectClass=*", attrs, TRUE, &results); - (void) ldap_msgfree(results); - if ((ld->ld_errno == LDAP_NO_SUCH_OBJECT) || (ld->ld_errno == LDAP_INVALID_DN_SYNTAX)) - return(0); - else if (ld->ld_errno == LDAP_SUCCESS) - return(1); - else { - ldap_perror(ld, "ldap_search"); - return(0); - } -} - - -static LDAPMessage * disambiguate( result, matches, read_attrs, who ) -LDAPMessage *result; -int matches; -char **read_attrs; -char *who; -{ - int choice; /* entry that user chooses */ - int i; - char *namelist[MAX_NUM_NAMES]; /* names found */ - char response[SMALL_BUF_SIZE]; /* results from user */ - char *name = NULL; /* DN to lookup */ - LDAPMessage *mp; - extern void Free(); - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->disambiguate(%x, %d, %x, %s)\n", result, matches, - read_attrs, who); -#endif - /* - * If we are here, it means that we got back multiple answers. - */ - if ((ld->ld_errno == LDAP_TIMELIMIT_EXCEEDED) - || (ld->ld_errno == LDAP_SIZELIMIT_EXCEEDED)) { - if (verbose) { - printf(" Your query was too general and a limit was exceeded. The results listed\n"); - printf(" are not complete. You may want to try again with a more refined query.\n\n"); - } - else - printf(" Time or size limit exceeded. Partial results follow.\n\n"); - } - printf(" %1d names matched \"%s\".\n", matches, who); - for (;;) { - printf(" Do you wish to see a list of names? "); - fflush(stdout); - (void) memset(response, 0, sizeof(response)); - fetch_buffer(response, sizeof(response), stdin); - switch (response[0]) { - case 'n' : - case 'N' : - case '\0' : - case '\n' : - return(NULL); - /* NOTREACHED */ - case 'y' : - case 'Y' : - print_list(result, namelist, &matches); - if (num_picked == 0) - choice = pick_one(matches); - else - choice = num_picked; - num_picked = 0; - if (choice >= 0) - name = strdup(namelist[choice]); - /* - * Now free up all of the pointers allocated in - * namelist. The print_list() routine that filled - * in this collection of strings starts at 1, not 0. - */ - for (i = 1; namelist[i] != NULL; i++) - Free(namelist[i]); - if (choice < 0) { - if (name != NULL) - Free(name); - return(NULL); - } -#ifdef DEBUG - if (debug & D_FIND) { - printf(" Calling ldap_search_s()\n"); - printf(" ld = 0x%x\n", ld); - printf(" search base = %s\n", name); - printf(" scope = LDAP_SCOPE_BASE\n"); - printf(" filter = objectClass=*\n"); - for (i = 0; read_attrs[i] != NULL; i++) - printf(" read_attrs[%d] = %s\n", i, read_attrs[i]); - printf(" read_attrs[%d] = NULL\n", i); - printf(" attrsonly = FALSE\n"); - printf(" &mp = 0x%x\n", &mp); - } -#endif - if (ldap_search_s(ld, name, LDAP_SCOPE_BASE, "objectClass=*", read_attrs, FALSE, &mp) != LDAP_SUCCESS) { - ldap_perror(ld, "ldap_search_s"); - Free(name); - ldap_msgfree(mp); - return(NULL); - } - Free(name); - return(mp); - /* NOTREACHED */ - default : - printf(" Please enter 'y', 'n', or RETURN.\n"); - break; - } - } -} - -LDAPMessage * find(who, quiet) -char *who; -int quiet; -{ - register int i, j, k; /* general ints */ - int matches; /* from ldap_count_entries() */ - int admonished = FALSE; - static int attrs_set = 0; - static char *read_attrs[MAX_ATTRS]; /* attrs to use in a read op */ - static char *search_attrs[MAX_ATTRS]; /* attrs to use in a srch op */ - static int rc; /* return from ldap_search */ - LDAPMessage *ldtmp, *res; /* results returned from search */ - char name[MED_BUF_SIZE]; - char response[SMALL_BUF_SIZE]; - char *cp, *dn, **rdns; - LDAPFiltInfo *fi; - extern LDAPFiltDesc *lfdp; /* LDAP filter descriptor */ - extern struct attribute attrlist[]; /* complete list of attrs */ - extern void Free(); - -#ifdef DEBUG - if (debug & D_TRACE) - fprintf(stderr, "->find(%s)\n", who); -#endif - /* did not specify a 'who' */ - if (who == NULL) { - printf(" Locate whose entry? "); - fflush(stdout); - fetch_buffer(name, sizeof(name), stdin); - if (name[0] != '\0') - who = name; - else - return(NULL); - } - if (attrs_set == 0) { - j = k = 0; - attrs_set = 1; - for (i = 0; attrlist[i].quipu_name != NULL; i++) { - if (attrlist[i].flags & ATTR_FLAG_READ) - read_attrs[j++] = attrlist[i].quipu_name; - if (attrlist[i].flags & ATTR_FLAG_SEARCH) - search_attrs[k++] = attrlist[i].quipu_name; - } - read_attrs[j] = NULL; - search_attrs[k] = NULL; - } - - /* - * If the user-supplied name has any commas in it, we - * assume that it is a UFN, and do everything right - * here. If we don't find it, treat it as NOT a UFN. - */ - if (strchr(who, ',') != NULL) { - int savederef; -#ifdef DEBUG - if (debug & D_FIND) - printf("\"%s\" appears to be a UFN\n", who); -#endif - savederef = ld->ld_deref; - ld->ld_deref = LDAP_DEREF_FINDING; - if ((rc = ldap_ufn_search_s(ld, who, search_attrs, FALSE, &res)) != - LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED && - rc != LDAP_TIMELIMIT_EXCEEDED) { - ldap_perror(ld, "ldap_ufn_search_s"); - ld->ld_deref = savederef; - return(NULL); - } - if ((matches = ldap_count_entries(ld, res)) < 0) { - ldap_perror(ld, "ldap_count_entries"); - ld->ld_deref = savederef; - return(NULL); - } else if (matches == 1) { - if (ldap_search_s(ld, ldap_get_dn(ld, ldap_first_entry(ld, res)), LDAP_SCOPE_BASE, "objectClass=*", read_attrs, FALSE, &res) != LDAP_SUCCESS) { - if (ld->ld_errno == LDAP_UNAVAILABLE) - printf(" Could not contact the X.500 server to find \"%s\".\n", who); - else - ldap_perror(ld, "ldap_search_s"); - return(NULL); - } - ld->ld_deref = savederef; - return(res); - } else if (matches > 1 ) { - return( disambiguate( ld, res, matches, read_attrs, - who ) ); - } - ld->ld_deref = savederef; - } - - /* - * Old users of the MTS *USERDIRECTORY will likely wrap the name - * in quotes. Not only is this unnecessary, but it also won't work. - */ - for (cp = strchr(who, '"'); cp != NULL; cp = strchr(cp, '"')) { - if (!admonished) { - printf(" You do not need to enclose names in quotes.\n"); - admonished = TRUE; - } - *cp++ = ' '; - if (*cp == '\0') - break; - } - - /* - * It wasn't a UFN, so look it up in the usual method. - */ - for (fi = ldap_getfirstfilter(lfdp, "ud", who); fi != NULL; - fi = ldap_getnextfilter(lfdp)) { -#ifdef DEBUG - if (debug & D_FIND) - printf("Searching, filter = %s\n", fi->lfi_filter); -#endif - - if ((rc = ldap_search_s(ld, search_base, fi->lfi_scope, - fi->lfi_filter, search_attrs, FALSE, &res)) != LDAP_SUCCESS && - rc != LDAP_SIZELIMIT_EXCEEDED && rc != LDAP_TIMELIMIT_EXCEEDED) { - ldap_perror(ld, "ldap_search_s"); - ldap_msgfree(res); - return(NULL); - } - if ((matches = ldap_count_entries(ld, res)) < 0) { - ldap_perror(ld, "ldap_count_entries"); - ldap_msgfree(res); - return(NULL); - } - else if (matches == 1) { - dn = ldap_get_dn(ld, ldap_first_entry(ld, res)); - ldap_msgfree(res); - if (!quiet) - printf(" Found one %s match for \"%s\"\n", - fi->lfi_desc, who); - if (!fi->lfi_isexact) { - rdns = ldap_explode_dn(dn, TRUE); - printf(" Do you mean %s? ", *rdns); - (void) ldap_value_free(rdns); - fflush(stdout); - fetch_buffer(response, sizeof(response), stdin); - if ((response[0] == 'n') || (response[0] == 'N')) - return(NULL); - } -#ifdef DEBUG - if (debug & D_FIND) { - printf(" Calling ldap_search_s()\n"); - printf(" ld = 0x%x\n", ld); - printf(" dn = %s\n", dn); - printf(" scope = LDAP_SCOPE_BASE\n"); - printf(" filter = %s\n", "objectClass=*"); - for (i = 0; read_attrs[i] != NULL; i++) - printf(" read_attrs[%d] = %s\n", i, read_attrs[i]); - printf(" read_attrs[%d] = NULL\n", i); - printf(" attrsonly = FALSE\n"); - printf(" &results = 0x%x\n", &res); - } -#endif - if (ldap_search_s(ld, dn, LDAP_SCOPE_BASE, "objectClass=*", read_attrs, FALSE, &res) != LDAP_SUCCESS) { - ldap_perror(ld, "ldap_search_s"); - ldap_msgfree(res); - return(NULL); - } - Free(dn); - return(res); - } - else if (matches > 0) { - ldtmp = disambiguate(res, matches, read_attrs, who); - ldap_msgfree(res); - return(ldtmp); - } - /* if we're here, there were zero matches */ - ldap_msgfree(res); - } - return(NULL); -} - -pick_one(i) -int i; -{ - int n; - char user_pick[SMALL_BUF_SIZE]; - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->pick_one(%d)\n", i); -#endif - - /* make the user pick an entry */ - for (;;) { - printf(" Enter the number of the name you want or Q to quit: "); - fflush(stdout); - fetch_buffer(user_pick, sizeof(user_pick), stdin); - if (user_pick[0] == 'q' || user_pick[0] == 'Q') - return(-1); - n = atoi(user_pick); - if ((n > 0) && (n <= i)) - return(n); - printf(" Invalid response\n"); - } - /* NOTREACHED */ -} - -print_list(list, names, matches) -LDAPMessage *list; -char *names[]; -int *matches; -{ - char **rdns, **cpp; - extern int lpp; - char resp[SMALL_BUF_SIZE]; - register LDAPMessage *ep; - register int i = 1; - register int rest = 4; /* 4, not 1 */ - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->print_list(%x, %x, %x)\n", list, names, matches); -#endif - /* print a list of names from which the user will select */ - for (ep = ldap_first_entry(ld, list); ep != NULL; ep = ldap_next_entry(ld, ep)) { - - names[i] = ldap_get_dn(ld, ep); - rdns = ldap_explode_dn(names[i], TRUE); - cpp = ldap_get_values(ld, ep, "title"); - if (cpp == NULL) - printf(" %3d. %s\n", i, *rdns); - else - printf(" %3d. %s, %s\n", i, *rdns, *cpp); - ldap_value_free(rdns); - ldap_value_free(cpp); - i++; - if ((rest++ > (lpp - 1)) && (i < *matches)) { -again: - printf(" More? "); - fflush(stdout); - fetch_buffer(resp, sizeof(resp), stdin); - if ((resp[0] == 'n') || (resp[0] == 'N')) - break; - else if ((num_picked = atoi(resp)) != 0) { - if (num_picked < i) - break; - else - goto again; - } - rest = 1; - } - } - *matches = i - 1; - names[i] = NULL; - return; -} - -find_all_subscribers(sub, group) -char *sub[]; -char *group; -{ - int count; - LDAPMessage *result; - static char *attributes[] = { "cn", NULL }; - char filter[MED_BUF_SIZE]; - register LDAPMessage *ep; - register int i = 0; - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->find_all_subscribers(%x, %s)\n", sub, group); -#endif - - sprintf(filter, "%s=%s", "memberOfGroup", group); - if (ldap_search_s(ld, search_base, LDAP_SCOPE_SUBTREE, filter, attributes, FALSE, &result) != LDAP_SUCCESS) { - if (ld->ld_errno == LDAP_NO_SUCH_ATTRIBUTE) - return(0); - ldap_perror(ld, "ldap_search_s"); - return(0); - } - count = ldap_count_entries(ld, result); - if (count < 1) { - ldap_msgfree(result); - return(0); - } - if ( count > MAX_VALUES ) { - printf( " Only retrieving the first %d subscribers....\n", - MAX_VALUES ); - } - - for (ep = ldap_first_entry(ld, result); i < MAX_VALUES && ep != NULL; ep = ldap_next_entry(ld, ep)) { - sub[i++] = ldap_get_dn(ld, ep); -#ifdef DEBUG - if (debug & D_PARSE) - printf("sub[%d] = %s\n", i - 1, sub[i - 1]); -#endif - } - sub[i] = NULL; - ldap_msgfree(result); - return(count); -} - -char * fetch_boolean_value(who, attr) -char *who; -struct attribute attr; -{ - LDAPMessage *result; /* from the search below */ - register LDAPMessage *ep; /* entry pointer */ - register char **vp; /* for parsing the result */ - static char *attributes[] = { NULL, NULL }; - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->fetch_boolean_value(%s, %s)\n", who, attr.quipu_name); -#endif - attributes[0] = attr.quipu_name; - if (ldap_search_s(ld, who, LDAP_SCOPE_BASE, "objectClass=*", attributes, FALSE, &result) != LDAP_SUCCESS) { - if (ld->ld_errno == LDAP_NO_SUCH_ATTRIBUTE) - return("FALSE"); - ldap_perror(ld, "ldap_search_s"); - ldap_msgfree(result); - return(NULL); - } - - /* - * We did a read on one name and only asked for one attribute. - * There's no reason to loop through any of these structures. - * - * If ldap_first_attribute() returns NULL, then this entry did - * not have this particular attribute. - */ - ep = ldap_first_entry(ld, result); - if ((vp = (char **) ldap_get_values(ld, ep, attr.quipu_name)) == NULL) { - ldap_msgfree(result); - return("FALSE"); - } - else { - ldap_msgfree(result); - if (!strcasecmp(*vp, "TRUE")) { - ldap_value_free(vp); - return("TRUE"); - } - else if (!strcasecmp(*vp, "FALSE")) { - ldap_value_free(vp); - return("FALSE"); - } - else { - fprintf(stderr, " Got garbage -> [%s]\n", *vp); - ldap_value_free(vp); - return(NULL); - } - } -} diff --git a/clients/ud/globals.c b/clients/ud/globals.c deleted file mode 100644 index 121f36be21..0000000000 --- a/clients/ud/globals.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 1992, 1993, 1994 Regents of the University of Michigan. - * All rights reserved. - * - * Redistribution and use in source and binary forms are permitted - * provided that this notice is preserved and that due credit is given - * to the University of Michigan at Ann Arbor. The name of the University - * may not be used to endorse or promote products derived from this - * software without specific prior written permission. This software - * is provided ``as is'' without express or implied warranty. - */ - -#include -#include "ud.h" - -extern void set_boolean(), - change_field(), -#ifdef UOFM - set_updates(), -#endif - mod_addrDN(); - -struct attribute attrlist[] = { - - /* - * Field 1 = Quipu name - * Field 2 = String used when printing the field - * Field 3 = function used to modify this field (if any) - * Field 4 = Flags specifying how this field is displayed - */ - { "memberOfGroup", "Subscriptions", NULL, ATTR_FLAG_PERSON | ATTR_FLAG_READ | ATTR_FLAG_IS_A_DN }, - { "acl", "Access Control", NULL, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ }, - { "cn", "Aliases", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_SEARCH | ATTR_FLAG_GROUP_MOD }, - { "title", "Title", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_READ | ATTR_FLAG_SEARCH | ATTR_FLAG_PERSON_MOD }, - { "postalAddress", "Business address", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_PERSON_MOD | ATTR_FLAG_GROUP_MOD | ATTR_FLAG_IS_MULTILINE }, - { "telephoneNumber", "Business phone", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_PERSON_MOD | ATTR_FLAG_GROUP_MOD }, - { "mail", "E-mail address", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_SEARCH | ATTR_FLAG_PERSON_MOD | ATTR_FLAG_MAY_EDIT }, - { "member", "Members", mod_addrDN, ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_IS_A_DN | ATTR_FLAG_GROUP_MOD }, - { "homePhone", "Home phone", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_READ | ATTR_FLAG_PERSON_MOD }, - { "homePostalAddress", "Home address", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_READ | ATTR_FLAG_PERSON_MOD | ATTR_FLAG_IS_MULTILINE }, - { "objectClass", "Object class", NULL, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_SEARCH }, -#ifdef UOFM - { "multiLineDescription", "Description", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_PERSON_MOD | ATTR_FLAG_GROUP_MOD | ATTR_FLAG_IS_MULTILINE }, -#endif -#ifdef KERBEROS - { "krbName", "Kerberos name", NULL, ATTR_FLAG_PERSON | ATTR_FLAG_READ }, -#endif - { "description", "Brief description", NULL, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ }, - { "facsimileTelephoneNumber", "Fax number", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_PERSON_MOD | ATTR_FLAG_GROUP_MOD }, - { "pager", "Pager number", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_READ | ATTR_FLAG_PERSON_MOD }, - { "uid", "Uniqname", NULL, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ }, - { "userPassword", "Password", NULL, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ }, -#ifdef UOFM - { "noBatchUpdates", "No batch updates", set_updates, ATTR_FLAG_PERSON | ATTR_FLAG_READ | ATTR_FLAG_PERSON_MOD }, -#endif - { "joinable", "Joinable flag", set_boolean, ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_GROUP_MOD }, - { "associatedDomain", "Associated domain", change_field, ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_GROUP_MOD }, - { "owner", "Owner", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_IS_A_DN | ATTR_FLAG_GROUP_MOD }, - { "rfc822ErrorsTo", "Errors to", change_field, ATTR_FLAG_GROUP | ATTR_FLAG_READ }, - { "ErrorsTo", "Errors to", mod_addrDN, ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_IS_A_DN | ATTR_FLAG_GROUP_MOD }, - { "rfc822RequestsTo", "Requests to", change_field, ATTR_FLAG_GROUP | ATTR_FLAG_READ }, - { "RequestsTo", "Requests to", mod_addrDN, ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_IS_A_DN | ATTR_FLAG_GROUP_MOD }, - { "moderator", "Moderated by", change_field, ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_GROUP_MOD }, - { "labeledURL", "More Info (URL)", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_PERSON_MOD | ATTR_FLAG_GROUP_MOD | ATTR_FLAG_IS_A_URL }, - { "onVacation", "On Vacation", set_boolean, ATTR_FLAG_PERSON | ATTR_FLAG_READ | ATTR_FLAG_PERSON_MOD | ATTR_FLAG_IS_A_BOOL }, - { "vacationMessage", "Vacation Message", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_READ | ATTR_FLAG_PERSON_MOD | ATTR_FLAG_IS_MULTILINE }, - { "drink", "Favorite Beverage", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_READ | ATTR_FLAG_PERSON_MOD }, - { "lastModifiedBy", "Last modified by", NULL, ATTR_FLAG_GROUP | ATTR_FLAG_PERSON | ATTR_FLAG_IS_A_DN | ATTR_FLAG_READ }, - { "lastModifiedTime", "Last modified at", NULL, ATTR_FLAG_GROUP | ATTR_FLAG_PERSON | ATTR_FLAG_READ | ATTR_FLAG_IS_A_DATE }, - { NULL, NULL, NULL, ATTR_FLAG_NONE } -}; diff --git a/clients/ud/group.c b/clients/ud/group.c deleted file mode 100644 index 64006170eb..0000000000 --- a/clients/ud/group.c +++ /dev/null @@ -1,1242 +0,0 @@ -/* - * Copyright (c) 1993, 1994 Regents of the University of Michigan. - * All rights reserved. - * - * Redistribution and use in source and binary forms are permitted - * provided that this notice is preserved and that due credit is given - * to the University of Michigan at Ann Arbor. The name of the University - * may not be used to endorse or promote products derived from this - * software without specific prior written permission. This software - * is provided ``as is'' without express or implied warranty. - * - */ - -#include -#include -#include -#include -#include -#include "ud.h" - -extern LDAPMessage * find(); - -#ifdef DEBUG -extern int debug; -#endif - -extern char *bound_dn, *group_base; -extern int verbose, bind_status; -extern struct entry Entry; -extern LDAP *ld; - -extern void Free(); - -void add_group(name) -char *name; -{ - register int i, idx = 0, prompt = 0; - char tmp[BUFSIZ], dn[BUFSIZ]; - static LDAPMod *attrs[9]; - LDAPMod init_rdn, init_owner, init_domain, - init_errors, init_request, init_joinable; - char *init_rdn_value[2], *init_owner_value[2], *init_domain_value[2], - *init_errors_value[MAX_VALUES], *init_joinable_value[2], - *init_request_value[MAX_VALUES]; - extern void ldap_flush_cache(); - extern char * strip_ignore_chars(); - -#ifdef DEBUG - if (debug & D_TRACE) { - if (name == NULL) - printf("->add_group(NULL)\n"); - else - printf("->add_group(%s)\n", name); - } -#endif - - if (bind_status == UD_NOT_BOUND) { - if (auth((char *) NULL, 1) < 0) { - return; - } - } - - /* - * If the user did not supply us with a name, prompt them for - * a name. - */ - if ((name == NULL) || (*name == '\0') || !strcasecmp(name, "group")) { - ++prompt; - printf(" Group to create? "); - fflush(stdout); - fetch_buffer(tmp, sizeof(tmp), stdin); - if (tmp[0] == '\0') - return; - name = strdup(tmp); - } - - /* remove quotes, dots, and underscores. */ - name = strip_ignore_chars(name); - -#ifdef UOFM - if (isauniqname(name)) { - printf(" '%s' could be confused with a U-M uniqname.\n", name); - printf(" You can create the group, but you need to make sure that\n"); - printf(" you reserve the uniqname for use as your groupname\n\n"); - printf(" Are you sure that you want to do this? "); - fflush(stdout); - fetch_buffer(tmp, sizeof(tmp), stdin); - if (!(tmp[0] == 'y' || tmp[0] == 'Y')) - return; - printf("\n Be sure to contact your uniqname administrator to reserve\n"); - printf(" the uniqname '%s' for use as your group name.\n", name); - } -#endif - sprintf(dn, "cn=%s, %s", name, group_base); - - /* - * Make sure that this group does not already exist. - */ - if (vrfy(dn) == TRUE) { - printf(" The group \"%s\" already exists.\n", name); - return; - } - - /* - * Take the easy way out: Fill in some reasonable values for - * the most important fields, and make the user use the modify - * command to change them, or to give values to other fields. - */ - init_rdn_value[0] = name; - init_rdn_value[1] = NULL; - init_rdn.mod_op = LDAP_MOD_ADD; - init_rdn.mod_type = "cn"; - init_rdn.mod_values = init_rdn_value; - attrs[idx++] = &init_rdn; - - init_owner_value[0] = bound_dn; - init_owner_value[1] = NULL; - init_owner.mod_op = LDAP_MOD_ADD; - init_owner.mod_type = "owner"; - init_owner.mod_values = init_owner_value; - attrs[idx++] = &init_owner; - -#ifdef UOFM - init_domain_value[0] = "umich.edu"; -#else - init_domain_value[0] = "."; -#endif - init_domain_value[1] = NULL; - init_domain.mod_op = LDAP_MOD_ADD; - init_domain.mod_type = "associatedDomain"; - init_domain.mod_values = init_domain_value; - attrs[idx++] = &init_domain; - - init_errors_value[0] = bound_dn; - init_errors_value[1] = NULL; - init_errors.mod_op = LDAP_MOD_ADD; - init_errors.mod_type = "ErrorsTo"; - init_errors.mod_values = init_errors_value; - attrs[idx++] = &init_errors; - - init_request_value[0] = bound_dn; - init_request_value[1] = NULL; - init_request.mod_op = LDAP_MOD_ADD; - init_request.mod_type = "RequestsTo"; - init_request.mod_values = init_request_value; - attrs[idx++] = &init_request; - - init_joinable_value[0] = "FALSE"; - init_joinable_value[1] = NULL; - init_joinable.mod_op = LDAP_MOD_ADD; - init_joinable.mod_type = "joinable"; - init_joinable.mod_values = init_joinable_value; - attrs[idx++] = &init_joinable; - - /* end it with a NULL */ - attrs[idx] = NULL; - -#ifdef DEBUG - if (debug & D_GROUPS) { - register LDAPMod **lpp; - register char **cpp; - register int j; - extern char * code_to_str(); - printf(" About to call ldap_add()\n"); - printf(" ld = 0x%x\n", ld); - printf(" dn = [%s]\n", dn); - for (lpp = attrs, i = 0; *lpp != NULL; lpp++, i++) { - printf(" attrs[%1d] code = %s type = %s\n", i, - code_to_str((*lpp)->mod_op), (*lpp)->mod_type); - for (cpp = (*lpp)->mod_values, j = 0; *cpp != NULL; cpp++, j++) - printf(" value #%1d = %s\n", j, *cpp); - printf(" value #%1d = NULL\n", j); - } - } -#endif - - /* - * Now add this to the X.500 Directory. - */ - if (ldap_add_s(ld, dn, attrs) != 0) { - ldap_perror(ld, " ldap_add_s"); - printf(" Group not added.\n"); - if (prompt) Free(name); - return; - } - if (verbose) - printf(" Group \"%s\" has been added to the Directory\n", - name); - - /* - * We need to blow away the cache here. - * - * Since we first looked up the name before trying to create it, - * and that look-up failed, the cache will falsely claim that this - * entry does not exist. - */ - (void) ldap_flush_cache(ld); - if (prompt) Free(name); - return; -} - -void remove_group(name) -char *name; -{ - char *dn, tmp[BUFSIZ]; - static char * bind_and_fetch(); - -#ifdef DEBUG - if (debug & D_TRACE) { - if (name == NULL) - printf("->remove_group(NULL)\n"); - else - printf("->remove_group(%s)\n", name); - } -#endif - if ((dn = bind_and_fetch(name)) == NULL) - return; - - printf("\n The group '%s' will be permanently removed from\n", - name); - printf(" the Directory. Are you absolutely sure that you want to\n" ); printf(" remove this entire group? "); - fflush(stdout); - fetch_buffer(tmp, sizeof(tmp), stdin); - if (!(tmp[0] == 'y' || tmp[0] == 'Y')) - return; - - /* - * Now remove this from the X.500 Directory. - */ - if (ldap_delete_s(ld, dn) != 0) { - if (ld->ld_errno == LDAP_INSUFFICIENT_ACCESS) - printf(" You do not own the group \"%s\".\n", name); - else - ldap_perror(ld, " ldap_delete_s"); - printf(" Group not removed.\n"); - Free(dn); - return; - } - ldap_uncache_entry(ld, dn); - if (verbose) - if (name == NULL) - printf(" The group has been removed.\n"); - else - printf(" The group \"%s\" has been removed.\n", name); - Free(dn); - return; -} - -void x_group(action, name) -int action; -char *name; -{ - char **vp; - char *values[2], *group_name; - LDAPMod mod, *mods[2]; - static char *actions[] = { "join", "resign from", NULL }; - static char * bind_and_fetch(); - -#ifdef DEBUG - if (debug & D_TRACE) { - if (name == NULL) - printf("->x_group(%d, NULL)\n", action); - else - printf("->x_group(%d, %s)\n", action, name); - } -#endif - - /* the action desired sets the opcode to use */ - switch (action) { - case G_JOIN: - mod.mod_op = LDAP_MOD_ADD; - break; - case G_RESIGN: - mod.mod_op = LDAP_MOD_DELETE; - break; - default: - printf("x_group: %d is not a known action\n", action); - } - - if ((group_name = bind_and_fetch(name)) == NULL) - return; - vp = Entry.attrs[attr_to_index("joinable")].values; - if (action == G_JOIN) { - if (vp == NULL) { - printf(" No one is permitted to join \"%s\"\n", group_name); - Free(group_name); - return; - } - if (!strcasecmp(*vp, "FALSE")) { - printf(" No one is permitted to join \"%s\"\n", group_name); - Free(group_name); - return; - } - } - - /* fill in the rest of the modification structure */ - mods[0] = &mod; - mods[1] = (LDAPMod *) NULL; - values[0] = Entry.DN; - values[1] = NULL; - mod.mod_type = "memberOfGroup"; - mod.mod_values = values; - -#ifdef DEBUG - if (debug & D_GROUPS) { - register LDAPMod **lpp; - register char **cp; - register int i, j; - printf(" About to call ldap_modify_s()\n"); - printf(" ld = 0x%x\n", ld); - printf(" dn = [%s]\n", bound_dn); - for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) { - printf(" mods[%1d] code = %1d\n", i, (*lpp)->mod_op); - printf(" mods[%1d] type = %s\n", i, (*lpp)->mod_type); - for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++) - printf(" mods[%1d] v[%1d] = %s\n", i, j, *cp); - - } - } -#endif - - if (ldap_modify_s(ld, bound_dn, mods)) { - if ((action == G_JOIN) && (ld->ld_errno == LDAP_TYPE_OR_VALUE_EXISTS)) - printf(" You are already subscribed to \"%s\"\n", group_name); - else if ((action == G_RESIGN) && (ld->ld_errno == LDAP_NO_SUCH_ATTRIBUTE)) - printf(" You are not subscribed to \"%s\"\n", group_name); - else - mod_perror(ld); - Free(group_name); - return; - } - ldap_uncache_entry(ld, bound_dn); - if (verbose) { - switch (action) { - case G_JOIN: - printf(" You are now subscribed to \"%s\"\n", group_name); - break; - case G_RESIGN: - printf(" You are no longer subscribed to \"%s\"\n", group_name); - break; - } - } - Free(group_name); - return; -} - -void bulk_load(group) -char *group; -{ - register int idx_mail, idx_x500; - register int count_mail, count_x500; - char *values_mail[MAX_VALUES + 1], *values_x500[MAX_VALUES + 1]; - int added_mail_entries = FALSE, added_x500_entries = FALSE; - char s[MED_BUF_SIZE]; - LDAPMod mod, *mods[2]; - LDAPMessage *lm; - FILE *fp; - int len; - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->bulk_load(%s)\n", group); -#endif - - /* you lose if going through MichNet */ - if ( !isatty( 1 )) { -#ifdef UOFM - printf(" Not allowed via UM-X500 connections.\n"); -#endif - return; - } - - /* fetch entries from the file containing the e-mail addresses */ - printf("\n File to load? "); - fflush(stdout); - fetch_buffer(s, sizeof(s), stdin); - if (s[0] == '\0') { - return; - /*NOTREACHED*/ - } - if ((fp = fopen(s, "r")) == NULL) { - perror("bulk_load: fopen"); - return; - } - if (verbose) - printf(" Loading group members from %s\n", s); - - /* load them in MAX_VALUES at a time */ - for (;;) { - for (idx_mail = 0, idx_x500 = 0; - idx_mail < MAX_VALUES && idx_x500 < MAX_VALUES; ) { - (void) fgets(s, sizeof(s), fp); - if (feof(fp)) - break; - len = strlen(s) - 1; - if (len == 0) - continue; - s[len] = '\0'; - if (strchr(s, '@')) - values_mail[idx_mail++] = strdup(s); - else { - if ((lm = find(s, !verbose)) == (LDAPMessage *) NULL) { - printf(" Could not locate \"%s\" -- skipping.\n", s); - } - else { - parse_answer(lm); - values_x500[idx_x500++] = strdup(Entry.DN); - } - } - } - values_mail[idx_mail] = NULL; - values_x500[idx_x500] = NULL; - count_mail = idx_mail; - count_x500 = idx_x500; - - /* - * Add the e-mail addresses. - */ - if (count_mail > 0) { - mods[0] = &mod; - mods[1] = (LDAPMod *) NULL; - mod.mod_type = "mail"; - mod.mod_values = values_mail; - if (added_mail_entries) - mod.mod_op = LDAP_MOD_ADD; - else - mod.mod_op = LDAP_MOD_REPLACE; - -#ifdef DEBUG - if (debug & D_GROUPS) { - register LDAPMod **lpp; - register char **cp; - register int i, j; - printf(" About to call ldap_modify_s()\n"); - printf(" ld = 0x%x\n", ld); - printf(" dn = [%s]\n", group); - for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) { - printf(" mods[%1d] code = %1d\n", i, (*lpp)->mod_op); - printf(" mods[%1d] type = %s\n", i, (*lpp)->mod_type); - for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++) - printf(" mods[%1d] v[%1d] = %s\n", i, j, *cp); - } - } -#endif - if (ldap_modify_s(ld, group, mods)) - mod_perror(ld); - for (idx_mail--; idx_mail >= 0; idx_mail--) - Free(values_mail[idx_mail]); - ldap_uncache_entry(ld, group); - added_mail_entries = TRUE; - - } - - /* - * Add the X.500 style names. - */ - if (count_x500 > 0) { - mods[0] = &mod; - mods[1] = (LDAPMod *) NULL; - mod.mod_type = "member"; - mod.mod_values = values_x500; - if (added_x500_entries) - mod.mod_op = LDAP_MOD_ADD; - else - mod.mod_op = LDAP_MOD_REPLACE; - -#ifdef DEBUG - if (debug & D_GROUPS) { - register LDAPMod **lpp; - register char **cp; - register int i, j; - printf(" About to call ldap_modify_s()\n"); - printf(" ld = 0x%x\n", ld); - printf(" dn = [%s]\n", group); - for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) { - printf(" mods[%1d] code = %1d\n", i, (*lpp)->mod_op); - printf(" mods[%1d] type = %s\n", i, (*lpp)->mod_type); - for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++) - printf(" mods[%1d] v[%1d] = %s\n", i, j, *cp); - } - } -#endif - if (ldap_modify_s(ld, group, mods)) - mod_perror(ld); - for (idx_x500--; idx_x500 >= 0; idx_x500--) - Free(values_x500[idx_x500]); - ldap_uncache_entry(ld, group); - added_x500_entries = TRUE; - - } - - /* - * If both counts were less than the maximum number we - * can handle at a time, then we are done. - */ - if ((count_mail < MAX_VALUES) && (count_x500 < MAX_VALUES)) - break; - } - fclose(fp); - return; -} - -void purge_group(group) -char *group; -{ - int isclean = TRUE; - LDAPMessage *lm; - LDAPMod mod, *mods[2]; - char dn[BUFSIZ], tmp[BUFSIZ], *values[2], **vp, **rdns; - extern char * my_ldap_dn2ufn(); - extern int col_size; - -#ifdef DEBUG - if (debug & D_TRACE) { - if (group == NULL) - printf("->purge_group(NULL)\n"); - else - printf("->purge_group(%s)\n", group); - } -#endif - if (bind_status == UD_NOT_BOUND) { - if (auth((char *) NULL, 1) < 0) - return; - } - /* - * If the user did not supply us with a name, prompt them for - * a name. - */ - if ((group == NULL) || (*group == '\0')) { - printf("Group to purge? "); - fflush(stdout); - fetch_buffer(tmp, sizeof(tmp), stdin); - if (tmp[0] == '\0') - return; - group = tmp; - } - sprintf(dn, "cn=%s, %s", group, group_base); - - /* make sure the group in question exists */ - if ((lm = find(group, FALSE)) == (LDAPMessage *) NULL) { - printf(" Could not locate group \"%s\"\n", group); - return; - } - parse_answer(lm); - ldap_msgfree(lm); - - /* none of this stuff changes */ - mods[0] = &mod; - mods[1] = (LDAPMod *) NULL; - - values[1] = NULL; - - mod.mod_values = values; - mod.mod_type = "member"; - mod.mod_op = LDAP_MOD_DELETE; - - /* - * Now cycle through all of the names in the "members" part of the - * group (but not the e-mail address part). Lookup each one, and - * if it isn't found, let the user know so s/he can delete it. - */ - vp = Entry.attrs[attr_to_index("member")].values; - if (vp == NULL) { - if (verbose) - printf(" \"%s\" has no X.500 members. There is nothing to purge.\n", group); - return; - } - for (; *vp != NULL; vp++) { - char ans[BUFSIZ], *ufn, *label = "Did not find: "; - int len = strlen(label); - - if (vrfy(*vp)) - continue; - isclean = FALSE; - ufn = my_ldap_dn2ufn(*vp); - format2(ufn, label, (char *) NULL, 2, 2 + len, col_size); -ask: - printf(" Purge, Keep, Replace, Abort [Keep]? "); - fflush(stdout); - fetch_buffer(ans, sizeof(ans), stdin); - if ((ans[0] == '\0') || !strncasecmp(ans, "Keep", strlen(ans))) - continue; - if (!strncasecmp(ans, "Abort", strlen(ans))) { - ldap_uncache_entry(ld, dn); - return; - } - if (!strncasecmp(ans, "Purge", strlen(ans)) || !strncasecmp(ans, "Replace", strlen(ans))) { - values[0] = *vp; -#ifdef DEBUG - if (debug & D_GROUPS) { - register LDAPMod **lpp; - register char **cp; - register int i, j; - printf(" About to call ldap_modify_s()\n"); - printf(" ld = 0x%x\n", ld); - printf(" dn = [%s]\n", Entry.DN); - for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) { - printf(" mods[%1d] code = %1d\n", i, (*lpp)->mod_op); - printf(" mods[%1d] type = %s\n", i, (*lpp)->mod_type); - for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++) - printf(" mods[%1d] v[%1d] = %s\n", i, j, *cp); - - } - } -#endif - if (ldap_modify_s(ld, Entry.DN, mods)) - mod_perror(ld); - - /* now add the replacement if requested */ - if (!strncasecmp(ans, "Purge", strlen(ans))) - continue; - rdns = ldap_explode_dn(*vp, TRUE); - if ((lm = find(*rdns, FALSE)) == NULL) { - printf(" Could not find a replacement for %s; purged only.\n", *rdns); - ldap_msgfree(lm); - ldap_value_free(rdns); - break; - } - values[0] = ldap_get_dn(ld, ldap_first_entry(ld, lm)); - mod.mod_op = LDAP_MOD_ADD; -#ifdef DEBUG - if (debug & D_GROUPS) { - register LDAPMod **lpp; - register char **cp; - register int i, j; - printf(" About to call ldap_modify_s()\n"); - printf(" ld = 0x%x\n", ld); - printf(" dn = [%s]\n", Entry.DN); - for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) { - printf(" mods[%1d] code = %1d\n", i, (*lpp)->mod_op); - printf(" mods[%1d] type = %s\n", i, (*lpp)->mod_type); - for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++) - printf(" mods[%1d] v[%1d] = %s\n", i, j, *cp); - - } - } -#endif - if (ldap_modify_s(ld, Entry.DN, mods)) - mod_perror(ld); - ldap_msgfree(lm); - ldap_value_free(rdns); - - /* set this back to DELETE for other purges */ - mod.mod_op = LDAP_MOD_DELETE; - } - else { - printf(" Did not recognize that answer.\n\n"); - goto ask; - } - } - ldap_uncache_entry(ld, Entry.DN); - if (isclean) - printf(" No entries were purged.\n"); - return; -} - -void tidy_up() -{ - register int i = 0; - int found_one = 0; - register char **vp; - LDAPMessage *lm; - static LDAPMod mod; - static LDAPMod *mods[2] = { &mod, NULL }; - static char *values[MAX_VALUES]; - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->tidy()\n"); -#endif - - if (bind_status == UD_NOT_BOUND) { - if (auth((char *) NULL, 1) < 0) { - return; - } - } - - /* lookup the user, and see to which groups he has subscribed */ - vp = ldap_explode_dn(bound_dn, TRUE); - if ((lm = find(*vp, TRUE)) == (LDAPMessage *) NULL) { - printf(" Could not locate \"%s\"\n", *vp); - ldap_value_free(vp); - return; - } - ldap_value_free(vp); - parse_answer(lm); - ldap_msgfree(lm); - vp = Entry.attrs[attr_to_index("memberOfGroup")].values; - if (vp == NULL) { - printf(" You have not subscribed to any groups.\n"); - return; - } - - /* now, loop through these groups, deleting the bogus */ - for ( ; *vp != NULL; vp++) { - if (vrfy(*vp)) - continue; - found_one++; - printf(" \"%s\" is not a valid group name.\n", *vp); - values[i++] = strdup(*vp); - if ( i >= MAX_VALUES ) { - printf( " At most %d invalid groups can be removed at one time; skipping the rest.\n", MAX_VALUES ); - break; - } - } - if (found_one == 0) { - if (verbose) - printf(" You are not a member of any invalid groups. There is nothing to tidy.\n"); - return; - } - - /* delete the most heinous entries */ - values[i] = NULL; - mod.mod_values = values; - mod.mod_op = LDAP_MOD_DELETE; - mod.mod_type = "memberOfGroup"; - if (ldap_modify_s(ld, bound_dn, mods)) - mod_perror(ld); - ldap_uncache_entry(ld, bound_dn); - - /* tidy up before we finish tidy_up */ - for ( ; i >= 1; i--) - Free(values[i - 1]); - return; -} - -/* - * This routine is used to modify lists that can contain either Distinguished - * Names or e-mail addresses. This includes things like group members, - * the errors-to field in groups, and so on. - */ -void mod_addrDN(group, offset) -char *group; -int offset; -{ - extern struct attribute attrlist[]; - char s[BUFSIZ], *new_value /* was member */, *values[2]; - char attrtype[ 64 ]; - int i; - LDAPMod mod, *mods[2]; - LDAPMessage *mp; - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->mod_addrDN(%s)\n", group); -#endif - /* - * At this point the user can indicate that he wishes to add values - * to the attribute, delete values from the attribute, or replace the - * current list of values with a new list. The first two cases - * are very straight-forward, but the last case requires a little - * extra care and work. - */ - if (verbose) { - printf("\n"); - if ( !isatty( 1 )) - format("There are three options available at this point. You may: Add additional values; Delete values; or Replace the entire list of values with a new list entered interactively.\n", 75, 2); - else - format("There are four options available at this point. You may: Add one or more additional values; Delete one or more existing values; Replace the entire list of values with a new list entered interactively; or Bulk load a new list of values from a file, overwriting the existing list.\n", 75, 2); - } - - /* initialize the modififier type */ - mod.mod_type = NULL; - - for (;;) { - if ( !isatty( 1 )) - printf(" Do you want to Add, Delete, or Replace? "); - else - printf(" Do you want to Add, Delete, Replace, or Bulk load? "); - fflush(stdout); - fetch_buffer(s, sizeof(s), stdin); - if (s[0] == '\0') { - return; - /*NOTREACHED*/ - } - if (!strncasecmp(s, "add", strlen(s))) { - mod.mod_op = LDAP_MOD_ADD; - break; - } - else if (!strncasecmp(s, "delete", strlen(s))) { - mod.mod_op = LDAP_MOD_DELETE; - break; - } - else if (!strncasecmp(s, "replace", strlen(s))) { - mod.mod_op = LDAP_MOD_REPLACE; - break; - } - else if(!strncasecmp(s, "bulk", strlen(s))) { - bulk_load(group); - return; - } - else if (verbose) { - printf("\n"); - if ( !isatty( 1 )) - format("Did not recognize that response. Please use 'A' to add, 'D' to delete, or 'R' to replace the entire list with a new list\n", 75, 2); - else - format("Did not recognize that response. Please use 'A' to add, 'D' to delete, 'R' to replace the entire list with a new list, or 'B' to bulk load a new list from a file\n", 75, 2); - } - } - if (mod.mod_op == LDAP_MOD_REPLACE) { - if ( verbose && !confirm_action( "The entire existing list will be overwritten with the new values you are about to enter." )) { - printf("\n Modification halted.\n"); - return; - } - } - if (verbose) { - printf("\n"); - format("Values may be specified as a name (which is then looked up in the X.500 Directory) or as a domain-style (i.e., user@domain) e-mail address. Simply hit the RETURN key at the prompt when finished.\n", 75, 2); - printf("\n"); - } - - for (;;) { - printf("%s? ", attrlist[offset].output_string); - fflush(stdout); - fetch_buffer(s, sizeof(s), stdin); - if (s[0] == '\0') - return; - - /* - * If the string the user has just typed has an @-sign in it, - * then we assume it is an e-mail address. In this case, we - * just store away whatever it is they have typed. - * - * If the string had no @-sign, then we look in the Directory, - * make sure it exists, and if it does, we add that. - * - * If the string begins with a comma, then strip off the - * comma, and pass it along to the LDAP server. This is - * the way one can force ud to accept a name. Handy for - * debugging purposes. - */ - if (*s == ',') { - new_value = s + 1; - mod.mod_type = attrlist[offset].quipu_name; - } - else if (strchr(s, '@') == NULL) { - if ((mp = find(s, FALSE)) == (LDAPMessage *) NULL) { - printf(" Could not find \"%s\"\n", s); - if (verbose && (mod.mod_op == LDAP_MOD_DELETE)){ - printf("\n"); - format("I could not find anything that matched what you typed. You might try the \"purge\" command instead. It is used to purge corrupted or unlocatable entries from a group.", 75, 2); - printf("\n"); - } - continue; - } - parse_answer(mp); - new_value = Entry.DN; - mod.mod_type = attrlist[offset].quipu_name; - } - else if (mod.mod_op != LDAP_MOD_DELETE) { - /* - * Don't screw around with what the user has typed - * if they are simply trying to delete a rfc822mailbox - * value. - * - * spaces on the left hand side of the e-mail - * address are bad news - we know that there - * must be a @-sign in the string, or else we - * would not be here - * - * note that this means a value like: - * - * first m. last@host.domain - * - * will be turned into: - * - * first.m..last@host.domain - * - * and the mailer will need to do the right thing - * with this; alternatively we could add code that - * collapsed multiple dots into a single dot - * - * Don't screw up things like: - * - * "Bryan Beecher" - * Bryan Beecher - */ - register char *cp; - if (strchr(s, '<') == NULL) { - for (cp = s; *cp != '@'; cp++) - if (isspace(*cp)) - *cp = '.'; - } - new_value = s; - strcpy(attrtype, "rfc822"); - strcat(attrtype, attrlist[offset].quipu_name); - mod.mod_type = attrtype; - } - else { - new_value = s; - strcpy(attrtype, "rfc822"); - strcat(attrtype, attrlist[offset].quipu_name); - mod.mod_type = attrtype; - } - - /* fill in the rest of the ldap_mod() structure */ - mods[0] = &mod; - mods[1] = (LDAPMod *) NULL; - - values[0] = new_value; - values[1] = NULL; - mod.mod_values = values; - -#ifdef DEBUG - if (debug & D_GROUPS) { - register LDAPMod **lpp; - register char **cp; - register int i, j; - printf(" About to call ldap_modify_s()\n"); - printf(" ld = 0x%x\n", ld); - printf(" dn = [%s]\n", group); - for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) { - printf(" mods[%1d] code = %1d\n", - i, (*lpp)->mod_op); - printf(" mods[%1d] type = %s\n", - i, (*lpp)->mod_type); - for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++) - printf(" mods[%1d] v[%1d] = %s\n", - i, j, *cp); - } - } -#endif - - if (my_ldap_modify_s(ld, group, mods)) { - if (ld->ld_errno == LDAP_NO_SUCH_ATTRIBUTE) { - printf(" Could not locate value \"%s\"\n", - new_value); - continue; - } - else { - mod_perror(ld); - return; - } - } - ldap_uncache_entry(ld, group); - - /* - * If the operation was REPLACE, we now need to "zero out" the - * other "half" of the list (e.g., user specified an e-mail - * address; now we need to clear the DN part of the list). - * - * NOTE: WE HAVE ALREADY DONE HALF OF THE REPLACE ABOVE. - * - * Also, change the opcode to LDAP_MOD_ADD and give the user an - * opportunity to add additional members to the group. We - * only take this branch the very first time during a REPLACE - * operation. - */ - if (mod.mod_op == LDAP_MOD_REPLACE) { - if (!strncmp(mod.mod_type, "rfc822", 6)) - mod.mod_type = mod.mod_type + 6; - else { - strcpy(attrtype, "rfc822"); - strcat(attrtype, mod.mod_type); - mod.mod_type = attrtype; - } - mods[0] = &mod; - values[0] = NULL; - mod.mod_values = values; - mod.mod_op = LDAP_MOD_DELETE; -#ifdef DEBUG - if (debug & D_GROUPS) { - register LDAPMod **lpp; - register char **cp; - register int i, j; - printf(" About to call ldap_modify_s()\n"); - printf(" ld = 0x%x\n", ld); - printf(" dn = [%s]\n", group); - for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) { - printf(" mods[%1d] code = %1d\n", - i, (*lpp)->mod_op); - printf(" mods[%1d] type = %s\n", - i, (*lpp)->mod_type); - for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++) - printf(" mods[%1d] v[%1d] = %s\n", i, j, *cp); - } - } -#endif - if (my_ldap_modify_s(ld, group, mods)) { - /* - * A "No such attribute" error is no big deal. - * We only wanted to clear the attribute anyhow. - */ - if (ld->ld_errno != LDAP_NO_SUCH_ATTRIBUTE) { - mod_perror(ld); - return; - } - } - ldap_uncache_entry(ld, group); - if (verbose) - printf(" \"%s\" has been added\n", new_value); - mod.mod_op = LDAP_MOD_ADD; - } - else if (verbose && (mod.mod_op == LDAP_MOD_ADD)) - printf(" \"%s\" has been added\n", new_value); - else if (verbose && (mod.mod_op == LDAP_MOD_DELETE)) - printf(" \"%s\" has been removed\n", new_value); - } -} - -my_ldap_modify_s(ldap, group, mods) -LDAP *ldap; -char *group; -LDAPMod *mods[]; -{ - int was_rfc822member, rc; - - was_rfc822member = 0; - - if (!strcasecmp(mods[0]->mod_type, "rfc822member")) { - mods[0]->mod_type = "mail"; - was_rfc822member = 1; - } - - rc = ldap_modify_s(ldap, group, mods); - - if (was_rfc822member) - mods[0]->mod_type = "rfc822member"; - - return(rc); -} - -void list_groups(who) -char *who; -{ - LDAPMessage *mp; - char name[BUFSIZ], filter[BUFSIZ], *search_attrs[2]; - char *work_area[MAX_NUM_NAMES]; - char *dn, **rdns; - int i, rc; - - -#ifdef DEBUG - if (debug & D_TRACE) { - if (who == NULL) - printf("->list_groups(NULL)\n"); - else - printf("->list_groups(%s)\n", who); - } -#endif - /* - * First, decide what entry we are going to list. If the - * user has not included a name on the list command line, - * we will use the person who was last looked up with a find - * command. - * - * Once we know who to modify, be sure that they exist, and - * parse out their DN. - */ - if (who == NULL) { - printf(" List groups belonging to whose entry? "); - fflush(stdout); - fetch_buffer(name, sizeof(name), stdin); - if (name[0] != '\0') - who = name; - else - return; - } - if ((mp = find(who, TRUE)) == NULL) { - (void) ldap_msgfree(mp); - printf(" Could not locate \"%s\" in the Directory.\n", who); - return; - } - dn = ldap_get_dn(ld, ldap_first_entry(ld, mp)); - ldap_msgfree(mp); - rdns = ldap_explode_dn(dn, TRUE); - if (verbose) - printf("\n Listing groups belonging to \"%s\"\n", *rdns); - - /* lookup the groups belonging to this person */ - sprintf(filter, "owner=%s", dn); - Free(dn); - search_attrs[0] = "cn"; - search_attrs[1] = NULL; - if ((rc = ldap_search_s(ld, UD_WHERE_ALL_GROUPS_LIVE, LDAP_SCOPE_SUBTREE, - filter, search_attrs, FALSE, &mp)) != LDAP_SUCCESS && - rc != LDAP_SIZELIMIT_EXCEEDED && rc != LDAP_TIMELIMIT_EXCEEDED) { - ldap_perror(ld, "ldap_search_s"); - ldap_value_free(rdns); - return; - } - if ((rc = ldap_count_entries(ld, mp)) < 0) { - ldap_perror(ld, "ldap_count_entries"); - ldap_value_free(rdns); - return; - } - if (rc == 0) { - printf(" %s owns no groups in this portion of the Directory.\n", *rdns); - ldap_value_free(rdns); - return; - } - if (verbose) - printf(" %s owns %d groups.\n\n", *rdns, rc); - print_list(mp, work_area, &rc); - for (i = 1; work_area[i] != NULL; i++) - Free(work_area[i]); - ldap_msgfree(mp); - ldap_value_free(rdns); - return; -} - -static char * bind_and_fetch(name) -char *name; -{ - LDAPMessage *lm; - char tmp[MED_BUF_SIZE]; - extern char * strip_ignore_chars(); - -#ifdef DEBUG - if (debug & D_TRACE) { - if (name == NULL) - printf("->bind_and_fetch(NULL)\n"); - else - printf("->bind_and_fetch(%s)\n", name); - } -#endif - if (bind_status == UD_NOT_BOUND) { - if (auth((char *) NULL, 1) < 0) - return(NULL); - } - - /* - * If the user did not supply us with a name, prompt them for - * a name. - */ - if ((name == NULL) || (*name == '\0')) { - printf(" Group? "); - fflush(stdout); - fetch_buffer(tmp, sizeof(tmp), stdin); - if (tmp[0] == '\0') - return(NULL); - name = tmp; - } - /* remove quotes, dots, and underscores. */ - name = strip_ignore_chars(name); - -#ifdef DEBUG - if (debug & D_GROUPS) - printf("Group name = (%s)\n", name); -#endif - - /* make sure the group in question exists and is joinable */ - if ((lm = find(name, TRUE)) == (LDAPMessage *) NULL) { - printf(" Could not locate group \"%s\"\n", name); - return(NULL); - } - parse_answer(lm); - ldap_msgfree(lm); - -#ifdef DEBUG - if (debug & D_GROUPS) - printf("Group DN = (%s)\n", Entry.DN); -#endif - return(strdup(Entry.DN)); -} - -void list_memberships(who) -char *who; -{ - LDAPMessage *mp; - char name[BUFSIZ], filter[BUFSIZ], *search_attrs[2]; - char *work_area[MAX_NUM_NAMES]; - char *dn, **rdns; - int i, rc; - - -#ifdef DEBUG - if (debug & D_TRACE) { - if (who == NULL) - printf("->list_memberships(NULL)\n"); - else - printf("->list_memberships(%s)\n", who); - } -#endif - /* - * First, decide what entry we are going to list. If the - * user has not included a name on the list command line, - * we will use the person who was last looked up with a find - * command. - * - * Once we know who to modify, be sure that they exist, and - * parse out their DN. - */ - if (who == NULL) { - printf(" List memberships containing whose entry? "); - fflush(stdout); - fetch_buffer(name, sizeof(name), stdin); - if (name[0] != '\0') - who = name; - else - return; - } - if ((mp = find(who, TRUE)) == NULL) { - (void) ldap_msgfree(mp); - printf(" Could not locate \"%s\" in the Directory.\n", who); - ldap_msgfree(mp); - return; - } - dn = ldap_get_dn(ld, ldap_first_entry(ld, mp)); - rdns = ldap_explode_dn(dn, TRUE); - if (verbose) - printf("\n Listing memberships of \"%s\"\n", *rdns); - - /* lookup the groups belonging to this person */ - sprintf(filter, "member=%s", dn); - Free(dn); - search_attrs[0] = "cn"; - search_attrs[1] = NULL; - ldap_msgfree(mp); - if ((rc = ldap_search_s(ld, UD_WHERE_ALL_GROUPS_LIVE, LDAP_SCOPE_SUBTREE, - filter, search_attrs, FALSE, &mp)) != LDAP_SUCCESS && - rc != LDAP_SIZELIMIT_EXCEEDED && rc != LDAP_TIMELIMIT_EXCEEDED) { - ldap_perror(ld, "ldap_search_s"); - ldap_msgfree(mp); - ldap_value_free(rdns); - return; - } - if ((rc = ldap_count_entries(ld, mp)) < 0) { - ldap_perror(ld, "ldap_count_entries"); - ldap_msgfree(mp); - ldap_value_free(rdns); - return; - } - if (rc == 0) { - printf(" %s is not a member of any groups in this portion of the Directory.\n", *rdns); - ldap_msgfree(mp); - ldap_value_free(rdns); - return; - } - if (verbose) - printf(" %s is a member of %d groups.\n\n", *rdns, rc); - - /* - * print_list fills in the char * array starting at 1, not 0 - */ - print_list(mp, work_area, &rc); - for (i = 1; work_area[i] != NULL; i++) - Free(work_area[i]); - ldap_msgfree(mp); - ldap_value_free(rdns); - return; -} diff --git a/clients/ud/help.c b/clients/ud/help.c deleted file mode 100644 index 5a1ff231e0..0000000000 --- a/clients/ud/help.c +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (c) 1992, 1993 Regents of the University of Michigan. - * All rights reserved. - * - * Redistribution and use in source and binary forms are permitted - * provided that this notice is preserved and that due credit is given - * to the University of Michigan at Ann Arbor. The name of the University - * may not be used to endorse or promote products derived from this - * software without specific prior written permission. This software - * is provided ``as is'' without express or implied warranty. - */ - -#include -#include -#include -#include -#include -#include "ud.h" - -#ifdef DEBUG -extern int debug; -#endif - -print_help(s) -char *s; -{ - int len; /* command length */ - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->print_help(%s)\n", s); -#endif - if (s == NULL) - len = 0; - else { - len = strlen(s); - if (!strcasecmp(s, "commands")) - len = 0; - } - - /* print general help, or just on topic 's' if provided */ - if (len == 0) { - printf("\n Here are brief descriptions of available commands:\n\n"); - printf(" ? To print this list.\n"); - printf(" bind [who] To bind (authenticate) to the directory.\n"); - printf(" cb [where] To change the search base.\n"); - printf(" change [entry] To change information associated with an entry.\n"); - printf(" create [group] To create a new group entry.\n"); - printf(" dereference To toggle dereferencing of aliases.\n"); -#ifdef UOFM - if (isatty( 1 )) { -#endif - printf(" vedit [entry] To edit a complete Directory entry using your editor.\n"); -#ifdef UOFM - } -#endif - printf(" find [entry] To find an entry in the directory.\n"); - - printf(" groupbase [where] To change the group base.\n"); - printf(" help [command] To display detailed help for a particular command.\n"); - printf(" join [group] To subscribe to a group.\n"); - printf(" list [who] To list the groups owned by someone.\n"); - printf(" memberships [who] To list out the groups in which someone is a member.\n"); - printf(" purge [group] To remove obsolete entries from a group.\n"); - printf(" quit To terminate the program.\n"); - printf(" remove [group] To remove a group entry.\n"); - printf(" resign [group] To unsubscribe from a group.\n"); - printf(" status To display directory connection status.\n"); - printf(" tidy To unsubscribe from groups that no longer exist.\n"); - printf(" verbose To toggle the verbose switch.\n"); - - printf("\n Type \"help \" to get help about a particular command."); - printf("\n Type \"help options\" to get help about options in brackets above.\n"); -#ifdef UOFM - printf("\n Bugs in ud should be reported via e-mail to: ud-bugs@umich.edu\n" ); - printf("\n For more assistance with ud, contact the ITD Consultants by phoning\n" ); - printf(" 764-HELP or by sending e-mail to: consulting.help@umich.edu\n" ); -#endif /* UOFM */ - } - else if (!strncasecmp("options", s, len)) { - printf("\n"); - format("Most commands need additional information in order to work. For example, the 'remove' command needs to know the name of the group to remove. This can be specified along with the 'remove' command, or the program will prompt you for the information.", 75, 2); - printf("\n"); - printf(" [entry] An entry needs to be specified. This may be a person or a\n"); - format("group. The name can be specified as either a ordinary name (e.g., 'Jane Doe'), or as some other identifying characteristic (e.g., 'uid=babs').", 75, 15); - printf("\n"); - printf(" [group] A group in the Directory needs to be specified. This name\n"); - format("should be specified as a ordinary name (e.g., 'Friends of maX500').", 75, 15); - printf("\n"); - printf(" [where] A place in the Directory needs to be specified. This name\n"); - format("should be specified as an X.500-style name (e.g., 'ou=people, o=University of Michigan, c=United States of America'). In most cases, it is easier to omit the [where] and allow the program to guide you.", 75, 15); - printf("\n"); - printf(" [who] A person in the Directory needs to be specified. This name\n"); - format("can be specified as either a ordinary name (e.g., 'Jane Doe'), or as some other identifying characteristic (e.g., 'uid=babs').", 75, 15); - } - else if (!strncasecmp("list", s, len)) { - printf(" list [who]\n\n"); - format("Prints out the list of groups owned by the person specified.", 75, 2); - } - else if (!strncasecmp("memberships", s, len)) { - printf(" memberships [who]\n\n"); - format("Prints out the list of groups in which the person specified is a member.", 75, 2); - } - else if (!strncasecmp("vedit", s, len)) { - printf(" vedit [entry]\n\n"); - format("Looks up the specified person in the Directory, and then writes this entry into a file. It then uses the EDITOR environment variable to select an editor, and then loads this file into the editor. The entry can now be modified in any way desired, and when the editor is exited, the entry will be written back into the Directory.", 75, 2); - } - else if (!strncasecmp("status", s, len)) { - printf(" status\n\n"); - format("Prints out the current connection status. Lists the name of the current LDAP server, the current search base, the current group base, and the identity to which you are bound. If you have not bound as anyone then ud considers you bound as Nobody. cd is an alias for cb.", 75, 2); - } - else if (!strncasecmp("groupbase", s, len)) { - printf(" groupbase [where]\n\n"); - format("The syntax and use of this command is identical to the more commonly used 'cb' command. This command sets the base which is used to create groups in the X.500 Directory. Setting the base to a certain value does not necessarily grant the person write-access to that part of the Directory in order to successfully create a group.", 75, 2); - } - else if (!strncasecmp("cd", s, len) || !strncasecmp("cb", s,len)) { - printf(" cb [where]\n"); - printf(" cd [where]\n\n"); - format("The cb command changes the search base. By default, this program looks only in the local part of the Directory. By using the cb command, you can search other parts of the Directory.", 75, 2); - printf("\n Examples:\n"); - printf("\n * cb ..\n\n"); - format("changes the search base so that it is one level higher in the Directory. Note that if you perform several of these in a row you will move to the root of the Directory tree.", 75, 2); - printf("\n * cb ?\n\n"); - format("prints out a list of the possible areas to search below the current search base. This is useful once you have moved high in the tree and wish to snoop about.", 75, 2); - printf("\n * cb default\n\n"); - format("sets the search base to its original default value.", 75, 2); - printf("\n * cb o=Merit Computer Network, c=US\n\n"); - format("sets the search base to organization given, the Merit Computer Network in this case. This comamnd checks the validity of the specified search base, and rejects it if it is not a valid Distinguished Name (DN). A DN uniquely identifies a portion of the global X.500 namespace.", 75, 2); - } - else if (!strncasecmp("quit", s, len) || !strncasecmp("stop",s, len)) { - printf(" quit\n"); - printf(" stop\n\n"); - printf(" Quits the program. 'stop' is an alias for 'quit'.\n"); - } - else if (!strncasecmp("find", s, len) || !strncasecmp("display", s, len) || !strncasecmp("show", s, len)) { - printf(" find [entry]\n"); - printf(" show [entry]\n"); - printf(" display [entry]\n\n"); - format("Displays information about the person specified. If the name specified matches more than one person, one will be presented a list from which to make a choice. 'show' and 'display' are aliases for 'find.'", 75, 2); - } - else if (!strncasecmp("bind", s, len)) { - printf(" bind [who]\n\n"); - format("Binds (authenticates) to the Directory. It is generally necessary to bind to the Directory in order to look at privileged entries or to modify an entry. Allows one to authenticate prior to issuing a 'change' or 'modify' command. Most often used by administrators to bind to an identity.", 75, 2); - } - else if (!strncasecmp("modify", s, len) || !strncasecmp("change", s, len)) { - printf(" modify [entry]\n"); - printf(" change [entry]\n\n"); - format("Changes information associated with an entry in the X.500 Directory. 'change' is an alias for 'modify'.", 75, 2); - } - else if (!strncasecmp("verbose", s, len)) { - printf(" verbose\n\n"); - format("Turns on long and windy messages which might be useful to new users of this program. If verbose mode is already on, this turns it off.", 75, 2); - } - else if (!strncasecmp("dereference", s, len)) { - printf(" dereference\n\n"); - format("Turns off following of aliases when searching, etc. If alias dereferencing has already been turned off, this turns it back on.", 75, 2); - } - else if (!strncasecmp("create", s, len)) { - printf(" create [group]\n\n"); - format("Creates a new group in the Directory.", 75, 2); - } - else if (!strncasecmp("join", s, len) || !strncasecmp("subscribe", s, len)) { - printf(" join [group]\n"); - printf(" subscribe [group]\n\n"); - format("Adds the person as a subscriber to the specified group.", 75, 2); - } - else if (!strncasecmp("purge", s, len)) { - printf(" purge [group]\n\n"); - format("Goes through the specified group looking for Distinguished Names that cannot be found. As it finds each one, it gives the person an opportunity to delete it.", 75, 2); - } - else if (!strncasecmp("resign", s, len) || !strncasecmp("unsubscribe", s, len)) { - printf(" resign [group]\n"); - printf(" unsubscribe [group]\n\n"); - format("Deletes the person from the specified group.", 75, 2); - } - else if (!strncasecmp("remove", s, len)) { - printf(" remove [group]\n\n"); - format("Removes a group from the Directory.", 75, 2); - } - else if (!strncasecmp("help", s, len)) { - format("Prints out a brief description of each command.", 75, 2); - } - else if (!strncasecmp("tidy", s, len)) { - printf(" tidy\n\n"); - format("Unsubscribes you from non-existent groups. Useful when you cannot resign from a group because, while your X.500 entry still contains a pointer to it, someone has removed a group of which you were a subscriber.", 75, 2); - } - else if (*s == '?') { - format("Prints out a brief description of each command. Same as typing 'help help'.", 75, 2); - } - else { - printf(" Don't recognize <%s>\n", s); - } -} diff --git a/clients/ud/main.c b/clients/ud/main.c deleted file mode 100644 index cb2030c283..0000000000 --- a/clients/ud/main.c +++ /dev/null @@ -1,724 +0,0 @@ -/* - * Copyright (c) 1991, 1992, 1993 - * Regents of the University of Michigan. All rights reserved. - * - * Redistribution and use in source and binary forms are permitted - * provided that this notice is preserved and that due credit is given - * to the University of Michigan at Ann Arbor. The name of the University - * may not be used to endorse or promote products derived from this - * software without specific prior written permission. This software - * is provided ``as is'' without express or implied warranty. - * - * The University of Michigan would like to thank the following people for - * their contributions to this piece of software: - * - * Robert Urquhart - * Simon Fraser University, Academic Computing Services - */ - -#include -#include -#if defined(NeXT) -#include -#include -#else NeXT -#include -#endif NeXT -#include -#include -#ifndef DOS -#if defined( NeXT ) || defined( ultrix ) || defined( osf1 ) || (defined(SunOS) && SunOS < 40) -#include -#else /* defined( NeXT ) || defined( ultrix ) etc. */ -#include -#endif /* defined( NeXT ) || defined( ultrix ) etc. */ -#endif /* !DOS */ -#if defined( aix ) || defined( __NetBSD__ ) -#include -#endif /* aix || __NetBSD__ */ -#include -#include -#include -#include -#include -#include -#include -#include "portable.h" -#include "ud.h" - -#ifndef lint -char copyright[] = -"@(#) Copyright (c) 1991, 1992, 1993 Regents of the University of Michigan.\nAll rights reserved.\n"; -#endif - -/* - * Used with change_base() to indicate which base we are changing. - */ -#define BASE_SEARCH 0 -#define BASE_GROUPS 1 - -#define iscom(x) (!strncasecmp(x, cmd, strlen(cmd))) - -static char *server = NULL; -static char *config_file = UD_CONFIG_FILE; -static char *filter_file = FILTERFILE; -static int ldap_port = LDAP_PORT; -static int dereference = TRUE; - -char *default_bind_object = UD_BINDDN; - -char *bound_dn; /* bound user's Distinguished Name */ -char *group_base; /* place in X.500 tree where groups are */ -char *search_base; /* place in X.500 tree where searches start */ - -static jmp_buf env; /* spot to jump to on an interrupt */ - -int lpp; /* lines per page */ -int verbose; /* 1 if verbose mode on */ -int col_size; /* characters across on the screen */ -int bind_status; /* user's bind status */ - -LDAP *ld; /* LDAP descriptor */ -LDAPFiltDesc *lfdp; /* LDAP filter descriptor */ - -#ifdef DEBUG -int debug; /* debug flag */ -#endif - -main(argc, argv) -int argc; -char *argv[]; -{ - extern char Version[]; /* version number */ - extern char *optarg; /* for parsing argv */ - register int c; /* for parsing argv */ - register char *cp; /* for parsing Version */ - extern void initialize_attribute_strings(); - - verbose = 1; - - /* handle argument list */ - while ((c = getopt(argc, argv, "c:d:Df:l:p:s:u:vV")) != -1) { - switch (c) { - case 'l' : -#ifdef LDAP_DEBUG - ldap_debug = (int) strtol(optarg, (char **) NULL, 0); - lber_debug = ldap_debug; -#endif - break; - case 'd' : -#ifdef DEBUG - debug = (int) strtol(optarg, (char **) NULL, 0); -#endif - break; - case 's' : - server = strdup(optarg); - break; - case 'c' : - filter_file = strdup(optarg); - break; - case 'f' : - config_file = optarg; - break; - case 'p' : - ldap_port = atoi(optarg); - break; - case 'u' : - default_bind_object = strdup(optarg); - break; - case 'v' : - verbose = 1; /* this is the default anyways... */ - break; - case 'V' : - verbose = 0; - break; - case 'D' : - printf("\n\n Debug flag values\n\n"); - printf(" 1 function trace\n"); - printf(" 2 find() information\n"); - printf(" 4 group information\n"); - printf(" 8 mod() information\n"); - printf(" 16 parsing information\n"); - printf(" 32 output information\n"); - printf(" 64 authentication information\n"); - printf(" 128 initialization information\n\n"); - format("These are masks, and may be added to form multiple debug levels. For example, '-d 35' would perform a function trace, print out information about the find() function, and would print out information about the output routines too.", 75, 2); - exit(0); - default: - fprintf(stderr, "Usage: %s [-c filter-config-file] [-d debug-level] [-l ldap-debug-level] [-s server] [-p port] [-V]\n", argv[0]); - exit(-1); - /* NOTREACHED */ - } - } - - /* just print the first line of Version[] */ - cp = strchr(Version, '\t'); - if (cp != NULL) - *cp = '\0'; - printf(Version); - fflush( stdout ); - - initialize_client(); - initialize_attribute_strings(); - - /* now tackle the user's commands */ - do_commands(); - /* NOTREACHED */ -} - -do_commands() -{ - LDAPMessage *mp; /* returned by find() */ - register char *cp; /* misc char pointer */ - register char *ap; /* misc char pointer */ - static char buf[MED_BUF_SIZE]; /* for prompting */ - static char cmd[MED_BUF_SIZE]; /* holds the command */ - static char input[MED_BUF_SIZE]; /* buffer for input */ - extern LDAPMessage *find(); - extern void purge_group(), add_group(), remove_group(), x_group(), - tidy_up(), list_groups(), list_memberships(), edit(); - extern char *nextstr(); - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->do_commands()\n"); -#endif - if (verbose) - printf("\n Enter a command. If you need help, type 'h' or '?' and hit RETURN.\n\n"); - /* jump here on an interrupt */ - (void) setjmp(env); - for (;;) { - printf("* "); - fflush(stdout); - cp = input; -/* Temporary kludge - if cp is null, dumps core under Solaris */ - if (cp == NULL) - break; - fetch_buffer(input, sizeof(input), stdin); - if (*input == '\0') { - putchar('\n'); - continue; - } - while (isspace(*cp)) - cp++; - ap = cmd; - if (memset(cmd, '\0', sizeof(cmd)) == NULL) - fatal("memset"); - while (!isspace(*cp) && (*cp != '\0')) - *ap++ = *cp++; - if (iscom("status")) - status(); - else if (iscom("stop") || iscom("quit")) - break; - else if (iscom("cb") || iscom("cd") || iscom("moveto")) { - while (isspace(*cp) && (*cp != '\0')) - cp++; - if (!strncasecmp(cp, "base", 4)) - cp += 4; - change_base(BASE_SEARCH, &search_base, nextstr(cp)); - } - else if (iscom("memberships")) - (void) list_memberships(nextstr(cp)); - else if (iscom("list")) - (void) list_groups(nextstr(cp)); - else if (iscom("groupbase")) - change_base(BASE_GROUPS, &group_base, nextstr(cp)); - else if (iscom("find") || iscom("display") || iscom("show")) { - cp = nextstr(cp); - if ((mp = find(cp, FALSE)) != NULL) { - parse_answer(mp); - print_an_entry(); - ldap_msgfree(mp); - } - else - printf(" Could not find \"%s\".\n", cp); - } -#ifdef UOFM - else if (iscom("vedit") && isatty( 1 )) { -#else - else if (iscom("vedit")) { -#endif - (void) edit(nextstr(cp)); - } - else if (iscom("modify") || iscom("change") || iscom("alter")) - (void) modify(nextstr(cp)); - else if (iscom("bind") || iscom("iam")) - (void) auth(nextstr(cp), 0); - else if ((cmd[0] == '?') || iscom("help")) - print_help(nextstr(cp)); - else if (iscom("join") || iscom("subscribe")) - (void) x_group(G_JOIN, nextstr(cp)); - else if (iscom("resign") || iscom("unsubscribe")) - (void) x_group(G_RESIGN, nextstr(cp)); - else if (!strncasecmp("create", cmd, strlen(cmd))) - add_group(nextstr(cp)); - else if (!strncasecmp("remove", cmd, strlen(cmd))) - remove_group(nextstr(cp)); - else if (!strncasecmp("purge", cmd, strlen(cmd))) - purge_group(nextstr(cp)); - else if (!strncasecmp("verbose", cmd, strlen(cmd))) { - verbose = 1 - verbose; - if (verbose) - printf(" Verbose mode has been turned on.\n"); - } - else if (!strncasecmp("dereference", cmd, strlen(cmd))) { - dereference = 1 - dereference; - if (dereference == 1) - ld->ld_deref = LDAP_DEREF_ALWAYS; - else - ld->ld_deref = LDAP_DEREF_NEVER; - } - else if (!strncasecmp("tidy", cmd, strlen(cmd))) - tidy_up(); - else if (cmd[0] == '\0') - putchar('\n'); - else - printf(" Invalid command. Type \"help commands.\"\n"); - } - printf(" Thank you!\n"); - - ldap_unbind(ld); -#ifdef KERBEROS - destroy_tickets(); -#endif - exit(0); - /* NOTREACHED */ -} - -status() -{ - void printbase(); - register char **rdns; - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->status()\n"); -#endif - printf(" Current server is %s", server); - if ( ld != NULL && ld->ld_host != NULL && strcasecmp( ld->ld_host, - server ) != 0 ) - printf( " (%s)", ld->ld_host ); - putchar( '\n' ); - printbase(" Search base is ", search_base); - printbase(" Group base is ", group_base); - if ( bound_dn != NULL ) { - rdns = ldap_explode_dn(bound_dn, TRUE); - printf(" Bound as \"%s\"\n", *rdns); - ldap_value_free(rdns); - } else { - printf(" Bound as Nobody\n" ); - } - printf( " Verbose mode is %sabled\n", ( verbose ? "en" : "dis" )); - if ( ld != NULL ) { - printf( " Aliases are %sbeing dereferenced\n", ( ld->ld_deref == LDAP_DEREF_ALWAYS ) ? "" : "not" ); - } -} - -change_base(type, base, s) -int type; -char **base, *s; -{ - register char *cp; /* utility pointers */ - char **rdns; /* for parsing */ - char *output_string; /* for nice output */ - int num_picked; /* # of selected base */ - int j; /* used with num_picked */ - int i = 1; /* index into choices array */ - int matches; /* # of matches found */ - int rest = 1; /* # left to display */ - char tmp[MED_BUF_SIZE]; /* temporary buffer */ - static char *choices[MED_BUF_SIZE]; /* bases from which to choose */ - static char resp[SMALL_BUF_SIZE]; /* for prompting user */ - static char buf[MED_BUF_SIZE]; - void printbase(); - static char *attrs[] = { "objectClass", NULL }; - LDAPMessage *mp; /* results from a search */ - LDAPMessage *ep; /* for going thru bases */ - extern char * friendly_name(); - extern void StrFreeDup(); - extern void Free(); - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->change_base(%s, %s)\n", s, s); -#endif - /* - * If s is NULL we need to prompt the user for an argument. - */ - while (s == NULL) { - if (verbose) { - printf(" You need to specify how the base is to be changed. Valid choices are:\n"); - printf(" ? - list the choices immediately below this level\n"); - printf(" .. - move up one level in the Directory tree\n"); - printf(" root - move to the root of the Directory tree\n"); - printf(" default - move to the default level built into this program\n"); - printf(" - move to the entry specified\n"); - } - printf(" Change base to? "); - fflush(stdout); - fetch_buffer(buf, sizeof(buf), stdin); - if ((buf != NULL) && (buf[0] != '\0')) - s = buf; - } - - /* set the output string */ - if (type == BASE_SEARCH) - output_string = " Search base is now "; - else if (type == BASE_GROUPS) - output_string = " Group base is now "; - - if (!strcasecmp(s, "root")) { - StrFreeDup(base, NULL); - printbase(" Search base is ", *base); - return; - } - - /* - * User wants to ascend one level in the X.500 tree. - * Easy: Just strip off the first element of the - * current search base, unless it's the root, in - * which case we just do nothing. - */ - if (!strcasecmp(s, "..")) { - if (*base == NULL) { - printf(" You are already at the root\n"); - return; - } - cp = strchr(*base, '='); - cp++; - /* - * If there isn't a second "=" in the base, then this was - * a one element base, and so now it should be NULL. - */ - if ((cp = strchr(cp, '=')) == NULL) - StrFreeDup(base, NULL); - else { - /* - * Back up to the start of this - * - * attr=value - * - * sequence now that 'cp' is pointing to the '='. - */ - while(!isspace(*cp)) - cp--; - cp++; - /* - * Goofy, but need to do it this way since both *base - * and cp point into the same chunk of memory, and - * we want to free *base, but keep part of it around. - */ - cp = strdup(cp); - StrFreeDup(base, cp); - Free(cp); - } - printbase(output_string, *base); - return; - } - - /* user wants to see what is directly below this level */ - if (*s == '?') { - /* - * Fetch the list of entries directly below this level. - * Once we have the list, we will print it for the user, one - * screenful at a time. At the end of each screen, we ask - * the user if they want to see more. They can also just - * type a number at that point too. - */ - if (ldap_search_s(ld, *base, LDAP_SCOPE_ONELEVEL, "(|(objectClass=quipuNonLeafObject)(objectClass=externalNonLeafObject))", attrs, FALSE, &mp) != LDAP_SUCCESS) { - if ((ld->ld_errno == LDAP_TIMELIMIT_EXCEEDED) || - (ld->ld_errno == LDAP_SIZELIMIT_EXCEEDED)) { - if (verbose) { - printf(" Your query was too general and a limit was exceeded. The results listed\n"); - printf(" are not complete. You may want to try again with a more refined query.\n\n"); - } - else - printf(" Time or size limit exceeded. Partial results follow.\n\n"); - } else { - ldap_perror(ld, "ldap_search_s"); - return; - } - } - if ((matches = ldap_count_entries(ld, mp)) < 1) { - printf(" There is nothing below this level.\n"); - (void) ldap_msgfree(mp); - return; - } - num_picked = 0; - printf(" There are %d choices:\n", matches); - for (ep = ldap_first_entry(ld, mp); ep != NULL; ep = ldap_next_entry(ld, ep)) { - /* - * Put the last component of the DN into 'lastDN'. - * If we are at the root level, convert any country - * codes to recognizable names for printing. - */ - choices[i] = ldap_get_dn(ld, ep); - rdns = ldap_explode_dn(choices[i], TRUE); - printf(" %2d. %s\n", i, friendly_name(*rdns)); - (void) ldap_value_free(rdns); - i++; - if ((rest++ > (lpp - 3)) && (i < matches)) { - printf("More? "); - fflush(stdout); - fetch_buffer(resp, sizeof(resp), stdin); - if ((resp[0] == 'n') || (resp[0] == 'N')) - break; - else if (((num_picked = atoi(resp)) != 0) && (num_picked < i)) - break; - rest = 1; - } - } - for (;;) { - if (num_picked != 0) { - j = num_picked; - num_picked = 0; - } - else { - printf(" Which number? "); - fflush(stdout); - fetch_buffer(resp, sizeof(resp), stdin); - j = atoi(resp); - } - if (j == 0) { - (void) ldap_msgfree(mp); - for (i = 0; i < matches; i++) - Free(choices[i]); - return; - } - if ((j < 1) || (j >= i)) - printf(" Invalid number\n"); - else { - StrFreeDup(base, choices[j]); - printbase(output_string, *base); - (void) ldap_msgfree(mp); - for (i = 0; choices[i] != NULL; i++) - Free(choices[i]); - return; - } - } - } - /* set the search base back to the original default value */ - else if (!strcasecmp(s, "default")) { - if (type == BASE_SEARCH) - StrFreeDup(base, UD_BASE); - else if (type == BASE_GROUPS) - StrFreeDup(base, UD_WHERE_GROUPS_ARE_CREATED); - printbase(output_string, *base); - } - /* they typed in something -- see if it is legit */ - else { - /* user cannot do something like 'cb 33' */ - if (atoi(s) != 0) { - printf(" \"%s\" is not a valid search base\n", s); - printf(" Base unchanged.\n"); - printf(" Try using 'cb ?'\n"); - return; - } - /* was it a fully-specified DN? */ - if (vrfy(s)) { - StrFreeDup(base, s); - printbase(output_string, *base); - return; - } - /* was it a RDN relative to the current base? */ - sprintf(tmp, "ou=%s, %s", s, *base); - if (vrfy(tmp)) { - StrFreeDup(base, tmp); - printbase(output_string, *base); - return; - } - printf(" \"%s\" is not a valid base\n Base unchanged.\n", s); - } -} - -initialize_client() -{ - FILE *fp; /* for config file */ - static char buffer[MED_BUF_SIZE]; /* for input */ - struct passwd *pw; /* for getting the home dir */ - register char *cp; /* for fiddling with buffer */ - char *term; /* for tty set-up */ - char *config; /* config file to use */ - static char bp[1024]; /* for tty set-up */ - extern SIG_FN attn(); /* ^C signal handler */ - extern char *getenv(); - extern void Free(); - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->initialize_client()\n"); -#endif - /* - * A per-user config file has precedence over any system-wide - * config file, if one exists. - */ - if ((pw = getpwuid((uid_t) geteuid())) == (struct passwd *) NULL) - config = config_file; - else { - if (pw->pw_dir == NULL) - config = config_file; - else { - sprintf(buffer, "%s/%s", pw->pw_dir, - UD_USER_CONFIG_FILE); - if (access(buffer, R_OK) == 0) - config = buffer; - else - config = config_file; - } - } -#ifdef DEBUG - if (debug & D_INITIALIZE) - printf("Using config file %s\n", config); -#endif - - /* - * If there is a config file, read it. - * - * Could have lines that look like this: - * - * server - * base - * groupbase - * - */ - if ((fp = fopen(config, "r")) != NULL) { - while (fgets(buffer, sizeof(buffer), fp) != NULL) { - buffer[strlen(buffer) - 1] = '\0'; - if (!strncasecmp(buffer, "server", 6)) { - if (server != NULL) - continue; - cp = buffer + 6; - while (isspace(*cp)) - cp++; - if ((*cp == '\0') || (*cp == '\n')) - continue; - server = strdup(cp); - } - else if (!strncasecmp(buffer, "base", 4)) { - cp = buffer + 4; - while (isspace(*cp)) - cp++; - if ((*cp == '\0') || (*cp == '\n')) - continue; - search_base = strdup(cp); - } - else if (!strncasecmp(buffer, "groupbase", 9)) { - cp = buffer + 9; - while (isspace(*cp)) - cp++; - if ((*cp == '\0') || (*cp == '\n')) - continue; - group_base = strdup(cp); - } - else - fprintf(stderr, "?? -> %s\n", buffer); - } - } - if (group_base == NULL) - group_base = strdup(UD_WHERE_GROUPS_ARE_CREATED); - if (search_base == NULL) - search_base = strdup(UD_BASE); - if (server == NULL) - server = strdup(LDAPHOST); - - /* - * Set up our LDAP connection. The values of retry and timeout - * are meaningless since we will immediately be doing a null bind - * because we want to be sure to use TCP, not UDP. - */ - if ((ld = ldap_open(server, ldap_port)) == NULL) { - fprintf(stderr, " The X.500 Directory is temporarily unavailable. Please try again later.\n"); - exit(0); - /* NOTREACHED */ - } - if (ldap_bind_s(ld, (char *) default_bind_object, (char *) UD_PASSWD, - LDAP_AUTH_SIMPLE) != LDAP_SUCCESS) { - fprintf(stderr, " The X.500 Directory is temporarily unavailable. Please try again later.\n"); - if (ld->ld_errno != LDAP_UNAVAILABLE) - ldap_perror(ld, " ldap_bind_s"); - exit(0); - /* NOTREACHED */ - } - ld->ld_deref = LDAP_DEREF_ALWAYS; - bind_status = UD_NOT_BOUND; - if ( default_bind_object != NULL ) { - bound_dn = strdup(default_bind_object); - } else { - bound_dn = NULL; - } - - /* enabled local caching of ldap results, 15 minute lifetime */ -#ifdef DOS - ldap_enable_cache( ld, 60 * 15, 100 * 1024 ); /* 100k max memory */ -#else /* DOS */ - ldap_enable_cache( ld, 60 * 15, 0 ); /* no memory limit */ -#endif /* DOS */ - - /* initialize the search filters */ - if ((lfdp = ldap_init_getfilter(filter_file)) == NULL) { - fprintf(stderr, " Problem with ldap_init_getfilter\n"); - fatal(filter_file); - /*NOTREACHED*/ - } - - /* terminal initialization stuff goes here */ - lpp = DEFAULT_TTY_HEIGHT; - col_size = DEFAULT_TTY_WIDTH; - - (void) signal(SIGINT, attn); - -#if !defined(DOS) && !defined(NOTERMCAP) - { - struct winsize win; /* for tty set-up */ - extern SIG_FN chwinsz(); /* WINSZ signal handler */ - - if (((term = getenv("TERM")) == NULL) || (tgetent(bp, term) <= 0)) - return; - else { - if (ioctl(fileno(stdout), TIOCGWINSZ, &win) < 0) { - lpp = tgetnum("li"); - col_size = tgetnum("co"); - } - else { - if ((lpp = win.ws_row) == 0) - lpp = tgetnum("li"); - if ((col_size = win.ws_col) == 0) - col_size = tgetnum("co"); - if ((lpp <= 0) || tgetflag("hc")) - lpp = DEFAULT_TTY_HEIGHT; - if ((col_size <= 0) || tgetflag("hc")) - col_size = DEFAULT_TTY_WIDTH; - } - } - (void) signal(SIGWINCH, chwinsz); - - } -#endif -} - -SIG_FN attn() -{ - fflush(stderr); - fflush(stdout); - printf("\n\n INTERRUPTED!\n"); -#if defined(DOS) || defined(SYSV) - (void) signal(SIGINT, attn); -#endif - longjmp(env, 1); -} - -#if !defined(DOS) && !defined(NOTERMCAP) -SIG_FN chwinsz() -{ - struct winsize win; - - (void) signal(SIGWINCH, SIG_IGN); - if (ioctl(fileno(stdout), TIOCGWINSZ, &win) != -1) { - if (win.ws_row != 0) - lpp = win.ws_row; - if (win.ws_col != 0) - col_size = win.ws_col; - } - (void) signal(SIGWINCH, chwinsz); -} -#endif diff --git a/clients/ud/mod.c b/clients/ud/mod.c deleted file mode 100644 index ef7099e948..0000000000 --- a/clients/ud/mod.c +++ /dev/null @@ -1,814 +0,0 @@ -/* - * Copyright (c) 1991,1993 Regents of the University of Michigan. - * All rights reserved. - * - * Redistribution and use in source and binary forms are permitted - * provided that this notice is preserved and that due credit is given - * to the University of Michigan at Ann Arbor. The name of the University - * may not be used to endorse or promote products derived from this - * software without specific prior written permission. This software - * is provided ``as is'' without express or implied warranty. - */ - -#include -#include -#include -#include -#include -#ifndef __STDC__ -#include -#endif -#include -#include "ud.h" - -extern struct entry Entry; -extern int verbose; -extern LDAP *ld; - -extern LDAPMessage *find(); - -#ifdef DEBUG -extern int debug; -#endif - -modify(who) -char *who; -{ -#ifdef UOFM - void set_updates(); /* routine to modify noBatchUpdates */ -#endif - LDAPMessage *mp; /* returned from find() */ - char *dn; /* distinguished name */ - char **rdns; /* for fiddling with the DN */ - char name[MED_BUF_SIZE]; /* entry to modify */ - int displayed_choices = 0; - static char ans[SMALL_BUF_SIZE]; /* for holding user input */ -#ifdef UOFM - static char printed_warning = 0; /* for use with the */ - struct attribute no_batch_update_attr; - extern char * fetch_boolean_value(); -#endif - int is_a_group; /* TRUE if it is; FALSE otherwise */ - extern void Free(); - extern int bind_status; - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->modify(%s)\n", who); -#endif - /* - * Require them to bind first if the are modifying a group. - */ - if (bind_status == UD_NOT_BOUND) { - if (auth((char *) NULL, 1) < 0) - return; - } - - /* - * First, decide what entry we are going to modify. If the - * user has not included a name on the modify command line, - * we will use the person who was last looked up with a find - * command. If there is no value there either, we don't know - * who to modify. - * - * Once we know who to modify, be sure that they exist, and - * parse out their DN. - */ - if (who == NULL) { - if (verbose) { - printf(" Enter the name of the person or\n"); - printf(" group whose entry you want to modify: "); - } - else - printf(" Modify whose entry? "); - fflush(stdout); - fetch_buffer(name, sizeof(name), stdin); - if (name[0] != '\0') - who = name; - else - return; - } - if ((mp = find(who, TRUE)) == NULL) { - (void) ldap_msgfree(mp); - printf(" Could not locate \"%s\" in the Directory.\n", who); - return; - } - dn = ldap_get_dn(ld, ldap_first_entry(ld, mp)); - rdns = ldap_explode_dn(dn, TRUE); - if (verbose) - printf("\n Modifying Directory entry of \"%s\"\n", *rdns); - -#ifdef UOFM - /* - * If verbose mode is turned on and the user has not set a value - * for noBatchUpdates, warn them that what they are about to do - * may be overwritten automatically by that Stinkbug. - */ - no_batch_update_attr.quipu_name = "noBatchUpdates"; - (void) fetch_boolean_value(dn, no_batch_update_attr); - if (verbose && !printed_warning && (ld->ld_errno == LDAP_NO_SUCH_ATTRIBUTE)) { - printed_warning = 1; - printf("\n WARNING!\n"); - printf(" You are about to make a modification to an X.500 entry\n"); - printf(" that has its \"automatic updates\" field set to ON.\n"); - printf(" This means that the entry will be automatically updated\n"); - printf(" each month from official University sources like the\n"); - printf(" Personnel Office. With \"automatic updates\" set to ON,\n"); - printf(" the following fields will be overwritten each month:\n"); - printf(" Title, home address and phone,\n"); - printf(" business address and phone\n"); - printf(" If you modify any of these fields, you may want to change\n"); - printf(" the \"automatic updates\" field to OFF so that your\n"); - printf(" changes will not be overwritten. You may change this\n"); - printf(" setting by choosing \"u\" at the \"Modify what?\" prompt\n"); - } -#endif - - /* - * Current values for user 'who' are being held in 'mp'. We - * should parse up that buffer and fill in the Entry structure. - * Once we're done with that, we can find out which fields the - * user would like to modify. - */ - parse_answer(mp); - is_a_group = isgroup(); - (void) ldap_msgfree(mp); - printf(" You now need to specify what field you'd like to modify.\n"); - for (;;) { - if ( verbose || !displayed_choices ) { - printf("\n Choices are:\n"); - printf(" -----------------------\n"); - print_mod_list(is_a_group); - printf("\n Pressing Return will cancel the process.\n"); - displayed_choices = 1; - } - printf("\n Modify what? "); - fflush(stdout); - fetch_buffer(ans, sizeof(ans), stdin); - if (ans[0] == '\0') - break; - perform_action(ans, dn, is_a_group); - if ((mp = find(*rdns, TRUE)) == NULL) - break; - parse_answer(mp); - (void) ldap_msgfree(mp); - } - (void) Free(dn); - ldap_value_free(rdns); - return; -} - -/* generic routine for changing any field */ -void change_field(who, attr) -char *who; /* DN of entry we are changing */ -struct attribute attr; /* attribute to change */ -{ - -#define IS_MOD(x) (!strncasecmp(resp, (x), strlen(resp))) - - char *get_value(); /* routine to extract values */ - static char buf[MED_BUF_SIZE]; /* for printing things */ - static char resp[SMALL_BUF_SIZE]; /* for user input */ - char *prompt, *prompt2, *more; - register int i; /* for looping thru values */ - static LDAPMod mod; - static LDAPMod *mods[2] = { &mod }; /* passed to ldap_modify */ - static char *values[MAX_VALUES]; /* passed to ldap_modify */ - extern void Free(); - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->change_field(%x, %s)\n", attr, who); -#endif - /* - * If there is no current value associated with the attribute, - * then this is the easy case. Collect one (or more) attributes - * from the user, and then call ldap_modify_s() to write the changes - * to the LDAP server. - */ - for (i = 0; i < MAX_VALUES; i++) - values[i] = NULL; - if (attr.values == (char **) NULL) { - printf("\n No current \"%s\"\n", attr.output_string); - values[0] = get_value(attr.quipu_name, "Enter a value"); - if ( values[0] == NULL ) - return; - mod.mod_op = LDAP_MOD_REPLACE; - mod.mod_type = attr.quipu_name; - mod.mod_values = values; - for (i = 1; i < MAX_VALUES; i++) { - printf(" Do you wish to add an additional value? "); - fflush(stdout); - fetch_buffer(resp, sizeof(resp), stdin); - if ((resp[0] == 'y') || (resp[0] == 'Y')) - values[i] = get_value(attr.quipu_name, "Enter an additional value"); - else - break; - } -#ifdef DEBUG - if (debug & D_MODIFY) { - printf(" ld = 0x%x\n", ld); - printf(" who = [%s]\n", who); - printf(" mods[0]->mod_op = %1d\n", mods[0]->mod_op); - printf(" mods[0]->mod_type = %s\n", mods[0]->mod_type); - for (i = 0; mods[0]->mod_values[i] != NULL; i++) - printf(" mods[0]->mod_values[%1d] = %s\n", i, mods[0]->mod_values[i]); - } -#endif - if (ldap_modify_s(ld, who, mods)) { - mod_perror(ld); - return; - } - else if (verbose) - printf(" Modification of '%s' complete.\n", attr.output_string); - ldap_uncache_entry( ld, who ); - for (i--; i > 0; i--) - (void) Free(values[i]); - } - /* - * There are values for this attribute already. In this case, - * we want to allow the user to delete all existing values, - * add additional values to the ones there already, or just - * delete some of the values already present. DIXIE does not - * handle modifications where the attribute occurs on the LHS - * more than once. So to delete entries and add entries, we - * need to call ldap_modify() twice. - */ - else { - /* - * If the attribute holds values which are DNs, print them - * in a most pleasant way. - */ - sprintf(buf, "%s: ", attr.output_string); - if (!strcmp(attr.quipu_name, "owner")) - (void) print_DN(attr); - else - (void) print_values(attr); - - if (verbose) { - printf(" You may now:\n"); - printf(" Add additional values to the existing ones, OR\n"); - printf(" Clear all values listed above, OR\n"); - printf(" Delete one of the values listed above, OR\n"); - printf(" Replace all of the values above with new ones.\n"); - } - printf("\n Add, Clear, Delete, or Replace? "); - fflush(stdout); - fetch_buffer(resp, sizeof(resp), stdin); - - /* - * Bail if they just hit the RETURN key. - */ - if (resp[0] == '\0') { - if (verbose) - printf("\n No changes made.\n"); - return; - } - - /* - * If the want to clear the values, just do it. - */ - mod.mod_type = attr.quipu_name; - mod.mod_values = values; - if (IS_MOD("clear")) { - mod.mod_op = LDAP_MOD_DELETE; - mod.mod_values = NULL; - if ( verbose && !confirm_action( "All existing values will be removed." )) { - printf(" Modification halted.\n"); - return; - } -#ifdef DEBUG - if (debug & D_MODIFY) { - printf("Clearing attribute '%s'\n", attr.quipu_name); - printf("who = [%s]\n", who); - printf("mod = [%d] [%s] [%x]\n", mod.mod_op, - mod.mod_type, mod.mod_values); - } -#endif - if (ldap_modify_s(ld, who, mods)) { - mod_perror(ld); - return; - } - else if (verbose) - printf(" '%s' has been cleared.\n", attr.output_string); - ldap_uncache_entry( ld, who ); - return; - } - - if (IS_MOD("add")) { - prompt = "Enter the value you wish to add"; - more = " Add an additional value? "; - prompt2 = "Enter another value you wish to add"; - mod.mod_op = LDAP_MOD_ADD; - } - else if (IS_MOD("delete")) { - prompt = "Enter the value you wish to delete"; - more = " Delete an additional value? "; - prompt2 = "Enter another value you wish to delete"; - mod.mod_op = LDAP_MOD_DELETE; - } - else if (IS_MOD("replace")) { - prompt = "Enter the new value"; - more = " Add an additional value? "; - prompt2 = "Enter another value you wish to add"; - mod.mod_op = LDAP_MOD_REPLACE; - if ( verbose && !confirm_action( "All existing values will be overwritten with the new values you are about to enter." )) { - printf(" Modification halted.\n"); - return; - } - - } - else { - printf(" No changes made.\n"); - return; - } - - values[0] = get_value(attr.quipu_name, prompt); - for (i = 1; i < MAX_VALUES; i++) { - printf(more); - fflush(stdout); - fetch_buffer(resp, sizeof(resp), stdin); - if ((resp[0] == 'y') || (resp[0] == 'Y')) - values[i] = get_value(attr.quipu_name, prompt2); - else - break; - } - - /* if the first value in the value-array is NULL, bail */ - if (values[0] == NULL) { - if (verbose) - printf(" No modification made.\n"); - return; - } -#ifdef DEBUG - if (debug & D_MODIFY) { - printf(" ld = 0x%x\n", ld); - printf(" who = [%s]\n", who); - printf(" mods[0]->mod_op = %1d\n", mods[0]->mod_op); - printf(" mods[0]->mod_type = %s\n", mods[0]->mod_type); - for (i = 0; mods[0]->mod_values[i] != NULL; i++) - printf(" mods[0]->mod_values[%1d] = %s\n", i, mods[0]->mod_values[i]); - } -#endif - if (ldap_modify_s(ld, who, mods)) { - mod_perror(ld); - return; - } - else if (verbose) - printf(" Modifications to '%s' complete.\n", attr.output_string); - ldap_uncache_entry( ld, who ); - for (i--; i > 0; i--) - (void) Free(values[i]); - } - return; -} - -/* - * These are used to size the buffers we use when collecting values that - * can cross more than one line. - */ -#define LINE_SIZE 80 -#define MAX_LINES 6 -#define MAX_DESC_LINES 24 -#define INTL_ADDR_LIMIT 30 - -char *get_value(id, prompt) -char *id, *prompt; -{ - char *cp; /* for the Malloc() */ - int count; /* line # of new value -- if multiline */ - int multiline = 0; /* 1 if this value is multiline */ - static char line[LINE_SIZE]; /* raw line from user */ - static char buffer[MAX_DESC_LINES * LINE_SIZE]; /* holds ALL of the - lines we get */ - extern void * Malloc(); - static char * get_URL(); - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->get_value(%s, %s)\n", id, prompt); -#endif - /* if this is a URL, have another routine handle this */ - if (!strcmp(id, "labeledURL")) - return(get_URL()); - - /* - * To start with, we have one line of input from the user. - * - * Addresses and multiline description can span multiple lines. - * Other attributes may not. - */ - count = 1; - (void) memset(buffer, 0, sizeof(buffer)); -#ifdef UOFM - if (!strcmp(id, "postalAddress") || !strcmp(id, "homePostalAddress") || !strcmp(id, "multiLineDescription") || !strcmp(id, "vacationMessage")) -#else - if (!strcmp(id, "postalAddress") || !strcmp(id, "homePostalAddress")) -#endif - multiline = 1; - printf("\n %s:\n", prompt); - - /* fetch lines */ - for (;;) { - if (multiline) - printf(" %1d: ", count); - else - printf(" > "); - fflush(stdout); - fetch_buffer(line, sizeof(line), stdin); - - if (line[0] == '\0') - break; -#ifdef UOFM - /* - * Screen out dangerous e-mail addresses of the form: - * - * user@umich.edu - * - * and addresses that have no '@' symbol at all. - */ - if (!strcmp(id, "mail")) { - int i; - char *tmp, *tmp2; - - /* if this is a group, don't worry */ - if (isgroup()) - goto mail_is_good; - - /* if this address is not @umich.edu, don't worry */ - /* ...unless there is no '@' at all! */ - tmp = strdup(line); - if ((tmp2 = strrchr(tmp, '@')) == NULL) { - printf("\n"); - format("The address you entered is not a valid e-mail address. E-mail addresses should be of the form \"local@domain\", e.g. bjensen@b.imap.itd.umich.edu", 75, 2 ); - goto mail_is_bad; - } - - *tmp2 = '\0'; - tmp2++; - if (strcasecmp(tmp2, "umich.edu")) - goto mail_is_good; - - /* if not of the form uid@umich.edu, don't worry */ - if ((i = attr_to_index("uid")) < 0) - goto mail_is_good; - if (strcasecmp(tmp, *(Entry.attrs[i].values))) - goto mail_is_good; - printf("\n"); - format("An e-mail address of the form uniqname@umich.edu is not the form that you want registered in the Directory. This form is the one to use on business cards, for example, but the Directory should contain your real e-mail address; that is, the address where you really read your mail.", 75, 2); - -mail_is_bad: - printf("\n"); - printf(" Please enter a legal e-mail address (or press RETURN to stop)\n"); - continue; - } -mail_is_good: -#endif - - /* - * If the attribute which we are gathering is a "owner" - * then we should lookup the name. The user is going to - * either have to change the search base before doing the - * modify, or the person is going to have to be within the - * scope of the current search base, or they will need to - * type in a UFN. - */ - if (!strcmp(id, "owner")) { - LDAPMessage *lmp, *elmp; - char *tmp; - - lmp = find(line, FALSE); - if (lmp == (LDAPMessage *) NULL) { - printf(" Could not find \"%s\" in the Directory\n", line); - if (verbose) - format("Owners of groups must be valid entries in the X.500 Directory. The name you have typed above could not be found in the X.500 Directory.", 72, 2); - return(NULL); - } - elmp = ldap_first_entry(ld, lmp); - if (lmp == (LDAPMessage *) NULL) { - ldap_perror(ld, "ldap_first_entry"); - return(NULL); - } - tmp = ldap_get_dn(ld, elmp); - strcpy(buffer, tmp); - (void) ldap_msgfree(lmp); - break; - } - - if (!strcmp(id, "postalAddress") || !strcmp(id, "homePostalAddress")) { - if (strlen(line) > INTL_ADDR_LIMIT) { - printf(" The international standard for addresses only allows for 30-character lines\n"); - printf(" Please re-enter your last line.\n"); - continue; - } - } - - /* - * Separate lines of multiline attribute values with - * dollar signs. Copy this line into the buffer we - * use to collect up all of the user-supplied input - * lines. If this is not a multiline attribute, we - * are done. - */ - if (count++ > 1) - (void) strcat(buffer, "$"); - (void) strcat(buffer, line); - if (!multiline) - break; - if ((count > MAX_LINES) && (!strcmp(id, "postalAddress") || !strcmp(id, "homePostalAddress"))) { - printf(" The international standard for addresses only allows for six lines\n"); - break; - } -#ifdef UOFM - if ((count > MAX_DESC_LINES) && !strcmp(id, "multiLineDescription")) { - printf(" We only allow %d lines of description\n", MAX_DESC_LINES); - break; - } -#endif - } - if (buffer[0] == '\0') - return(NULL); -#ifdef DEBUG - if (debug & D_MODIFY) - printf(" Value is [%s]\n", buffer); -#endif - cp = (char *) Malloc((unsigned) (strlen(buffer) + 1)); - strcpy(cp, buffer); - return(cp); -} - -void set_boolean(who, attr) -char *who; /* DN of entry we are changing */ -struct attribute attr; /* boolean attribute to change */ -{ - char *cp, *s; - extern char * fetch_boolean_value(); - static char response[16]; - static char *newsetting[2] = { NULL, NULL }; - LDAPMod mod, *mods[2]; - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->set_boolean(%s, %s)\n", who, attr.quipu_name); -#endif - mods[0] = &mod; - mods[1] = (LDAPMod *) NULL; - mod.mod_op = LDAP_MOD_REPLACE; - mod.mod_type = attr.quipu_name; - mod.mod_values = newsetting; - - /* fetch the current setting */ - if ((cp = fetch_boolean_value(who, attr)) == NULL) - return; - if (!strcmp(cp, "TRUE")) - newsetting[0] = "FALSE"; - else if (!strcmp(cp, "FALSE")) - newsetting[0] = "TRUE"; - else { - printf(" This field needs to be set to either TRUE or to FALSE.\n"); - printf(" \"%s\" is not a legal value. Please set this field to either TRUE or to FALSE.\n", cp); - newsetting[0] = "FALSE"; - } - - /* see if they want to change it */ - printf("\n"); - printf(" The current value of this field is %s.\n", cp); - printf(" Should I change the value of this field to %s?\n", - newsetting[0]); - printf(" Please enter Y for yes, N for no, or RETURN to cancel: "); - fflush(stdout); - (void) fetch_buffer(response, sizeof(response), stdin); - for (s = response; isspace(*s); s++) - ; - if ((*s == 'y') || (*s == 'Y')) { - if (ldap_modify_s(ld, who, mods)) { - mod_perror(ld); - return; - } - else if (verbose) - printf(" Setting has been changed\n"); - ldap_uncache_entry(ld, who); - return; - } - if (verbose) - printf(" Setting has not been changed\n"); -} - -#ifdef UOFM - -void set_updates(who) -char *who; -{ - char *cp, *s; - extern char * fetch_boolean_value(); - static char response[16]; - static char value[6]; - static char *newsetting[2] = { value, NULL }; - LDAPMod mod, *mods[2]; - struct attribute attr; - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->set_updates(%s)\n", who); -#endif - mods[0] = &mod; - mods[1] = (LDAPMod *) NULL; - mod.mod_op = LDAP_MOD_REPLACE; - mod.mod_type = "noBatchUpdates"; - mod.mod_values = newsetting; - /* explain what the implications are */ - if (verbose) { - printf("\n By default, updates that are received from the Personnel\n"); - printf(" Office and the Office of the Registrar are applied to all\n"); - printf(" entries in the X.500 database each month. Sometimes this\n"); - printf(" feature is undesirable. For example, if you maintain your\n"); - printf(" entry in the X.500 database manually, you may not want to\n"); - printf(" have these updates applied to your entry, possibly overwriting\n"); - printf(" correct information with out-dated information.\n\n"); - } - - /* fetch the current setting */ - attr.quipu_name = "noBatchUpdates"; - if ((cp = fetch_boolean_value(who, attr)) == NULL) - return; - if (!strcmp(cp, "TRUE")) - printf(" Automatic updates are currently turned OFF\n"); - else if (!strcmp(cp, "FALSE")) - printf(" Automatic updates are currently turned ON\n"); - else { - fprintf(stderr, " Unknown update flag -> [%s]\n", cp); - return; - } - - /* see if they want to change it */ - printf("\n Change this setting [no]? "); - fflush(stdout); - (void) fetch_buffer(response, sizeof(response), stdin); - for (s = response; isspace(*s); s++) - ; - if ((*s == 'y') || (*s == 'Y')) { - if (!strcmp(cp, "TRUE")) - strcpy(value, "FALSE"); - else - strcpy(value, "TRUE"); - if (ldap_modify_s(ld, who, mods)) { - mod_perror(ld); - return; - } - else if (verbose) - printf(" Setting has been changed\n"); - ldap_uncache_entry( ld, who ); - return; - } - if (verbose) - printf(" Setting has not been changed\n"); -} - -#endif - -print_mod_list(group) -int group; -{ - register int i, j = 1; - extern struct attribute attrlist[]; - - if (group == TRUE) { - for (i = 0; attrlist[i].quipu_name != NULL; i++) { - if (attrlist[i].flags & ATTR_FLAG_GROUP_MOD) { - printf(" %2d -> %s\n", j, attrlist[i].output_string); - j++; - } - } - } else { - for (i = 0; attrlist[i].quipu_name != NULL; i++) { - if (attrlist[i].flags & ATTR_FLAG_PERSON_MOD) { - printf(" %2d -> %s\n", j, attrlist[i].output_string); - j++; - } - } - } - printf(" ? -> Print this list\n\n"); - printf(" Press the RETURN key without typing a number to quit.\n"); -#ifdef UOFM - if (group == FALSE) - printf(" To add nicknames, send mail to x500-nicknames@umich.edu\n"); -#endif -} - -perform_action(choice, dn, group) -char choice[]; -char *dn; -int group; -{ - int selection; - register int i, j = 1; - extern struct attribute attrlist[]; - extern void mod_addrDN(), change_field(), set_boolean(); - - selection = atoi(choice); - if (selection < 1) { - printf("\n Choices are:\n"); - printf(" -----------------------\n"); - print_mod_list(group); - return(1); - /* NOTREACHED */ - } - - if (group == TRUE) { - for (i = 0; attrlist[i].quipu_name != NULL; i++) { - if (attrlist[i].flags & ATTR_FLAG_GROUP_MOD) { - if (j == selection) - break; - j++; - } - } - } else { - for (i = 0; attrlist[i].quipu_name != NULL; i++) { - if (attrlist[i].flags & ATTR_FLAG_PERSON_MOD) { - if (j == selection) - break; - j++; - } - } - } - - if (attrlist[i].quipu_name == NULL) { - printf("\n Choices are:\n"); - printf(" -----------------------\n"); - print_mod_list(group); - return(1); - /* NOTREACHED */ - } - if (attrlist[i].mod_func == change_field) - (*attrlist[i].mod_func)(dn, Entry.attrs[attr_to_index(attrlist[i].quipu_name)]); - else if (attrlist[i].mod_func == mod_addrDN) - (*attrlist[i].mod_func)(dn, i); - else if (attrlist[i].mod_func == set_boolean) - (*attrlist[i].mod_func)(dn, Entry.attrs[attr_to_index(attrlist[i].quipu_name)]); - else - (*attrlist[i].mod_func)(dn); - return(0); -} - -static char * get_URL() -{ - char *rvalue, label[MED_BUF_SIZE], url[MED_BUF_SIZE]; - static int check_URL(); - extern void * Malloc(); - - if (verbose) { - printf(" First, enter the URL. (Example: http://www.us.itd.umich.edu/users/).\n"); - printf(" The URL may be up to %d characters long.\n", MED_BUF_SIZE); - } - for (;;) { - printf(" URL: "); - fflush(stdout); - (void) fetch_buffer(url, sizeof(url), stdin); - if (*url == '\0') - continue; - if (check_URL(url) == 0) - break; - printf(" A URL may not have any spaces or tabs in it. Please re-enter your URL.\n\n"); - } - if (verbose) - printf("\n Now please enter a descriptive label for this URL\n"); - do { - printf(" Label: "); - fflush(stdout); - (void) fetch_buffer(label, sizeof(label), stdin); - } while (label[0] == '\0'); - rvalue = (char *) Malloc((unsigned) (strlen(url) + 2 + strlen(label))); - sprintf(rvalue, "%s %s", url, label); - return((char *) rvalue); -} - -static check_URL(url) -char *url; -{ - register char *cp; - - for (cp = url; *cp != '\n' && *cp != '\0'; cp++) { - if (isspace(*cp)) - return(-1); - /*NOTREACHED*/ - } - *cp = '\0'; - return(0); -} - - -mod_perror( LDAP *ld ) -{ - if ( ld == NULL || ( ld->ld_errno != LDAP_UNAVAILABLE && - ld->ld_errno != LDAP_UNWILLING_TO_PERFORM )) { - ldap_perror( ld, "modify" ); - return; - } - - fprintf( stderr, "\n modify: failed because part of the online directory is not able\n" ); - fprintf( stderr, " to be modified right now" ); - if ( ld->ld_errno == LDAP_UNAVAILABLE ) { - fprintf( stderr, " or is temporarily unavailable" ); - } - fprintf( stderr, ".\n Please try again later.\n" ); -} diff --git a/clients/ud/print.c b/clients/ud/print.c deleted file mode 100644 index 4185bdaef3..0000000000 --- a/clients/ud/print.c +++ /dev/null @@ -1,653 +0,0 @@ -/* - * Copyright (c) 1991, 1993 - * Regents of the University of Michigan. All rights reserved. - * - * Redistribution and use in source and binary forms are permitted - * provided that this notice is preserved and that due credit is given - * to the University of Michigan at Ann Arbor. The name of the University - * may not be used to endorse or promote products derived from this - * software without specific prior written permission. This software - * is provided ``as is'' without express or implied warranty. - */ - -#include -#include -#include -#ifndef __STDC__ -#include -#endif -#include -#include -#include -#include "ud.h" - -#ifdef DEBUG -extern int debug; -#endif - -struct entry Entry; -extern LDAP *ld; - -extern void * Malloc(); -extern void Free(); -extern char * my_ldap_dn2ufn(); - -/* - * When displaying entries, display only these attributes, and in this - * order. - */ -static char *person_attr_print_order[] = { - "cn", - "mail", - "telephoneNumber", - "facsimileTelephoneNumber", - "pager", - "postalAddress", - "title", - "uid", - "multiLineDescription", - "homePhone", - "homePostalAddress", - "drink", - "labeledURL", - "onVacation", - "vacationMessage", - "memberOfGroup", - "lastModifiedBy", - "lastModifiedTime", - NULL -}; - -static char *group_attr_print_order[] = { - "cn", - "facsimileTelephoneNumber", - "telephoneNumber", - "postalAddress", - "multiLineDescription", - "joinable", - "associatedDomain", - "owner", - "moderator", - "ErrorsTo", - "rfc822ErrorsTo", - "RequestsTo", - "rfc822RequestsTo", - "member", - "mail", - "labeledURL", - "lastModifiedBy", - "lastModifiedTime", - NULL -}; - -parse_answer(s) -LDAPMessage *s; -{ - int idx; - char **rdns; - BerElement *cookie; - register LDAPMessage *ep; - register char *ap; - void clear_entry(); - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->parse_answer(%x)\n", s); -#endif - - clear_entry(); - -#ifdef DEBUG - if (debug & D_PARSE) - printf(" Done clearing entry\n"); -#endif - for (ep = ldap_first_entry(ld, s); ep != NULL; ep = ldap_next_entry(ld, ep)) { -#ifdef DEBUG - if (debug & D_PARSE) - printf(" Determining DN and name\n"); -#endif - Entry.DN = ldap_get_dn(ld, ep); -#ifdef DEBUG - if (debug & D_PARSE) - printf(" DN = %s\n", Entry.DN); -#endif - rdns = ldap_explode_dn(Entry.DN, TRUE); -#ifdef DEBUG - if (debug & D_PARSE) - printf(" Name = %s\n", *rdns); -#endif - Entry.name = strdup(*rdns); - ldap_value_free(rdns); - for (ap = ldap_first_attribute(ld, ep, &cookie); ap != NULL; ap = ldap_next_attribute(ld, ep, cookie)) { - -#ifdef DEBUG - if (debug & D_PARSE) - printf("parsing ap = %s\n", ap); -#endif - if ((idx = attr_to_index(ap)) < 0) { - printf(" Unknown attribute \"%s\"\n", ap); - continue; - } - add_value(&(Entry.attrs[idx]), ep, ap); - } - } -#ifdef DEBUG - if (debug & D_PARSE) - printf(" Done parsing entry\n"); -#endif -} - -add_value(attr, ep, ap) -struct attribute *attr; -LDAPMessage *ep; -char *ap; -{ - register int i = 0; - char **vp, **tp, **avp; - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->add_value(%x, %x, %s)\n", attr, ep, ap); -#endif - vp = (char **) ldap_get_values(ld, ep, ap); - - /* - * Fill in the attribute structure for this attribute. This - * stores away the values (using strdup()) and the count. Terminate - * the list with a NULL pointer. - * - * attr->quipu_name has already been set during initialization. - */ - if ((attr->number_of_values = ldap_count_values(vp)) > 0) { - attr->values = (char **) Malloc((unsigned) ((attr->number_of_values + 1) * sizeof(char *))); - avp = attr->values; - - for (i = 1, tp = vp; *tp != NULL; i++, tp++) { -#ifdef DEBUG - if (debug & D_PARSE) - printf(" value #%d %s\n", i, *tp); -#endif - /* - * The 'name' field of the Entry structure already has - * has the first part of the DN copied into it. Thus, - * we don't need to save it away here again. Also, by - * tossing it away here, we make printing this info out - * a bit easier later. - */ - if (!strcmp(ap, "cn") && !strcmp(*tp, Entry.name)) { - attr->number_of_values--; - continue; - } - *avp++ = strdup(*tp); - } - *avp = NULL; - } - ldap_value_free(vp); -} - -print_an_entry() -{ - int n = 0, i, idx; - char is_a_group, **order; - char *sub_list[MAX_VALUES], buf[SMALL_BUF_SIZE]; - extern int col_size, isaurl(), isadn(); - static char *time2text(); - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->print_an_entry()\n"); -#endif - printf(" \"%s\"\n", Entry.name); - - /* - * If the entry is a group, find all of the subscribers to that - * group. A subscriber is an entry that *points* to a group entry, - * and a member is an entry that is included as part of a group - * entry. - * - * We also need to select the appropriate output format here. - */ - is_a_group = isgroup(); - if (is_a_group) { - order = (char **) group_attr_print_order; - n = find_all_subscribers(sub_list, Entry.DN); -#ifdef DEBUG - if (debug & D_PRINT) - printf(" Group \"%s\" has %d subscribers\n", - Entry.name, n); -#endif - } - else - order = (char **) person_attr_print_order; - - for (i = 0; order[i] != NULL; i++) { - idx = attr_to_index(order[i]); -#ifdef DEBUG - if (debug & D_PRINT) { - printf(" ATTR #%2d = %s [%s] (%d values)\n", i + 1, - Entry.attrs[idx].output_string, - Entry.attrs[idx].quipu_name, - Entry.attrs[idx].number_of_values); - } -#endif - if (idx < 0) - continue; - if (Entry.attrs[idx].number_of_values == 0) - continue; - if (isadn(order[i])) - print_DN(Entry.attrs[idx]); - else if (isaurl(order[i])) - print_URL(Entry.attrs[idx]); - else if (isadate(order[i])) { - /* fix time and date, then call usual routine */ - Entry.attrs[idx].values[0] = - time2text(Entry.attrs[idx].values[0], FALSE); - print_values(Entry.attrs[idx]); - } - else - print_values(Entry.attrs[idx]); - } - - /* - * If it is a group, then we should print the subscriber list (if - * there are any). If there are a lot of them, prompt the user - * before printing them. - */ - if (is_a_group && (n > 0)) { - char *label = "Subscribers: "; - - if (n > TOO_MANY_TO_PRINT) { - printf(" There are %d subscribers. Print them? ", n); - fflush(stdout); - fetch_buffer(buf, sizeof(buf), stdin); - if (!((buf[0] == 'y') || (buf[0] == 'Y'))) - return; - } - format2((char *) my_ldap_dn2ufn(sub_list[n - 1]), label, (char *) NULL, 2, - 2 + strlen(label) + 1, col_size); - for (n--; n > 0; n--) - format2((char *) my_ldap_dn2ufn(sub_list[n - 1]), (char *) NULL, - (char *) NULL, 2 + strlen(label), - 2 + strlen(label) + 2, col_size); - } - - return; -} - -#define OUT_LABEL_LEN 20 - -/* prints the values associated with an attribute */ -print_values(A) -struct attribute A; -{ - register int i, k; - register char *cp, **vp; - char out_buf[MED_BUF_SIZE], *padding = NULL; - int lead; - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->print_values(%x)\n", A); -#endif - if (A.number_of_values == 0) - return; - if ((vp = A.values) == NULL) - return; - - /* - * Pad out the output string label so that it fills the - * whole field of length OUT_LABEL_LEN. - */ - out_buf[0] = '\0'; - i = OUT_LABEL_LEN - strlen(A.output_string); - if (i < 0) { - printf("Output string for \"%s\" is too long. Maximum length is %d characters\n", A.quipu_name, OUT_LABEL_LEN); - return; - } - if (isgroup() && !strcmp(A.quipu_name, "mail") && (Entry.attrs[attr_to_index("member")].number_of_values == 0)) { - A.output_string = "Members"; - i = OUT_LABEL_LEN - strlen(A.output_string); - padding = (char *) Malloc((unsigned) (i + 1)); - (void) memset(padding, ' ', i); - *(padding + i) = '\0'; - sprintf(out_buf, "%s:%s", A.output_string, padding); - } - else if (!(isgroup() && !strcmp(A.quipu_name, "mail") && (Entry.attrs[attr_to_index("member")].number_of_values > 0))) { - padding = (char *) Malloc((unsigned) (i + 1)); - (void) memset(padding, ' ', i); - *(padding + i) = '\0'; - sprintf(out_buf, "%s:%s", A.output_string, padding); - } - /* - * If this happens to be a group, then do not print the output - * string if we have already printed out some members. - */ - else if (isgroup() && !strcmp(A.quipu_name, "mail") && (Entry.attrs[attr_to_index("member")].number_of_values > 0)) { - padding = (char *) Malloc((unsigned) (OUT_LABEL_LEN + 2)); - (void) memset(padding, ' ', OUT_LABEL_LEN + 1); - *(padding + OUT_LABEL_LEN + 1) = '\0'; - sprintf(out_buf, "%s", padding); - } - lead = strlen(out_buf) + 2; - - printf(" %s", out_buf); - for (i = 0; *vp != NULL; i++, vp++) { - if (i > 0) { - if (!strncmp(A.output_string, "Home a", 6) || !strncmp(A.output_string, "Business a", 10)) { - printf(" %s", out_buf); - } - else { - for (k = lead; k > 0; k--) - putchar(' '); - } - } - for (cp = *vp; *cp != '\0'; cp++) { - switch (*cp) { - case '$' : - if (!strncmp(A.output_string, "Home a", 6) || !strncmp(A.output_string, "Business a", 10) || !strcmp(A.quipu_name, "multiLineDescription")) { - putchar('\n'); - for (k = lead; k > 0; k--) - putchar(' '); - while (isspace(*(cp + 1))) - cp++; - } - else - putchar(*cp); - break; - case '\n' : - putchar('%'); - putchar('\n'); - break; - default: - putchar(*cp); - } - } - putchar('\n'); - } - if (padding != NULL) - Free(padding); - return; -} - -/* prints the DN's associated with an attribute */ -print_DN(A) -struct attribute A; -{ - int i, lead; - register char **vp; - char out_buf[MED_BUF_SIZE], *padding = NULL; - extern int col_size; - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->print_DN(%x)\n", A); -#endif - if (A.number_of_values == 0) - return; - /* - * Pad out the output string label so that it fills the - * whole field of length OUT_LABEL_LEN. - */ - i = OUT_LABEL_LEN - strlen(A.output_string); - if (i > 0) { - padding = (char *) Malloc((unsigned) (i + 1)); - (void) memset(padding, ' ', i); - *(padding + i) = '\0'; - sprintf(out_buf, "%s:%s", A.output_string, padding); - (void) Free(padding); - } - lead = strlen(out_buf) + 2; - - vp = A.values; - format2((char *) my_ldap_dn2ufn(*vp), out_buf, (char *) NULL, 2, lead + 1, col_size); - for (vp++; *vp != NULL; vp++) { - format2((char *) my_ldap_dn2ufn(*vp), (char *) NULL, (char *) NULL, lead, - lead + 1, col_size); - } - return; -} - -void clear_entry() -{ - register int i; - extern struct attribute attrlist[]; - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->clear_entry()\n"); - if ((debug & D_PRINT) && (Entry.name != NULL)) - printf(" Clearing entry \"%s\"\n", Entry.name); -#endif - if (Entry.DN != NULL) - Free(Entry.DN); - if (Entry.name != NULL) - Free(Entry.name); - Entry.may_join = FALSE; - Entry.subscriber_count = -1; - Entry.DN = Entry.name = NULL; - - /* clear all of the values associated with all attributes */ - for (i = 0; attrlist[i].quipu_name != NULL; i++) { -#ifdef DEBUG - if (debug & D_PRINT) - printf(" Clearing attribute \"%s\" -- ", - Entry.attrs[i].quipu_name); -#endif - if (Entry.attrs[i].values == NULL) { -#ifdef DEBUG - if (debug & D_PRINT) - printf(" no values, skipping\n"); -#endif - continue; - } -#ifdef DEBUG - if (debug & D_PRINT) - printf(" freeing %d values\n", - Entry.attrs[i].number_of_values); -#endif - Entry.attrs[i].number_of_values = 0; - ldap_value_free(Entry.attrs[i].values); - Entry.attrs[i].values = (char **) NULL; - - /* - * Note: We do not clear either of the char * fields - * since they will always be applicable. - */ - } -} - -attr_to_index(s) -char *s; -{ - register int i; - extern struct attribute attrlist[]; - - for (i = 0; attrlist[i].quipu_name != NULL; i++) - if (!strcasecmp(s, attrlist[i].quipu_name)) - return(i); - return(-1); -} - -void initialize_attribute_strings() -{ - register int i; - extern struct entry Entry; - extern struct attribute attrlist[]; - - for (i = 0; attrlist[i].quipu_name != NULL; i++) - Entry.attrs[i].quipu_name = attrlist[i].quipu_name; - for (i = 0; attrlist[i].quipu_name != NULL; i++) - Entry.attrs[i].output_string = attrlist[i].output_string; -} - -/* prints the URL/label pairs associated with an attribute */ -print_URL(A) -struct attribute A; -{ - int i, lead; - register char **vp; - char out_buf[MED_BUF_SIZE], *padding = NULL; - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->print_URL(%x)\n", A); -#endif - if (A.number_of_values == 0) - return; - /* - * Pad out the output string label so that it fills the - * whole field of length OUT_LABEL_LEN. - */ - i = OUT_LABEL_LEN - strlen(A.output_string); - if (i > 0) { - padding = (char *) Malloc((unsigned) (i + 1)); - (void) memset(padding, ' ', i); - *(padding + i) = '\0'; - sprintf(out_buf, "%s:%s", A.output_string, padding); - } - lead = strlen(out_buf) + 2; - - vp = A.values; - print_one_URL(*vp, 2, out_buf, lead); - for (vp++; *vp != NULL; vp++) - print_one_URL(*vp, lead, (char *) NULL, lead); - if (padding != NULL) - Free(padding); - return; -} - -print_one_URL(s, label_lead, tag, url_lead) -char *s; -int label_lead; -char *tag; -int url_lead; -{ - register int i; - char c, *cp, *url; - extern int col_size; - extern void Free(); - - for (cp = s; !isspace(*cp) && (*cp != '\0'); cp++) - ; - c = *cp; - *cp = '\0'; - url = strdup(s); - *cp = c; - if (*cp != '\0') { - for (cp++; isspace(*cp); cp++) - ; - } - else - cp = "(no description available)"; - format2(cp, tag, (char *) NULL, label_lead, label_lead + 1, col_size); - for (i = url_lead + 2; i > 0; i--) - printf(" "); - printf("%s\n", url); - Free(url); -} - - -#define GET2BYTENUM( p ) (( *p - '0' ) * 10 + ( *(p+1) - '0' )) - -static char * -time2text( char *ldtimestr, int dateonly ) -{ - struct tm t; - char *p, *timestr, zone, *fmterr = "badly formatted time"; - time_t gmttime; - static long gtime(); - - memset( (char *)&t, 0, sizeof( struct tm )); - if ( strlen( ldtimestr ) < 13 ) { - return( fmterr ); - } - - for ( p = ldtimestr; p - ldtimestr < 12; ++p ) { - if ( !isdigit( *p )) { - return( fmterr ); - } - } - - p = ldtimestr; - t.tm_year = GET2BYTENUM( p ); p += 2; - t.tm_mon = GET2BYTENUM( p ) - 1; p += 2; - t.tm_mday = GET2BYTENUM( p ); p += 2; - t.tm_hour = GET2BYTENUM( p ); p += 2; - t.tm_min = GET2BYTENUM( p ); p += 2; - t.tm_sec = GET2BYTENUM( p ); p += 2; - - if (( zone = *p ) == 'Z' ) { /* GMT */ - zone = '\0'; /* no need to indicate on screen, so we make it null */ - } - - gmttime = gtime( &t ); - timestr = ctime( &gmttime ); - - timestr[ strlen( timestr ) - 1 ] = zone; /* replace trailing newline */ - if ( dateonly ) { - strcpy( timestr + 11, timestr + 20 ); - } - - Free ( ldtimestr ); - return( strdup( timestr ) ); -} - - -/* gtime.c - inverse gmtime */ - -#if !defined( MACOS ) && !defined( _WIN32 ) && !defined( DOS ) -#include -#endif /* !MACOS */ - -/* gtime(): the inverse of localtime(). - This routine was supplied by Mike Accetta at CMU many years ago. - */ - -int dmsize[] = { - 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 -}; - -#define dysize(y) \ - (((y) % 4) ? 365 : (((y) % 100) ? 366 : (((y) % 400) ? 365 : 366))) - -#define YEAR(y) ((y) >= 100 ? (y) : (y) + 1900) - -/* */ - -static long gtime ( struct tm *tm ) -{ - register int i, - sec, - mins, - hour, - mday, - mon, - year; - register long result; - - if ((sec = tm -> tm_sec) < 0 || sec > 59 - || (mins = tm -> tm_min) < 0 || mins > 59 - || (hour = tm -> tm_hour) < 0 || hour > 24 - || (mday = tm -> tm_mday) < 1 || mday > 31 - || (mon = tm -> tm_mon + 1) < 1 || mon > 12) - return ((long) -1); - if (hour == 24) { - hour = 0; - mday++; - } - year = YEAR (tm -> tm_year); - - result = 0L; - for (i = 1970; i < year; i++) - result += dysize (i); - if (dysize (year) == 366 && mon >= 3) - result++; - while (--mon) - result += dmsize[mon - 1]; - result += mday - 1; - result = 24 * result + hour; - result = 60 * result + mins; - result = 60 * result + sec; - - return result; -} diff --git a/clients/ud/ud.h b/clients/ud/ud.h deleted file mode 100644 index 40b6ecff7a..0000000000 --- a/clients/ud/ud.h +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (c) 1991, 1992, 1993 - * Regents of the University of Michigan. All rights reserved. - * - * Redistribution and use in source and binary forms are permitted - * provided that this notice is preserved and that due credit is given - * to the University of Michigan at Ann Arbor. The name of the University - * may not be used to endorse or promote products derived from this - * software without specific prior written permission. This software - * is provided ``as is'' without express or implied warranty. - */ - -#ifdef DOS -#include "protoud.h" -#define strncasecmp(a, b, n) strnicmp(a, b, n) -#define strcasecmp(a, b) stricmp(a, b) -#define MAX_VALUES 8 -#else -#define MAX_VALUES 1000 -#endif /* end of DOS ifdef */ - -/***************************************************************************** - ** - ** Limits which ud imposes. Also subject to change. - ** - *****************************************************************************/ - -/* - * Names are parsed somewhat like 'awk' parses them. This is the - * maximum number of components we store away. - * - * The isnamesepartor() macro should return TRUE if x is equal to one of the - * characters that delimits name fields. The ignorechar() macro should - * return TRUE if it is equal to a character that should be ignored when - * parsing names. - */ -#define MAX_NAME_COMPS 8 -#define isnamesepartor(x) (isspace(x)) -#define isignorechar(x) (((x) == '.') || ((x) == '_')) - -/* - * Quite often a search will turn up more than one match. When it does we - * print out a list of the matches, and ask the user to select the one that - * s/he wants. This defines how many we will save and show. - */ -#define MAX_NUM_NAMES 128 - -/* - * When a user displays a group, we will automatically print out this many - * members and subscribers. If the number is greater than this, we will - * prompt the user before printing them. - */ -#define TOO_MANY_TO_PRINT 16 - -/* - * This is the default size of a tty if we can't figure out the actual size. - */ -#define DEFAULT_TTY_HEIGHT 24 -#define DEFAULT_TTY_WIDTH 80 - -/* - * The number of attributes we know about must be less than this number. - * Don't add lots of attributes to the list in globals.c without checking - * this number too. - */ -#define MAX_ATTRS 64 - -/***************************************************************************** - ** - ** No user servicable parts beyond this point. - ** - *****************************************************************************/ - -/* - * Generic buffer sizes. - */ -#define SMALL_BUF_SIZE 16 -#define MED_BUF_SIZE 128 -#define LARGE_BUF_SIZE 512 - -/* - * Used to specify the operation in x_group(). - */ -#define G_JOIN 0 -#define G_RESIGN 1 - -/* - * Authentication method we will be using. - */ -#ifdef KERBEROS -#define UD_AUTH_METHOD LDAP_AUTH_KRBV4 -#else -#define UD_AUTH_METHOD LDAP_AUTH_SIMPLE -#endif - -/* - * TRUE and FALSE - just in case we need them. - */ -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif - -/* - * Bound status. - */ -#define UD_NOT_BOUND 0 /* bound only as the default defined above */ -#define UD_BOUND 1 /* bound as an actual Directory entity */ - -/* - * Debug masks. - */ -#define D_TRACE 0x0001 -#define D_FIND 0x0002 -#define D_GROUPS 0x0004 -#define D_MODIFY 0x0008 -#define D_PARSE 0x0010 -#define D_PRINT 0x0020 -#define D_AUTHENTICAT 0x0040 -#define D_INITIALIZE 0x0080 - -/* - * Used in the flags field of an attribute structure. - */ -#define ATTR_FLAG_NONE 0x0000 -#define ATTR_FLAG_PERSON 0x0001 -#define ATTR_FLAG_GROUP 0x0002 -#define ATTR_FLAG_PERSON_MOD 0x0010 -#define ATTR_FLAG_GROUP_MOD 0x0020 -#define ATTR_FLAG_MAY_EDIT 0x0040 -#define ATTR_FLAG_SEARCH 0x0100 -#define ATTR_FLAG_READ 0x0200 -#define ATTR_FLAG_IS_A_DATE 0x0800 -#define ATTR_FLAG_IS_A_DN 0x1000 -#define ATTR_FLAG_IS_A_URL 0x2000 -#define ATTR_FLAG_IS_A_BOOL 0x4000 -#define ATTR_FLAG_IS_MULTILINE 0x8000 - -/* - * These are the structures we use when parsing an answer we get from the LDAP - * server. - */ -struct attribute { - char *quipu_name; - char *output_string; - void (*mod_func)(); - unsigned short flags; - int number_of_values; - char **values; -}; - -struct entry { - char may_join; - int subscriber_count; - char *DN; - char *name; - struct attribute attrs[MAX_ATTRS]; -}; diff --git a/clients/ud/util.c b/clients/ud/util.c deleted file mode 100644 index 2edb5aa265..0000000000 --- a/clients/ud/util.c +++ /dev/null @@ -1,662 +0,0 @@ -/* - * Copyright (c) 1992, 1993 Regents of the University of Michigan. - * All rights reserved. - * - * Redistribution and use in source and binary forms are permitted - * provided that this notice is preserved and that due credit is given - * to the University of Michigan at Ann Arbor. The name of the University - * may not be used to endorse or promote products derived from this - * software without specific prior written permission. This software - * is provided ``as is'' without express or implied warranty. - */ - -#include -#include -#include -#ifdef DOS -#include -#endif -#include -#if defined( NeXT ) -#include -#endif -#include -#include -#include -#include -#include -#if !defined(DOS) && !defined( VMS) -#include -#endif -#include "portable.h" -#ifdef USE_TERMIOS -#include -#else /* USE_TERMIOS */ -#include -#endif /* USE_TERMIOS */ -#include "ud.h" - -#if defined(VMS) -#define getch getchar -#endif - -#ifdef DEBUG -extern int debug; -#endif - -char * mygetpass(prompt) -char *prompt; -{ -#if defined(DOS) || defined(VMS) - static char buf[256]; - int i, c; - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->mygetpass(%s)\n", prompt); -#endif - printf("%s", prompt); - i = 0; - while ( (c = getch()) != EOF && c != '\n' && c != '\r' ) - buf[i++] = c; - if ( c == EOF ) - return( NULL ); - buf[i] = '\0'; - return (buf); -#else - int no_pass = 0; - char i, j, k; - TERMIO_TYPE ttyb; - TERMFLAG_TYPE flags; - static char pbuf[513]; - register char *p; - register int c; - FILE *fi; - SIG_FN (*sig)(); - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->mygetpass(%s)\n", prompt); -#endif - /* - * Stolen from the getpass() routine. Can't use the plain - * getpass() for two reasons. One is that X.500 passwords - * can be really, really long - much longer than 8 chars. - * The second is that we like to make this client available - * out of inetd via a Merit asynch port, and we need to be - * able to do telnet control codes to turn on and off line - * blanking. - */ - if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL) - fi = stdin; - else - setbuf(fi, (char *)NULL); - sig = signal(SIGINT, SIG_IGN); - if (fi != stdin) { - if (GETATTR(fileno(fi), &ttyb) < 0) - perror("GETATTR"); - } - flags = GETFLAGS( ttyb ); - SETFLAGS( ttyb, flags & ~ECHO ); - if (fi != stdin) { - if (SETATTR(fileno(fi), &ttyb) < 0) - perror("SETATTR"); - } - - /* blank the line if through Merit */ - if (fi == stdin) { - printf("%c%c%c", 255, 251, 1); - fflush(stdout); - (void) scanf("%c%c%c", &i, &j, &k); - fflush(stdin); - } - - /* fetch the password */ - fprintf(stdout, "%s", prompt); - fflush(stdout); - for (p=pbuf; (c = getc(fi))!='\n' && c!=EOF;) { - if (c == '\r') - break; - if (p < &pbuf[512]) - *p++ = c; - } - if (c == EOF) - no_pass = 1; - else { - *p = '\0'; - if (*(p - 1) == '\r') - *(p - 1) = '\0'; - } - - /* unblank the line if through Merit */ - if (fi == stdin) { - printf("%c%c%c", 255, 252, 1); - fflush(stdout); - (void) scanf("%c%c%c", &i, &j, &k); - fflush(stdin); - printf("\n"); fflush(stdout); - } - fprintf(stdout, "\n"); - fflush(stdout); - - /* tidy up */ - SETFLAGS( ttyb, flags ); - if (fi != stdin) { - if (SETATTR(fileno(fi), &ttyb) < 0) - perror("SETATTR"); - } - (void) signal(SIGINT, sig); - if (fi != stdin) - (void) fclose(fi); - else - i = getchar(); - if (no_pass) - return(NULL); - return(pbuf); -#endif /* DOS */ -} - -void printbase(lead, s) -char *lead, *s; -{ - register char **cp; - char **rdns; - char * friendly_name(); - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->printbase(%s, %s)\n", lead, s); -#endif - if (s == NULL) { - printf("%sroot\n", lead); - return; - } - printf("%s", lead); - rdns = ldap_explode_dn(s, TRUE); - for (cp = rdns; ; ) { - printf("%s", friendly_name(*cp)); - cp++; - if (*cp == NULL) { - printf("\n"); - break; - } - else - printf(", "); - } - ldap_value_free(rdns); - return; -} - -fetch_buffer(buffer, length, where) -char *buffer; -int length; -FILE *where; -{ - extern LDAP *ld; - register int i; - char *p; - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->fetch_buffer(%x, %d, %x)\n", buffer, length, where); -#endif - /* - * Fetch a buffer and strip off any leading or trailing non-printing - * characters, namely newlines and carriage returns. - */ - if (fgets(buffer, length, where) == NULL) { - if (feof(where)) - errno = 0; /* so fatal() doesn't bitch */ - fatal("fgets"); - } - for (i = strlen(buffer) - 1; i >= 0 && !isprint(buffer[i]); i--) - buffer[i] = '\0'; - - p = buffer; - while ( *p != '\0' ) { - if ( isprint( *p )) { - ++p; - } else { - strcpy( p, p + 1 ); - } - } - -} - -fatal(s) -char *s; -{ - void exit(); - - if (errno != 0) - perror(s); -#ifdef KERBEROS - destroy_tickets(); -#endif - exit(-1); -} - -isgroup() -{ - extern struct entry Entry; - char **vp; - register int i; - int group = FALSE; - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->isgroup()\n"); -#endif - if ((i = attr_to_index("objectClass")) == -1) - return(FALSE); - vp = Entry.attrs[i].values; - for (i = 0; *vp != NULL; vp++) { -#ifdef DEBUG - i++; - if (debug & D_GROUPS) - printf("class #%1d: (%s)\n", i, *vp); -#endif - if (!strcmp(*vp, "rfc822MailGroup")) - group = TRUE; - } - return(group); -} - -/* - * Print out the string 's' on a field of 'width' chracters. Each line - * should be indented 'lead' characters. - */ -format(str, width, lead) -char *str; -int width, lead; -{ - char *s, *original, *leader = ""; - register char *cp; - void * Malloc(); - void Free(); - -#ifdef DEBUG - if (debug & D_TRACE) - printf("->format(%s, %d, %d)\n", str, width, lead); -#endif - if (lead >= width) { - fprintf(stderr, " Cannot format (%s, %d, %d)\n", str, width, lead); - return; - } - if (lead > 0) { - leader = (char *) Malloc((unsigned) (lead + 1)); - (void) memset(leader, ' ', lead); - *(leader + lead) = '\0'; - } - - /* - * Some compilers get really unhappy with this function since it - * fiddles around with the first argument, which could be a string - * constant. We do a strdup() here so we can do whatever the hell - * we want. - */ - s = original = strdup(str); - for (;;) { - if ((strlen(s) + lead) < width) { - printf("%s%s\n", leader, s); - Free(leader); - Free(original); - return; - /*NOTREACHED*/ - } - cp = s + width - lead; - while (!isspace(*cp) && (cp != s)) - cp--; - *cp = '\0'; - while (isspace(*s)) - s++; - printf("%s%s\n", leader, s); - s = cp + 1; - } -} - -/* - * Print out the string 's' on a field of 'width' chracters. The first line - * should be indented 'first_indent' spaces, then followed by 'first_tag', - * and then followed by the first line of 's'. Subsequent lines should be - * indented 'indent' spaces, then followed by 'tag', and then followed by - * subsequent lines of 's'. - */ -format2(s, first_tag, tag, first_indent, indent, width) -char *s, *first_tag, *tag; -int first_indent, indent, width; -{ - char c, *fi, *i; - register char *cp; - void * Malloc(); - void Free(); - - if (first_tag == NULL) - first_tag = ""; - if (tag == NULL) - tag = ""; -#ifdef DEBUG - if (debug & D_TRACE) - printf("format2(\"%s\", \"%s\", \"%s\", %1d, %1d, %1d)\n", s, - first_tag, tag, first_indent, indent, width); -#endif - - /* make sure the indents are sane */ - if ((first_indent >= width) || (indent >= width)) { - fprintf(stderr, " Cannot format: indent too large\n"); - return; - } - - /* make the indentations */ - if (first_indent > 0) { - fi = (char *) Malloc((unsigned) (first_indent + 1)); - (void) memset(fi, ' ', first_indent); - *(fi + first_indent) = '\0'; - } - else - fi = ""; - if (indent > 0) { - i = (char *) Malloc((unsigned) (indent + 1)); - (void) memset(i, ' ', indent); - *(i + indent) = '\0'; - } - else - i = ""; - - /* now do the first line */ - if ((strlen(s) + strlen(first_tag) + first_indent) < width) { - printf("%s%s%s\n", fi, first_tag, s); - Free(fi); - Free(i); - return; - /*NOTREACHED*/ - } - - /* - * 's' points to the beginning of the string we want to print. - * We point 'cp' to the end of the maximum amount of text we - * can print (i.e., total width less the indentation and the - * length of the tag). Once we have set 'cp' initially we - * back it up to the first space character. - */ - cp = s + width - first_indent - strlen(first_tag); - while (!isspace(*cp) && (cp != s)) - cp--; - - /* - * Once there, we change that space character to a null, print the - * string, and then restore the space character. - */ - c = *cp; - *cp = '\0'; - printf("%s%s%s\n", fi, first_tag, s); - *cp = c; - - /* - * Since 'cp' may have been set to a space initially (and so no - * back-tracking was performed), it could have a space after it - * as well. We should gobble up all of these since we don't want - * unexpected leading blanks. - */ - for (s = cp + 1; isspace(*s); s++) - ; - - /* now do all of the other lines */ - for (;;) { - if ((strlen(s) + strlen(tag) + indent) < width) { - printf("%s%s%s\n", i, tag, s); - Free(fi); - Free(i); - return; - /*NOTREACHED*/ - } - cp = s + width - indent - strlen(tag); - while (!isspace(*cp) && (cp != s)) - cp--; - c = *cp; - *cp = '\0'; - printf("%s%s%s\n", i, tag, s); - s = cp + 1; - *cp = c; /* don't mess up 's' */ - } -} - -#define IN_A_QUOTE 0 -#define OUT_OF_QUOTE 1 - -char * strip_ignore_chars(cp) -char *cp; -{ - int had_a_comma = FALSE; - int flag = OUT_OF_QUOTE; - register char *rcp, *cp1; - char *tmp; - void * Malloc(); - void Free(); - -#ifdef DEBUG - if (debug & D_TRACE) - printf("strip_ignore_chars(%s)\n", cp); -#endif - for (rcp = cp; *rcp != '\0'; rcp++) - if (isignorechar(*rcp) || (*rcp == '"')) - break; - if (*rcp == '\0') - return(cp); - - cp1 = tmp = (char *) Malloc((unsigned) strlen(cp)); - for (rcp = cp; *rcp != '\0'; rcp++) { - /* toss quotes and flip the flag */ - if (*rcp == '"') - flag = OUT_OF_QUOTE - flag; - else if (isignorechar(*rcp)) { - if (flag == OUT_OF_QUOTE) - *cp1++ = ' '; - else - *cp1++ = *rcp; - } - else if (*rcp == ',') { - *cp1++ = *rcp; - had_a_comma = TRUE; - } - else - *cp1++ = *rcp; - } - *cp1 = '\0'; - - /* re-quote the name if it had a comma in it */ - if (had_a_comma == TRUE) { - rcp = cp1 = (char *) Malloc((unsigned) (strlen(tmp) + 3)); - *rcp++ = '"'; - *rcp = '\0'; - strcat(rcp, tmp); - strcat(rcp, "\""); - Free(tmp); - tmp = cp1; - } - return(tmp); -} - -char * code_to_str(i) -{ - switch(i) { - case LDAP_MOD_ADD : return("ADD"); - case LDAP_MOD_DELETE : return("DELETE"); - case LDAP_MOD_REPLACE : return("REPLACE"); - default : return("?????"); - } -} - -char * friendly_name(s) -char *s; -{ - static FriendlyMap *map = NULL; - static char *cp; - - cp = ldap_friendly_name(FRIENDLYFILE, s, &map); - if (cp == NULL) - return(s); - return(cp); -} - -#ifdef UOFM - -/* return TRUE if s has the syntax of a uniqname */ -isauniqname(s) -char *s; -{ - int i = strlen(s); - - if ((i < 3) || (i > 8)) /* uniqnames are 3-8 chars */ - return(FALSE); - if (!isalpha(*s)) /* uniqnames begin with a letter */ - return(FALSE); - for ( ; *s != '\0'; s++) /* uniqnames are alphanumeric */ - if (!isalnum(*s)) - return(FALSE); - return(TRUE); -} -#endif - -/* return TRUE if this attribute should be printed as a DN */ -isadn(s) -char *s; -{ - register int i; - extern struct attribute attrlist[]; - - for (i = 0; attrlist[i].quipu_name != NULL; i++) - if (!strcasecmp(s, attrlist[i].quipu_name)) - break; - if (attrlist[i].flags & ATTR_FLAG_IS_A_DN) - return(TRUE); - return(FALSE); -} - -char * my_ldap_dn2ufn(s) -char *s; -{ - register char **cpp; - static char short_DN[BUFSIZ]; - - if (strstr(s, UD_BASE) == NULL) - return(ldap_dn2ufn(s)); - cpp = ldap_explode_dn(s, TRUE); - sprintf(short_DN, "%s, %s", *cpp, *(cpp + 1)); - ldap_value_free(cpp); - return(short_DN); -} - -/* return TRUE if this attribute should be printed as a URL */ -isaurl(s) -char *s; -{ - register int i; - extern struct attribute attrlist[]; - - for (i = 0; attrlist[i].quipu_name != NULL; i++) - if (!strcasecmp(s, attrlist[i].quipu_name)) - break; - if (attrlist[i].flags & ATTR_FLAG_IS_A_URL) - return(TRUE); - return(FALSE); -} - -/* return TRUE if this attribute should be printed as a date and time */ -isadate(s) -char *s; -{ - register int i; - extern struct attribute attrlist[]; - - for (i = 0; attrlist[i].quipu_name != NULL; i++) - if (!strcasecmp(s, attrlist[i].quipu_name)) - break; - if (attrlist[i].flags & ATTR_FLAG_IS_A_DATE) - return(TRUE); - return(FALSE); -} - -void * Malloc(size) -unsigned int size; -{ - void *void_ptr; - - void_ptr = (void *) malloc(size); - if (void_ptr == NULL) { - perror("malloc"); - exit(-1); - /*NOTREACHED*/ - } - return(void_ptr); -} - -void Free(ptr) -char *ptr; -{ - extern int free(); - - if (free(ptr) < 0) { - perror("free"); - exit(-1); - /*NOTREACHED*/ - } - return; -} - -char * nextstr(s) -char *s; -{ - while (isspace(*s) && (*s != '\0')) - s++; - if (s == NULL) - return(NULL); - if (*s == '\0') - return(NULL); - return(s); -} - -void free_mod_struct(modp) -LDAPMod *modp; -{ - void Free(); - - if (modp->mod_values != NULL) - (void) ldap_value_free(modp->mod_values); - Free(modp->mod_type); - Free(modp); -} - -void StrFreeDup(ptr, new_value) -char **ptr, *new_value; -{ - void Free(); - - if (*ptr != NULL) - Free(*ptr); - if (new_value == NULL) - *ptr = NULL; - else - *ptr = strdup(new_value); -} - - -confirm_action( msg ) - char *msg; -{ - char tmp[SMALL_BUF_SIZE]; - int i; - - if ( msg != NULL ) { - putchar( '\n' ); - format( msg, 75, 2 ); - } - - printf("\n Is this OK? "); - fflush(stdout); - tmp[0] = '\0'; - fetch_buffer(tmp, sizeof(tmp), stdin); - i = strlen(tmp); - return( i > 0 && - ( !strncasecmp(tmp, "YES", i) || !strncasecmp(tmp, "OK", i))); -} diff --git a/doc/man/man1/ud.1 b/doc/man/man1/ud.1 deleted file mode 100644 index d7b0feabb6..0000000000 --- a/doc/man/man1/ud.1 +++ /dev/null @@ -1,89 +0,0 @@ -.TH UD 1 "RELEASEDATE" "OpenLDAP LDVERSION" -.\" $OpenLDAP$ -.\" Copyright 1998-2002 The OpenLDAP Foundation All Rights Reserved. -.\" Copying restrictions apply. See COPYRIGHT/LICENSE. -.UC 6 -.SH NAME -ud \- interactive LDAP Directory Server query program -.SH SYNOPSIS -.B ud -[\c -.BR -Dv ] -.RB [ -s -.IR server ] -.RB [ -d -.IR debug-mask ] -.RB [ -l -.IR ldap-debug-mask ] -.RB [ -f -.IR file ] -.SH DESCRIPTION -.IR ud -is used to interogate a directory server via the Lightweight Directory -Access Protocol (LDAP). -.SH OPTIONS -.TP 1i -.BI \-s \ server -Used to specify the name of an LDAP server to which -.B ud -should connect. If this -flag is omitted, the value specified in the -.B ud -configuration file is used. If -no value is specified in the configuration file, or the configuration -file does not exist, the name -.IR ldap -is used. Of course, it is up to the system administrator to make sure that -the name -.IR ldap -can be resolved (presumably through the use of a CNAME or A record in the DNS -and the appropriate search path specified in the resolver config file). -.TP 1i -.BI \-d \ debug-mask -Sets the -.B ud -debug mask to the value specified. -Values for the mask can be dumped by using the -.IR \-D -flag. -.TP 1i -.BI \-f \ file -Sets the configuration file to the name specified. -.TP 1i -.BI \-l \ ldap-debug-mask -Sets the LDAP debug mask to the value specified. -.TP 1i -.B \-v -Turns on verbose output. Also toggable via the ud -.IR verbose -command. -.TP 1i -.B \-D -Prints out a list of valid ud debug masks. -.SH FILES -.TP -.I ETCDIR/ud.conf -system-wide ud configuration file -.TP -.I $HOME/.udrc -personal ud configuration file, overriding system file -.SH "SEE ALSO" -.BR ud.conf (5), -.BR ldap.conf (5), -.BR ldap (3) -.SH DIAGNOSTICS -.B ud -will try to be nice about error conditions, and in most cases prints a warm -and fuzzy error message when it encounters a problem. Sometimes the error -will be unexpected, and in these cases, -.B ud -uses the ldap_perror() routine to print an informative diagnostic. -.SH BUGS -Too numerous to mention. -.SH AUTHOR -Bryan Beecher, University of Michigan -.SH ACKNOWLEDGEMENTS -.B OpenLDAP -is developed and maintained by The OpenLDAP Project (http://www.openldap.org/). -.B OpenLDAP -is derived from University of Michigan LDAP 3.3 Release. diff --git a/doc/man/man3/ldap_search.3 b/doc/man/man3/ldap_search.3 index c43d2e671e..a78fb09842 100644 --- a/doc/man/man3/ldap_search.3 +++ b/doc/man/man3/ldap_search.3 @@ -86,9 +86,7 @@ attribute. The filter "mail=*@terminator.rs.itd.umich.edu" will find any entries that have a mail attribute ending in the specified string. To put parentheses in a filter, escape them with a backslash '\\' character. See RFC 2254 for a more complete description of allowable -filters. See -.BR ldap_getfilter (3) -for routines to help in constructing search filters automatically. +filters. .LP \fIAttrs\fP is a null-terminated array of attribute types to return from entries that match \fIfilter\fP. diff --git a/doc/man/man5/ud.conf.5 b/doc/man/man5/ud.conf.5 deleted file mode 100644 index 91cb5bf733..0000000000 --- a/doc/man/man5/ud.conf.5 +++ /dev/null @@ -1,109 +0,0 @@ -.TH UD.CONF 5 "RELEASEDATE" "OpenLDAP LDVERSION" -.\" $OpenLDAP$ -.\" Copyright 1998-2002 The OpenLDAP Foundation All Rights Reserved. -.\" Copying restrictions apply. See COPYRIGHT/LICENSE. -.UC 6 -.SH NAME -ud.conf \- ud configuration file -.SH SYNOPSIS -ETCDIR/ud.conf -.SH DESCRIPTION -The -.I ud -configuration file is used to set system-wide defaults to be applied when -running -.IR ud . -Note that each user may specify an optional configuration file, -.IR .udrc , -in his/her home directory which will be used instead of the system-wide -configuration file. -.SH OPTIONS -The different configuration options are: -.TP 1i -\fBHOST \fP -Used to specify the name of an LDAP server to which -.I ud -should connect. There may be only one entry per config file. -The server's name can be specified as a domain-style name or an IP address. -.TP 1i -\fBBASE \fP -Used to specify the search base to use when performing search operations. -The base may be changed by those using -.I ud -by using the -.I cb -command. -There may be only one entry per config file. -The base must be specified as a Distinguished Name in LDAP format. -.TP 1i -\fBGROUPBASE \fP -Used to specify the base used when creating groups. -The base may be changed by those using -.I ud -by using the -.I changegroup -command. -There may be only one entry per config file. -The base must be specified as a Distinguished Name in LDAP format. -.TP 1i -\fBSEARCH \fP -Used to specify a search algorithm to use when performing searches. More than -one algorithm may be specified, and each is tried in turn until a suitable -response is found. - -Each algorithm specifies a filter that should be used when performing a find -operation. Filters contain LDAP-style attribute types (e.g., uid, cn, -postalAddress) -and operators to test for equality or approximate equality. Prefix operators -may also be used to specify AND, OR and NOT operations (see ldap(3) for -more details on the filter format). Algorithms use a -compile-time constant as a separator to use when parsing the input the user -has provided. This parsed input can then be referenced similarly to an -.I awk -program using symbols like $1, $2, and $0 for the entire batch of input. - -For example, the algoritm -.I cn=$0 -causes -.I ud -to perform a lookup on the entire string the user has typed, searching for -anything where the commonName exactly matches the whole thing. - -Another example, -.I sn~=$NF -causes -.I ud -to do a search where the last element the user has typed (NF = number of fields -and is a special "number" that can be used in -.I awk -as well as -.IR ud ) -searching for any matches that approximately match Surname. - -Search algorithms also support a special feature which allows one to specify -the -.I exact -number of fields that must be present in order for the algorithm to be -applied. This number must be specified between square brackets. - -For example, -.I [1] uid=$1 -causes this algorithm to be applied when the number of fields is exactly equal -to one. If there is exactly one field, the token is looked up as a UID. -.SH FILES -.TP -.I ETCDIR/ud.conf -system-wide ud configuration file -.TP -.I $HOME/.udrc -personal ud configuration file, overriding system file -.SH "SEE ALSO" -.BR ud (1), -.BR ldap (3) -.SH AUTHOR -Bryan Beecher, University of Michigan -.SH ACKNOWLEDGEMENTS -.B OpenLDAP -is developed and maintained by The OpenLDAP Project (http://www.openldap.org/). -.B OpenLDAP -is derived from University of Michigan LDAP 3.3 Release. diff --git a/doc/man/man8/mail500.8 b/doc/man/man8/mail500.8 deleted file mode 100644 index 5c23263ed7..0000000000 --- a/doc/man/man8/mail500.8 +++ /dev/null @@ -1,295 +0,0 @@ -.TH MAIL500 8C "RELEASEDATE" "OpenLDAP LDVERSION" -.\" $OpenLDAP$ -.\" Copyright 1998-2002 The OpenLDAP Foundation All Rights Reserved. -.\" Copying restrictions apply. See COPYRIGHT/LICENSE. -.SH NAME -mail500 \- X.500 capable mailer -.LP -fax500 \- X.500 capable fax delivery agent -.SH SYNOPSIS -.B LIBEXECDIR/mail500 [\-d level] [\-f mailfrom] -.B [\-h hostname] [\-l ldaphost] -.B [\-m address] [\-v vacationhost] -.LP -.B LIBEXECDIR/fax500 [\-d level] [\-f mailfrom] -.B [\-h hostname] [\-l ldaphost] -.B [\-m address] -.SH DESCRIPTION -.B mail500 -is an LDAP/X.500-capable mailer, suitable to be invoked from a -mail delivery agent such as -.BR sendmail (8). -It supports mail to both individuals and groups. -.B fax500 -is an LDAP/X.500-capable facsimile delivery agent. It utilizes the -Internet remote-printing experiment (tpc.int). For more -information on tpc.int, look in -.B /mrose/tpc -on -.BR ftp.ics.uci.edu , -or send mail to -.BR tpc-faq@town.hall.org . -.SH OPTIONS -.RB \- d level -Turn on debugging as defined by -.I level. -This option directs -.B mail500/fax500 -to produce various debugging output via the -.BR syslog (8) -facility at the LOG_ALERT level. -.TP -.BI \-f " mailfrom" -This option tells -.B mail500/fax500 -what to set the envelop from address to when (re)invoking sendmail -to deliver mail. -.I mailfrom -should be a valid email address. Normally, this option is passed -to -.B mail500/fax500 -via the sendmail.cf(5) mailer definition, and is set -to something like the $f macro. -.TP -.BI \-l " ldaphost" -Specify an alternate host on which the LDAP server is running. -.TP -.BI \-m " address" -If -.I mail500/fax500 -produces a rejection message, this is the -.I address -from which it will com. Normally, this option is passed to -.I mail500/fax500 -via the sendmail.cf(5) mailer definition, and is set to something -like $n@$w (typically, mailer-daemon@hostname). -.TP -.BI \-v " vacationhost" -If the vacation facility is operative, this option specifies the -host to which the mail of users who are on vacation should be sent. -.SH HOW MAIL500 AND FAX500 WORK -When mail500/fax500 gets invoked with one or more names to which to -deliver mail, it searches for each name in X.500. Where it searches, -and what kind(s) of search(es) it does are compile-time configurable -by changing the -.B base -array in -.BR main.c . -For example, the configuration we use at U-M is like this: -.LP -.nf -Base base[] = - { "ou=People, o=University of Michigan, c=US", 0 - "uid=%s", "cn=%s", NULL, - "ou=System Groups, ou=Groups, o=University of Michigan, c=US", 1 - "(&(cn=%s)(associatedDomain=%h))", NULL, NULL, - "ou=User Groups, ou=Groups, o=University of Michigan, c=US", 1 - "(&(cn=%s)(associatedDomain=%h))", NULL, NULL, - NULL - }; -.fi -.LP -which means that in delivering mail to "name@umich.edu" -.B mail500/fax500would do the -the following searches, stopping if it finds a match at any step: -.LP -.nf -subtree search of "ou=People, o=University of Michigan, c=US" - for (uid=name) -subtree search of "ou=People, o=University of Michigan, c=US" - for (cn=name) -subtree search of "ou=System Groups, ou=Groups, o=University of Michigan, c=US" - for (&(cn=name)(associatedDomain=umich.edu)) -subtree search of "ou=User Groups, ou=Groups, o=University of Michigan, c=US" - for (&(cn=name)(associatedDomain=umich.edu)) -.fi -.LP -Notice that when specifying a filter %s is replaced by the name, -or user portion of the address while %h is replaced by whatever is -passed in to -.B mail500/fax500 -via the -.RB \- h -option (typically the host portion of the address). -.LP -You can also specify whether you want search results that matched -because the entry's RDN matched the search to be given preference -or not. At U-M, we only give such preference in the mail group -portion of the searches. Beware with this option: the algorithm -used to decide whether an entry's RDN matched the search is very -simple-minded, and may not always be correct. -.LP -There is currently no limit on the number of areas searched (the base -array can be as large as you want), and an arbitrary limit of 2 filters -for each base. If you want more than that, simply changing the 3 in -the typedef for Base should do the trick. -.SH X.500 SUPPORT -In X.500, there are several new attribute types and one new object -class defined that -.B mail500/fax500 -uses. At its most basic, for normal -entries -.B mail500 -will deliver to the value(s) listed in the -.B mail -attribute of the entry, and -.B fax500 -will attempt to deliver a fax to the telephone number listed in the -.B facsimileTelephoneNumber -attribute. For example, at U-M my entry has the attribute -.LP -.nf - mail= tim@terminator.rs.itd.umich.edu -.fi -.LP -So mail sent to tim@umich.edu will be delivered via -.B mail500 -to that -address (assuming the -.BR sendmail.cf (5) -file is set up to call -.B mail500 -for mail to somebody@umich.edu - see below). If there were multiple -values for the mail attribute, multiple copies of the mail would be sent. -.LP -In the case of -.BR fax500 , if my entry has the attribute -.LP -.nf - facsimileTelephoneNumber= +1 313 764 5140 -.fi -.LP -A message sent to tim@fax.umich.edu (assuming the sendmail.cf file -is set up to pass mail @fax.umich.edu to -.BR fax500 \- -see below) -will generate a message to -remote-printer.Timothy_A_Howes@0.4.1.5.4.6.7.3.1.3.1.tpc.int. -.LP -A new object class, rfc822MailGroup, and several new attributes have -been defined to handle email groups/mailing lists. To use this, you -will need to add this to your local -.BR oidtable.oc : -.LP -.nf - # object class for representing rfc 822 mailgroups - rfc822MailGroup: umichObjectClass.2 : \\ - top : \\ - cn : \\ - rfc822Mailbox, member, memberOfGroup, owner, \\ - errorsTo, rfc822ErrorsTo, requestsTo, rfc822RequestsTo, \\ - joinable, associatedDomain, \\ - description, multiLineDescription, \\ - userPassword, krbName, \\ - telecommunicationAttributeSet, postalAttributeSet -.fi -.LP -And you will need to add these to your local oidtable.at: -.LP -.nf - # attrs for rfc822mailgroups - multiLineDescription: umichAttributeType.2 : CaseIgnoreList - rfc822ErrorsTo: umichAttributeType.26 : CaseIgnoreIA5String - rfc822RequestsTo: umichAttributeType.27 : CaseIgnoreIA5String - joinable: umichAttributeType.28 : Boolean - memberOfGroup: umichAttributeType.29 : DN - errorsTo: umichAttributeType.30 : DN - requestsTo: umichAttributeType.31 : DN -.fi -.LP -The idea was to define a kind of hybrid mail group that could handle -people who were in X.500 or not. So, for example, members of a group -can be specified via the member attribute (for X.500 members) or the -rfc822MailBox attribute (for non-X.500 members). Similarly for the -errorsTo and rfc822ErrorsTo, and the requestsTo and rfc822RequestsTo -attributes. -.LP -To create a real mailing list, with a list maintainer, all you have to -do is create an rfc822MailGroup and fill in the errorsTo or -rfc822ErrorsTo attributes (or both). That will cause any errors -encountered when delivering mail to the group to go to the addresses -listed (or X.500 entry via it's mail attribute). -.LP -If you fill in the requestsTo or rfc822RequestsTo (or both) attributes, -mail sent to groupname-request will be sent to the addresses listed -there. If you fill in the owner attribute, mail sent to -groupname-owner will be sent to the addresses listed there. mail500 -does this automatically, so you don't have to explicitly add the -groupname-request or groupname-owner aliases to your group. -.LP -To allow users to join a group, there is the joinable flag. If TRUE, -mail500 will search for entries that have a memberOfGroup attribute -equal to the DN of the group, using the same algorithm it used to find -the group in the first place (i.e. the DNs and filters listed in the -base array). This allows people to join (or subscribe to) a group -without having to modify the group entry directly. If joinable is -FALSE, the search is not done. -.SH SENDMAIL CONFIGURATION -The idea is that you might have a rule like this in your sendmail.cf -file somewhere in rule set 0: -.LP -.nf - R$*<@umich.edu>$* $#mail500$@umich.edu$:<$1> - R$*<@fax.umich.edu>$* $#fax500$@fax.umich.edu$:<$1> -.fi -.LP -These rules say that any address that ends in @umich.edu will cause -the mail500 mailer to be called to deliver the mail, and any address -that ends in @fax.umich.edu will cause the fax500 mailer to -be called. You probably -also want to do something to prevent addresses like terminator!tim@umich.edu -or tim%terminator.rs.itd.umich.edu@umich.edu from being passed to mail500. -At U-M, we do this by adding rules like this to rule set 9 where we -strip off our local names: -.LP -.nf - R<@umich.edu>$*:$* $>10<@>$1:$2 - R$+%$+<@umich.edu> $>10$1%$2<@> - R$+!$+<@umich.edu> $>10$1!$2<@> -.fi -.LP -Of course, you would substitute your domain name for umich.edu in the -above examples. See the sample sendmail.cf file in the ldap source -directory clients/mail500/ for more details. -.LP -The mail500 and fax500 mailers should be defined similar to this in the -sendmail.cf file: -.LP -.nf -Mmail500, P=LIBEXECDIR/mail500, F=DFMSmnXuh, A=mail500 -f $f -h $h -m $n@$w $u -Mfax500, P=LIBEXECDIR/fax500, F=DFMSmnXuh, A=fax500 -f $f -h $h -m $n@$w $u -.fi -.LP -This defines how mail500/fax500 will be treated by sendmail and what -arguments it will have when it's called. The various flags specified -by the F=... parameter are explained in your local sendmail book (with -any luck). The arguments to mail500/fax500 are as defined under OPTIONS -above. The final argument $u is used to stand for the addresses to which -to deliver the mail. -.SH NOTES -The default values for several #defines that control how mail500 -and fax500 works are configured at compile time in the -include/ldapconfig.h.edit include file. You should edit this -file to suit your site. -.SH BUGS -mail500/fax500 should use the ldap_getfilter(3) facility, instead of -compiling in the search filters to use. This is shameful. -.LP -The support for joinable groups (searching to find members who have -set something in their own entry) is really a hack because we did not -have good enough access control to allow people to add and delete -themselves from the group itself. -.LP -At one point, mail500 and fax500 were exactly the same binary, and -would behave appropriately based on how they were invoked. Unfortunately, -several new features (e.g. vacation support) were added to mail500 -but not to fax500. -.SH "SEE ALSO" -.BR ldap (3), -.BR sendmail.cf (5), -.BR sendmail (8) -.SH ACKNOWLEDGEMENTS -.B OpenLDAP -is developed and maintained by The OpenLDAP Project (http://www.openldap.org/). -.B OpenLDAP -is derived from University of Michigan LDAP 3.3 Release. diff --git a/doc/man/man8/mail500.8.links b/doc/man/man8/mail500.8.links deleted file mode 100644 index a94161bbfd..0000000000 --- a/doc/man/man8/mail500.8.links +++ /dev/null @@ -1 +0,0 @@ -fax500.8