##
## Clients Makefile.in for OpenLDAP
-SUBDIRS = tools ud
-CLEANDIRS = mail500 maildap
+SUBDIRS = tools
+++ /dev/null
-# $OpenLDAP$
-
-UNIX_PRGS = mail500
-PROGRAMS = $(@PLAT@_PRGS)
-
-SRCS= main.c
-XSRCS= version.c
-OBJS= main.o
-
-LDAP_INCDIR= ../../include
-LDAP_LIBDIR= ../../libraries
-
-XLIBS = $(LDAP_L)
-XXLIBS = $(SECURITY_LIBS) $(LUTIL_LIBS)
-
-mail500 : version.o
- $(LTLINK) -o $@ version.o $(OBJS) $(LIBS)
-
-version.c: $(OBJS) $(XLIBS)
- @-$(RM) $@
- $(MKVERSION) mail500 > $@
-
-install-local: $(PROGRAMS) FORCE
- -$(MKDIR) $(DESTDIR)$(libexecdir)
- @( \
- for prg in $(PROGRAMS); do \
- $(LTINSTALL) $(INSTALLFLAGS) -s -m 755 $$prg$(EXEEXT) \
- $(DESTDIR)$(libexecdir); \
- done \
- )
-
+++ /dev/null
-This is the README file for mail500, a mailer that does directory
-lookups via LDAP. The name is historical and refers to X.500.
-
-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
-directory 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$*<@example.com>$* $#mail500$@example.com$:<$1>
-
-This rule says that any address that ends in @example.com will cause the
-mail500 mailer to be called to deliver the mail. You probably also want
-to do something to prevent addresses like uuhost!user@example.com or
-user%host@example.com from being passed to mail500. This can be done by
-adding rules like this to rule set 9 where we strip off our local names:
-
-R<@example.com>$*:$* $>10<@>$1:$2
-R$+%$+<@example.com> $>10$1%$2<@>
-R$+!$+<@example.com> $>10$1!$2<@>
-
-See the sample sendmail.cf in this directory for more details.
-For sendmail 8.9 (and later) users can use MAILER(mail500) if
-mail500.m4 is placed within sendmail's cf/mailer directory.
-
-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 LDAP. Where it searches,
-and what kind(s) of search(es) it does are compile-time configurable
-by changing the base array in main.c. The configuration:
-
- Base base[] =
- { "ou=People, dc=example, dc=com", 0
- "uid=%s", "cn=%s", NULL,
- "ou=System Groups, ou=Groups, dc=example, dc=com", 1
- "(&(cn=%s)(associatedDomain=%h))", NULL, NULL,
- "ou=User Groups, ou=Groups, dc=example, dc=com", 1
- "(&(cn=%s)(associatedDomain=%h))", NULL, NULL,
- NULL
- };
-
-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]: dc=com@dc=example@ou=People
- Search subtree (uid=name)
- Search (18) [3]: dc=com@dc=example@ou=People
- Search subtree (cn=name)
-
- Search (18) [4]: dc=com@dc=example@ou=Groups@ou=System Groups
- Search subtree & ((cn=name)(associatedDomain=OpenLDAP.org))
-
- Search (18) [5]: dc=com@dc=example@ou=Groups@ou=User Groups
- Search subtree & ((cn=name)(associatedDomain=example.com))
-
-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. 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 LDAP side): ***
-
-In LDAP, 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, an entry has
-the attribute
-
- mail: user@example.com
-
-So mail sent to user@example.com 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 LDAP or not. So, for example, members of a group
-can be specified via the member attribute (for LDAP members) or the
-rfc822MailBox attribute (for non-LDAP 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 LDAP 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...
+++ /dev/null
-PUSHDIVERT(-1)
-## Copyright 1998-2002 The OpenLDAP Foundation, Redwood City, California, USA
-## All rights reserved.
-##
-## Redistribution and use in source and binary forms are permitted only
-## as authorized by the OpenLDAP Public License. A copy of this
-## license is available at http://www.OpenLDAP.org/license.html or
-## in file LICENSE in the top-level directory of the distribution.
-POPDIVERT
-
-dnl
-dnl mail500 mailer
-dnl
-dnl This file should be placed in the sendmail's cf/mailer directory.
-dnl To include this mailer in your .cf file, use the directive:
-dnl MAILER(mail500)
-dnl
-
-ifdef(`MAIL500_HOST',
- `define(`MAIL500_HOST_FLAG', `')',
- `define(`MAIL500_HOST_FLAG', CONCAT(` -l ', CONCAT(MAIL500_HOST,` ')))')
-ifdef(`MAIL500_MAILER_PATH',,
- `ifdef(`MAIL500_PATH',
- `define(`MAIL500_MAILER_PATH', MAIL500_PATH)',
- `define(`MAIL500_MAILER_PATH', /usr/local/libexec/mail500)')')
-ifdef(`MAIL500_MAILER_FLAGS',,
- `define(`MAIL500_MAILER_FLAGS', `SmnXuh')')
-ifdef(`MAIL500_MAILER_ARGS',,
- `define(`MAIL500_MAILER_ARGS',
- CONCAT(`mail500',CONCAT(MAIL500_HOST_FLAG,`-f $f -h $h -m $n@$w $u')))')
-dnl
-
-MAILER_DEFINITIONS
-
-######################*****##############
-### MAIL500 Mailer specification ###
-##################*****##################
-
-VERSIONID(`$OpenLDAP$')
-
-Mmail500, P=MAIL500_MAILER_PATH, F=CONCAT(`DFM', MAIL500_MAILER_FLAGS), S=11/31, R=20/40, T=DNS/RFC822/X-Unix,
- ifdef(`MAIL500_MAILER_MAX', `M=500_MAILER_MAX, ')A=MAIL500_MAILER_ARGS
-
-LOCAL_CONFIG
-# Mail500 Domains
-#CQ foo.com
-
-PUSHDIVERT(3)
-# mail500 additions
-R$* < @ $=Q > $* $#mail500 $@ $2 $: <$1> domain handled by mail500
-POPDIVERT
+++ /dev/null
-/* $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 <stdio.h>
-
-#include <ac/stdlib.h>
-
-#include <ac/ctype.h>
-#include <ac/param.h>
-#include <ac/signal.h>
-#include <ac/string.h>
-#include <ac/sysexits.h>
-#include <ac/syslog.h>
-#include <ac/time.h>
-#include <ac/unistd.h>
-#include <ac/wait.h>
-
-#include <sys/stat.h>
-
-#ifdef HAVE_SYS_RESOURCE_H
-#include <sys/resource.h>
-#endif
-
-#include <ldap.h>
-
-#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 = NULL;
-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
- 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;
-} 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, dc=example, dc=com",
- 0, USER,
- {"uid=%s", "cn=%s", NULL}},
- {"ou=System Groups, ou=Groups, dc=example, dc=com",
- 1, 0xff,
- {"(&(cn=%s)(associatedDomain=%h))", NULL, NULL}},
- {"ou=User Groups, ou=Groups, dc=example, dc=com",
- 1, 0xff,
- {"(&(cn=%s)(associatedDomain=%h))", NULL, NULL}},
- {NULL}
-};
-
-char *sendmailargs[] = { MAIL500_SENDMAIL, "-oMrLDAP", "-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 void do_address( char *name, char ***to, int *nto, Group **togroups, int *ngroups, Error **err, int *nerr, int type );
-static int do_group( LDAPMessage *e, char *dn, char ***to, int *nto, Group **togroups, int *ngroups, Error **err, int *nerr );
-static void do_group_members( LDAPMessage *e, char *dn, char ***to, int *nto, Group **togroups, int *ngroups, Error **err, int *nerr );
-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 void add_to( char ***list, int *nlist, char **new );
-static int isgroup( LDAPMessage *e );
-static void add_error( Error **err, int *nerr, int code, char *addr, LDAPMessage *msg );
-static void add_group( char *dn, Group **list, int *nlist );
-static void unbind_and_exit( int rc );
-static int group_loop( char *dn );
-static void send_group( Group *group, int ngroup );
-static int has_attributes( LDAPMessage *e, char *attr1, char *attr2 );
-static char **get_attributes_mail_dn( LDAPMessage *e, char *attr1, char *attr2 );
-static char *canonical( char *s );
-static int connect_to_x500( void );
-
-static void do_group_errors( LDAPMessage *e, char *dn, char ***to, int *nto, Error **err, int *nerr );
-static void do_group_request( LDAPMessage *e, char *dn, char ***to, int *nto, Error **err, int *nerr );
-static void do_group_owner( LDAPMessage *e, char *dn, char ***to, int *nto, Error **err, int *nerr );
-static void add_member( char *gdn, char *dn, char ***to, int *nto, Group **togroups, int *ngroups, Error **err, int *nerr, char **suppress );
-
-int
-main ( int argc, char **argv )
-{
- char *myname;
- char **tolist;
- Error *errlist;
- Group *togroups;
- int numto, ngroups, numerr, nargs;
- int i, j;
-
- 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: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 ) {
- 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 int
-connect_to_x500( void )
-{
- int opt;
-
- if ( (ld = ldap_init( ldaphost, 0 )) == NULL ) {
- syslog( LOG_ALERT, "ldap_init failed" );
- return( -1 );
- }
-
- 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 int
-mailcmp( 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 void
-do_address(
- 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, NULL );
- } else {
- add_error( err, nerr, E_GROUPUNKNOWN, name, NULL );
- }
- 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 );
-}
-
-static int
-do_group(
- 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 (strcmp(MAIL500_BOUNCEFROM, mailfrom) != 0 &&
- 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 void
-do_group_members(
- 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;
- int opt;
-
- /*
- * 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,
- NULL );
- }
-
- 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... */
- opt = MAIL500_MAXAMBIGUOUS;
- ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &opt);
- 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, NULL );
-
- free( ndn );
- }
- }
-
- ldap_msgfree( res );
- }
- opt = MAIL500_MAXAMBIGUOUS;
- ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &opt);
- }
-
- if ( ! anymembers ) {
- add_error( err, nerr, E_NOMEMBERS, dn, NULL );
- }
-}
-
-static void
-add_member(
- char *gdn,
- char *dn,
- char ***to,
- int *nto,
- Group **togroups,
- int *ngroups,
- Error **err,
- int *nerr,
- char **suppress
-)
-{
- char *ndn;
- char **mail;
- int 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, NULL );
-
- 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, NULL );
- }
- }
-
- free( ndn );
-}
-
-static void
-do_group_request(
- 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, NULL );
- }
-}
-
-static void
-do_group_errors(
- 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, NULL );
- }
-}
-
-static void
-do_group_owner(
- 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, 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;
-
- 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" );
- }
-
- 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 int
-isgroup( 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 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
-add_group( 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 );
-}
-
-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 );
-}
-
-static char *
-canonical( char *s )
-{
- char *saves = s;
-
- for ( ; *s != '\0'; s++ ) {
- if ( *s == ' ' )
- *s = '.';
- }
-
- return( saves );
-}
-
-static int
-group_loop( 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 int
-has_attributes( 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(
- LDAPMessage *e,
- char *attr1,
- char *attr2 /* this one is dn-valued */
-)
-{
- LDAPMessage *ee, *res;
- char **vals, **dnlist, **mail, **grname;
- 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 );
-}
+++ /dev/null
-#
-# It's recommended use Sendmail's m4 configuration system to avoid
-# mucking directly with .cf files
-#
-
-# 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 -> <a!>b
-R<$+.uucp!>$+ <$1!>$2 <a.uucp!>b -> <a!>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> <a.b!>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 <a!b!>c -> <a!>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
+++ /dev/null
-# $OpenLDAP$
-
-UNIX_PRGS = maildap
-PROGRAMS = $(@PLAT@_PRGS)
-
-SRCS= main.c
-XSRCS= version.c
-OBJS= main.o
-
-LDAP_INCDIR= ../../include
-LDAP_LIBDIR= ../../libraries
-
-XLIBS = $(LDAP_L)
-XXLIBS = $(SECURITY_LIBS) $(LUTIL_LIBS)
-
-maildap : version.o
- $(LTLINK) -o $@ version.o $(OBJS) $(LIBS)
-
-version.c: $(OBJS) $(XLIBS)
- @-$(RM) $@
- $(MKVERSION) maildap > $@
-
-install-local: $(PROGRAMS) FORCE
- -$(MKDIR) $(DESTDIR)$(libexecdir)
- @( \
- for prg in $(PROGRAMS); do \
- $(LTINSTALL) $(INSTALLFLAGS) -s -m 755 $$prg$(EXEEXT) \
- $(DESTDIR)$(libexecdir); \
- done \
- )
-
+++ /dev/null
-
-*** WARNING: Preliminary ***
-
-This is the README file for maildap, a mailer that does X.500 lookups
-via LDAP. It is based on mail500.
-
-If you are planning to run maildap at your site, you need to create a
-configuration file. Previous versions required modifying the source
-code for configuration. This is no longer necessary.
-there are several
-
-*** WHAT maildap DOES: ***
-
-maildap 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>$* $#maildap$@umich.edu$:<$1>
-
-This rule says that any address that ends in @umich.edu will cause
-the maildap 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 maildap.
-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<@>
-
-You can also feed complete FQDN addresses to maildap. For instance,
-you could define a class containing the list of domains you want to
-serve like this:
-
-FQ/etc/mail/maildapdomains
-
-and then use a rule in rule set 0 like this:
-
-R$*<$=Q>$* $#maildap $@$2 $:<$1@$2>
-
-See the sample sendmail.cf in this directory for more details.
-For sendmail 8.9 (and later) users can use MAILER(maildap) if
-maildap.m4 is placed within sendmail's cf/mailer directory.
-
-The maildap mailer should be defined similar to this in the
-sendmail.cf file:
-
-Mmaildap, P=/usr/local/etc/maildap, F=DFMSmnXuh, A=maildap -f $f -h $h -m $n@$w $u
-
-This defines how maildap 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 maildap 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 maildap 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 maildap side): ***
-
-When maildap 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) is controlled by a configuration file. There
-are a number of different approaches to handling mail and no general
-rules can be given. We will however present some examples of what you
-can do. The new maildap is designed to be flexible and able to
-accommodate most scenarios.
-
-For instance, if you are following the mail distribution model that
-the old maildap used, you need lines in the configuration file like
-these:
-
-search ldap:///ou=People, dc=OpenLDAP, dc=org??sub?\
- (|(uid=%25l)(cn==%25l))
-
-search ldap:///ou=System Groups, ou=Groups, dc=OpenLDAP, dc=org??sub?\
- (&(cn=%25l)(associatedDomain==%25h))
-
-search ldap:///ou=User Groups, ou=Groups, dc=OpenLDAP, dc=org??sub?\
- (&(cn=%25l)(associatedDomain==%25h))
-
-As you can see, searches are described by using LDAP URLs. You can
-have as many searches as you want, but the first search that succeeds
-completes the processing for a recipient address. You can provide an
-attribute list in the URL and it will be honored. Otherwise, the
-attribute list will default as explained below.
-
-Filters can contain substitutions. Actually, they *should* contain
-substitutions or the search result would not change with the recipient
-address. Since the usual substitution character is % and it has
-special meaning in URLs, you have to represent it according to the URL
-syntax, that is, %25, 25 being the hex code of %. The filter can be
-as complex as you want and you may make as many substitutions as you
-want. Known substitutions at this time are:
-
- %m The recipient address we are considering now, maybe fully
- qualified
- %h The host, that is, the value of the -h argument to
- maildap
- %l The local part from %m
- %d The domain part from %m
-
-So, in the above example, if the recipient address were
-name@OpenLDAP.org, maildap would do the the following searches,
-stopping if it found anything at any step:
-
- Search (18) [2]: dc=org@dc=OpenLDAP@ou=People
- Search subtree (uid=name)
- Search (18) [3]: dc=org@dc=OpenLDAP@ou=People
- Search subtree (cn=name)
-
- Search (18) [4]: dc=org@dc=OpenLDAP@ou=Groups@ou=System Groups
- Search subtree & ((cn=name)(associatedDomain=OpenLDAP.org))
-
- Search (18) [5]: dc=org@dc=OpenLDAP@ou=Groups@ou=User Groups
- Search subtree & ((cn=name)(associatedDomain=OpenLDAP.org))
-
-[Beware: Currently unimplemented]
-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.
-
-*** HOW IT WORKS (from the X.500 side): ***
-
-First you need to decide what attributes you will search for and what
-attributes will be used to deliver the message. In the classical
-maildap, we would search by uid or cn and deliver to the mail
-attribute. Another model is to search by the mail attribute and
-deliver to something else, such as the uid if determined that the user
-has a local account.
-
-*** THE CONFIGURATION FILE
-
-The configuration file is composed of lines that prescribe the
-operation of maildap. Blank lines are ignored and lines beginning
-with # are considered comments and ignored. Outside comments, the
-sequence '\', newline, whitespace is ignored so that long lines can be
-split for readability.
-
-Attribute Definitions
-
-Lines starting with 'attribute' define the semantics of an attribute.
-Notice that attributes will be considered in the order they are
-defined in the configuration file. This means that the presence of
-some can preempt processing of other attributes and that attributes
-that simply collect needed information must be defined before others
-that use that information. The format is:
-
-attribute name [multivalued] [final] [multiple-entries] [<syntax>] [<kind>]
-
-If the attribute is "multivalued", all values will be considered. If
-it is not and several values are found the entry is declared in error.
-
-If the attribute is "final", its presence in an entry prevents further
-analysis of the entry.
-
-If the attribute is "multiple-entries" and it is of an appropriate
-syntax that can point to other entries, all such entries are
-considered, otherwise the entry is in error.
-
-The known kinds are:
-
-recipient The value(s) of this attribute should be
- used as the address(es) to deliver the message
- to if they are in an appropriate syntax. If
- they otherwise point at other entries, they
- should be retrieved and expanded as necessary
- to complete the resolution of this entry. The
- process is recursive and all.
-
-errors The value(s) of this attribute represent the
- entities that should receive error messages
- for mail messages directed to this entry.
- The presence of an attribute of this kind
- force a change in the envelope sender address
- of the message.
-
-The known syntaxes are:
-
-local-native-mailbox An unqualified mailbox name
-rfc822 A fully qualified RFC822 mail address
-rfc822-extended Currently identical to rfc822
-dn The Distinguished Name of some other entry
-url A URL either of the mailto: or ldap: styles,
- others styles, notably file:, could be added.
- No substitutions are supported currently.
-search-with-filter=<filter> Do a search on all known search bases
- with the give filter. The only currenty
- substitution available is %D, the DN of the
- current entry.
-
-The default attributes to search
-
-A line starting with "default-attributes" contains a comma-separated
-list of attributes to use in searches everytime a specific list is not
-known.
-
-Search bases
-
-As shown in the example above, lines starting with "search" provide
-the search bases to use to initially try to resolve each entry or when
-using attributes of syntax "search-with-filter".
-
-*** EXAMPLES
-
-A configuration file that approximates the operation of the old
-maildap runs as follows:
-
-attribute errorsTo errors dn
-attribute rfc822ErrorsTo errors rfc822
-attribute requestsTo request dn
-attribute rfc822RequestsTo request rfc822
-attribute owner owner dn
-attribute mail multivalued recipient rfc822
-attribute member multivalued recipient dn
-attribute joinable multiple-entries recipient \
- search-with-filter=(memberOfGroup=%D)
-
-default-attributes objectClass,title,postaladdress,telephoneNumber,\
- mail,description,owner,errorsTo,rfc822ErrorsTo,requestsTo,\
- rfc822RequestsTo,joinable,cn,member,moderator,onVacation,uid,\
- suppressNoEmailError
-
-# Objectclasses that, when present, identify an entry as a group
-group-classes mailGroup
-
-search ldap:///ou=People, dc=OpenLDAP, dc=org??sub?\
- (|(uid=%25l)(cn==%25l))
-
-search ldap:///ou=System Groups, ou=Groups, dc=OpenLDAP, dc=org??sub?\
- (&(cn=%25l)(associatedDomain==%25h))
-
-search ldap:///ou=User Groups, ou=Groups, dc=OpenLDAP, dc=org??sub?\
- (&(cn=%25l)(associatedDomain==%25h))
-
-A configuration that approximates the semantics of the mailRecipient
-and mailGroup classes used by Netscape:
-
-attribute mgrpErrorsTo errors url
-attribute rfc822ErrorsTo errors rfc822
-attribute mailRoutingAddress final recipient rfc822
-attribute mailHost final host forward-to-host
-attribute uid final recipient local-native-mailbox
-attribute uniqueMember multivalued recipient dn
-attribute mgrpRFC822MailMember multivalued recipient rfc822-extended
-attribute mgrpDeliverTo multivalued multiple-entries recipient url
-
-default-attributes objetcClass,mailRoutingAddress,mailHost,uid,uniqueMember,\
- mgrpRFC822MailMember,mgrpErrorsTo,rfc822ErrorsTo
-
-# Objectclasses that, when present, identify an entry as a group
-group-classes mailGroup
-
-search ldap://localhost/dc=OpenLDAP,dc=org?\
- objectClass,mailRoutingAddress,mailHost,uid?\
- sub?\
- (&(|(mail=%25m)(mailAlternateAddress=%25m))(objectClass=mailRecipient))
-
-search ldap://localhost/dc=OpenLDAP,dc=org?\
- objectClass,uniqueMember,mgrpRFC822MailMember,mgrpErrorsTo,mgrpDeliverTo,rfc822ErrorsTo?\
- sub?\
- (&(|(mail=%25m)(mailAlternateAddress=%25m))(objectClass=mailGroup))
-
-[ The rest is from the original README and I did not rewrite it yet ]
-
-In X.500, there are several new attribute types and one new object
-class defined that maildap makes use of. At its most basic, for normal
-entries maildap 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 maildap 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. maildap 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,
-maildap 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...
+++ /dev/null
-PUSHDIVERT(-1)
-## Copyright 1998-2002 The OpenLDAP Foundation, Redwood City, California, USA
-## All rights reserved.
-##
-## Redistribution and use in source and binary forms are permitted only
-## as authorized by the OpenLDAP Public License. A copy of this
-## license is available at http://www.OpenLDAP.org/license.html or
-## in file LICENSE in the top-level directory of the distribution.
-
-dnl
-dnl maildap mailer
-dnl
-dnl This file should be placed in the sendmail's cf/mailer directory.
-dnl To include this mailer in your .cf file, use the directive:
-dnl MAILER(maildap)
-dnl
-
-ifdef(`MAILDAP_HOST',
- `define(`MAILDAP_HOST_FLAG', CONCAT(` -l ', CONCAT(MAILDAP_HOST,` ')))',
- `define(`MAILDAP_HOST_FLAG', `')')
-ifdef(`MAILDAP_CONFIG_PATH',,
- `define(`MAILDAP_CONFIG_PATH', /etc/mail/maildap.conf)')
-ifdef(`MAILDAP_MAILER_PATH',,
- `ifdef(`MAILDAP_PATH',
- `define(`MAILDAP_MAILER_PATH', MAILDAP_PATH)',
- `define(`MAILDAP_MAILER_PATH', /usr/local/libexec/maildap)')')
-ifdef(`MAILDAP_MAILER_FLAGS',,
- `define(`MAILDAP_MAILER_FLAGS', `SmnXuh')')
-ifdef(`MAILDAP_MAILER_ARGS',,
- `define(`MAILDAP_MAILER_ARGS',
- CONCAT(`maildap',CONCAT(` -C ',MAILDAP_CONFIG_PATH,MAILDAP_HOST_FLAG,`-f $f -m $n@$w $u')))')
-
-POPDIVERT
-
-MAILER_DEFINITIONS
-
-######################*****##############
-### MAILDAP Mailer specification ###
-##################*****##################
-
-VERSIONID(`$OpenLDAP$')
-
-Mmaildap, P=MAILDAP_MAILER_PATH, F=CONCAT(`DFM', MAILDAP_MAILER_FLAGS), S=11/31, R=20/40, T=DNS/RFC822/X-Unix,
- ifdef(`MAILDAP_MAILER_MAX', `M=500_MAILER_MAX, ')A=MAILDAP_MAILER_ARGS
-
-LOCAL_CONFIG
-# Maildap Domains
-#CQ foo.com
-
-PUSHDIVERT(3)
-# maildap additions
-R$* < @ $=Q > $* $#maildap $@ $2 $: <$1@$2> domain handled by maildap
-POPDIVERT
+++ /dev/null
-/* $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 <stdio.h>
-
-#include <ac/stdlib.h>
-
-#include <ac/ctype.h>
-#include <ac/param.h>
-#include <ac/signal.h>
-#include <ac/string.h>
-#include <ac/sysexits.h>
-#include <ac/syslog.h>
-#include <ac/time.h>
-#include <ac/unistd.h>
-#include <ac/wait.h>
-
-#include <sys/stat.h>
-
-#ifdef HAVE_SYS_RESOURCE_H
-#include <sys/resource.h>
-#endif
-
-#include <ldap.h>
-
-#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; j<delivery_types_total; j++ ) {
- if ( !strcasecmp( as->as_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; j<own_addresses_total; j++ ) {
- if ( strcasecmp( vals[0], own_addresses[j] ) ) {
- cur_priority = as->as_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 );
-}
+++ /dev/null
-# $OpenLDAP$
-
-SRCS= main.c find.c mod.c print.c auth.c util.c help.c \
- group.c edit.c globals.c
-XSRCS= version.c
-OBJS= main.o find.o mod.o print.o auth.o util.o help.o \
- group.o globals.o edit.o
-HDRS= ud.h
-
-UNIX_PRGS = ud
-PROGRAMS = $(@PLAT@_PRGS)
-
-LDAP_INCDIR= ../../include
-LDAP_LIBDIR= ../../libraries
-
-XLIBS = $(LDAP_L)
-XXLIBS = $(TERMCAP_LIBS) $(SECURITY_LIBS) $(LDIF_LIBS) $(LUTIL_LIBS)
-
-ud : version.o
- $(LTLINK) -o $@ version.o $(OBJS) $(LIBS)
-
-version.c: ${OBJS} $(XLIBS)
- @-$(RM) $@
- $(MKVERSION) -s -c -n Version UserDirectory > $@
-
-install-local: FORCE
- -$(MKDIR) $(DESTDIR)$(bindir)
- -mv -f $(DESTDIR)$(bindir)/ud $(DESTDIR)$(bindir)/ud-
- @( \
- for prg in $(PROGRAMS); do \
- $(LTINSTALL) $(INSTALLFLAGS) -s -m 755 $$prg$(EXEEXT) \
- $(DESTDIR)$(bindir); \
- done \
- )
-
+++ /dev/null
-/* $OpenLDAP$ */
-/*
- * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
- * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
- */
-/*
- * 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 "portable.h"
-
-#include <stdio.h>
-
-#include <ac/stdlib.h>
-
-#include <ac/ctype.h>
-#include <ac/krb.h>
-#include <ac/string.h>
-#include <ac/time.h>
-#include <ac/unistd.h>
-
-#ifdef HAVE_PWD_H
-#include <pwd.h>
-#endif
-
-#include <ldap.h>
-
-#include "ldap_defaults.h"
-#include "ud.h"
-
-static void set_bound_dn(char *s);
-
-
-int
-auth( char *who, int implicit )
-{
- int rc; /* return code from ldap_bind() */
- char *passwd = NULL; /* returned by getpassphrase() */
- char **rdns; /* for fiddling with the DN */
- int authmethod;
- int name_provided; /* was a name passed in? */
-#ifdef HAVE_GETPWUID
- struct passwd *pw; /* for getting user id */
-#else
- char *user;
-#endif
- char uidname[20];
- 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 */
-
-#ifdef DEBUG
- if (debug & D_TRACE)
- fprintf(stderr, "auth(%s, NULL)\n", who);
-#endif
- name_provided = ( who != NULL );
-
- /*
- * The user needs to bind. If <who> is not specified, we
- * assume that authenticating as user id is what user wants.
- */
- if (who == NULL && implicit) {
- uidname[0] = '\0';
-
-#ifdef HAVE_GETPWUID
- if ((pw = getpwuid((uid_t)geteuid())) != (struct passwd *) NULL) {
- sprintf(uidname, "uid=%s", pw->pw_name);
- }
-#else
- user = getenv("USER");
- if(user == NULL) user = getenv("USERNAME");
- if(user == NULL) user = getenv("LOGNAME");
-
- if(user != NULL) {
- sprintf(uidname, "uid=%s", user);
- }
-#endif
-
- if(uidname[0] != '\0') {
- 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) {
- 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 LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
- if ( authmethod != LDAP_AUTH_KRBV4 )
-#endif
- {
- authmethod = LDAP_AUTH_SIMPLE;
- sprintf(prompt, " Enter your LDAP password: ");
- do {
- passwd = getpassphrase(prompt);
- } while (passwd != NULL && *passwd == '\0');
- if (passwd == NULL) {
- (void) ldap_value_free(rdns);
- return(0);
- }
- }
-
- ldap_flush_cache( ld );
- rc = ldap_bind_s(ld, Entry.DN, passwd, authmethod);
- if (rc != LDAP_SUCCESS) {
- int ld_errno;
- ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
- if (ld_errno == LDAP_NO_SUCH_ATTRIBUTE)
- fprintf(stderr, " Entry has no password\n");
- else if (ld_errno == LDAP_INVALID_CREDENTIALS)
-#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
- if ( authmethod == LDAP_AUTH_KRBV4 ) {
- fprintf(stderr, " The Kerberos credentials are invalid.\n");
- } else
-#endif
- {
- fprintf(stderr, " The password you provided is incorrect.\n");
- }
- else
- ldap_perror(ld, "ldap_bind_s" );
- (void) ldap_bind_s(ld, default_bind_object,
- (char *) NULL, 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);
-}
-
-static void
-set_bound_dn( char *s )
-{
- if (bound_dn != NULL)
- Free(bound_dn);
- bound_dn = (s == NULL) ? NULL : strdup(s);
-}
+++ /dev/null
-/* $OpenLDAP$ */
-/*
- * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
- * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
- */
-/*
- * 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 "portable.h"
-
-#include <stdio.h>
-#include <sys/stat.h>
-
-#include <ac/stdlib.h>
-
-#include <ac/signal.h>
-#include <ac/string.h>
-#include <ac/ctype.h>
-#include <ac/time.h>
-#include <ac/wait.h>
-#include <ac/unistd.h>
-
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#ifdef HAVE_SYS_RESOURCE_H
-#include <sys/resource.h>
-#endif
-#ifdef HAVE_PROCESS_H
-#include <process.h>
-#endif
-
-#ifdef HAVE_IO_H
-#include <io.h>
-#endif
-
-#include <ldap.h>
-#include "lutil.h"
-#include "ldap_defaults.h"
-#include "ud.h"
-
-static int load_editor( void );
-static int modifiable( char *s, short flag );
-static int print_attrs_and_values( FILE *fp, struct attribute *attrs, short flag );
-static int ovalues( char *attr );
-static void write_entry( void );
-
-static char entry_temp_file[L_tmpnam];
-
-
-void
-edit( char *who )
-{
- LDAPMessage *mp; /* returned from find() */
- char *dn, **rdns; /* distinguished name */
- char name[MED_BUF_SIZE]; /* entry to modify */
-
-#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);
- ldap_memfree(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;
- write_entry();
- (void) unlink(entry_temp_file);
- ldap_uncache_entry(ld, Entry.DN);
- return;
-}
-
-static int
-load_editor( void )
-{
- FILE *fp;
- char *cp, *editor = UD_DEFAULT_EDITOR;
-#ifndef HAVE_SPAWNLP
- int pid;
- int status;
-#endif
- int rc;
-
-#ifdef DEBUG
- if (debug & D_TRACE)
- printf("->load_editor()\n");
-#endif
-
- strcpy(entry_temp_file, LDAP_TMPDIR LDAP_DIRSEP "udXXXXXX");
-
- {
- int tmpfd = mkstemp(entry_temp_file);
-
- if( tmpfd < 0 ) {
- perror("mkstemp");
- return -1;
- }
-
- if ((fp = fdopen(tmpfd, "w")) == NULL) {
- perror("fdopen");
- return(-1);
- }
- }
-
- fprintf(fp, "## Directory entry of %s\n", Entry.name);
- fprintf(fp, "##\n");
- fprintf(fp, "## Syntax is:\n");
- fprintf(fp, "## <attribute-name>\n");
- fprintf(fp, "## <TAB> <value 1>\n");
- fprintf(fp, "## <TAB> : :\n");
- fprintf(fp, "## <TAB> <value N>\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, *LDAP_DIRSEP )) == NULL ) {
- p = editor;
- } else {
- ++p;
- }
- printf(" Using %s as the editor...\n", p );
-#ifndef HAVE_SPAWNLP
- sleep(2);
-#endif
- }
-#ifdef HAVE_SPAWNLP
- rc = _spawnlp( _P_WAIT, editor, editor, entry_temp_file, NULL );
- if(rc != 0) {
- fatal("spawnlp");
- }
-#else
- 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 */
- RETSIGTYPE (*handler)();
- handler = SIGNAL(SIGINT, SIG_IGN);
- (void) wait(&status);
- (void) SIGNAL(SIGINT, handler);
- }
- else {
- fatal("fork");
- /*NOTREACHED*/
- }
-#endif
- return(0);
-}
-
-static int
-print_attrs_and_values( FILE *fp, struct attribute *attrs, short int flag )
-{
- register int i, j;
-
- for (i = 0; attrs[i].quipu_name != NULL; i++) {
- if (!modifiable(attrs[i].quipu_name,
- (short) (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 int
-modifiable( char *s, short int flag )
-{
- register int i;
-
- 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 void
-write_entry( void )
-{
- 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;
-
- /* 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((unsigned char)*cp)) { /* value */
- while (isspace((unsigned char)*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((unsigned char)*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 int
-ovalues( 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);
-}
+++ /dev/null
-server <your ldap server host name here>
-base <your X.500 default search base here>
+++ /dev/null
-/* $OpenLDAP$ */
-/*
- * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
- * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
- */
-/*
- * 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 "portable.h"
-
-#include <stdio.h>
-
-#include <ac/stdlib.h>
-
-#include <ac/ctype.h>
-#include <ac/string.h>
-#include <ac/time.h>
-
-#include <ldap.h>
-
-#include "ud.h"
-
-static int num_picked = 0; /* used when user picks entry at More prompt */
-
-
-int
-vrfy( char *dn )
-{
- LDAPMessage *results = NULL;
- static char *attrs[2] = { "1.1", NULL };
- int ld_errno = 0;
-
-#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, NULL, attrs, TRUE, &results);
- (void) ldap_msgfree(results);
-
- ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
-
- if ((ld_errno == LDAP_NO_SUCH_OBJECT) || (ld_errno == LDAP_INVALID_DN_SYNTAX))
- return(0);
- else if (ld_errno == LDAP_SUCCESS)
- return(1);
- else {
- ldap_perror(ld, "ldap_search");
- return(0);
- }
-}
-
-
-static LDAPMessage *
-disambiguate( 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 = NULL;
- int ld_errno = 0;
-
-#ifdef DEBUG
- if (debug & D_TRACE)
- printf("->disambiguate(%x, %d, %x, %s)\n", result, matches,
- read_attrs, who);
-#endif
-
- ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
-
- /*
- * If we are here, it means that we got back multiple answers.
- */
- if ((ld_errno == LDAP_TIMELIMIT_EXCEEDED)
- || (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, NULL, 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( 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;
-
-#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;
- }
-
- /*
- * 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;
- }
-
- 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'))
- {
- ldap_memfree(dn);
- 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, NULL, read_attrs, FALSE, &res) != LDAP_SUCCESS) {
- ldap_perror(ld, "ldap_search_s");
- ldap_msgfree(res);
- res = NULL;
- }
- ldap_memfree(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);
-}
-
-int
-pick_one( 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 */
-}
-
-void
-print_list( LDAPMessage *list, char **names, int *matches )
-{
- char **rdns, **cpp;
- 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;
-}
-
-int
-find_all_subscribers( 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) {
- int ld_errno = 0;
- ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
- if (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( 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, NULL, attributes, FALSE, &result) != LDAP_SUCCESS) {
- int ld_errno = 0;
- ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
- if (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);
- }
- }
-}
+++ /dev/null
-/* $OpenLDAP$ */
-/*
- * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
- * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
- */
-/*
- * 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 "portable.h"
-
-#include <stdio.h>
-#include <ac/time.h> /* ldap.h needs time_t */
-#include <ldap.h>
-#include "ud.h"
-
-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", 0, ATTR_FLAG_PERSON | ATTR_FLAG_READ | ATTR_FLAG_IS_A_DN },
- { "acl", "Access Control", 0, 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", 0, 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 LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
- { "krbName", "Kerberos name", 0, ATTR_FLAG_PERSON | ATTR_FLAG_READ },
-#endif
- { "description", "Brief description", 0, 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", 0, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ },
- { "userPassword", "Password", 0, 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", 0, ATTR_FLAG_GROUP | ATTR_FLAG_PERSON | ATTR_FLAG_IS_A_DN | ATTR_FLAG_READ },
- { "lastModifiedTime", "Last modified at", 0, ATTR_FLAG_GROUP | ATTR_FLAG_PERSON | ATTR_FLAG_READ | ATTR_FLAG_IS_A_DATE },
- { "modifiersname", "Modifier's Name", 0, ATTR_FLAG_GROUP | ATTR_FLAG_PERSON | ATTR_FLAG_IS_A_DN | ATTR_FLAG_READ },
- { "modifytimestamp", "Modify Timestamp", 0, ATTR_FLAG_GROUP | ATTR_FLAG_PERSON | ATTR_FLAG_READ | ATTR_FLAG_IS_A_DATE },
- { "creatorsname", "Creator's Name", 0, ATTR_FLAG_GROUP | ATTR_FLAG_PERSON | ATTR_FLAG_IS_A_DN | ATTR_FLAG_READ },
- { "createtimestamp", "Create Timestamp", 0, ATTR_FLAG_GROUP | ATTR_FLAG_PERSON | ATTR_FLAG_READ | ATTR_FLAG_IS_A_DATE },
- { NULL, NULL, 0, ATTR_FLAG_NONE }
-};
+++ /dev/null
-/* $OpenLDAP$ */
-/*
- * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
- * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
- */
-/*
- * 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 "portable.h"
-
-#include <stdio.h>
-
-#include <ac/string.h>
-#include <ac/ctype.h>
-#include <ac/time.h>
-#include <ac/unistd.h>
-
-#ifdef HAVE_IO_H
-#include <io.h>
-#endif
-
-#include <ldap.h>
-
-#include "ldap_defaults.h"
-#include "ud.h"
-
-static char * bind_and_fetch(char *name);
-
-
-void
-add_group( char *name )
-{
- int 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];
-
-#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) {
- LDAPMod **lpp;
- char **cpp;
- int i, j;
- 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 LDAP 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( char *name )
-{
- char *dn, tmp[BUFSIZ];
-
-#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 entry\n '%s'\n will be permanently removed from", dn);
- printf(" the Directory.\n Are you absolutely sure that you want to" );
- 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 LDAP Directory.
- */
- if (ldap_delete_s(ld, dn) != 0) {
- int ld_errno = 0;
- ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
- if (ld_errno == LDAP_INSUFFICIENT_ACCESS)
- printf(" You do not own the entry\n\t\"%s\".\n", dn);
- 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( int action, char *name )
-{
- char **vp;
- char *values[2], *group_name;
- LDAPMod mod, *mods[2];
-
-#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)) {
- int ld_errno = 0;
- ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
- if ((action == G_JOIN) && (ld_errno == LDAP_TYPE_OR_VALUE_EXISTS))
- printf(" You are already subscribed to \"%s\"\n", group_name);
- else if ((action == G_RESIGN) && (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( 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 LDAP 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( char *group )
-{
- int isclean = TRUE;
- LDAPMessage *lm;
- LDAPMod mod, *mods[2];
- char dn[BUFSIZ], tmp[BUFSIZ], *values[2], **vp, **rdns;
-
-#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 LDAP 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( void )
-{
- 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( char *group, int offset )
-{
- char s[BUFSIZ], *new_value /* was member */, *values[2];
- char attrtype[ 64 ];
- 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 LDAP 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@umich.edu>
- * Bryan Beecher <bryan@umich.edu>
- */
- char *cp;
- if (strchr(s, '<') == NULL) {
- for (cp = s; *cp != '@'; cp++)
- if (isspace((unsigned char)*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) {
- LDAPMod **lpp;
- char **cp;
- 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)) {
- int ld_errno = 0;
- ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
- if (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) {
- LDAPMod **lpp;
- char **cp;
- 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.
- */
- int ld_errno = 0;
- ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
- if (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);
- }
-}
-
-int
-my_ldap_modify_s( 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( 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);
- ldap_memfree(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( char *name )
-{
- LDAPMessage *lm;
- char tmp[MED_BUF_SIZE];
-
-#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( 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);
- ldap_memfree(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;
-}
+++ /dev/null
-/* $OpenLDAP$ */
-/*
- * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
- * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
- */
-/*
- * 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 "portable.h"
-
-#include <stdio.h>
-
-#include <ac/ctype.h>
-#include <ac/string.h>
-#include <ac/time.h>
-
-#include <ldap.h>
-
-#include "ud.h"
-
-
-void
-print_help( 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 <command-name>\" 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: OpenLDAP-its@OpenLDAP.org\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 LDAP-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 LDAP 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 LDAP 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 LDAP 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 LDAP 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);
- }
-}
+++ /dev/null
-/* $OpenLDAP$ */
-/*
- * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
- * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
- */
-/*
- * 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 <robert@sfu.ca>
- * Simon Fraser University, Academic Computing Services
- */
-
-#include "portable.h"
-
-#include <stdio.h>
-
-#include <ac/stdlib.h>
-
-#include <setjmp.h>
-
-#ifdef HAVE_PWD_H
-#include <pwd.h>
-#endif
-
-#include <ac/signal.h>
-#include <ac/string.h>
-#include <ac/ctype.h>
-#include <ac/termios.h>
-#include <ac/time.h>
-#include <ac/unistd.h>
-
-#ifdef HAVE_SYS_FILE_H
-#include <sys/file.h>
-#endif
-
-#include <ldap.h>
-
-#include "ldap_defaults.h"
-#include "ud.h"
-
-/*
- * 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 = 0;
-static int dereference = TRUE;
-
-char *default_bind_object = NULL;
-
-char *bound_dn; /* bound user's Distinguished Name */
-char *group_base; /* place in LDAP tree where groups are */
-char *search_base; /* place in LDAP 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
-int ldebug; /* library debug flag */
-
-#ifndef HAVE_MKVERSION
-char Version[] = OPENLDAP_PACKAGE " " OPENLDAP_VERSION " UserDirectory (ud)";
-#endif
-
-int
-main( int argc, char **argv )
-{
- register int c; /* for parsing argv */
- register char *cp; /* for parsing Version */
-
- verbose = 1;
-
- /* handle argument list */
- while ((c = getopt(argc, argv, "c:d:Df:l:p:s:u:vV")) != -1) {
- switch (c) {
- case 'l' :
- ldebug |= (int) strtol(optarg, (char **) NULL, 0);
- 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( EXIT_SUCCESS );
- 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( EXIT_FAILURE);
- /* NOTREACHED */
- }
- }
-
- /* just print the first line of Version[] */
- cp = strchr(Version, '\t');
- if (cp != NULL)
- *cp = '\0';
- printf(Version);
- fflush( stdout );
-
-#ifdef SIGPIPE
- (void) SIGNAL (SIGPIPE, SIG_IGN);
-#endif
-
- initialize_client();
- initialize_attribute_strings();
-
- /* now tackle the user's commands */
- do_commands();
- /* NOTREACHED */
-
- return 0;
-}
-
-void
-do_commands( void )
-{
- LDAPMessage *mp; /* returned by find() */
- register char *cp; /* misc char pointer */
- register char *ap; /* misc char pointer */
- static char cmd[MED_BUF_SIZE]; /* holds the command */
- static char input[MED_BUF_SIZE]; /* buffer for input */
-
-#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((unsigned char)*cp))
- cp++;
- ap = cmd;
- if (memset(cmd, '\0', sizeof(cmd)) == NULL)
- fatal("memset");
- while (!isspace((unsigned char)*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((unsigned char)*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))) {
- int deref;
- dereference = 1 - dereference;
- if (dereference == 1) {
- deref = LDAP_DEREF_ALWAYS;
- } else {
- deref = LDAP_DEREF_NEVER;
- }
- ldap_set_option(ld, LDAP_OPT_DEREF, (void *) &deref);
- }
- 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);
- exit( EXIT_SUCCESS );
- /* NOTREACHED */
-}
-
-void
-status( void )
-{
- register char **rdns;
-
-#ifdef DEBUG
- if (debug & D_TRACE)
- printf("->status()\n");
-#endif
- printf(" Current server is %s", server != NULL ? server : "<default>" );
- if ( ld != NULL ) {
- char *host = NULL;
-
- ldap_get_option(ld, LDAP_OPT_HOST_NAME, &host);
-
- if ( host != NULL &&
- ( server == NULL || strcasecmp( host, server ) != 0 ) )
- {
- printf( " (%s)", 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 ) {
- int deref = LDAP_DEREF_NEVER;
- ldap_get_option(ld, LDAP_OPT_DEREF, &deref);
- printf( " Aliases are %sbeing dereferenced\n",
- ( deref == LDAP_DEREF_ALWAYS ) ? "" : "not" );
- }
-}
-
-void
-change_base( int type, char **base, char *s )
-{
- register char *cp; /* utility pointers */
- char *output_string = NULL; /* 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];
- static char *attrs[] = { "objectClass", NULL };
- LDAPMessage *mp; /* results from a search */
- LDAPMessage *ep; /* for going thru bases */
-
-#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.
- */
- if (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(" <entry> - 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;
- else
- return;
- }
-
- /* 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 LDAP 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((unsigned char)*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, NULL, attrs, FALSE, &mp) != LDAP_SUCCESS) {
- int ld_errno = 0;
- ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
- if ((ld_errno == LDAP_TIMELIMIT_EXCEEDED) ||
- (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);
- printf(" %2d. %s\n", i, choices[i]);
- 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++)
- ldap_memfree(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++)
- ldap_memfree(choices[i]);
- return;
- }
- }
- }
- /* set the search base back to the original default value */
- else if (!strcasecmp(s, "default")) {
- if (type == BASE_SEARCH)
- StrFreeDup(base, NULL);
- 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);
- }
-}
-
-void
-initialize_client( void )
-{
- FILE *fp; /* for config file */
- static char buffer[MED_BUF_SIZE]; /* for input */
-#ifdef HAVE_GETPWUID
- struct passwd *pw; /* for getting the home dir */
-#endif
- register char *cp; /* for fiddling with buffer */
- char *config; /* config file to use */
- static char bp[1024]; /* for tty set-up */
-
-#ifdef DEBUG
- if (debug & D_TRACE)
- printf("->initialize_client()\n");
-#endif
-
- if (ldebug) {
- ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &ldebug );
- ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, &ldebug );
- }
-
- /*
- * A per-user config file has precedence over any system-wide
- * config file, if one exists.
- */
-#ifdef HAVE_GETPWUID
- 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;
- }
- }
-#else
- config = config_file;
-#endif /* getpwduid() */
-#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 <ip-address or domain-name>
- * base <default search base>
- * groupbase <default place where groups are created>
- *
- */
- 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((unsigned char)*cp))
- cp++;
- if ((*cp == '\0') || (*cp == '\n'))
- continue;
- server = strdup(cp);
- }
- else if (!strncasecmp(buffer, "host", 4)) {
- if (server != NULL)
- continue;
- cp = buffer + 4;
- while (isspace((unsigned char)*cp))
- cp++;
- if ((*cp == '\0') || (*cp == '\n'))
- continue;
- server = strdup(cp);
- }
- else if (!strncasecmp(buffer, "base", 4)) {
- cp = buffer + 4;
- while (isspace((unsigned char)*cp))
- cp++;
- if ((*cp == '\0') || (*cp == '\n'))
- continue;
- search_base = strdup(cp);
- }
- else if (!strncasecmp(buffer, "groupbase", 9)) {
- cp = buffer + 9;
- while (isspace((unsigned char)*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);
-
- /*
- * 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_init(server, ldap_port)) == NULL) {
- fprintf(stderr, " Initialization of LDAP session failed.\n");
- exit( EXIT_FAILURE );
- /* NOTREACHED */
- }
- if (ldap_bind_s(ld, (char *) default_bind_object, NULL,
- LDAP_AUTH_SIMPLE) != LDAP_SUCCESS) {
- ldap_perror(ld, " ldap_bind_s");
- exit( EXIT_FAILURE );
- /* NOTREACHED */
- }
- {
- int deref = LDAP_DEREF_ALWAYS;
- ldap_set_option(ld, LDAP_OPT_DEREF, (void *) &deref);
- }
- 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 */
- ldap_enable_cache( ld, 60 * 15, 0 ); /* no memory limit */
-
- /* 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);
-
-#ifndef NO_TERMCAP
- {
- char *term;
-
- if (((term = getenv("TERM")) == NULL) || (tgetent(bp, term) <= 0))
- return;
- else {
-#ifdef TIOCGWINSZ
- struct winsize win; /* for tty set-up */
- if (ioctl(fileno(stdout), TIOCGWINSZ, &win) >= 0) {
- 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);
- } else
-#endif
- {
- lpp = tgetnum("li");
- col_size = tgetnum("co");
- }
- }
- }
-#endif
-}
-
-RETSIGTYPE
-attn( int sig )
-{
- fflush(stderr);
- fflush(stdout);
- printf("\n\n INTERRUPTED!\n");
-
- (void) SIGNAL_REINSTALL (SIGINT, attn);
-
- longjmp(env, 1);
-}
-
-#if !defined(NO_TERMCAP) && defined(TIOCGWINSZ)
-RETSIGTYPE
-chwinsz( int sig )
-{
- 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_REINSTALL (SIGWINCH, chwinsz);
-}
-#endif
+++ /dev/null
-/* $OpenLDAP$ */
-/*
- * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
- * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
- */
-/*
- * 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 "portable.h"
-
-#include <stdio.h>
-
-#include <ac/stdlib.h>
-
-#include <ac/ctype.h>
-#include <ac/string.h>
-#include <ac/time.h>
-
-#include <ldap.h>
-#include "ud.h"
-
-static char *get_URL( void );
-static int check_URL( char *url );
-
-
-void
-modify( char *who )
-{
- 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;
- int ld_errno;
-#endif
- int is_a_group; /* TRUE if it is; FALSE otherwise */
-
-#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);
-
- ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
-
- if (verbose && !printed_warning && (ld_errno == LDAP_NO_SUCH_ATTRIBUTE)) {
- printed_warning = 1;
- printf("\n WARNING!\n");
- printf(" You are about to make a modification to an LDAP 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);
- }
- ldap_memfree(dn);
- ldap_value_free(rdns);
- return;
-}
-
-/* generic routine for changing any field */
-void
-change_field(
- char *who, /* DN of entry we are changing */
- int attr_idx /* attribute to change */
-)
-{
- struct attribute attr = Entry.attrs[attr_to_index(attrlist[attr_idx].quipu_name)];
-
-#define IS_MOD(x) (!strncasecmp(resp, (x), strlen(resp)))
-
- 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 */
-
-#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( char *id, char *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+2)]; /* holds ALL of the
- lines we get */
-#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.
- */
- 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 LDAP Directory. The name you have typed above could not be found in the LDAP 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);
- ldap_memfree(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(
- char *who, /* DN of entry we are changing */
- int attr_idx /* boolean attribute to change */
-)
-{
- struct attribute attr = Entry.attrs[attr_to_index(attrlist[attr_idx].quipu_name)];
-
- char *cp, *s;
- 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((unsigned char)*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( char *who, int dummy )
-{
- char *cp, *s;
- 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 LDAP database each month. Sometimes this\n");
- printf(" feature is undesirable. For example, if you maintain your\n");
- printf(" entry in the LDAP 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((unsigned char)*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
-
-void
-print_mod_list( int group )
-{
- register int i, j = 1;
-
- 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
-}
-
-int
-perform_action( char *choice, char *dn, int group )
-{
- int selection;
- register int i, j = 1;
-
- 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 */
- }
- (*attrlist[i].mod_func)(dn, i);
- return(0);
-}
-
-static char *
-get_URL( void )
-{
- char *rvalue, label[MED_BUF_SIZE], url[MED_BUF_SIZE];
-
- 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 int
-check_URL( char *url )
-{
- register char *cp;
-
- for (cp = url; *cp != '\n' && *cp != '\0'; cp++) {
- if (isspace((unsigned char)*cp))
- return(-1);
- /*NOTREACHED*/
- }
- *cp = '\0';
- return(0);
-}
-
-
-void
-mod_perror( LDAP *ld )
-{
- int ld_errno = LDAP_SUCCESS;
- char *ld_errtext = NULL;
-
- ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno );
-
- if( ld_errno != LDAP_SUCCESS ) {
- ldap_get_option(ld, LDAP_OPT_ERROR_STRING, &ld_errtext );
- }
-
- fprintf( stderr, " modify failed: %s (%d)\n",
- ldap_err2string( ld_errno ), ld_errno );
-
- if( ld_errtext != NULL ) {
- fprintf( stderr, " additional information: %s\n",
- ld_errtext );
- }
-
- fprintf( stderr, " Please try again later.\n" );
-}
+++ /dev/null
-/* $OpenLDAP$ */
-/*
- * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
- * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
- */
-/*
- * 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 "portable.h"
-
-#include <stdio.h>
-
-#include <ac/ctype.h>
-#include <ac/string.h>
-#include <ac/time.h>
-
-#include <ldap.h>
-
-#include "ud.h"
-
-struct entry Entry;
-
-static char *time2text(char *ldtimestr, int dateonly);
-static long gtime(struct tm *tm);
-
-/*
- * 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",
- "modifiersname",
- "modifytimestamp",
- 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",
- "modifiersname",
- "modifytimestamp",
- "creatorsname",
- "createtimestamp",
- NULL
-};
-
-
-void
-parse_answer( LDAPMessage *s )
-{
- int idx;
- char **rdns;
- register LDAPMessage *ep;
- register char *ap;
-
-#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)) {
- BerElement *cookie = NULL;
-#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);
- }
-
- if( cookie != NULL ) {
- ber_free( cookie, 0 );
- }
- }
-#ifdef DEBUG
- if (debug & D_PARSE)
- printf(" Done parsing entry\n");
-#endif
-}
-
-void
-add_value( 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);
-}
-
-void
-print_an_entry( void )
-{
- int n = 0, i, idx;
- char is_a_group, **order;
- char *sub_list[MAX_VALUES], buf[SMALL_BUF_SIZE];
-
-#ifdef DEBUG
- if (debug & D_TRACE)
- printf("->print_an_entry()\n");
-#endif
-
- if( Entry.name == NULL ) {
- printf(" No Entry found.\n");
- return;
- }
-
- 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 */
-void
-print_values( 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((unsigned char) 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 */
-void
-print_DN( 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_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( void )
-{
- register int i;
-
-#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)
- ldap_memfree(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.
- */
- }
-}
-
-int
-attr_to_index( char *s )
-{
- register int i;
-
- for (i = 0; attrlist[i].quipu_name != NULL; i++)
- if (!strcasecmp(s, attrlist[i].quipu_name))
- return(i);
- return(-1);
-}
-
-void
-initialize_attribute_strings( void )
-{
- register int i;
-
- 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 */
-void
-print_URL( 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;
-}
-
-void
-print_one_URL( char *s, int label_lead, char *tag, int url_lead )
-{
- register int i;
- char c, *cp, *url;
-
- for (cp = s; !isspace((unsigned char)*cp) && (*cp != '\0'); cp++)
- ;
- c = *cp;
- *cp = '\0';
- url = strdup(s);
- *cp = c;
- if (*cp != '\0') {
- for (cp++; isspace((unsigned char)*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;
- int ndigits;
-
- if (strlen( ldtimestr ) < 12 ) {
- return( fmterr );
- }
-
- for ( ndigits=0; isdigit((unsigned char) ldtimestr[ndigits]); ndigits++) {
- ; /* EMPTY */
- }
-
- if ( ndigits != 12 && ndigits != 14) {
- return( fmterr );
- }
-
- memset( (char *)&t, '\0', sizeof( struct tm ));
-
- p = ldtimestr;
-
- if( ndigits == 14) {
- /* came with a century */
- /* POSIX says tm_year should be year - 1900 */
- t.tm_year = 100 * GET2BYTENUM( p ) - 1900;
- p += 2;
- } else {
- t.tm_year = 0;
- }
- 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 ) {
- AC_MEMCPY( timestr + 11, timestr + 20, strlen( timestr + 20 ) + 1 );
- }
-
- return( strdup( timestr ) );
-}
-
-
-/* gtime.c - inverse gmtime */
-
-#include <ac/time.h>
-
-/* 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)))
-
-/*
- * Y2K YEAR
- */
- /* per STDC & POSIX tm_year *should* be offset by 1900 */
-#define YEAR_POSIX(y) ((y) + 1900)
-
- /*
- * year is < 1900, year is offset by 1900
- */
-#define YEAR_CAREFUL(y) ((y) < 1900 ? (y) + 1900 : (y))
-
-#define YEAR(y) YEAR_CAREFUL(y)
-
-
-/* \f */
-
-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;
-}
+++ /dev/null
-# Microsoft Developer Studio Project File - Name="ud" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 5.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Console Application" 0x0103
-
-CFG=ud - Win32 Single Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "ud.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "ud.mak" CFG="ud - Win32 Single Debug"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "ud - Win32 Release" (based on "Win32 (x86) Console Application")
-!MESSAGE "ud - Win32 Debug" (based on "Win32 (x86) Console Application")
-!MESSAGE "ud - Win32 Single Release" (based on\
- "Win32 (x86) Console Application")
-!MESSAGE "ud - Win32 Single Debug" (based on "Win32 (x86) Console Application")
-!MESSAGE
-
-# Begin Project
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "ud - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "..\..\Release"
-# PROP Intermediate_Dir "..\..\Release\ud"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
-# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
-# ADD BASE RSC /l 0x409 /d "NDEBUG"
-# ADD RSC /l 0x409 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:console /machine:I386
-# ADD LINK32 oldap32.lib olber32.lib oldif32.lib olutil32.lib hs_regex.lib sasl.lib libsasl.lib ws2_32.lib /nologo /subsystem:console /machine:I386 /libpath:"..\..\Release"
-
-!ELSEIF "$(CFG)" == "ud - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "..\..\Debug"
-# PROP Intermediate_Dir "..\..\Debug\ud"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
-# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c
-# ADD BASE RSC /l 0x409 /d "_DEBUG"
-# ADD RSC /l 0x409 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 oldap32.lib olber32.lib oldif32.lib olutil32.lib hs_regex.lib libsasl.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\Debug"
-
-!ELSEIF "$(CFG)" == "ud - Win32 Single Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "ud___Wi0"
-# PROP BASE Intermediate_Dir "ud___Wi0"
-# PROP BASE Ignore_Export_Lib 0
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "..\..\SRelease"
-# PROP Intermediate_Dir "..\..\SRelease\ud"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /GX /O2 /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
-# ADD CPP /nologo /W3 /GX /O2 /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
-# ADD BASE RSC /l 0x409 /d "NDEBUG"
-# ADD RSC /l 0x409 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 oldap32.lib olber32.lib oldif32.lib olutil32.lib ws2_32.lib hs_regex.lib /nologo /subsystem:console /machine:I386 /libpath:"..\..\libraries\Release"
-# ADD LINK32 oldap32.lib olber32.lib oldif32.lib olutil32.lib hs_regex.lib sasl.lib libsasl.lib ws2_32.lib /nologo /subsystem:console /machine:I386 /libpath:"..\..\SRelease"
-
-!ELSEIF "$(CFG)" == "ud - Win32 Single Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "ud___Wi1"
-# PROP BASE Intermediate_Dir "ud___Wi1"
-# PROP BASE Ignore_Export_Lib 0
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "..\..\SDebug"
-# PROP Intermediate_Dir "..\..\SDebug\ud"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
-# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c
-# ADD BASE RSC /l 0x409 /d "_DEBUG"
-# ADD RSC /l 0x409 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 oldap32.lib olber32.lib oldif32.lib olutil32.lib ws2_32.lib hs_regex.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\libraries\Debug"
-# ADD LINK32 oldap32.lib olber32.lib oldif32.lib olutil32.lib hs_regex.lib libsasl.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\SDebug"
-
-!ENDIF
-
-# Begin Target
-
-# Name "ud - Win32 Release"
-# Name "ud - Win32 Debug"
-# Name "ud - Win32 Single Release"
-# Name "ud - Win32 Single Debug"
-# Begin Source File
-
-SOURCE=.\auth.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\edit.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\find.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\globals.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\group.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\help.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\main.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\mod.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\print.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\ud.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\util.c
-# End Source File
-# End Target
-# End Project
+++ /dev/null
-/* $OpenLDAP$ */
-/*
- * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
- * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
- */
-/*
- * 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.
- */
-
-#define MAX_VALUES 1000
-
-/*****************************************************************************
- **
- ** 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((unsigned char) (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
-
-/*
- * 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
-
-LDAP_BEGIN_DECL
-
-/*
- * 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) LDAP_P(( char *who, int attr_idx ));
- 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];
-};
-
-
-
-/*
- * Variables
- */
-
-/* in globals.c: */
-extern struct attribute attrlist[];/* complete list of attrs */
-/* in main.c: */
-extern char copyright[];
-extern char *default_bind_object;
-extern char *bound_dn;
-extern char *group_base;
-extern char *search_base; /* search base */
-extern int lpp;
-extern int verbose; /* verbose mode flag */
-extern int col_size;
-extern int bind_status;
-extern LDAP *ld; /* our ldap descriptor */
-extern LDAPFiltDesc *lfdp; /* LDAP filter descriptor */
-#ifdef DEBUG
-extern int debug; /* debug flag */
-#endif
-/* in print.c: */
-extern struct entry Entry;
-extern int dmsize[];
-/* in version.c: */
-extern char Version[];
-
-
-/*
- * Functions
- */
-
-/* in auth.c: */
-int auth LDAP_P(( char *who, int implicit ));
-
-/* in edit.c: */
-void edit LDAP_P(( char *who ));
-
-/* in find.c: */
-int vrfy LDAP_P(( char *dn ));
-LDAPMessage *find LDAP_P(( char *who, int quiet ));
-int pick_one LDAP_P(( int i ));
-void print_list LDAP_P(( LDAPMessage *list, char **names, int *matches ));
-int find_all_subscribers LDAP_P(( char **sub, char *group ));
-char *fetch_boolean_value LDAP_P(( char *who, struct attribute attr ));
-
-/* in globals.c: */
-
-/* in group.c: */
-void add_group LDAP_P(( char *name ));
-void remove_group LDAP_P(( char *name ));
-void x_group LDAP_P(( int action, char *name ));
-void bulk_load LDAP_P(( char *group ));
-void purge_group LDAP_P(( char *group ));
-void tidy_up LDAP_P(( void ));
-void mod_addrDN LDAP_P(( char *group, int offset ));
-int my_ldap_modify_s LDAP_P(( LDAP *ldap, char *group, LDAPMod **mods ));
-void list_groups LDAP_P(( char *who ));
-void list_memberships LDAP_P(( char *who ));
-
-/* in help.c: */
-void print_help LDAP_P(( char *s ));
-
-/* in main.c: */
-#ifdef DEBUG
-#endif
-
-void do_commands LDAP_P(( void )) LDAP_GCCATTR((noreturn));
-void status LDAP_P(( void ));
-void change_base LDAP_P(( int type, char **base, char *s ));
-void initialize_client LDAP_P(( void ));
-RETSIGTYPE attn LDAP_P(( int sig ));
-#if !defined(NO_TERMCAP) && defined(TIOCGWINSZ)
-RETSIGTYPE chwinsz LDAP_P(( int sig ));
-#endif
-
-/* in mod.c: */
-void modify LDAP_P(( char *who ));
-void change_field LDAP_P(( char *who, int attr_idx ));
-char *get_value LDAP_P(( char *id, char *prompt ));
-void set_boolean LDAP_P(( char *who, int attr_idx ));
-#ifdef UOFM
-void set_updates LDAP_P(( char *who, int dummy ));
-#endif
-void print_mod_list LDAP_P(( int group ));
-int perform_action LDAP_P(( char *choice, char *dn, int group ));
-void mod_perror LDAP_P(( LDAP *ld ));
-
-/* in print.c: */
-void parse_answer LDAP_P(( LDAPMessage *s ));
-void add_value LDAP_P(( struct attribute *attr, LDAPMessage *ep, char *ap ));
-void print_an_entry LDAP_P(( void ));
-void print_values LDAP_P(( struct attribute A ));
-void print_DN LDAP_P(( struct attribute A ));
-void clear_entry LDAP_P(( void ));
-int attr_to_index LDAP_P(( char *s ));
-void initialize_attribute_strings LDAP_P(( void ));
-void print_URL LDAP_P(( struct attribute A ));
-void print_one_URL LDAP_P(( char *s, int l_lead, char *tag, int u_lead ));
-
-/* in util.c: */
-void printbase LDAP_P(( char *lead, char *s ));
-void fetch_buffer LDAP_P(( char *buffer, int length, FILE *where ));
-void fatal LDAP_P(( char *s )) LDAP_GCCATTR((noreturn));
-int isgroup LDAP_P(( void ));
-void format LDAP_P(( char *str, int width, int lead ));
-void format2 LDAP_P(( char *s, char *ft, char *t, int fi, int i, int w ));
-char *strip_ignore_chars LDAP_P(( char *cp ));
-char *code_to_str LDAP_P(( int i ));
-char *friendly_name LDAP_P(( char *s ));
-#ifdef UOFM
-int isauniqname LDAP_P(( char *s ));
-#endif
-int isadn LDAP_P(( char *s ));
-char *my_ldap_dn2ufn LDAP_P(( char *s ));
-int isaurl LDAP_P(( char *s ));
-int isadate LDAP_P(( char *s ));
-void *Malloc LDAP_P(( unsigned int size ));
-void Free LDAP_P(( void *ptr ));
-char *nextstr LDAP_P(( char *s ));
-void free_mod_struct LDAP_P(( LDAPMod *modp ));
-void StrFreeDup LDAP_P(( char **ptr, char *new_value ));
-int confirm_action LDAP_P(( char *msg ));
-
-LDAP_END_DECL
+++ /dev/null
-/* $OpenLDAP$ */
-/*
- * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
- * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
- */
-/*
- * 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 "portable.h"
-
-#include <stdio.h>
-
-#include <ac/stdlib.h>
-
-#include <ac/ctype.h>
-#include <ac/errno.h>
-#include <ac/signal.h>
-#include <ac/string.h>
-#include <ac/termios.h>
-#include <ac/time.h>
-#include <ac/unistd.h>
-
-#include <ldap.h>
-
-#include "ldap_defaults.h"
-#include "ud.h"
-
-void
-printbase( char *lead, char *s )
-{
-#ifdef DEBUG
- if (debug & D_TRACE)
- printf("->printbase(%s, %s)\n", lead, s);
-#endif
- if (lead == NULL) {
- printf("root\n");
- return;
- }
- if (s == NULL) {
- printf("%sroot\n", lead);
- return;
- }
- printf("%s%s\n", lead, s);
- return;
-}
-
-void
-fetch_buffer( char *buffer, int length, FILE *where )
-{
- 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((unsigned char) buffer[i]); i--)
- buffer[i] = '\0';
-
- p = buffer;
- while ( *p != '\0' ) {
- if ( isprint( (unsigned char) *p )) {
- ++p;
- } else {
- AC_MEMCPY( p, p + 1, strlen( p + 1 ) + 1 );
- }
- }
-
-}
-
-void
-fatal( char *s )
-{
- if (errno != 0)
- perror(s);
- exit( EXIT_FAILURE );
-}
-
-int
-isgroup( void )
-{
- 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.
- */
-void
-format( char *str, int width, int lead )
-{
- char *s, *original, *leader = "";
- register char *cp;
-
-#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 (((int) strlen(s) + lead) < width) {
- printf("%s%s\n", leader, s);
- Free(leader);
- Free(original);
- return;
- /*NOTREACHED*/
- }
- cp = s + width - lead;
- while (!isspace((unsigned char)*cp) && (cp != s))
- cp--;
- *cp = '\0';
- while (isspace((unsigned char)*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'.
- */
-void
-format2(
- char *s,
- char *first_tag,
- char *tag,
- int first_indent,
- int indent,
- int width
-)
-{
- char c, *fi, *i;
- register char *cp;
-
- 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 (((int) strlen(s) + (int) 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((unsigned char)*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((unsigned char)*s); s++)
- ;
-
- /* now do all of the other lines */
- for (;;) {
- if (((int) strlen(s) + (int) 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((unsigned char)*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( char *cp )
-{
- int had_a_comma = FALSE;
- int flag = OUT_OF_QUOTE;
- register char *rcp, *cp1;
- char *tmp;
-
-#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( int i )
-{
- switch(i) {
- case LDAP_MOD_ADD : return("ADD");
- case LDAP_MOD_DELETE : return("DELETE");
- case LDAP_MOD_REPLACE : return("REPLACE");
- default : return("?????");
- }
-}
-
-#ifdef UOFM
-
-/* return TRUE if s has the syntax of a uniqname */
-int
-isauniqname( char *s )
-{
- int i = strlen(s);
-
- if ((i < 3) || (i > 8)) /* uniqnames are 3-8 chars */
- return(FALSE);
- if (!isalpha((unsigned char)*s)) /* uniqnames begin with a letter */
- return(FALSE);
- for ( ; *s != '\0'; s++) /* uniqnames are alphanumeric */
- if (!isalnum((unsigned char)*s))
- return(FALSE);
- return(TRUE);
-}
-#endif
-
-/* return TRUE if this attribute should be printed as a DN */
-int
-isadn( char *s )
-{
- register int i;
-
- 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( char *s )
-{
-#ifdef UD_BASE
- 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);
-#else
- return(ldap_dn2ufn(s));
-#endif
-}
-
-/* return TRUE if this attribute should be printed as a URL */
-int
-isaurl( char *s )
-{
- register int i;
-
- 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 */
-int
-isadate( char *s )
-{
- register int i;
-
- 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( unsigned int size )
-{
- void *void_ptr;
-
- void_ptr = (void *) malloc(size);
- if (void_ptr == NULL) {
- perror("malloc");
- exit( EXIT_FAILURE );
- /*NOTREACHED*/
- }
- return(void_ptr);
-}
-
-void
-Free( void *ptr )
-{
- free(ptr);
-}
-
-char *
-nextstr( char *s )
-{
- while (isspace((unsigned char) *s) && (*s != '\0'))
- s++;
- if (s == NULL)
- return(NULL);
- if (*s == '\0')
- return(NULL);
- return(s);
-}
-
-void
-free_mod_struct( LDAPMod *modp )
-{
- if (modp->mod_values != NULL)
- (void) ldap_value_free(modp->mod_values);
- Free(modp->mod_type);
- Free(modp);
-}
-
-void
-StrFreeDup( char **ptr, char *new_value )
-{
- if (*ptr != NULL)
- Free(*ptr);
- if (new_value == NULL)
- *ptr = NULL;
- else
- *ptr = strdup(new_value);
-}
-
-
-int
-confirm_action( 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)));
-}
doc/man/man5/Makefile:build/top.mk:doc/man/man5/Makefile.in:build/man.mk \
doc/man/man8/Makefile:build/top.mk:doc/man/man8/Makefile.in:build/man.mk \
clients/Makefile:build/top.mk:clients/Makefile.in:build/dir.mk \
-clients/mail500/Makefile:build/top.mk:clients/mail500/Makefile.in:build/rules.mk \
-clients/ud/Makefile:build/top.mk:clients/ud/Makefile.in:build/rules.mk \
-clients/maildap/Makefile:build/top.mk:clients/maildap/Makefile.in:build/rules.mk \
clients/tools/Makefile:build/top.mk:clients/tools/Makefile.in:build/rules.mk \
include/Makefile:build/top.mk:include/Makefile.in \
libraries/Makefile:build/top.mk:libraries/Makefile.in:build/dir.mk \
+++ /dev/null
-.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.
+++ /dev/null
-.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 <name>\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 <base>\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 <base>\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 <algorithm>\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.
+++ /dev/null
-.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.
#define mod_bvalues mod_vals.modv_bvals
} LDAPMod;
-/*
- * structures for ldap getfilter routines
- */
-
-typedef struct ldap_filt_info {
- char *lfi_filter;
- char *lfi_desc;
- int lfi_scope;
- int lfi_isexact;
- struct ldap_filt_info *lfi_next;
-} LDAPFiltInfo;
-
-typedef struct ldap_filt_list {
- char *lfl_tag;
- char *lfl_pattern;
- char *lfl_delims;
- LDAPFiltInfo *lfl_ilist;
- struct ldap_filt_list *lfl_next;
-} LDAPFiltList;
-
-
-#define LDAP_FILT_MAXSIZ 1024
-
-typedef struct ldap_filt_desc {
- LDAPFiltList *lfd_filtlist;
- LDAPFiltInfo *lfd_curfip;
- LDAPFiltInfo lfd_retfi;
- char lfd_filter[ LDAP_FILT_MAXSIZ ];
- char *lfd_curval;
- char *lfd_curvalcopy;
- char **lfd_curvalwords;
- char *lfd_filtprefix;
- char *lfd_filtsuffix;
-} LDAPFiltDesc;
-
-
/*
* structure representing an ldap session which can
* encompass connections to multiple servers (in the
LDAPControl **clientctrls));
/*
- * in getfilter.c
- * (deprecated)
+ * in filter.c
*/
-LDAP_F( LDAPFiltDesc * )
-ldap_init_getfilter LDAP_P(( /* deprecated */
- LDAP_CONST char *fname ));
-
-LDAP_F( LDAPFiltInfo * )
-ldap_getfirstfilter LDAP_P(( /* deprecated */
- LDAPFiltDesc *lfdp,
- /* LDAP_CONST */ char *tagpat,
- /* LDAP_CONST */ char *value ));
-
-LDAP_F( LDAPFiltInfo * )
-ldap_getnextfilter LDAP_P(( /* deprecated */
- LDAPFiltDesc *lfdp ));
-
LDAP_F( int )
ldap_put_vrFilter LDAP_P((
BerElement *ber,
ldap_strdup LDAP_P((
LDAP_CONST char * ));
-LDAP_F( void )
-ldap_getfilter_free LDAP_P((
- LDAPFiltDesc *lfdp ));
-
LDAP_F( void )
ldap_mods_free LDAP_P((
LDAPMod **mods,
SRCS = bind.c open.c result.c error.c compare.c search.c \
controls.c messages.c references.c extended.c cyrus.c \
modify.c add.c modrdn.c delete.c abandon.c cache.c \
- getfilter.c sasl.c sbind.c kbind.c unbind.c \
- filter.c free.c dsparse.c sort.c \
+ sasl.c sbind.c kbind.c unbind.c \
+ filter.c free.c sort.c \
getdn.c getentry.c getattr.c getvalues.c addentry.c \
request.c os-ip.c url.c sortctrl.c vlvctrl.c \
init.c options.c print.c string.c util-int.c schema.c \
OBJS = bind.lo open.lo result.lo error.lo compare.lo search.lo \
controls.lo messages.lo references.lo extended.lo cyrus.lo \
modify.lo add.lo modrdn.lo delete.lo abandon.lo cache.lo \
- getfilter.lo sasl.lo sbind.lo kbind.lo unbind.lo \
- filter.lo free.lo dsparse.lo sort.lo \
+ sasl.lo sbind.lo kbind.lo unbind.lo \
+ filter.lo free.lo sort.lo \
getdn.lo getentry.lo getattr.lo getvalues.lo addentry.lo \
request.lo os-ip.lo url.lo sortctrl.lo vlvctrl.lo \
init.lo options.lo print.lo string.lo util-int.lo schema.lo \
ltest: $(XLIBS) test.o
$(LTLINK) -o $@ test.o $(LIBS)
-CFFILES=ldap.conf ldapfilter.conf
+CFFILES=ldap.conf
install-local: $(CFFILES) FORCE
-$(MKDIR) $(DESTDIR)$(libdir)
+++ /dev/null
-/* $OpenLDAP$ */
-/*
- * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
- * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
- */
-/* Portions
- * 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.
- *
- * dsparse.c: parsing routines used by display template and search
- * preference file library routines for LDAP clients.
- *
- * 7 March 1994 by Mark C Smith
- */
-
-#include "portable.h"
-
-#include <stdio.h>
-#include <ac/stdlib.h>
-
-#include <ac/string.h>
-#include <ac/time.h>
-
-#ifdef HAVE_SYS_FILE_H
-#include <sys/file.h>
-#endif
-
-#include "ldap-int.h"
-
-static int next_line LDAP_P(( char **bufp, ber_len_t *blenp, char **linep ));
-static char *next_token LDAP_P(( char ** sp ));
-
-
-int
-ldap_int_next_line_tokens( char **bufp, ber_len_t *blenp, char ***toksp )
-{
- char *p, *line, *token, **toks;
- int rc, tokcnt;
-
- *toksp = NULL;
-
- if (( rc = next_line( bufp, blenp, &line )) <= 0 ) {
- return( rc );
- }
-
- if (( toks = (char **)LDAP_CALLOC( 1, sizeof( char * ))) == NULL ) {
- LBER_FREE( line );
- return( -1 );
- }
- tokcnt = 0;
-
- p = line;
- while (( token = next_token( &p )) != NULL ) {
- if (( toks = (char **)LDAP_REALLOC( toks, ( tokcnt + 2 ) *
- sizeof( char * ))) == NULL ) {
- LBER_FREE( (char *)toks );
- LBER_FREE( line );
- return( -1 );
- }
- toks[ tokcnt ] = token;
- toks[ ++tokcnt ] = NULL;
- }
-
- if ( tokcnt == 1 && strcasecmp( toks[ 0 ], "END" ) == 0 ) {
- tokcnt = 0;
- LDAP_VFREE( toks );
- toks = NULL;
- }
-
- LBER_FREE( line );
-
- if ( tokcnt == 0 ) {
- if ( toks != NULL ) {
- LBER_FREE( (char *)toks );
- }
- } else {
- *toksp = toks;
- }
-
- return( tokcnt );
-}
-
-
-static int
-next_line( char **bufp, ber_len_t *blenp, char **linep )
-{
- char *linestart, *line, *p;
- ber_slen_t plen;
-
- linestart = *bufp;
- p = *bufp;
- plen = *blenp;
-
- do {
- for ( linestart = p; plen > 0; ++p, --plen ) {
- if ( *p == '\r' ) {
- if ( plen > 1 && *(p+1) == '\n' ) {
- ++p;
- --plen;
- }
- break;
- }
-
- if ( *p == '\n' ) {
- if ( plen > 1 && *(p+1) == '\r' ) {
- ++p;
- --plen;
- }
- break;
- }
- }
- ++p;
- --plen;
- } while ( plen > 0 && ( *linestart == '#' || linestart + 1 == p ));
-
-
- *bufp = p;
- *blenp = plen;
-
-
- if ( plen <= 0 ) {
- *linep = NULL;
- return( 0 ); /* end of file */
- }
-
- if (( line = LDAP_MALLOC( p - linestart )) == NULL ) {
- *linep = NULL;
- return( -1 ); /* fatal error */
- }
-
- AC_MEMCPY( line, linestart, p - linestart );
- line[ p - linestart - 1 ] = '\0';
- *linep = line;
- return( strlen( line ));
-}
-
-
-static char *
-next_token( char **sp )
-{
- int in_quote = 0;
- char *p, *tokstart, *t;
-
- if ( **sp == '\0' ) {
- return( NULL );
- }
-
- p = *sp;
-
- while ( LDAP_SPACE( (unsigned char) *p )) { /* skip leading white space */
- ++p;
- }
-
- if ( *p == '\0' ) {
- return( NULL );
- }
-
- if ( *p == '\"' ) {
- in_quote = 1;
- ++p;
- }
- t = tokstart = p;
-
- for ( ;; ) {
- if ( *p == '\0' || ( LDAP_SPACE( (unsigned char) *p ) && !in_quote )) {
- if ( *p != '\0' ) {
- ++p;
- }
- *t++ = '\0'; /* end of token */
- break;
- }
-
- if ( *p == '\"' ) {
- in_quote = !in_quote;
- ++p;
- } else {
- *t++ = *p++;
- }
- }
-
- *sp = p;
-
- if ( t == tokstart ) {
- return( NULL );
- }
-
- return( LDAP_STRDUP( tokstart ));
-}
return LDAP_STRDUP( p );
}
-void
-ldap_getfilter_free( LDAPFiltDesc *lfdp )
-{
- LDAPFiltList *flp, *nextflp;
- LDAPFiltInfo *fip, *nextfip;
-
- for ( flp = lfdp->lfd_filtlist; flp != NULL; flp = nextflp ) {
- for ( fip = flp->lfl_ilist; fip != NULL; fip = nextfip ) {
- nextfip = fip->lfi_next;
- LDAP_FREE( fip->lfi_filter );
- LDAP_FREE( fip->lfi_desc );
- LDAP_FREE( fip );
- }
- nextflp = flp->lfl_next;
- LDAP_FREE( flp->lfl_pattern );
- LDAP_FREE( flp->lfl_delims );
- LDAP_FREE( flp->lfl_tag );
- LDAP_FREE( flp );
- }
-
- if ( lfdp->lfd_curvalcopy != NULL ) {
- LDAP_FREE( lfdp->lfd_curvalcopy );
- }
- if ( lfdp->lfd_curvalwords != NULL ) {
- LDAP_FREE( lfdp->lfd_curvalwords );
- }
- if ( lfdp->lfd_filtprefix != NULL ) {
- LDAP_FREE( lfdp->lfd_filtprefix );
- }
- if ( lfdp->lfd_filtsuffix != NULL ) {
- LDAP_FREE( lfdp->lfd_filtsuffix );
- }
-
- LDAP_FREE( lfdp );
-}
-
/*
* free a null-terminated array of pointers to mod structures. the
* structures are freed, not the array itself, unless the freemods
+++ /dev/null
-/* $OpenLDAP$ */
-/*
- * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
- * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
- */
-/* Portions
- * Copyright (c) 1993 Regents of the University of Michigan.
- * All rights reserved.
- *
- * getfilter.c -- optional add-on to libldap
- */
-
-#include "portable.h"
-
-#include <stdio.h>
-
-#include <ac/stdlib.h>
-
-#include <ac/errno.h>
-#include <ac/regex.h>
-#include <ac/string.h>
-#include <ac/time.h>
-#include <ac/unistd.h>
-
-#ifdef HAVE_SYS_FILE_H
-#include <sys/file.h>
-#endif
-
-#include "ldap-int.h"
-
-static int break_into_words LDAP_P((
- /* LDAP_CONST */ char *str,
- LDAP_CONST char *delims,
- char ***wordsp ));
-
-#define FILT_MAX_LINE_LEN 1024
-
-static LDAPFiltDesc *
-ldap_init_getfilter_buf( char *buf, ber_len_t buflen )
-{
- LDAPFiltDesc *lfdp;
- LDAPFiltList *flp, *nextflp;
- LDAPFiltInfo *fip, *nextfip;
- char *tag, **tok;
- int tokcnt, i;
- int rc;
- regex_t re;
-
- if (( lfdp = (LDAPFiltDesc *)LDAP_CALLOC( 1, sizeof( LDAPFiltDesc))) == NULL ) {
- return( NULL );
- }
-
- flp = nextflp = NULL;
- fip = NULL;
- tag = NULL;
-
- while ( buflen > 0 && ( tokcnt = ldap_int_next_line_tokens( &buf, &buflen, &tok ))
- > 0 ) {
-
- switch( tokcnt ) {
- case 1: /* tag line */
- if ( tag != NULL ) {
- LDAP_FREE( tag );
- }
- tag = tok[ 0 ];
- LDAP_FREE( tok );
- break;
- case 4:
- case 5: /* start of filter info. list */
- if (( nextflp = (LDAPFiltList *)LDAP_CALLOC( 1, sizeof( LDAPFiltList )))
- == NULL ) {
- ldap_getfilter_free( lfdp );
- return( NULL );
- }
- nextflp->lfl_tag = LDAP_STRDUP( tag );
- nextflp->lfl_pattern = tok[ 0 ];
- if ( (rc = regcomp( &re, nextflp->lfl_pattern, 0 )) != 0 ) {
- char error[512];
- regerror(rc, &re, error, sizeof(error));
- ldap_getfilter_free( lfdp );
-#ifdef NEW_LOGGING
- LDAP_LOG ( FILTER, ERR,
- "ldap_init_get_filter_buf: bad regular expression %s, %s\n",
- nextflp->lfl_pattern, error, 0 );
-#else
- Debug( LDAP_DEBUG_ANY, "ldap_init_get_filter_buf: "
- "bad regular expression %s, %s\n",
- nextflp->lfl_pattern, error, 0 );
-#endif
- errno = EINVAL;
- LDAP_VFREE( tok );
- return( NULL );
- }
- regfree(&re);
-
- nextflp->lfl_delims = tok[ 1 ];
- nextflp->lfl_ilist = NULL;
- nextflp->lfl_next = NULL;
- if ( flp == NULL ) { /* first one */
- lfdp->lfd_filtlist = nextflp;
- } else {
- flp->lfl_next = nextflp;
- }
- flp = nextflp;
- fip = NULL;
- for ( i = 2; i < 5; ++i ) {
- tok[ i - 2 ] = tok[ i ];
- }
- /* fall through */
-
- case 2:
- case 3: /* filter, desc, and optional search scope */
- if ( nextflp != NULL ) { /* add to info list */
- if (( nextfip = (LDAPFiltInfo *)LDAP_CALLOC( 1,
- sizeof( LDAPFiltInfo ))) == NULL ) {
- ldap_getfilter_free( lfdp );
- LDAP_VFREE( tok );
- return( NULL );
- }
- if ( fip == NULL ) { /* first one */
- nextflp->lfl_ilist = nextfip;
- } else {
- fip->lfi_next = nextfip;
- }
- fip = nextfip;
- nextfip->lfi_next = NULL;
- nextfip->lfi_filter = tok[ 0 ];
- nextfip->lfi_desc = tok[ 1 ];
- if ( tok[ 2 ] != NULL ) {
- if ( strcasecmp( tok[ 2 ], "subtree" ) == 0 ) {
- nextfip->lfi_scope = LDAP_SCOPE_SUBTREE;
- } else if ( strcasecmp( tok[ 2 ], "onelevel" ) == 0 ) {
- nextfip->lfi_scope = LDAP_SCOPE_ONELEVEL;
- } else if ( strcasecmp( tok[ 2 ], "base" ) == 0 ) {
- nextfip->lfi_scope = LDAP_SCOPE_BASE;
- } else {
- LDAP_VFREE( tok );
- ldap_getfilter_free( lfdp );
- errno = EINVAL;
- return( NULL );
- }
- LDAP_FREE( tok[ 2 ] );
- tok[ 2 ] = NULL;
- } else {
- nextfip->lfi_scope = LDAP_SCOPE_SUBTREE; /* default */
- }
- nextfip->lfi_isexact = ( strchr( tok[ 0 ], '*' ) == NULL &&
- strchr( tok[ 0 ], '~' ) == NULL );
- LDAP_FREE( tok );
- }
- break;
-
- default:
- LDAP_VFREE( tok );
- ldap_getfilter_free( lfdp );
- errno = EINVAL;
- return( NULL );
- }
- }
-
- if ( tag != NULL ) {
- LDAP_FREE( tag );
- }
-
- return( lfdp );
-}
-
-LDAPFiltDesc *
-ldap_init_getfilter( LDAP_CONST char *fname )
-{
- FILE *fp;
- char *buf;
- long rlen, len;
- int eof;
- LDAPFiltDesc *lfdp;
-
- if (( fp = fopen( fname, "r" )) == NULL ) {
- return( NULL );
- }
-
- if ( fseek( fp, 0L, SEEK_END ) != 0 ) { /* move to end to get len */
- fclose( fp );
- return( NULL );
- }
-
- len = ftell( fp );
-
- if ( fseek( fp, 0L, SEEK_SET ) != 0 ) { /* back to start of file */
- fclose( fp );
- return( NULL );
- }
-
- if (( buf = LDAP_MALLOC( (size_t)len )) == NULL ) {
- fclose( fp );
- return( NULL );
- }
-
- rlen = fread( buf, 1, (size_t)len, fp );
- eof = feof( fp );
- fclose( fp );
-
- if ( rlen != len && !eof ) { /* error: didn't get the whole file */
- LDAP_FREE( buf );
- return( NULL );
- }
-
-
- lfdp = ldap_init_getfilter_buf( buf, rlen );
- LDAP_FREE( buf );
-
- return( lfdp );
-}
-
-LDAPFiltInfo *
-ldap_getfirstfilter(
- LDAPFiltDesc *lfdp,
- /* LDAP_CONST */ char *tagpat,
- /* LDAP_CONST */ char *value )
-{
- LDAPFiltList *flp;
- int rc;
- regex_t re;
-
- if ( lfdp->lfd_curvalcopy != NULL ) {
- LDAP_FREE( lfdp->lfd_curvalcopy );
- LDAP_FREE( lfdp->lfd_curvalwords );
- }
-
- lfdp->lfd_curval = value;
- lfdp->lfd_curfip = NULL;
-
- for ( flp = lfdp->lfd_filtlist; flp != NULL; flp = flp->lfl_next ) {
- /* compile tagpat, continue if we fail */
- if (regcomp(&re, tagpat, REG_EXTENDED|REG_NOSUB) != 0)
- continue;
-
- /* match tagpattern and tag, continue if we fail */
- rc = regexec(&re, flp->lfl_tag, 0, NULL, 0);
- regfree(&re);
- if (rc != 0)
- continue;
-
- /* compile flp->ifl_pattern, continue if we fail */
- if (regcomp(&re, flp->lfl_pattern, REG_EXTENDED|REG_NOSUB) != 0)
- continue;
-
- /* match ifl_pattern and lfd_curval, continue if we fail */
- rc = regexec(&re, lfdp->lfd_curval, 0, NULL, 0);
- regfree(&re);
- if (rc != 0)
- continue;
-
- /* we successfully compiled both patterns and matched both values */
- lfdp->lfd_curfip = flp->lfl_ilist;
- break;
- }
-
- if ( lfdp->lfd_curfip == NULL ) {
- return( NULL );
- }
-
- if (( lfdp->lfd_curvalcopy = LDAP_STRDUP( value )) == NULL ) {
- return( NULL );
- }
-
- if ( break_into_words( lfdp->lfd_curvalcopy, flp->lfl_delims,
- &lfdp->lfd_curvalwords ) < 0 ) {
- LDAP_FREE( lfdp->lfd_curvalcopy );
- lfdp->lfd_curvalcopy = NULL;
- return( NULL );
- }
-
- return( ldap_getnextfilter( lfdp ));
-}
-
-static void
-ldap_build_filter(
- char *filtbuf,
- ber_len_t buflen,
- LDAP_CONST char *pattern,
- LDAP_CONST char *prefix,
- LDAP_CONST char *suffix,
- LDAP_CONST char *attr,
- LDAP_CONST char *value,
- char **valwords );
-
-LDAPFiltInfo *
-ldap_getnextfilter( LDAPFiltDesc *lfdp )
-{
- LDAPFiltInfo *fip;
-
- fip = lfdp->lfd_curfip;
-
- if ( fip == NULL ) {
- return( NULL );
- }
-
- lfdp->lfd_curfip = fip->lfi_next;
-
- ldap_build_filter( lfdp->lfd_filter, LDAP_FILT_MAXSIZ, fip->lfi_filter,
- lfdp->lfd_filtprefix, lfdp->lfd_filtsuffix, NULL,
- lfdp->lfd_curval, lfdp->lfd_curvalwords );
- lfdp->lfd_retfi.lfi_filter = lfdp->lfd_filter;
- lfdp->lfd_retfi.lfi_desc = fip->lfi_desc;
- lfdp->lfd_retfi.lfi_scope = fip->lfi_scope;
- lfdp->lfd_retfi.lfi_isexact = fip->lfi_isexact;
-
- return( &lfdp->lfd_retfi );
-}
-
-static void
-ldap_build_filter(
- char *filtbuf,
- ber_len_t buflen,
- LDAP_CONST char *pattern,
- LDAP_CONST char *prefix,
- LDAP_CONST char *suffix,
- LDAP_CONST char *attr,
- LDAP_CONST char *value,
- char **valwords )
-{
- const char *p;
- char *f;
- size_t slen;
- int i, wordcount, wordnum, endwordnum;
-
- if ( valwords == NULL ) {
- wordcount = 0;
- } else {
- for ( wordcount = 0; valwords[ wordcount ] != NULL; ++wordcount ) {
- ;
- }
- }
-
- f = filtbuf;
-
- if ( prefix != NULL ) {
- strcpy( f, prefix );
- f += strlen( prefix );
- }
-
- for ( p = pattern; *p != '\0'; ++p ) {
- if ( *p == '%' ) {
- ++p;
- if ( *p == 'v' ) {
- if ( LDAP_DIGIT( (unsigned char) p[1] )) {
- ++p;
- wordnum = *p - '1';
- if ( *(p+1) == '-' ) {
- ++p;
- if ( LDAP_DIGIT( (unsigned char) p[1] )) {
- ++p;
- endwordnum = *p - '1'; /* e.g., "%v2-4" */
- if ( endwordnum > wordcount - 1 ) {
- endwordnum = wordcount - 1;
- }
- } else {
- endwordnum = wordcount - 1; /* e.g., "%v2-" */
- }
- } else {
- endwordnum = wordnum; /* e.g., "%v2" */
- }
-
- if ( wordcount > 0 ) {
- for ( i = wordnum; i <= endwordnum; ++i ) {
- if ( i > wordnum ) { /* add blank btw words */
- *f++ = ' ';
- }
- slen = strlen( valwords[ i ] );
- AC_MEMCPY( f, valwords[ i ], slen );
- f += slen;
- }
- }
- } else if ( *(p+1) == '$' ) {
- ++p;
- if ( wordcount > 0 ) {
- wordnum = wordcount - 1;
- slen = strlen( valwords[ wordnum ] );
- AC_MEMCPY( f, valwords[ wordnum ], slen );
- f += slen;
- }
- } else if ( value != NULL ) {
- slen = strlen( value );
- AC_MEMCPY( f, value, slen );
- f += slen;
- }
- } else if ( *p == 'a' && attr != NULL ) {
- slen = strlen( attr );
- AC_MEMCPY( f, attr, slen );
- f += slen;
- } else {
- *f++ = *p;
- }
- } else {
- *f++ = *p;
- }
-
- if ( (size_t) (f - filtbuf) > buflen ) {
- /* sanity check */
- --f;
- break;
- }
- }
-
- if ( suffix != NULL && ( (size_t) (f - filtbuf) < buflen ) )
- {
- strcpy( f, suffix );
- } else {
- *f = '\0';
- }
-}
-
-static int
-break_into_words( /* LDAP_CONST */ char *str, LDAP_CONST char *delims, char ***wordsp )
-{
- char *word, **words;
- int count;
- char *tok_r;
-
- if (( words = (char **)LDAP_CALLOC( 1, sizeof( char * ))) == NULL ) {
- return( -1 );
- }
- count = 0;
- words[ count ] = NULL;
-
- word = ldap_pvt_strtok( str, delims, &tok_r );
- while ( word != NULL ) {
- if (( words = (char **)LDAP_REALLOC( words,
- ( count + 2 ) * sizeof( char * ))) == NULL ) {
- return( -1 );
- }
-
- words[ count ] = word;
- words[ ++count ] = NULL;
- word = ldap_pvt_strtok( NULL, delims, &tok_r );
- }
-
- *wordsp = words;
- return( count );
-}
+++ /dev/null
-# $OpenLDAP$
-#
-# ldap filter file
-#
-# lines like this that start with # or empty lines are ignored
-#
-# syntax:
-#
-# <tag>
-# <pattern1> <delimiters> <filter1-1> <desc1-1> [<scope>]
-# <filter1-2> <desc1-2> [<scope>]
-#
-# <pattern2> <delimiters> <filter2-1> <desc2-1> [<scope>] ...
-#
-# The "desc" should describe the filter and it should correctly complete
-# both of the following phrases:
-#
-# One <desc> match was found for...
-# Three <desc> matches were found for...
-#
-# The scope is optional, and should be one of:
-# "base"
-# "onelevel"
-# "subtree"
-# if it is included.
-#
-
-"finger and ud and go500 and go500gw subtree and web500gw subtree and rp500 and rcpt500 and ufn last"
- "^$" "" "(objectclass=*)" "default filter"
- "=" " " "%v" "arbitrary filter"
-
- "^[0-9][0-9\-]*$" " " "(telephoneNumber=*%v)" "phone number"
-
- "@" " " "(mail=%v)" "email address"
- "(mail=%v*)" "start of email address"
-
- "^.[\. _].*" ". _" "(cn=%v1* %v2-)" "first initial"
-
- ".*[. _].$" ". _" "(cn=%v1-*)" "last initial"
-
- "[. _]" ". _" "(|(sn=%v1-)(cn=%v1-))" "exact"
- "(|(sn~=%v1-)(cn~=%v1-))" "approximate"
-
- ".*" ". " "(|(cn=%v1)(sn=%v1)(ou=%v1))" "exact"
- "(|(cn~=%v1)(sn~=%v1)(ou~=%v1))" "approximate"
-
-"go500gw onelevel and web500gw onelevel and ufn first and ufn intermediate"
- "^$" "" "(!(objectclass=dSA))" "default filter"
- "=" " " "%v" "arbitrary filter"
-
- "^..$" " " "(|(o=%v)(c=%v)(l=%v)(co=%v))" "exact2"
- "(|(o~=%v)(c~=%v)(l~=%v)(co~=%v))" "approximate2"
-
- " " " " "(|(o=%v)(l=%v)(co=%v)(ou=%v))" "exact"
- "(|(o~=%v)(l~=%v)(co~=%v)(ou~=%v))" "approximate"
-
- "\." " " "(associatedDomain=%v)" "exact"
-
- ".*" " " "(|(o=%v)(l=%v)(co=%v)(ou=%v))" "exact"
- "(|(o~=%v)(l~=%v)(co~=%v)(ou~=%v))" "approximate"
-
-
-#
-# xax500
-#
-
-"xax500"
- "=" " " "(%v)" "arbitrary filter"
-
- "^[0-9][0-9-]*$" " " "(telephoneNumber=*%v)" "phone number"
-
- "@" " " "(mail=%v)" "email address"
- "(mail=%v*)" "start of email address"
-
- "^.[. _].*" ". _" "(cn=%v1* %v2-)" "first initial"
-
- ".*[. _].$" ". _" "(cn=%v1-*)" "last initial"
-
- "[. _]" ". _" "(|(sn=%v1-)(cn=%v1-))" "exact"
- "(|(sn~=%v1-)(cn~=%v1-))" "approximate"
-
- ".*" ". " "(|(cn=%v1)(sn=%v1)(uid=%v1))" "exact"
- "(|(cn=%v1)(sn~=%v1))" "approximate"
-
-
-"xax500-auth"
- "=" " " "(%v)" "arbitrary filter"
-
- "^[0-9][0-9-]*$" " " "(telephoneNumber=*%v)" "phone number"
-
- "@" " " "(mail=%v)" "email address"
- "(mail=%v*)" "start of email address"
-
- "^.[. _].*" ". _" "(cn=%v1* %v2-)" "first initial"
-
- ".*[. _].$" ". _" "(cn=%v1-*)" "last initial"
-
- "[. _]" ". _" "(|(sn=%v1-)(cn=%v1-))" "exact"
- "(|(sn~=%v1-)(cn~=%v1-))" "approximate"
-
- ".*" ". " "(|(cn=%v1)(sn=%v1)(uid=%v1))" "exact"
- "(|(cn=%v1)(sn~=%v1))" "approximate"
-
-"list500"
- "[. _]" ". _" "(|(sn=%v1-)(cn=%v1-))" "exact"
- "(|(sn~=%v1-)(cn~=%v1-))" "approximate"
-
- ".*" ". " "(|(cn=%v1)(sn=%v1)(uid=%v1))" "exact"
- "(|(cn~=%v1)(sn~=%v1))" "approximate"
# End Source File
# Begin Source File
-SOURCE=.\dsparse.c
-# End Source File
-# Begin Source File
-
SOURCE=.\error.c
# End Source File
# Begin Source File
# End Source File
# Begin Source File
-SOURCE=.\getfilter.c
-# End Source File
-# Begin Source File
-
SOURCE=.\getvalues.c
# End Source File
# Begin Source File
bind.c open.c result.c error.c compare.c search.c \
controls.c messages.c references.c extended.c cyrus.c \
modify.c add.c modrdn.c delete.c abandon.c cache.c \
- getfilter.c sasl.c sbind.c kbind.c unbind.c \
- filter.c free.c dsparse.c sort.c \
+ sasl.c sbind.c kbind.c unbind.c \
+ filter.c free.c sort.c \
getdn.c getentry.c getattr.c getvalues.c addentry.c \
request.c os-ip.c url.c sortctrl.c vlvctrl.c \
init.c options.c print.c string.c util-int.c schema.c \
bind.lo open.lo result.lo error.lo compare.lo search.lo \
controls.lo messages.lo references.lo extended.lo cyrus.lo \
modify.lo add.lo modrdn.lo delete.lo abandon.lo cache.lo \
- getfilter.lo sasl.lo sbind.lo kbind.lo unbind.lo \
- filter.lo free.lo dsparse.lo sort.lo \
+ sasl.lo sbind.lo kbind.lo unbind.lo \
+ filter.lo free.lo sort.lo \
getdn.lo getentry.lo getattr.lo getvalues.lo addentry.lo \
request.lo os-ip.lo url.lo sortctrl.lo vlvctrl.lo \
init.lo options.lo print.lo string.lo util-int.lo schema.lo \
case REWRITE_MAP_XLDAPMAP: {
LDAP *ld;
- char filter[ LDAP_FILT_MAXSIZ ];
+ char filter[1024];
LDAPMessage *res = NULL, *entry;
LDAPURLDesc *lud = ( LDAPURLDesc * )map->lm_args;
int attrsonly = 0;