Zap ldapv2-only stuff

This commit is contained in:
Kurt Zeilenga 2002-08-10 00:20:45 +00:00
parent 301bd9056d
commit c6d5a774df
22 changed files with 2 additions and 10548 deletions

View file

@ -4,6 +4,5 @@
##
## Clients Makefile.in for OpenLDAP
SUBDIRS = tools ud
CLEANDIRS = mail500 maildap
SUBDIRS = tools

View file

@ -1,186 +0,0 @@
This is the README file for mail500, a mailer that does X.500 lookups
via LDAP.
If you are planning to run mail500 at your site, there are several
things you will have to tailor in main.c:
LDAPHOST - The host running an LDAP server
base[] - The array telling mail500 where/how to search for
things. See the explanation below.
*** WHAT mail500 DOES: ***
mail500 is designed to be invoked as a mailer (e.g., from sendmail),
similar to the way /bin/mail works. It takes a few required arguments
and then a list of addresses to deliver to. It expects to find the
message to deliver on its standard input. It looks up the addresses in
X.500 to figure out where to route the mail, and then execs sendmail to
do the actual delivery. It supports simple aliases, groups, and
mailing lists, the details of which are given below.
*** HOW IT WORKS (from the sendmail side): ***
The idea is that you might have a rule like this in your sendmail.cf
file somewhere in rule set 0:
R$*<@umich.edu>$* $#mail500$@umich.edu$:<$1>
This rule says that any address that ends in @umich.edu will cause
the mail500 mailer to be called to deliver the mail. You probably
also want to do something to prevent addresses like terminator!tim@umich.edu
or tim%terminator.rs.itd.umich.edu@umich.edu from being passed to mail500.
At U-M, we do this by adding rules like this to rule set 9 where we
strip off our local names:
R<@umich.edu>$*:$* $>10<@>$1:$2
R$+%$+<@umich.edu> $>10$1%$2<@>
R$+!$+<@umich.edu> $>10$1!$2<@>
See the sample sendmail.cf in this directory for more details.
The mail500 mailer should be defined similar to this in the
sendmail.cf file:
Mmail500, P=/usr/local/etc/mail500, F=DFMSmnXuh, A=mail500 -f $f -h $h -m $n@$w $u
This defines how mail500 will be treated by sendmail and what
arguments it will have when it's called. The various flags specified
by the F=... parameter are explained in your local sendmail book (with
any luck). The arguments to mail500 are as follows:
-f Who the mail is from. This will be used as the address
to which any errors should be sent (unless the address
specifies a mailing list - see below). Normally, sendmail
defines the $f macro to be the sender.
-h The domain for which the mail is destined. This is passed
in to mail500 via the $h macro, which is set by the
$@ metasymbol in the rule added to rule set 0 above.
It's normally used when searching for groups.
-m The mailer-daemon address. If errors have to be sent,
this is the address they will come from. $n is normally
set to mailer-daemon and $w is normally the local host
name.
The final argument $u is used to stand for the addresses to which to
deliver the mail.
*** HOW IT WORKS (from the mail500 side): ***
When mail500 gets invoked with one or more names to which to
deliver mail, it searches for each name in X.500. Where it searches,
and what kind(s) of search(es) it does are compile-time configurable
by changing the base array in main.c. For example, the configuration
we use at U-M is like this:
Base base[] =
{ "ou=People, o=University of Michigan, c=US", 0
"uid=%s", "cn=%s", NULL,
"ou=System Groups, ou=Groups, o=University of Michigan, c=US", 1
"(&(cn=%s)(associatedDomain=%h))", NULL, NULL,
"ou=User Groups, ou=Groups, o=University of Michigan, c=US", 1
"(&(cn=%s)(associatedDomain=%h))", NULL, NULL,
NULL
};
which means that in delivering mail to "name" mail500 would do the
the following searches, stopping if it found anything at any step:
Search (18) [2]: c=US@o=University of Michigan@ou=People
Search subtree (uid=name)
Search (18) [3]: c=US@o=University of Michigan@ou=People
Search subtree (cn=name)
Search (18) [4]: c=US@o=University of Michigan@ou=Groups@ou=System Groups
Search subtree & ((cn=name)(associatedDomain=umich.edu))
Search (18) [5]: c=US@o=University of Michigan@ou=Groups@ou=User Groups
Search subtree & ((cn=name)(associatedDomain=umich.edu))
Notice that when specifying a filter %s is replaced by the name,
or user portion of the address while %h is replaced by whatever is
passed in to mail500 via the -h option (typically the host portion
of the address).
You can also specify whether you want search results that matched
because the entry's RDN matched the search to be given preference
or not. At U-M, we only give such preference in the mail group
portion of the searches. Beware with this option: the algorithm
used to decide whether an entry's RDN matched the search is very
simple-minded, and may not always be correct.
There is currently no limit on the number of areas searched (the base
array can be as large as you want), and an arbitrary limit of 2 filters
for each base. If you want more than that, simply changing the 3 in
the typedef for Base should do the trick.
*** HOW IT WORKS (from the X.500 side): ***
In X.500, there are several new attribute types and one new object
class defined that mail500 makes use of. At its most basic, for normal
entries mail500 will deliver to the value(s) listed in the
rfc822Mailbox attribute of the entry. For example, at U-M my entry has
the attribute
mail= tim@terminator.rs.itd.umich.edu
So mail sent to tim@umich.edu will be delivered via mail500 to that
address. If there were multiple values for the mail attribute, multiple
copies of the mail would be sent.
A new object class, rfc822MailGroup, and several new attributes have
been defined to handle email groups/mailing lists. To use this, you
will need to add this to your local oidtable.oc:
# object class for representing rfc 822 mailgroups
rfc822MailGroup: umichObjectClass.2 : \
top : \
cn : \
rfc822Mailbox, member, memberOfGroup, owner, \
errorsTo, rfc822ErrorsTo, requestsTo, rfc822RequestsTo,
joinable, associatedDomain, \
description, multiLineDescription, \
userPassword, krbName, \
telecommunicationAttributeSet, postalAttributeSet
And you will need to add these to your local oidtable.at:
# attrs for rfc822mailgroups
multiLineDescription: umichAttributeType.2 : CaseIgnoreList
rfc822ErrorsTo: umichAttributeType.26 : CaseIgnoreIA5String
rfc822RequestsTo: umichAttributeType.27 : CaseIgnoreIA5String
joinable: umichAttributeType.28 : Boolean
memberOfGroup: umichAttributeType.29 : DN
errorsTo: umichAttributeType.30 : DN
requestsTo: umichAttributeType.31 : DN
The idea was to define a kind of hybrid mail group that could handle
people who were in X.500 or not. So, for example, members of a group
can be specified via the member attribute (for X.500 members) or the
rfc822MailBox attribute (for non-X.500 members). Similarly for the
errorsTo and rfc822ErrorsTo, and the requestsTo and rfc822RequestsTo
attributes.
To create a real mailing list, with a list maintainer, all you have to
do is create an rfc822MailGroup and fill in the errorsTo or
rfc822ErrorsTo attributes (or both). That will cause any errors
encountered when delivering mail to the group to go to the addresses
listed (or X.500 entry via it's mail attribute).
If you fill in the requestsTo or rfc822RequestsTo (or both) attributes,
mail sent to groupname-request will be sent to the addresses listed
there. mail500 does this automatically, so you don't have to explicitly
add the groupname-request alias to your group.
To allow users to join a group, there is the joinable flag. If TRUE,
mail500 will search for entries that have a memberOfGroup attribute
equal to the DN of the group, using the same algorithm it used to find
the group in the first place (i.e. the DNs and filters listed in the
base array). This allows people to join (or subscribe to) a group
without having to modify the group entry directly. If joinable is
FALSE, the search is not done.
Finally, keep in mind that this is somewhat experimental at the moment.
We are using it in production at U-M, but your mileage may vary...

File diff suppressed because it is too large Load diff

View file

@ -1,203 +0,0 @@
# Mostly rfc1123 compliant sendmail.cf
#
# Mail sendmail-admins-request@itd.umich.edu to join
# sendmail-admins@itd.umich.edu. sendmail-admins carries information
# regarding this sendmail.cf, including announcements of changes
# and discussions of interest to admins.
#
DWtotalrecall
Dw$W.rs.itd.umich.edu
DBcunyvm.cuny.edu
DUdestroyer.rs.itd.umich.edu
DV2.2
De$j sendmail ($v/$V) ready at $b
Dj$w
DlFrom $g $d
Dnmailer-daemon
Do.:%@!^=/[]
Dq$?x\"$x\" <$g>$|$g$.
OA/etc/aliases
OQ/var/spool/mqueue
OH/usr/lib/sendmail.hf
OS/usr/lib/sendmail.st
OP
OD
OX10
Ox5
Ou1
Og1
Odb
OF0600
OL9
Oo
Or15m
Os
OT3d
H?P?Return-Path: <$g>
HReceived: $?sfrom $s $.by $j ($v/$V)
$?rwith $r $.id $i; $b
H?D?Resent-Date: $a
H?F?Resent-From: $q
H?M?Resent-Message-Id: <$t.$i@$j>
H?M?Message-Id: <$t.$i@$j>
H?D?Date: $a
H?x?Full-Name: $x
H?F?From: $q
Troot uucp daemon
Pspecial-delivery=100
Pfirst-class=0
Pjunk=-100
# Organization:
#
# ruleset 3 and friends
# focus addresses, don't screw with them
# ruleset 0 and friends
# beat the hell out of addresses, convert them to
# their deliverable form
# mailers and associated rulesets
# * focused addresses are body addresses, and should be
# left as they are
# * unfocused addresses are envelope addresses, and should
# be converted to the mailers format
# ruleset 4
# remove focus on all addresses
# All addresses are passed through this rule. It functions by finding
# the host to delivery to, and marking it with <>
S3
R$*<$+>$* $2 remove comments
R$+:$*; $@ $1:$2; done if list
R$*@$+ $: $>5$1@$2 focus rfc822 addresses
R$+!$+ $: $>6$1!$2 focus uucp
R$*<@$+>$* $: $1<@$[$2$]>$3 canonicalize
R$*<$+>$* $@ $1<$2>$3 done if focused
R$+%$+ $: $1@$2 a%b -> a@b
R$+@$+%$+ $1%$2@$3 a@b%c -> a%b@c
R$+@$+ $: $>3$1@$2 try again...
# Find the "next hop" in normal rfc822 syntax. These rules
# all return upon marking the next hop with <>
S5
R@$+,@$+:$+ $@ <@$1>,@$2:$3 @a,@b:@c -> <@a>,@b:c
R@$+:$+ $@ <@$1>:$2 @a:b -> <@a>:b
R$+@$+ $@ $1<@$2> a@b -> a<@b>
# Focus bang style addresses. Won't change already focused addresses.
# Strips .uucp in bang paths, and converts domain syntax to rfc822 adresses.
S6
R$*<$+>$* $@ $1<$2>$3 already focused
R$+!$+ $: <$1!>$2 a!b -> <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

File diff suppressed because it is too large Load diff

View file

@ -1,427 +0,0 @@
/*
* Copyright (c) 1991, 1992 Regents of the University of Michigan.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to the University of Michigan at Ann Arbor. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
*/
#include <stdio.h>
#include <pwd.h>
#include <string.h>
#include <ctype.h>
#include <lber.h>
#include <ldap.h>
#include <ldapconfig.h>
#include "ud.h"
#ifdef KERBEROS
#include <sys/types.h>
#include <krb.h>
#endif
extern LDAP *ld; /* our LDAP descriptor */
extern int verbose; /* verbosity indicator */
extern char *mygetpass(); /* getpass() passwds are too short */
#ifdef DEBUG
extern int debug; /* debug flag */
#endif
#ifdef KERBEROS
static char tktpath[20]; /* ticket file path */
static int kinit();
static int valid_tgt();
#endif
auth(who, implicit)
char *who;
int implicit;
{
int rc; /* return code from ldap_bind() */
char *passwd = NULL; /* returned by mygetpass() */
char **rdns; /* for fiddling with the DN */
int authmethod;
int name_provided; /* was a name passed in? */
struct passwd *pw; /* for getting user id */
char uidname[20];
#ifdef KERBEROS
char **krbnames; /* for kerberos names */
int kinited, ikrb;
char buf[5];
extern int krb_debug;
#endif
LDAPMessage *mp; /* returned from find() */
static char prompt[MED_BUF_SIZE]; /* place for us to sprintf the prompt */
static char name[MED_BUF_SIZE]; /* place to store the user's name */
static char password[MED_BUF_SIZE]; /* password entered by user */
extern struct entry Entry; /* look here for a name if needed */
extern LDAPMessage *find(); /* for looking up 'name' */
extern char *search_base; /* for printing later */
extern char *default_bind_object; /* bind as this on failure */
extern void printbase(); /* used to pretty-print a base */
extern int bind_status;
extern void Free();
static void set_bound_dn();
#ifdef DEBUG
if (debug & D_TRACE)
fprintf(stderr, "auth(%s, NULL)\n", who);
#endif
name_provided = ( who != NULL );
/*
* The user needs to bind. If <who> is not specified, we
* assume that authenticating as user id is what user wants.
*/
if (who == NULL && implicit && (pw = getpwuid((uid_t)geteuid()))
!= (struct passwd *) NULL) {
sprintf(uidname, "uid=%s", pw->pw_name);
/* who = pw->pw_name; /* */
who = uidname;
}
if ( who == NULL ) {
if ( implicit )
printf( "You must first authenticate yourself to the Directory.\n" );
#ifdef UOFM
printf(" What is your name or uniqname? ");
#else
printf(" What is your name or user id? ");
#endif
fflush(stdout);
fetch_buffer(name, sizeof(name), stdin);
if (name[0] == '\0')
return( -1 );
who = name;
}
#ifdef DEBUG
if (debug & D_AUTHENTICAT)
printf(" Authenticating as \"%s\"\n", who);
#endif
/*
* Bail out if the name is bogus. If not, strip off the junk
* at the start of the DN, build a prompt, and get a password
* from the user. Then perform the ldap_bind().
*/
if ((mp = find(who, TRUE)) == NULL) {
(void) ldap_msgfree(mp);
printf(" I could not find \"%s\" in the Directory.\n", who);
printf(" I used a search base of ");
printbase("", search_base);
printf("\n");
#ifdef DEBUG
if (debug & D_AUTHENTICAT)
printf(" Could not find \"%s\"\n", who);
#endif
return(-1);
}
/*
* Fill in the Entry structure. May be handy later.
*/
(void) parse_answer(mp);
rdns = ldap_explode_dn(Entry.DN, TRUE);
printf(" Authenticating to the directory as \"%s\"...\n", *rdns );
#ifdef KERBEROS
/*
* First, if the user has a choice of auth methods, ask which
* one they want to use. if they want kerberos, ask which
* krbname they want to bind as.
*/
if ( (krbnames = ldap_get_values( ld, mp, "krbName" )) != NULL ) {
int choice, hassimple;
hassimple = (ldap_compare_s( ld, Entry.DN,
"userPassword", "x" ) == LDAP_COMPARE_FALSE);
(void) ldap_msgfree(mp);
/* if we're running as a server (e.g., out of inetd) */
if ( ! isatty( 1 ) ) {
strcpy( tktpath, "/tmp/ud_tktXXXXXX" );
mktemp( tktpath );
krb_set_tkt_string( tktpath );
}
kinited = valid_tgt( krbnames );
if ( hassimple && !kinited ) {
printf(" Which password would you like to use?\n");
printf(" 1 -> X.500 password\n");
#ifdef UOFM
printf(" 2 -> UMICH password (aka Uniqname or Kerberos password)\n");
#else
printf(" 2 -> Kerberos password\n");
#endif
do {
printf(" Enter 1 or 2: ");
fflush(stdout);
fetch_buffer(buf, sizeof(buf), stdin);
choice = atoi(buf);
} while (choice != 1 && choice != 2);
authmethod = (choice == 1 ? LDAP_AUTH_SIMPLE :
LDAP_AUTH_KRBV4);
} else {
authmethod = LDAP_AUTH_KRBV4;
}
} else {
authmethod = LDAP_AUTH_SIMPLE;
(void) ldap_msgfree(mp);
}
/*
* if they are already kinited, we don't need to ask for a
* password.
*/
if ( authmethod == LDAP_AUTH_KRBV4 ) {
if ( ! kinited ) {
if ( krbnames[1] != NULL ) {
int i;
/* ask which one to use */
#ifdef UOFM
printf(" Which UMICH (aka Kerberos or uniqname) name would you like to use?\n");
#else
printf(" Which Kerberos name would you like to use?\n");
#endif
for ( i = 0; krbnames[i] != NULL; i++ ) {
printf( " %d -> %s\n", i + 1,
krbnames[i] );
}
do {
printf(" Enter a number between 1 and %d: ", i );
fflush( stdout );
fetch_buffer(buf, sizeof(buf), stdin);
ikrb = atoi(buf) - 1;
} while ( ikrb > i - 1 || ikrb < 0 );
} else {
ikrb = 0;
}
/* kinit */
if ( kinit( krbnames[ikrb] ) != 0 ) {
(void) ldap_value_free(rdns);
(void) ldap_value_free(krbnames);
return(-1);
}
}
} else {
#endif
authmethod = LDAP_AUTH_SIMPLE;
sprintf(prompt, " Enter your X.500 password: ");
do {
passwd = mygetpass(prompt);
} while (passwd != NULL && *passwd == '\0');
if (passwd == NULL) {
(void) ldap_value_free(rdns);
return(0);
}
#ifdef KERBEROS
}
(void) ldap_value_free(krbnames);
#endif
ldap_flush_cache( ld );
rc = ldap_bind_s(ld, Entry.DN, passwd, authmethod);
if (rc != LDAP_SUCCESS) {
if (ld->ld_errno == LDAP_NO_SUCH_ATTRIBUTE)
fprintf(stderr, " Entry has no password\n");
else if (ld->ld_errno == LDAP_INVALID_CREDENTIALS)
#ifdef KERBEROS
if ( authmethod == LDAP_AUTH_KRBV4 ) {
fprintf(stderr, " The Kerberos credentials are invalid.\n");
} else {
#endif
fprintf(stderr, " The password you provided is incorrect.\n");
#ifdef KERBEROS
}
#endif
else
ldap_perror(ld, "ldap_bind_s" );
(void) ldap_bind_s(ld, default_bind_object,
(char *) UD_PASSWD, LDAP_AUTH_SIMPLE);
if (default_bind_object == NULL)
set_bound_dn(NULL);
else
set_bound_dn(default_bind_object);
bind_status = UD_NOT_BOUND;
if (verbose)
printf(" Authentication failed.\n\n");
(void) ldap_value_free(rdns);
return(-1);
}
else if (verbose)
printf(" Authentication successful.\n\n");
else
printf("\n");
set_bound_dn(Entry.DN);
bind_status = UD_BOUND;
if (passwd != NULL)
(void) strcpy(password, passwd);
(void) ldap_value_free(rdns);
return(0);
}
#ifdef KERBEROS
#define FIVEMINS ( 5 * 60 )
#define TGT "krbtgt"
str2upper( s )
char *s;
{
char *p;
for ( p = s; *p != '\0'; ++p ) {
if ( islower( *p )) {
*p = toupper( *p );
}
}
}
static valid_tgt( names )
char **names;
{
int i;
char name[ ANAME_SZ ], inst[ INST_SZ ], realm[ REALM_SZ ];
CREDENTIALS cred;
for ( i = 0; names[i] != NULL; i++ ) {
if ( kname_parse( name, inst, realm, names[i] ) != KSUCCESS ) {
fprintf( stderr, "Bad format for krbName %s\n",
names[i] );
fprintf( stderr, "Contact x500@umich.edu\n" );
return( 0 );
}
#ifdef AFSKERBEROS
/*
* realm must be uppercase for krb_ routines
*/
str2upper( realm );
#endif /* AFSKERBEROS */
/*
* check ticket file for a valid ticket granting ticket
* my check is: have ticket granting ticket and it is good for
* at least 5 more minutes
*/
if ( krb_get_cred( TGT, realm, realm,
&cred ) == KSUCCESS && time( 0 ) + FIVEMINS <
cred.issue_date + (u_char)cred.lifetime * FIVEMINS ) {
return( 1 );
}
}
return( 0 );
}
static char *kauth_name;
/*ARGSUSED*/
int
krbgetpass( user, inst, realm, pw, key )
char *user, *inst, *realm, *pw;
C_Block key;
{
char *p, lcrealm[ REALM_SZ ], prompt[256], *passwd;
#ifdef UOFM
sprintf(prompt, " Enter the UMICH password (same as Uniqname or Kerberos password)\n for %s: ", kauth_name );
#else
sprintf(prompt, " Enter Kerberos password for %s: ", kauth_name );
#endif
do {
passwd = mygetpass(prompt);
} while (passwd != NULL && *passwd == '\0');
if (passwd == NULL) {
return(-1);
}
#ifdef AFSKERBEROS
strcpy( lcrealm, realm );
for ( p = lcrealm; *p != '\0'; ++p ) {
if ( isupper( *p )) {
*p = tolower( *p );
}
}
ka_StringToKey( passwd, lcrealm, key );
#else /* AFSKERBEROS */
string_to_key( passwd, key );
#endif /* AFSKERBEROS */
return( 0 );
}
static kinit( kname )
char *kname;
{
int rc;
char name[ ANAME_SZ ], inst[ INST_SZ ], realm[ REALM_SZ ];
kauth_name = kname;
if ( kname_parse( name, inst, realm, kname ) != KSUCCESS ) {
fprintf( stderr, "Bad format for krbName %s\n",
kname );
fprintf( stderr, "Contact x500@umich.edu\n" );
return( -1 );
}
#ifdef AFSKERBEROS
/*
* realm must be uppercase for krb_ routines
*/
str2upper( realm );
#endif /* AFSKERBEROS */
rc = krb_get_in_tkt( name, inst, realm, TGT, realm,
DEFAULT_TKT_LIFE, krbgetpass, NULL, NULL );
if ( rc != KSUCCESS ) {
switch ( rc ) {
case SKDC_CANT:
fprintf( stderr, "Can't contact Kerberos server for %s\n", realm );
break;
default:
fprintf( stderr, "%s: %s\n", name, krb_err_txt[ rc ] );
break;
}
return( -1 );
}
return( 0 );
}
destroy_tickets()
{
if ( *tktpath != '\0' ) {
unlink( tktpath );
}
}
#endif
static void set_bound_dn(s)
char *s;
{
extern void Free();
extern char *bound_dn;
if (bound_dn != NULL)
Free(bound_dn);
bound_dn = strdup(s);
}

View file

@ -1,453 +0,0 @@
/*
* Copyright (c) 1994 Regents of the University of Michigan.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to the University of Michigan at Ann Arbor. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <signal.h>
#include <lber.h>
#include <ldap.h>
#include <ldapconfig.h>
#include "ud.h"
extern struct entry Entry;
extern int verbose;
extern LDAP *ld;
extern LDAPMessage *find();
static char *entry_temp_file;
#ifdef DEBUG
extern int debug;
#endif
edit(who)
char *who;
{
LDAPMessage *mp; /* returned from find() */
char *dn, **rdns; /* distinguished name */
char name[MED_BUF_SIZE]; /* entry to modify */
extern int bind_status;
static int load_editor();
static int write_entry();
#ifdef DEBUG
if (debug & D_TRACE)
printf("->edit(%s)\n", who);
#endif
/*
* One must be bound in order to edit an entry.
*/
if (bind_status == UD_NOT_BOUND) {
if (auth((char *) NULL, 1) < 0)
return;
}
/*
* First, decide what entry we are going to modify. If the
* user has not included a name on the modify command line,
* we will use the person who was last looked up with a find
* command. If there is no value there either, we don't know
* who to modify.
*
* Once we know who to modify, be sure that they exist, and
* parse out their DN.
*/
if (who == NULL) {
if (verbose) {
printf(" Enter the name of the person or\n");
printf(" group whose entry you want to edit: ");
}
else
printf(" Edit whose entry? ");
fflush(stdout);
fetch_buffer(name, sizeof(name), stdin);
if (name[0] != '\0')
who = name;
else
return;
}
if ((mp = find(who, TRUE)) == NULL) {
(void) ldap_msgfree(mp);
printf(" Could not locate \"%s\" in the Directory.\n", who);
return;
}
dn = ldap_get_dn(ld, ldap_first_entry(ld, mp));
rdns = ldap_explode_dn(dn, TRUE);
Free(dn);
if (verbose) {
printf("\n Editing directory entry \"%s\"...\n", *rdns);
}
parse_answer(mp);
(void) ldap_msgfree(mp);
(void) ldap_value_free(rdns);
if (load_editor() < 0)
return;
(void) write_entry();
(void) unlink(entry_temp_file);
ldap_uncache_entry(ld, Entry.DN);
return;
}
static load_editor()
{
FILE *fp;
char *cp, *editor = UD_DEFAULT_EDITOR;
static char template[MED_BUF_SIZE];
extern char * mktemp();
extern int isgroup(), fatal();
static int print_attrs_and_values();
int pid;
int status;
int rc;
void (*handler)();
#ifdef DEBUG
if (debug & D_TRACE)
printf("->load_editor()\n");
#endif
/* write the entry into a temp file */
(void) strcpy(template, "/tmp/udEdit.XXXXXX");
if ((entry_temp_file = mktemp(template)) == NULL) {
perror("mktemp");
return(-1);
}
if ((fp = fopen(entry_temp_file, "w")) == NULL) {
perror("fopen");
return(-1);
}
fprintf(fp, "## Directory entry of %s\n", Entry.name);
fprintf(fp, "##\n");
fprintf(fp, "## Syntax is:\n");
fprintf(fp, "## <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, '/' )) == NULL ) {
p = editor;
} else {
++p;
}
printf(" Using %s as the editor...\n", p );
sleep(2);
}
if ((pid = fork()) == 0) {
/* child - edit the Directory entry */
(void) signal(SIGINT, SIG_IGN);
(void) execlp(editor, editor, entry_temp_file, NULL);
/*NOTREACHED*/
(void) fatal(editor);
}
else if (pid > 0) {
/* parent - wait until the child proc is done editing */
handler = signal(SIGINT, SIG_IGN);
(void) wait(&status);
(void) signal(SIGINT, handler);
}
else {
fatal("fork");
/*NOTREACHED*/
}
return(0);
}
static int print_attrs_and_values(fp, attrs, flag)
FILE *fp;
struct attribute attrs[];
short flag;
{
static int modifiable();
register int i, j;
for (i = 0; attrs[i].quipu_name != NULL; i++) {
if (!modifiable(attrs[i].quipu_name, flag|ATTR_FLAG_MAY_EDIT))
continue;
fprintf(fp, "%s\n", attrs[i].quipu_name);
if ( attrs[i].number_of_values > MAX_VALUES ) {
printf(" The %s attribute has more than %d values.\n",
attrs[i].quipu_name, MAX_VALUES );
printf(" You cannot use the vedit command on this entry. Sorry!\n" );
return( -1 );
}
for (j = 0; j < attrs[i].number_of_values; j++)
fprintf(fp, "\t%s\n", attrs[i].values[j]);
}
return( 0 );
}
static modifiable(s, flag)
char *s;
short flag;
{
register int i;
extern struct attribute attrlist[];
for (i = 0; attrlist[i].quipu_name != NULL; i++) {
if (strcasecmp(s, attrlist[i].quipu_name))
continue;
if ((attrlist[i].flags & flag) == ATTR_FLAG_NONE)
return(FALSE);
return(TRUE);
}
/* should never be here */
return(FALSE);
}
static write_entry()
{
int i = 0, j, number_of_values = -1;
FILE *fp;
char *cp, line[LARGE_BUF_SIZE], *values[MAX_VALUES], **vp;
LDAPMod *mods[MAX_ATTRS + 1];
LDAPMod *modp = NULL;
static int ovalues();
extern char * code_to_str();
extern void free_mod_struct();
/* parse the file and write the values to the Directory */
if ((fp = fopen(entry_temp_file, "r")) == NULL) {
perror("fopen");
return;
}
for (;;) {
(void) fgets(line, sizeof(line), fp);
if (feof(fp))
break;
line[strlen(line) - 1] = '\0'; /* kill newline */
cp = line;
if (*cp == '#')
continue;
if (isspace(*cp)) { /* value */
while (isspace(*cp))
cp++;
values[number_of_values++] = strdup(cp);
if ( number_of_values >= MAX_VALUES ) {
printf(" A maximum of %d values can be handled at one time. Sorry!\n", MAX_VALUES );
return;
}
continue;
}
/* attribute */
while (isspace(*cp))
cp++;
/*
* If the number of values is greater than zero, then we
* know that this is not the first time through this
* loop, and we also know that we have a little bit
* of work to do:
*
* o The modify operation needs to be changed from
* a DELETE to a REPLACE
*
* o The list of values pointer needs to be changed
* from NULL, to a NULL-terminated list of char
* pointers.
*/
if (number_of_values > 0) {
modp->mod_op = LDAP_MOD_REPLACE;
if ((vp = (char **) Malloc(sizeof(char *) * (number_of_values + 2))) == (char **) NULL) {
fatal("Malloc");
/*NOTREACHED*/
}
modp->mod_values = vp;
for (j = 0; j < number_of_values; j++) {
*vp++ = strdup(values[j]);
(void) Free(values[j]);
}
*vp = NULL;
}
/*
* If there are no values, and there were no values to begin
* with, then there is nothing to do.
*/
if ((number_of_values == 0) && (ovalues(modp->mod_type) == 0)) {
#ifdef DEBUG
if (debug & D_MODIFY)
printf(" %s has zero values - skipping\n",
modp->mod_type);
#endif
(void) Free(modp->mod_type);
modp->mod_type = strdup(cp);
modp->mod_op = LDAP_MOD_DELETE;
modp->mod_values = NULL;
continue;
}
/*
* Fetch a new modify structure.
*
* Assume a DELETE operation with no values.
*/
if ((modp = (LDAPMod *) Malloc(sizeof(LDAPMod))) == NULL) {
fatal("Malloc");
/*NOTREACHED*/
}
modp->mod_values = NULL;
modp->mod_type = strdup(cp);
modp->mod_op = LDAP_MOD_DELETE;
mods[i++] = modp;
number_of_values = 0;
}
fclose(fp);
/* check the last one too */
if (number_of_values > 0) {
modp->mod_op = LDAP_MOD_REPLACE;
/*
* Fetch some value pointers.
*
* number_of_values To store the values
* 1 For the NULL terminator
* 1 In case we need it to store
* the RDN as on of the values
* of 'cn' in case it isn't there
*/
if ((vp = (char **) Malloc(sizeof(char *) * (number_of_values +
2))) == (char **) NULL) {
fatal("Malloc");
/*NOTREACHED*/
}
modp->mod_values = vp;
for (j = 0; j < number_of_values; j++) {
*vp++ = strdup(values[j]);
(void) Free(values[j]);
}
*vp = NULL;
}
else if ((number_of_values == 0) &&
(ovalues(mods[i - 1]->mod_type) == 0)) {
#ifdef DEBUG
if (debug & D_MODIFY)
printf(" %s has zero values - skipping\n",
mods[i - 1]->mod_type);
#endif
Free(mods[i - 1]->mod_type);
Free(mods[i - 1]);
i--;
}
mods[i] = (LDAPMod *) NULL;
/*
* If one of the mods pointers is 'cn', be sure that the RDN is one
* of the values.
*/
for (j = 0; j < i; j++) {
if (strcasecmp("cn", mods[j]->mod_type))
continue;
/*
* True only if there WERE values, but the person deleted
* them all.
*/
if (mods[j]->mod_values == NULL) {
mods[j]->mod_op = LDAP_MOD_REPLACE;
if ((vp = (char **) Malloc(sizeof(char *) * 2)) == (char **) NULL) {
fatal("Malloc");
/*NOTREACHED*/
}
mods[j]->mod_values = vp;
*vp++ = strdup(Entry.name);
*vp = NULL;
break;
}
/*
* Be sure that one of the values of 'cn' is the RDN.
*/
for (vp = mods[j]->mod_values; *vp != NULL; vp++) {
if (strcasecmp(*vp, Entry.DN))
continue;
break;
}
if (*vp == NULL) {
*vp++ = strdup(Entry.name);
*vp = NULL;
break;
}
}
#ifdef DEBUG
if (debug & D_MODIFY) {
register int x, y;
printf(" ld = 0x%x\n", ld);
printf(" dn = [%s]\n", Entry.DN);
for (x = 0; mods[x] != (LDAPMod *) NULL; x++) {
printf(" mods[%d]->mod_op = %s\n",
x, code_to_str(mods[x]->mod_op));
printf(" mods[%d]->mod_type = %s\n",
x, mods[x]->mod_type);
if (mods[x]->mod_values == NULL)
printf(" mods[%d]->mod_values = NULL\n", x);
else {
for (y = 0; mods[x]->mod_values[y] != NULL; y++)
printf(" mods[%d]->mod_values[%1d] = %s\n",
x, y, mods[x]->mod_values[y]);
printf(" mods[%d]->mod_values[%1d] = NULL\n",
x, y);
}
printf("\n");
}
}
#endif
if (ldap_modify_s(ld, Entry.DN, mods))
mod_perror(ld);
else
printf(" Modification complete.\n" );
/* clean up */
for (i = 0; mods[i] != NULL; i++)
free_mod_struct(mods[i]);
return;
}
static ovalues(attr)
char *attr;
{
struct attribute *ap;
/*
* Lookup the attribute with quipu_name 'attr' in the Entry
* structure and return the number of values.
*/
for (ap = Entry.attrs; ap->quipu_name != NULL; ap++) {
if (!strcasecmp(ap->quipu_name, attr))
return(ap->number_of_values);
}
/* should never get to this point unless 'attr' was something odd */
return(0);
}

View file

@ -1,2 +0,0 @@
server <your ldap server host name here>
base <your X.500 default search base here>

View file

@ -1,496 +0,0 @@
/*
* Copyright (c) 1991, 1992, 1993
* Regents of the University of Michigan. All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to the University of Michigan at Ann Arbor. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#ifndef __STDC__
#include <memory.h>
#endif
#include <lber.h>
#include <ldap.h>
#include "ud.h"
extern char *search_base; /* search base */
extern int verbose; /* verbose mode flag */
extern LDAP *ld; /* our ldap descriptor */
static int num_picked = 0; /* used when user picks entry at More prompt */
#ifdef DEBUG
extern int debug; /* debug flag */
#endif
vrfy(dn)
char *dn;
{
LDAPMessage *results;
static char *attrs[2] = { "objectClass", NULL };
#ifdef DEBUG
if (debug & D_TRACE)
printf("->vrfy(%s)\n", dn);
#endif
/* verify that this DN exists in the directory */
(void) ldap_search_s(ld, dn, LDAP_SCOPE_BASE, "objectClass=*", attrs, TRUE, &results);
(void) ldap_msgfree(results);
if ((ld->ld_errno == LDAP_NO_SUCH_OBJECT) || (ld->ld_errno == LDAP_INVALID_DN_SYNTAX))
return(0);
else if (ld->ld_errno == LDAP_SUCCESS)
return(1);
else {
ldap_perror(ld, "ldap_search");
return(0);
}
}
static LDAPMessage * disambiguate( result, matches, read_attrs, who )
LDAPMessage *result;
int matches;
char **read_attrs;
char *who;
{
int choice; /* entry that user chooses */
int i;
char *namelist[MAX_NUM_NAMES]; /* names found */
char response[SMALL_BUF_SIZE]; /* results from user */
char *name = NULL; /* DN to lookup */
LDAPMessage *mp;
extern void Free();
#ifdef DEBUG
if (debug & D_TRACE)
printf("->disambiguate(%x, %d, %x, %s)\n", result, matches,
read_attrs, who);
#endif
/*
* If we are here, it means that we got back multiple answers.
*/
if ((ld->ld_errno == LDAP_TIMELIMIT_EXCEEDED)
|| (ld->ld_errno == LDAP_SIZELIMIT_EXCEEDED)) {
if (verbose) {
printf(" Your query was too general and a limit was exceeded. The results listed\n");
printf(" are not complete. You may want to try again with a more refined query.\n\n");
}
else
printf(" Time or size limit exceeded. Partial results follow.\n\n");
}
printf(" %1d names matched \"%s\".\n", matches, who);
for (;;) {
printf(" Do you wish to see a list of names? ");
fflush(stdout);
(void) memset(response, 0, sizeof(response));
fetch_buffer(response, sizeof(response), stdin);
switch (response[0]) {
case 'n' :
case 'N' :
case '\0' :
case '\n' :
return(NULL);
/* NOTREACHED */
case 'y' :
case 'Y' :
print_list(result, namelist, &matches);
if (num_picked == 0)
choice = pick_one(matches);
else
choice = num_picked;
num_picked = 0;
if (choice >= 0)
name = strdup(namelist[choice]);
/*
* Now free up all of the pointers allocated in
* namelist. The print_list() routine that filled
* in this collection of strings starts at 1, not 0.
*/
for (i = 1; namelist[i] != NULL; i++)
Free(namelist[i]);
if (choice < 0) {
if (name != NULL)
Free(name);
return(NULL);
}
#ifdef DEBUG
if (debug & D_FIND) {
printf(" Calling ldap_search_s()\n");
printf(" ld = 0x%x\n", ld);
printf(" search base = %s\n", name);
printf(" scope = LDAP_SCOPE_BASE\n");
printf(" filter = objectClass=*\n");
for (i = 0; read_attrs[i] != NULL; i++)
printf(" read_attrs[%d] = %s\n", i, read_attrs[i]);
printf(" read_attrs[%d] = NULL\n", i);
printf(" attrsonly = FALSE\n");
printf(" &mp = 0x%x\n", &mp);
}
#endif
if (ldap_search_s(ld, name, LDAP_SCOPE_BASE, "objectClass=*", read_attrs, FALSE, &mp) != LDAP_SUCCESS) {
ldap_perror(ld, "ldap_search_s");
Free(name);
ldap_msgfree(mp);
return(NULL);
}
Free(name);
return(mp);
/* NOTREACHED */
default :
printf(" Please enter 'y', 'n', or RETURN.\n");
break;
}
}
}
LDAPMessage * find(who, quiet)
char *who;
int quiet;
{
register int i, j, k; /* general ints */
int matches; /* from ldap_count_entries() */
int admonished = FALSE;
static int attrs_set = 0;
static char *read_attrs[MAX_ATTRS]; /* attrs to use in a read op */
static char *search_attrs[MAX_ATTRS]; /* attrs to use in a srch op */
static int rc; /* return from ldap_search */
LDAPMessage *ldtmp, *res; /* results returned from search */
char name[MED_BUF_SIZE];
char response[SMALL_BUF_SIZE];
char *cp, *dn, **rdns;
LDAPFiltInfo *fi;
extern LDAPFiltDesc *lfdp; /* LDAP filter descriptor */
extern struct attribute attrlist[]; /* complete list of attrs */
extern void Free();
#ifdef DEBUG
if (debug & D_TRACE)
fprintf(stderr, "->find(%s)\n", who);
#endif
/* did not specify a 'who' */
if (who == NULL) {
printf(" Locate whose entry? ");
fflush(stdout);
fetch_buffer(name, sizeof(name), stdin);
if (name[0] != '\0')
who = name;
else
return(NULL);
}
if (attrs_set == 0) {
j = k = 0;
attrs_set = 1;
for (i = 0; attrlist[i].quipu_name != NULL; i++) {
if (attrlist[i].flags & ATTR_FLAG_READ)
read_attrs[j++] = attrlist[i].quipu_name;
if (attrlist[i].flags & ATTR_FLAG_SEARCH)
search_attrs[k++] = attrlist[i].quipu_name;
}
read_attrs[j] = NULL;
search_attrs[k] = NULL;
}
/*
* If the user-supplied name has any commas in it, we
* assume that it is a UFN, and do everything right
* here. If we don't find it, treat it as NOT a UFN.
*/
if (strchr(who, ',') != NULL) {
int savederef;
#ifdef DEBUG
if (debug & D_FIND)
printf("\"%s\" appears to be a UFN\n", who);
#endif
savederef = ld->ld_deref;
ld->ld_deref = LDAP_DEREF_FINDING;
if ((rc = ldap_ufn_search_s(ld, who, search_attrs, FALSE, &res)) !=
LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED &&
rc != LDAP_TIMELIMIT_EXCEEDED) {
ldap_perror(ld, "ldap_ufn_search_s");
ld->ld_deref = savederef;
return(NULL);
}
if ((matches = ldap_count_entries(ld, res)) < 0) {
ldap_perror(ld, "ldap_count_entries");
ld->ld_deref = savederef;
return(NULL);
} else if (matches == 1) {
if (ldap_search_s(ld, ldap_get_dn(ld, ldap_first_entry(ld, res)), LDAP_SCOPE_BASE, "objectClass=*", read_attrs, FALSE, &res) != LDAP_SUCCESS) {
if (ld->ld_errno == LDAP_UNAVAILABLE)
printf(" Could not contact the X.500 server to find \"%s\".\n", who);
else
ldap_perror(ld, "ldap_search_s");
return(NULL);
}
ld->ld_deref = savederef;
return(res);
} else if (matches > 1 ) {
return( disambiguate( ld, res, matches, read_attrs,
who ) );
}
ld->ld_deref = savederef;
}
/*
* Old users of the MTS *USERDIRECTORY will likely wrap the name
* in quotes. Not only is this unnecessary, but it also won't work.
*/
for (cp = strchr(who, '"'); cp != NULL; cp = strchr(cp, '"')) {
if (!admonished) {
printf(" You do not need to enclose names in quotes.\n");
admonished = TRUE;
}
*cp++ = ' ';
if (*cp == '\0')
break;
}
/*
* It wasn't a UFN, so look it up in the usual method.
*/
for (fi = ldap_getfirstfilter(lfdp, "ud", who); fi != NULL;
fi = ldap_getnextfilter(lfdp)) {
#ifdef DEBUG
if (debug & D_FIND)
printf("Searching, filter = %s\n", fi->lfi_filter);
#endif
if ((rc = ldap_search_s(ld, search_base, fi->lfi_scope,
fi->lfi_filter, search_attrs, FALSE, &res)) != LDAP_SUCCESS &&
rc != LDAP_SIZELIMIT_EXCEEDED && rc != LDAP_TIMELIMIT_EXCEEDED) {
ldap_perror(ld, "ldap_search_s");
ldap_msgfree(res);
return(NULL);
}
if ((matches = ldap_count_entries(ld, res)) < 0) {
ldap_perror(ld, "ldap_count_entries");
ldap_msgfree(res);
return(NULL);
}
else if (matches == 1) {
dn = ldap_get_dn(ld, ldap_first_entry(ld, res));
ldap_msgfree(res);
if (!quiet)
printf(" Found one %s match for \"%s\"\n",
fi->lfi_desc, who);
if (!fi->lfi_isexact) {
rdns = ldap_explode_dn(dn, TRUE);
printf(" Do you mean %s? ", *rdns);
(void) ldap_value_free(rdns);
fflush(stdout);
fetch_buffer(response, sizeof(response), stdin);
if ((response[0] == 'n') || (response[0] == 'N'))
return(NULL);
}
#ifdef DEBUG
if (debug & D_FIND) {
printf(" Calling ldap_search_s()\n");
printf(" ld = 0x%x\n", ld);
printf(" dn = %s\n", dn);
printf(" scope = LDAP_SCOPE_BASE\n");
printf(" filter = %s\n", "objectClass=*");
for (i = 0; read_attrs[i] != NULL; i++)
printf(" read_attrs[%d] = %s\n", i, read_attrs[i]);
printf(" read_attrs[%d] = NULL\n", i);
printf(" attrsonly = FALSE\n");
printf(" &results = 0x%x\n", &res);
}
#endif
if (ldap_search_s(ld, dn, LDAP_SCOPE_BASE, "objectClass=*", read_attrs, FALSE, &res) != LDAP_SUCCESS) {
ldap_perror(ld, "ldap_search_s");
ldap_msgfree(res);
return(NULL);
}
Free(dn);
return(res);
}
else if (matches > 0) {
ldtmp = disambiguate(res, matches, read_attrs, who);
ldap_msgfree(res);
return(ldtmp);
}
/* if we're here, there were zero matches */
ldap_msgfree(res);
}
return(NULL);
}
pick_one(i)
int i;
{
int n;
char user_pick[SMALL_BUF_SIZE];
#ifdef DEBUG
if (debug & D_TRACE)
printf("->pick_one(%d)\n", i);
#endif
/* make the user pick an entry */
for (;;) {
printf(" Enter the number of the name you want or Q to quit: ");
fflush(stdout);
fetch_buffer(user_pick, sizeof(user_pick), stdin);
if (user_pick[0] == 'q' || user_pick[0] == 'Q')
return(-1);
n = atoi(user_pick);
if ((n > 0) && (n <= i))
return(n);
printf(" Invalid response\n");
}
/* NOTREACHED */
}
print_list(list, names, matches)
LDAPMessage *list;
char *names[];
int *matches;
{
char **rdns, **cpp;
extern int lpp;
char resp[SMALL_BUF_SIZE];
register LDAPMessage *ep;
register int i = 1;
register int rest = 4; /* 4, not 1 */
#ifdef DEBUG
if (debug & D_TRACE)
printf("->print_list(%x, %x, %x)\n", list, names, matches);
#endif
/* print a list of names from which the user will select */
for (ep = ldap_first_entry(ld, list); ep != NULL; ep = ldap_next_entry(ld, ep)) {
names[i] = ldap_get_dn(ld, ep);
rdns = ldap_explode_dn(names[i], TRUE);
cpp = ldap_get_values(ld, ep, "title");
if (cpp == NULL)
printf(" %3d. %s\n", i, *rdns);
else
printf(" %3d. %s, %s\n", i, *rdns, *cpp);
ldap_value_free(rdns);
ldap_value_free(cpp);
i++;
if ((rest++ > (lpp - 1)) && (i < *matches)) {
again:
printf(" More? ");
fflush(stdout);
fetch_buffer(resp, sizeof(resp), stdin);
if ((resp[0] == 'n') || (resp[0] == 'N'))
break;
else if ((num_picked = atoi(resp)) != 0) {
if (num_picked < i)
break;
else
goto again;
}
rest = 1;
}
}
*matches = i - 1;
names[i] = NULL;
return;
}
find_all_subscribers(sub, group)
char *sub[];
char *group;
{
int count;
LDAPMessage *result;
static char *attributes[] = { "cn", NULL };
char filter[MED_BUF_SIZE];
register LDAPMessage *ep;
register int i = 0;
#ifdef DEBUG
if (debug & D_TRACE)
printf("->find_all_subscribers(%x, %s)\n", sub, group);
#endif
sprintf(filter, "%s=%s", "memberOfGroup", group);
if (ldap_search_s(ld, search_base, LDAP_SCOPE_SUBTREE, filter, attributes, FALSE, &result) != LDAP_SUCCESS) {
if (ld->ld_errno == LDAP_NO_SUCH_ATTRIBUTE)
return(0);
ldap_perror(ld, "ldap_search_s");
return(0);
}
count = ldap_count_entries(ld, result);
if (count < 1) {
ldap_msgfree(result);
return(0);
}
if ( count > MAX_VALUES ) {
printf( " Only retrieving the first %d subscribers....\n",
MAX_VALUES );
}
for (ep = ldap_first_entry(ld, result); i < MAX_VALUES && ep != NULL; ep = ldap_next_entry(ld, ep)) {
sub[i++] = ldap_get_dn(ld, ep);
#ifdef DEBUG
if (debug & D_PARSE)
printf("sub[%d] = %s\n", i - 1, sub[i - 1]);
#endif
}
sub[i] = NULL;
ldap_msgfree(result);
return(count);
}
char * fetch_boolean_value(who, attr)
char *who;
struct attribute attr;
{
LDAPMessage *result; /* from the search below */
register LDAPMessage *ep; /* entry pointer */
register char **vp; /* for parsing the result */
static char *attributes[] = { NULL, NULL };
#ifdef DEBUG
if (debug & D_TRACE)
printf("->fetch_boolean_value(%s, %s)\n", who, attr.quipu_name);
#endif
attributes[0] = attr.quipu_name;
if (ldap_search_s(ld, who, LDAP_SCOPE_BASE, "objectClass=*", attributes, FALSE, &result) != LDAP_SUCCESS) {
if (ld->ld_errno == LDAP_NO_SUCH_ATTRIBUTE)
return("FALSE");
ldap_perror(ld, "ldap_search_s");
ldap_msgfree(result);
return(NULL);
}
/*
* We did a read on one name and only asked for one attribute.
* There's no reason to loop through any of these structures.
*
* If ldap_first_attribute() returns NULL, then this entry did
* not have this particular attribute.
*/
ep = ldap_first_entry(ld, result);
if ((vp = (char **) ldap_get_values(ld, ep, attr.quipu_name)) == NULL) {
ldap_msgfree(result);
return("FALSE");
}
else {
ldap_msgfree(result);
if (!strcasecmp(*vp, "TRUE")) {
ldap_value_free(vp);
return("TRUE");
}
else if (!strcasecmp(*vp, "FALSE")) {
ldap_value_free(vp);
return("FALSE");
}
else {
fprintf(stderr, " Got garbage -> [%s]\n", *vp);
ldap_value_free(vp);
return(NULL);
}
}
}

View file

@ -1,71 +0,0 @@
/*
* Copyright (c) 1992, 1993, 1994 Regents of the University of Michigan.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to the University of Michigan at Ann Arbor. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
*/
#include <stdio.h>
#include "ud.h"
extern void set_boolean(),
change_field(),
#ifdef UOFM
set_updates(),
#endif
mod_addrDN();
struct attribute attrlist[] = {
/*
* Field 1 = Quipu name
* Field 2 = String used when printing the field
* Field 3 = function used to modify this field (if any)
* Field 4 = Flags specifying how this field is displayed
*/
{ "memberOfGroup", "Subscriptions", NULL, ATTR_FLAG_PERSON | ATTR_FLAG_READ | ATTR_FLAG_IS_A_DN },
{ "acl", "Access Control", NULL, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ },
{ "cn", "Aliases", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_SEARCH | ATTR_FLAG_GROUP_MOD },
{ "title", "Title", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_READ | ATTR_FLAG_SEARCH | ATTR_FLAG_PERSON_MOD },
{ "postalAddress", "Business address", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_PERSON_MOD | ATTR_FLAG_GROUP_MOD | ATTR_FLAG_IS_MULTILINE },
{ "telephoneNumber", "Business phone", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_PERSON_MOD | ATTR_FLAG_GROUP_MOD },
{ "mail", "E-mail address", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_SEARCH | ATTR_FLAG_PERSON_MOD | ATTR_FLAG_MAY_EDIT },
{ "member", "Members", mod_addrDN, ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_IS_A_DN | ATTR_FLAG_GROUP_MOD },
{ "homePhone", "Home phone", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_READ | ATTR_FLAG_PERSON_MOD },
{ "homePostalAddress", "Home address", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_READ | ATTR_FLAG_PERSON_MOD | ATTR_FLAG_IS_MULTILINE },
{ "objectClass", "Object class", NULL, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_SEARCH },
#ifdef UOFM
{ "multiLineDescription", "Description", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_PERSON_MOD | ATTR_FLAG_GROUP_MOD | ATTR_FLAG_IS_MULTILINE },
#endif
#ifdef KERBEROS
{ "krbName", "Kerberos name", NULL, ATTR_FLAG_PERSON | ATTR_FLAG_READ },
#endif
{ "description", "Brief description", NULL, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ },
{ "facsimileTelephoneNumber", "Fax number", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_PERSON_MOD | ATTR_FLAG_GROUP_MOD },
{ "pager", "Pager number", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_READ | ATTR_FLAG_PERSON_MOD },
{ "uid", "Uniqname", NULL, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ },
{ "userPassword", "Password", NULL, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ },
#ifdef UOFM
{ "noBatchUpdates", "No batch updates", set_updates, ATTR_FLAG_PERSON | ATTR_FLAG_READ | ATTR_FLAG_PERSON_MOD },
#endif
{ "joinable", "Joinable flag", set_boolean, ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_GROUP_MOD },
{ "associatedDomain", "Associated domain", change_field, ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_GROUP_MOD },
{ "owner", "Owner", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_IS_A_DN | ATTR_FLAG_GROUP_MOD },
{ "rfc822ErrorsTo", "Errors to", change_field, ATTR_FLAG_GROUP | ATTR_FLAG_READ },
{ "ErrorsTo", "Errors to", mod_addrDN, ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_IS_A_DN | ATTR_FLAG_GROUP_MOD },
{ "rfc822RequestsTo", "Requests to", change_field, ATTR_FLAG_GROUP | ATTR_FLAG_READ },
{ "RequestsTo", "Requests to", mod_addrDN, ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_IS_A_DN | ATTR_FLAG_GROUP_MOD },
{ "moderator", "Moderated by", change_field, ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_GROUP_MOD },
{ "labeledURL", "More Info (URL)", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_PERSON_MOD | ATTR_FLAG_GROUP_MOD | ATTR_FLAG_IS_A_URL },
{ "onVacation", "On Vacation", set_boolean, ATTR_FLAG_PERSON | ATTR_FLAG_READ | ATTR_FLAG_PERSON_MOD | ATTR_FLAG_IS_A_BOOL },
{ "vacationMessage", "Vacation Message", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_READ | ATTR_FLAG_PERSON_MOD | ATTR_FLAG_IS_MULTILINE },
{ "drink", "Favorite Beverage", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_READ | ATTR_FLAG_PERSON_MOD },
{ "lastModifiedBy", "Last modified by", NULL, ATTR_FLAG_GROUP | ATTR_FLAG_PERSON | ATTR_FLAG_IS_A_DN | ATTR_FLAG_READ },
{ "lastModifiedTime", "Last modified at", NULL, ATTR_FLAG_GROUP | ATTR_FLAG_PERSON | ATTR_FLAG_READ | ATTR_FLAG_IS_A_DATE },
{ NULL, NULL, NULL, ATTR_FLAG_NONE }
};

File diff suppressed because it is too large Load diff

View file

@ -1,193 +0,0 @@
/*
* Copyright (c) 1992, 1993 Regents of the University of Michigan.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to the University of Michigan at Ann Arbor. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
*/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <lber.h>
#include <ldap.h>
#include "ud.h"
#ifdef DEBUG
extern int debug;
#endif
print_help(s)
char *s;
{
int len; /* command length */
#ifdef DEBUG
if (debug & D_TRACE)
printf("->print_help(%s)\n", s);
#endif
if (s == NULL)
len = 0;
else {
len = strlen(s);
if (!strcasecmp(s, "commands"))
len = 0;
}
/* print general help, or just on topic 's' if provided */
if (len == 0) {
printf("\n Here are brief descriptions of available commands:\n\n");
printf(" ? To print this list.\n");
printf(" bind [who] To bind (authenticate) to the directory.\n");
printf(" cb [where] To change the search base.\n");
printf(" change [entry] To change information associated with an entry.\n");
printf(" create [group] To create a new group entry.\n");
printf(" dereference To toggle dereferencing of aliases.\n");
#ifdef UOFM
if (isatty( 1 )) {
#endif
printf(" vedit [entry] To edit a complete Directory entry using your editor.\n");
#ifdef UOFM
}
#endif
printf(" find [entry] To find an entry in the directory.\n");
printf(" groupbase [where] To change the group base.\n");
printf(" help [command] To display detailed help for a particular command.\n");
printf(" join [group] To subscribe to a group.\n");
printf(" list [who] To list the groups owned by someone.\n");
printf(" memberships [who] To list out the groups in which someone is a member.\n");
printf(" purge [group] To remove obsolete entries from a group.\n");
printf(" quit To terminate the program.\n");
printf(" remove [group] To remove a group entry.\n");
printf(" resign [group] To unsubscribe from a group.\n");
printf(" status To display directory connection status.\n");
printf(" tidy To unsubscribe from groups that no longer exist.\n");
printf(" verbose To toggle the verbose switch.\n");
printf("\n Type \"help <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: ud-bugs@umich.edu\n" );
printf("\n For more assistance with ud, contact the ITD Consultants by phoning\n" );
printf(" 764-HELP or by sending e-mail to: consulting.help@umich.edu\n" );
#endif /* UOFM */
}
else if (!strncasecmp("options", s, len)) {
printf("\n");
format("Most commands need additional information in order to work. For example, the 'remove' command needs to know the name of the group to remove. This can be specified along with the 'remove' command, or the program will prompt you for the information.", 75, 2);
printf("\n");
printf(" [entry] An entry needs to be specified. This may be a person or a\n");
format("group. The name can be specified as either a ordinary name (e.g., 'Jane Doe'), or as some other identifying characteristic (e.g., 'uid=babs').", 75, 15);
printf("\n");
printf(" [group] A group in the Directory needs to be specified. This name\n");
format("should be specified as a ordinary name (e.g., 'Friends of maX500').", 75, 15);
printf("\n");
printf(" [where] A place in the Directory needs to be specified. This name\n");
format("should be specified as an X.500-style name (e.g., 'ou=people, o=University of Michigan, c=United States of America'). In most cases, it is easier to omit the [where] and allow the program to guide you.", 75, 15);
printf("\n");
printf(" [who] A person in the Directory needs to be specified. This name\n");
format("can be specified as either a ordinary name (e.g., 'Jane Doe'), or as some other identifying characteristic (e.g., 'uid=babs').", 75, 15);
}
else if (!strncasecmp("list", s, len)) {
printf(" list [who]\n\n");
format("Prints out the list of groups owned by the person specified.", 75, 2);
}
else if (!strncasecmp("memberships", s, len)) {
printf(" memberships [who]\n\n");
format("Prints out the list of groups in which the person specified is a member.", 75, 2);
}
else if (!strncasecmp("vedit", s, len)) {
printf(" vedit [entry]\n\n");
format("Looks up the specified person in the Directory, and then writes this entry into a file. It then uses the EDITOR environment variable to select an editor, and then loads this file into the editor. The entry can now be modified in any way desired, and when the editor is exited, the entry will be written back into the Directory.", 75, 2);
}
else if (!strncasecmp("status", s, len)) {
printf(" status\n\n");
format("Prints out the current connection status. Lists the name of the current LDAP server, the current search base, the current group base, and the identity to which you are bound. If you have not bound as anyone then ud considers you bound as Nobody. cd is an alias for cb.", 75, 2);
}
else if (!strncasecmp("groupbase", s, len)) {
printf(" groupbase [where]\n\n");
format("The syntax and use of this command is identical to the more commonly used 'cb' command. This command sets the base which is used to create groups in the X.500 Directory. Setting the base to a certain value does not necessarily grant the person write-access to that part of the Directory in order to successfully create a group.", 75, 2);
}
else if (!strncasecmp("cd", s, len) || !strncasecmp("cb", s,len)) {
printf(" cb [where]\n");
printf(" cd [where]\n\n");
format("The cb command changes the search base. By default, this program looks only in the local part of the Directory. By using the cb command, you can search other parts of the Directory.", 75, 2);
printf("\n Examples:\n");
printf("\n * cb ..\n\n");
format("changes the search base so that it is one level higher in the Directory. Note that if you perform several of these in a row you will move to the root of the Directory tree.", 75, 2);
printf("\n * cb ?\n\n");
format("prints out a list of the possible areas to search below the current search base. This is useful once you have moved high in the tree and wish to snoop about.", 75, 2);
printf("\n * cb default\n\n");
format("sets the search base to its original default value.", 75, 2);
printf("\n * cb o=Merit Computer Network, c=US\n\n");
format("sets the search base to organization given, the Merit Computer Network in this case. This comamnd checks the validity of the specified search base, and rejects it if it is not a valid Distinguished Name (DN). A DN uniquely identifies a portion of the global X.500 namespace.", 75, 2);
}
else if (!strncasecmp("quit", s, len) || !strncasecmp("stop",s, len)) {
printf(" quit\n");
printf(" stop\n\n");
printf(" Quits the program. 'stop' is an alias for 'quit'.\n");
}
else if (!strncasecmp("find", s, len) || !strncasecmp("display", s, len) || !strncasecmp("show", s, len)) {
printf(" find [entry]\n");
printf(" show [entry]\n");
printf(" display [entry]\n\n");
format("Displays information about the person specified. If the name specified matches more than one person, one will be presented a list from which to make a choice. 'show' and 'display' are aliases for 'find.'", 75, 2);
}
else if (!strncasecmp("bind", s, len)) {
printf(" bind [who]\n\n");
format("Binds (authenticates) to the Directory. It is generally necessary to bind to the Directory in order to look at privileged entries or to modify an entry. Allows one to authenticate prior to issuing a 'change' or 'modify' command. Most often used by administrators to bind to an identity.", 75, 2);
}
else if (!strncasecmp("modify", s, len) || !strncasecmp("change", s, len)) {
printf(" modify [entry]\n");
printf(" change [entry]\n\n");
format("Changes information associated with an entry in the X.500 Directory. 'change' is an alias for 'modify'.", 75, 2);
}
else if (!strncasecmp("verbose", s, len)) {
printf(" verbose\n\n");
format("Turns on long and windy messages which might be useful to new users of this program. If verbose mode is already on, this turns it off.", 75, 2);
}
else if (!strncasecmp("dereference", s, len)) {
printf(" dereference\n\n");
format("Turns off following of aliases when searching, etc. If alias dereferencing has already been turned off, this turns it back on.", 75, 2);
}
else if (!strncasecmp("create", s, len)) {
printf(" create [group]\n\n");
format("Creates a new group in the Directory.", 75, 2);
}
else if (!strncasecmp("join", s, len) || !strncasecmp("subscribe", s, len)) {
printf(" join [group]\n");
printf(" subscribe [group]\n\n");
format("Adds the person as a subscriber to the specified group.", 75, 2);
}
else if (!strncasecmp("purge", s, len)) {
printf(" purge [group]\n\n");
format("Goes through the specified group looking for Distinguished Names that cannot be found. As it finds each one, it gives the person an opportunity to delete it.", 75, 2);
}
else if (!strncasecmp("resign", s, len) || !strncasecmp("unsubscribe", s, len)) {
printf(" resign [group]\n");
printf(" unsubscribe [group]\n\n");
format("Deletes the person from the specified group.", 75, 2);
}
else if (!strncasecmp("remove", s, len)) {
printf(" remove [group]\n\n");
format("Removes a group from the Directory.", 75, 2);
}
else if (!strncasecmp("help", s, len)) {
format("Prints out a brief description of each command.", 75, 2);
}
else if (!strncasecmp("tidy", s, len)) {
printf(" tidy\n\n");
format("Unsubscribes you from non-existent groups. Useful when you cannot resign from a group because, while your X.500 entry still contains a pointer to it, someone has removed a group of which you were a subscriber.", 75, 2);
}
else if (*s == '?') {
format("Prints out a brief description of each command. Same as typing 'help help'.", 75, 2);
}
else {
printf(" Don't recognize <%s>\n", s);
}
}

View file

@ -1,724 +0,0 @@
/*
* Copyright (c) 1991, 1992, 1993
* Regents of the University of Michigan. All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to the University of Michigan at Ann Arbor. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
*
* The University of Michigan would like to thank the following people for
* their contributions to this piece of software:
*
* Robert Urquhart <robert@sfu.ca>
* Simon Fraser University, Academic Computing Services
*/
#include <stdio.h>
#include <sys/types.h>
#if defined(NeXT)
#include <stdlib.h>
#include <sys/file.h>
#else NeXT
#include <unistd.h>
#endif NeXT
#include <pwd.h>
#include <string.h>
#ifndef DOS
#if defined( NeXT ) || defined( ultrix ) || defined( osf1 ) || (defined(SunOS) && SunOS < 40)
#include <sgtty.h>
#else /* defined( NeXT ) || defined( ultrix ) etc. */
#include <termios.h>
#endif /* defined( NeXT ) || defined( ultrix ) etc. */
#endif /* !DOS */
#if defined( aix ) || defined( __NetBSD__ )
#include <sys/ioctl.h>
#endif /* aix || __NetBSD__ */
#include <ctype.h>
#include <signal.h>
#include <setjmp.h>
#include <memory.h>
#include <lber.h>
#include <ldap.h>
#include <ldapconfig.h>
#include "portable.h"
#include "ud.h"
#ifndef lint
char copyright[] =
"@(#) Copyright (c) 1991, 1992, 1993 Regents of the University of Michigan.\nAll rights reserved.\n";
#endif
/*
* Used with change_base() to indicate which base we are changing.
*/
#define BASE_SEARCH 0
#define BASE_GROUPS 1
#define iscom(x) (!strncasecmp(x, cmd, strlen(cmd)))
static char *server = NULL;
static char *config_file = UD_CONFIG_FILE;
static char *filter_file = FILTERFILE;
static int ldap_port = LDAP_PORT;
static int dereference = TRUE;
char *default_bind_object = UD_BINDDN;
char *bound_dn; /* bound user's Distinguished Name */
char *group_base; /* place in X.500 tree where groups are */
char *search_base; /* place in X.500 tree where searches start */
static jmp_buf env; /* spot to jump to on an interrupt */
int lpp; /* lines per page */
int verbose; /* 1 if verbose mode on */
int col_size; /* characters across on the screen */
int bind_status; /* user's bind status */
LDAP *ld; /* LDAP descriptor */
LDAPFiltDesc *lfdp; /* LDAP filter descriptor */
#ifdef DEBUG
int debug; /* debug flag */
#endif
main(argc, argv)
int argc;
char *argv[];
{
extern char Version[]; /* version number */
extern char *optarg; /* for parsing argv */
register int c; /* for parsing argv */
register char *cp; /* for parsing Version */
extern void initialize_attribute_strings();
verbose = 1;
/* handle argument list */
while ((c = getopt(argc, argv, "c:d:Df:l:p:s:u:vV")) != -1) {
switch (c) {
case 'l' :
#ifdef LDAP_DEBUG
ldap_debug = (int) strtol(optarg, (char **) NULL, 0);
lber_debug = ldap_debug;
#endif
break;
case 'd' :
#ifdef DEBUG
debug = (int) strtol(optarg, (char **) NULL, 0);
#endif
break;
case 's' :
server = strdup(optarg);
break;
case 'c' :
filter_file = strdup(optarg);
break;
case 'f' :
config_file = optarg;
break;
case 'p' :
ldap_port = atoi(optarg);
break;
case 'u' :
default_bind_object = strdup(optarg);
break;
case 'v' :
verbose = 1; /* this is the default anyways... */
break;
case 'V' :
verbose = 0;
break;
case 'D' :
printf("\n\n Debug flag values\n\n");
printf(" 1 function trace\n");
printf(" 2 find() information\n");
printf(" 4 group information\n");
printf(" 8 mod() information\n");
printf(" 16 parsing information\n");
printf(" 32 output information\n");
printf(" 64 authentication information\n");
printf(" 128 initialization information\n\n");
format("These are masks, and may be added to form multiple debug levels. For example, '-d 35' would perform a function trace, print out information about the find() function, and would print out information about the output routines too.", 75, 2);
exit(0);
default:
fprintf(stderr, "Usage: %s [-c filter-config-file] [-d debug-level] [-l ldap-debug-level] [-s server] [-p port] [-V]\n", argv[0]);
exit(-1);
/* NOTREACHED */
}
}
/* just print the first line of Version[] */
cp = strchr(Version, '\t');
if (cp != NULL)
*cp = '\0';
printf(Version);
fflush( stdout );
initialize_client();
initialize_attribute_strings();
/* now tackle the user's commands */
do_commands();
/* NOTREACHED */
}
do_commands()
{
LDAPMessage *mp; /* returned by find() */
register char *cp; /* misc char pointer */
register char *ap; /* misc char pointer */
static char buf[MED_BUF_SIZE]; /* for prompting */
static char cmd[MED_BUF_SIZE]; /* holds the command */
static char input[MED_BUF_SIZE]; /* buffer for input */
extern LDAPMessage *find();
extern void purge_group(), add_group(), remove_group(), x_group(),
tidy_up(), list_groups(), list_memberships(), edit();
extern char *nextstr();
#ifdef DEBUG
if (debug & D_TRACE)
printf("->do_commands()\n");
#endif
if (verbose)
printf("\n Enter a command. If you need help, type 'h' or '?' and hit RETURN.\n\n");
/* jump here on an interrupt */
(void) setjmp(env);
for (;;) {
printf("* ");
fflush(stdout);
cp = input;
/* Temporary kludge - if cp is null, dumps core under Solaris */
if (cp == NULL)
break;
fetch_buffer(input, sizeof(input), stdin);
if (*input == '\0') {
putchar('\n');
continue;
}
while (isspace(*cp))
cp++;
ap = cmd;
if (memset(cmd, '\0', sizeof(cmd)) == NULL)
fatal("memset");
while (!isspace(*cp) && (*cp != '\0'))
*ap++ = *cp++;
if (iscom("status"))
status();
else if (iscom("stop") || iscom("quit"))
break;
else if (iscom("cb") || iscom("cd") || iscom("moveto")) {
while (isspace(*cp) && (*cp != '\0'))
cp++;
if (!strncasecmp(cp, "base", 4))
cp += 4;
change_base(BASE_SEARCH, &search_base, nextstr(cp));
}
else if (iscom("memberships"))
(void) list_memberships(nextstr(cp));
else if (iscom("list"))
(void) list_groups(nextstr(cp));
else if (iscom("groupbase"))
change_base(BASE_GROUPS, &group_base, nextstr(cp));
else if (iscom("find") || iscom("display") || iscom("show")) {
cp = nextstr(cp);
if ((mp = find(cp, FALSE)) != NULL) {
parse_answer(mp);
print_an_entry();
ldap_msgfree(mp);
}
else
printf(" Could not find \"%s\".\n", cp);
}
#ifdef UOFM
else if (iscom("vedit") && isatty( 1 )) {
#else
else if (iscom("vedit")) {
#endif
(void) edit(nextstr(cp));
}
else if (iscom("modify") || iscom("change") || iscom("alter"))
(void) modify(nextstr(cp));
else if (iscom("bind") || iscom("iam"))
(void) auth(nextstr(cp), 0);
else if ((cmd[0] == '?') || iscom("help"))
print_help(nextstr(cp));
else if (iscom("join") || iscom("subscribe"))
(void) x_group(G_JOIN, nextstr(cp));
else if (iscom("resign") || iscom("unsubscribe"))
(void) x_group(G_RESIGN, nextstr(cp));
else if (!strncasecmp("create", cmd, strlen(cmd)))
add_group(nextstr(cp));
else if (!strncasecmp("remove", cmd, strlen(cmd)))
remove_group(nextstr(cp));
else if (!strncasecmp("purge", cmd, strlen(cmd)))
purge_group(nextstr(cp));
else if (!strncasecmp("verbose", cmd, strlen(cmd))) {
verbose = 1 - verbose;
if (verbose)
printf(" Verbose mode has been turned on.\n");
}
else if (!strncasecmp("dereference", cmd, strlen(cmd))) {
dereference = 1 - dereference;
if (dereference == 1)
ld->ld_deref = LDAP_DEREF_ALWAYS;
else
ld->ld_deref = LDAP_DEREF_NEVER;
}
else if (!strncasecmp("tidy", cmd, strlen(cmd)))
tidy_up();
else if (cmd[0] == '\0')
putchar('\n');
else
printf(" Invalid command. Type \"help commands.\"\n");
}
printf(" Thank you!\n");
ldap_unbind(ld);
#ifdef KERBEROS
destroy_tickets();
#endif
exit(0);
/* NOTREACHED */
}
status()
{
void printbase();
register char **rdns;
#ifdef DEBUG
if (debug & D_TRACE)
printf("->status()\n");
#endif
printf(" Current server is %s", server);
if ( ld != NULL && ld->ld_host != NULL && strcasecmp( ld->ld_host,
server ) != 0 )
printf( " (%s)", ld->ld_host );
putchar( '\n' );
printbase(" Search base is ", search_base);
printbase(" Group base is ", group_base);
if ( bound_dn != NULL ) {
rdns = ldap_explode_dn(bound_dn, TRUE);
printf(" Bound as \"%s\"\n", *rdns);
ldap_value_free(rdns);
} else {
printf(" Bound as Nobody\n" );
}
printf( " Verbose mode is %sabled\n", ( verbose ? "en" : "dis" ));
if ( ld != NULL ) {
printf( " Aliases are %sbeing dereferenced\n", ( ld->ld_deref == LDAP_DEREF_ALWAYS ) ? "" : "not" );
}
}
change_base(type, base, s)
int type;
char **base, *s;
{
register char *cp; /* utility pointers */
char **rdns; /* for parsing */
char *output_string; /* for nice output */
int num_picked; /* # of selected base */
int j; /* used with num_picked */
int i = 1; /* index into choices array */
int matches; /* # of matches found */
int rest = 1; /* # left to display */
char tmp[MED_BUF_SIZE]; /* temporary buffer */
static char *choices[MED_BUF_SIZE]; /* bases from which to choose */
static char resp[SMALL_BUF_SIZE]; /* for prompting user */
static char buf[MED_BUF_SIZE];
void printbase();
static char *attrs[] = { "objectClass", NULL };
LDAPMessage *mp; /* results from a search */
LDAPMessage *ep; /* for going thru bases */
extern char * friendly_name();
extern void StrFreeDup();
extern void Free();
#ifdef DEBUG
if (debug & D_TRACE)
printf("->change_base(%s, %s)\n", s, s);
#endif
/*
* If s is NULL we need to prompt the user for an argument.
*/
while (s == NULL) {
if (verbose) {
printf(" You need to specify how the base is to be changed. Valid choices are:\n");
printf(" ? - list the choices immediately below this level\n");
printf(" .. - move up one level in the Directory tree\n");
printf(" root - move to the root of the Directory tree\n");
printf(" default - move to the default level built into this program\n");
printf(" <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;
}
/* set the output string */
if (type == BASE_SEARCH)
output_string = " Search base is now ";
else if (type == BASE_GROUPS)
output_string = " Group base is now ";
if (!strcasecmp(s, "root")) {
StrFreeDup(base, NULL);
printbase(" Search base is ", *base);
return;
}
/*
* User wants to ascend one level in the X.500 tree.
* Easy: Just strip off the first element of the
* current search base, unless it's the root, in
* which case we just do nothing.
*/
if (!strcasecmp(s, "..")) {
if (*base == NULL) {
printf(" You are already at the root\n");
return;
}
cp = strchr(*base, '=');
cp++;
/*
* If there isn't a second "=" in the base, then this was
* a one element base, and so now it should be NULL.
*/
if ((cp = strchr(cp, '=')) == NULL)
StrFreeDup(base, NULL);
else {
/*
* Back up to the start of this
*
* attr=value
*
* sequence now that 'cp' is pointing to the '='.
*/
while(!isspace(*cp))
cp--;
cp++;
/*
* Goofy, but need to do it this way since both *base
* and cp point into the same chunk of memory, and
* we want to free *base, but keep part of it around.
*/
cp = strdup(cp);
StrFreeDup(base, cp);
Free(cp);
}
printbase(output_string, *base);
return;
}
/* user wants to see what is directly below this level */
if (*s == '?') {
/*
* Fetch the list of entries directly below this level.
* Once we have the list, we will print it for the user, one
* screenful at a time. At the end of each screen, we ask
* the user if they want to see more. They can also just
* type a number at that point too.
*/
if (ldap_search_s(ld, *base, LDAP_SCOPE_ONELEVEL, "(|(objectClass=quipuNonLeafObject)(objectClass=externalNonLeafObject))", attrs, FALSE, &mp) != LDAP_SUCCESS) {
if ((ld->ld_errno == LDAP_TIMELIMIT_EXCEEDED) ||
(ld->ld_errno == LDAP_SIZELIMIT_EXCEEDED)) {
if (verbose) {
printf(" Your query was too general and a limit was exceeded. The results listed\n");
printf(" are not complete. You may want to try again with a more refined query.\n\n");
}
else
printf(" Time or size limit exceeded. Partial results follow.\n\n");
} else {
ldap_perror(ld, "ldap_search_s");
return;
}
}
if ((matches = ldap_count_entries(ld, mp)) < 1) {
printf(" There is nothing below this level.\n");
(void) ldap_msgfree(mp);
return;
}
num_picked = 0;
printf(" There are %d choices:\n", matches);
for (ep = ldap_first_entry(ld, mp); ep != NULL; ep = ldap_next_entry(ld, ep)) {
/*
* Put the last component of the DN into 'lastDN'.
* If we are at the root level, convert any country
* codes to recognizable names for printing.
*/
choices[i] = ldap_get_dn(ld, ep);
rdns = ldap_explode_dn(choices[i], TRUE);
printf(" %2d. %s\n", i, friendly_name(*rdns));
(void) ldap_value_free(rdns);
i++;
if ((rest++ > (lpp - 3)) && (i < matches)) {
printf("More? ");
fflush(stdout);
fetch_buffer(resp, sizeof(resp), stdin);
if ((resp[0] == 'n') || (resp[0] == 'N'))
break;
else if (((num_picked = atoi(resp)) != 0) && (num_picked < i))
break;
rest = 1;
}
}
for (;;) {
if (num_picked != 0) {
j = num_picked;
num_picked = 0;
}
else {
printf(" Which number? ");
fflush(stdout);
fetch_buffer(resp, sizeof(resp), stdin);
j = atoi(resp);
}
if (j == 0) {
(void) ldap_msgfree(mp);
for (i = 0; i < matches; i++)
Free(choices[i]);
return;
}
if ((j < 1) || (j >= i))
printf(" Invalid number\n");
else {
StrFreeDup(base, choices[j]);
printbase(output_string, *base);
(void) ldap_msgfree(mp);
for (i = 0; choices[i] != NULL; i++)
Free(choices[i]);
return;
}
}
}
/* set the search base back to the original default value */
else if (!strcasecmp(s, "default")) {
if (type == BASE_SEARCH)
StrFreeDup(base, UD_BASE);
else if (type == BASE_GROUPS)
StrFreeDup(base, UD_WHERE_GROUPS_ARE_CREATED);
printbase(output_string, *base);
}
/* they typed in something -- see if it is legit */
else {
/* user cannot do something like 'cb 33' */
if (atoi(s) != 0) {
printf(" \"%s\" is not a valid search base\n", s);
printf(" Base unchanged.\n");
printf(" Try using 'cb ?'\n");
return;
}
/* was it a fully-specified DN? */
if (vrfy(s)) {
StrFreeDup(base, s);
printbase(output_string, *base);
return;
}
/* was it a RDN relative to the current base? */
sprintf(tmp, "ou=%s, %s", s, *base);
if (vrfy(tmp)) {
StrFreeDup(base, tmp);
printbase(output_string, *base);
return;
}
printf(" \"%s\" is not a valid base\n Base unchanged.\n", s);
}
}
initialize_client()
{
FILE *fp; /* for config file */
static char buffer[MED_BUF_SIZE]; /* for input */
struct passwd *pw; /* for getting the home dir */
register char *cp; /* for fiddling with buffer */
char *term; /* for tty set-up */
char *config; /* config file to use */
static char bp[1024]; /* for tty set-up */
extern SIG_FN attn(); /* ^C signal handler */
extern char *getenv();
extern void Free();
#ifdef DEBUG
if (debug & D_TRACE)
printf("->initialize_client()\n");
#endif
/*
* A per-user config file has precedence over any system-wide
* config file, if one exists.
*/
if ((pw = getpwuid((uid_t) geteuid())) == (struct passwd *) NULL)
config = config_file;
else {
if (pw->pw_dir == NULL)
config = config_file;
else {
sprintf(buffer, "%s/%s", pw->pw_dir,
UD_USER_CONFIG_FILE);
if (access(buffer, R_OK) == 0)
config = buffer;
else
config = config_file;
}
}
#ifdef DEBUG
if (debug & D_INITIALIZE)
printf("Using config file %s\n", config);
#endif
/*
* If there is a config file, read it.
*
* Could have lines that look like this:
*
* server <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(*cp))
cp++;
if ((*cp == '\0') || (*cp == '\n'))
continue;
server = strdup(cp);
}
else if (!strncasecmp(buffer, "base", 4)) {
cp = buffer + 4;
while (isspace(*cp))
cp++;
if ((*cp == '\0') || (*cp == '\n'))
continue;
search_base = strdup(cp);
}
else if (!strncasecmp(buffer, "groupbase", 9)) {
cp = buffer + 9;
while (isspace(*cp))
cp++;
if ((*cp == '\0') || (*cp == '\n'))
continue;
group_base = strdup(cp);
}
else
fprintf(stderr, "?? -> %s\n", buffer);
}
}
if (group_base == NULL)
group_base = strdup(UD_WHERE_GROUPS_ARE_CREATED);
if (search_base == NULL)
search_base = strdup(UD_BASE);
if (server == NULL)
server = strdup(LDAPHOST);
/*
* Set up our LDAP connection. The values of retry and timeout
* are meaningless since we will immediately be doing a null bind
* because we want to be sure to use TCP, not UDP.
*/
if ((ld = ldap_open(server, ldap_port)) == NULL) {
fprintf(stderr, " The X.500 Directory is temporarily unavailable. Please try again later.\n");
exit(0);
/* NOTREACHED */
}
if (ldap_bind_s(ld, (char *) default_bind_object, (char *) UD_PASSWD,
LDAP_AUTH_SIMPLE) != LDAP_SUCCESS) {
fprintf(stderr, " The X.500 Directory is temporarily unavailable. Please try again later.\n");
if (ld->ld_errno != LDAP_UNAVAILABLE)
ldap_perror(ld, " ldap_bind_s");
exit(0);
/* NOTREACHED */
}
ld->ld_deref = LDAP_DEREF_ALWAYS;
bind_status = UD_NOT_BOUND;
if ( default_bind_object != NULL ) {
bound_dn = strdup(default_bind_object);
} else {
bound_dn = NULL;
}
/* enabled local caching of ldap results, 15 minute lifetime */
#ifdef DOS
ldap_enable_cache( ld, 60 * 15, 100 * 1024 ); /* 100k max memory */
#else /* DOS */
ldap_enable_cache( ld, 60 * 15, 0 ); /* no memory limit */
#endif /* DOS */
/* initialize the search filters */
if ((lfdp = ldap_init_getfilter(filter_file)) == NULL) {
fprintf(stderr, " Problem with ldap_init_getfilter\n");
fatal(filter_file);
/*NOTREACHED*/
}
/* terminal initialization stuff goes here */
lpp = DEFAULT_TTY_HEIGHT;
col_size = DEFAULT_TTY_WIDTH;
(void) signal(SIGINT, attn);
#if !defined(DOS) && !defined(NOTERMCAP)
{
struct winsize win; /* for tty set-up */
extern SIG_FN chwinsz(); /* WINSZ signal handler */
if (((term = getenv("TERM")) == NULL) || (tgetent(bp, term) <= 0))
return;
else {
if (ioctl(fileno(stdout), TIOCGWINSZ, &win) < 0) {
lpp = tgetnum("li");
col_size = tgetnum("co");
}
else {
if ((lpp = win.ws_row) == 0)
lpp = tgetnum("li");
if ((col_size = win.ws_col) == 0)
col_size = tgetnum("co");
if ((lpp <= 0) || tgetflag("hc"))
lpp = DEFAULT_TTY_HEIGHT;
if ((col_size <= 0) || tgetflag("hc"))
col_size = DEFAULT_TTY_WIDTH;
}
}
(void) signal(SIGWINCH, chwinsz);
}
#endif
}
SIG_FN attn()
{
fflush(stderr);
fflush(stdout);
printf("\n\n INTERRUPTED!\n");
#if defined(DOS) || defined(SYSV)
(void) signal(SIGINT, attn);
#endif
longjmp(env, 1);
}
#if !defined(DOS) && !defined(NOTERMCAP)
SIG_FN chwinsz()
{
struct winsize win;
(void) signal(SIGWINCH, SIG_IGN);
if (ioctl(fileno(stdout), TIOCGWINSZ, &win) != -1) {
if (win.ws_row != 0)
lpp = win.ws_row;
if (win.ws_col != 0)
col_size = win.ws_col;
}
(void) signal(SIGWINCH, chwinsz);
}
#endif

View file

@ -1,814 +0,0 @@
/*
* Copyright (c) 1991,1993 Regents of the University of Michigan.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to the University of Michigan at Ann Arbor. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <lber.h>
#include <ldap.h>
#ifndef __STDC__
#include <memory.h>
#endif
#include <sys/types.h>
#include "ud.h"
extern struct entry Entry;
extern int verbose;
extern LDAP *ld;
extern LDAPMessage *find();
#ifdef DEBUG
extern int debug;
#endif
modify(who)
char *who;
{
#ifdef UOFM
void set_updates(); /* routine to modify noBatchUpdates */
#endif
LDAPMessage *mp; /* returned from find() */
char *dn; /* distinguished name */
char **rdns; /* for fiddling with the DN */
char name[MED_BUF_SIZE]; /* entry to modify */
int displayed_choices = 0;
static char ans[SMALL_BUF_SIZE]; /* for holding user input */
#ifdef UOFM
static char printed_warning = 0; /* for use with the */
struct attribute no_batch_update_attr;
extern char * fetch_boolean_value();
#endif
int is_a_group; /* TRUE if it is; FALSE otherwise */
extern void Free();
extern int bind_status;
#ifdef DEBUG
if (debug & D_TRACE)
printf("->modify(%s)\n", who);
#endif
/*
* Require them to bind first if the are modifying a group.
*/
if (bind_status == UD_NOT_BOUND) {
if (auth((char *) NULL, 1) < 0)
return;
}
/*
* First, decide what entry we are going to modify. If the
* user has not included a name on the modify command line,
* we will use the person who was last looked up with a find
* command. If there is no value there either, we don't know
* who to modify.
*
* Once we know who to modify, be sure that they exist, and
* parse out their DN.
*/
if (who == NULL) {
if (verbose) {
printf(" Enter the name of the person or\n");
printf(" group whose entry you want to modify: ");
}
else
printf(" Modify whose entry? ");
fflush(stdout);
fetch_buffer(name, sizeof(name), stdin);
if (name[0] != '\0')
who = name;
else
return;
}
if ((mp = find(who, TRUE)) == NULL) {
(void) ldap_msgfree(mp);
printf(" Could not locate \"%s\" in the Directory.\n", who);
return;
}
dn = ldap_get_dn(ld, ldap_first_entry(ld, mp));
rdns = ldap_explode_dn(dn, TRUE);
if (verbose)
printf("\n Modifying Directory entry of \"%s\"\n", *rdns);
#ifdef UOFM
/*
* If verbose mode is turned on and the user has not set a value
* for noBatchUpdates, warn them that what they are about to do
* may be overwritten automatically by that Stinkbug.
*/
no_batch_update_attr.quipu_name = "noBatchUpdates";
(void) fetch_boolean_value(dn, no_batch_update_attr);
if (verbose && !printed_warning && (ld->ld_errno == LDAP_NO_SUCH_ATTRIBUTE)) {
printed_warning = 1;
printf("\n WARNING!\n");
printf(" You are about to make a modification to an X.500 entry\n");
printf(" that has its \"automatic updates\" field set to ON.\n");
printf(" This means that the entry will be automatically updated\n");
printf(" each month from official University sources like the\n");
printf(" Personnel Office. With \"automatic updates\" set to ON,\n");
printf(" the following fields will be overwritten each month:\n");
printf(" Title, home address and phone,\n");
printf(" business address and phone\n");
printf(" If you modify any of these fields, you may want to change\n");
printf(" the \"automatic updates\" field to OFF so that your\n");
printf(" changes will not be overwritten. You may change this\n");
printf(" setting by choosing \"u\" at the \"Modify what?\" prompt\n");
}
#endif
/*
* Current values for user 'who' are being held in 'mp'. We
* should parse up that buffer and fill in the Entry structure.
* Once we're done with that, we can find out which fields the
* user would like to modify.
*/
parse_answer(mp);
is_a_group = isgroup();
(void) ldap_msgfree(mp);
printf(" You now need to specify what field you'd like to modify.\n");
for (;;) {
if ( verbose || !displayed_choices ) {
printf("\n Choices are:\n");
printf(" -----------------------\n");
print_mod_list(is_a_group);
printf("\n Pressing Return will cancel the process.\n");
displayed_choices = 1;
}
printf("\n Modify what? ");
fflush(stdout);
fetch_buffer(ans, sizeof(ans), stdin);
if (ans[0] == '\0')
break;
perform_action(ans, dn, is_a_group);
if ((mp = find(*rdns, TRUE)) == NULL)
break;
parse_answer(mp);
(void) ldap_msgfree(mp);
}
(void) Free(dn);
ldap_value_free(rdns);
return;
}
/* generic routine for changing any field */
void change_field(who, attr)
char *who; /* DN of entry we are changing */
struct attribute attr; /* attribute to change */
{
#define IS_MOD(x) (!strncasecmp(resp, (x), strlen(resp)))
char *get_value(); /* routine to extract values */
static char buf[MED_BUF_SIZE]; /* for printing things */
static char resp[SMALL_BUF_SIZE]; /* for user input */
char *prompt, *prompt2, *more;
register int i; /* for looping thru values */
static LDAPMod mod;
static LDAPMod *mods[2] = { &mod }; /* passed to ldap_modify */
static char *values[MAX_VALUES]; /* passed to ldap_modify */
extern void Free();
#ifdef DEBUG
if (debug & D_TRACE)
printf("->change_field(%x, %s)\n", attr, who);
#endif
/*
* If there is no current value associated with the attribute,
* then this is the easy case. Collect one (or more) attributes
* from the user, and then call ldap_modify_s() to write the changes
* to the LDAP server.
*/
for (i = 0; i < MAX_VALUES; i++)
values[i] = NULL;
if (attr.values == (char **) NULL) {
printf("\n No current \"%s\"\n", attr.output_string);
values[0] = get_value(attr.quipu_name, "Enter a value");
if ( values[0] == NULL )
return;
mod.mod_op = LDAP_MOD_REPLACE;
mod.mod_type = attr.quipu_name;
mod.mod_values = values;
for (i = 1; i < MAX_VALUES; i++) {
printf(" Do you wish to add an additional value? ");
fflush(stdout);
fetch_buffer(resp, sizeof(resp), stdin);
if ((resp[0] == 'y') || (resp[0] == 'Y'))
values[i] = get_value(attr.quipu_name, "Enter an additional value");
else
break;
}
#ifdef DEBUG
if (debug & D_MODIFY) {
printf(" ld = 0x%x\n", ld);
printf(" who = [%s]\n", who);
printf(" mods[0]->mod_op = %1d\n", mods[0]->mod_op);
printf(" mods[0]->mod_type = %s\n", mods[0]->mod_type);
for (i = 0; mods[0]->mod_values[i] != NULL; i++)
printf(" mods[0]->mod_values[%1d] = %s\n", i, mods[0]->mod_values[i]);
}
#endif
if (ldap_modify_s(ld, who, mods)) {
mod_perror(ld);
return;
}
else if (verbose)
printf(" Modification of '%s' complete.\n", attr.output_string);
ldap_uncache_entry( ld, who );
for (i--; i > 0; i--)
(void) Free(values[i]);
}
/*
* There are values for this attribute already. In this case,
* we want to allow the user to delete all existing values,
* add additional values to the ones there already, or just
* delete some of the values already present. DIXIE does not
* handle modifications where the attribute occurs on the LHS
* more than once. So to delete entries and add entries, we
* need to call ldap_modify() twice.
*/
else {
/*
* If the attribute holds values which are DNs, print them
* in a most pleasant way.
*/
sprintf(buf, "%s: ", attr.output_string);
if (!strcmp(attr.quipu_name, "owner"))
(void) print_DN(attr);
else
(void) print_values(attr);
if (verbose) {
printf(" You may now:\n");
printf(" Add additional values to the existing ones, OR\n");
printf(" Clear all values listed above, OR\n");
printf(" Delete one of the values listed above, OR\n");
printf(" Replace all of the values above with new ones.\n");
}
printf("\n Add, Clear, Delete, or Replace? ");
fflush(stdout);
fetch_buffer(resp, sizeof(resp), stdin);
/*
* Bail if they just hit the RETURN key.
*/
if (resp[0] == '\0') {
if (verbose)
printf("\n No changes made.\n");
return;
}
/*
* If the want to clear the values, just do it.
*/
mod.mod_type = attr.quipu_name;
mod.mod_values = values;
if (IS_MOD("clear")) {
mod.mod_op = LDAP_MOD_DELETE;
mod.mod_values = NULL;
if ( verbose && !confirm_action( "All existing values will be removed." )) {
printf(" Modification halted.\n");
return;
}
#ifdef DEBUG
if (debug & D_MODIFY) {
printf("Clearing attribute '%s'\n", attr.quipu_name);
printf("who = [%s]\n", who);
printf("mod = [%d] [%s] [%x]\n", mod.mod_op,
mod.mod_type, mod.mod_values);
}
#endif
if (ldap_modify_s(ld, who, mods)) {
mod_perror(ld);
return;
}
else if (verbose)
printf(" '%s' has been cleared.\n", attr.output_string);
ldap_uncache_entry( ld, who );
return;
}
if (IS_MOD("add")) {
prompt = "Enter the value you wish to add";
more = " Add an additional value? ";
prompt2 = "Enter another value you wish to add";
mod.mod_op = LDAP_MOD_ADD;
}
else if (IS_MOD("delete")) {
prompt = "Enter the value you wish to delete";
more = " Delete an additional value? ";
prompt2 = "Enter another value you wish to delete";
mod.mod_op = LDAP_MOD_DELETE;
}
else if (IS_MOD("replace")) {
prompt = "Enter the new value";
more = " Add an additional value? ";
prompt2 = "Enter another value you wish to add";
mod.mod_op = LDAP_MOD_REPLACE;
if ( verbose && !confirm_action( "All existing values will be overwritten with the new values you are about to enter." )) {
printf(" Modification halted.\n");
return;
}
}
else {
printf(" No changes made.\n");
return;
}
values[0] = get_value(attr.quipu_name, prompt);
for (i = 1; i < MAX_VALUES; i++) {
printf(more);
fflush(stdout);
fetch_buffer(resp, sizeof(resp), stdin);
if ((resp[0] == 'y') || (resp[0] == 'Y'))
values[i] = get_value(attr.quipu_name, prompt2);
else
break;
}
/* if the first value in the value-array is NULL, bail */
if (values[0] == NULL) {
if (verbose)
printf(" No modification made.\n");
return;
}
#ifdef DEBUG
if (debug & D_MODIFY) {
printf(" ld = 0x%x\n", ld);
printf(" who = [%s]\n", who);
printf(" mods[0]->mod_op = %1d\n", mods[0]->mod_op);
printf(" mods[0]->mod_type = %s\n", mods[0]->mod_type);
for (i = 0; mods[0]->mod_values[i] != NULL; i++)
printf(" mods[0]->mod_values[%1d] = %s\n", i, mods[0]->mod_values[i]);
}
#endif
if (ldap_modify_s(ld, who, mods)) {
mod_perror(ld);
return;
}
else if (verbose)
printf(" Modifications to '%s' complete.\n", attr.output_string);
ldap_uncache_entry( ld, who );
for (i--; i > 0; i--)
(void) Free(values[i]);
}
return;
}
/*
* These are used to size the buffers we use when collecting values that
* can cross more than one line.
*/
#define LINE_SIZE 80
#define MAX_LINES 6
#define MAX_DESC_LINES 24
#define INTL_ADDR_LIMIT 30
char *get_value(id, prompt)
char *id, *prompt;
{
char *cp; /* for the Malloc() */
int count; /* line # of new value -- if multiline */
int multiline = 0; /* 1 if this value is multiline */
static char line[LINE_SIZE]; /* raw line from user */
static char buffer[MAX_DESC_LINES * LINE_SIZE]; /* holds ALL of the
lines we get */
extern void * Malloc();
static char * get_URL();
#ifdef DEBUG
if (debug & D_TRACE)
printf("->get_value(%s, %s)\n", id, prompt);
#endif
/* if this is a URL, have another routine handle this */
if (!strcmp(id, "labeledURL"))
return(get_URL());
/*
* To start with, we have one line of input from the user.
*
* Addresses and multiline description can span multiple lines.
* Other attributes may not.
*/
count = 1;
(void) memset(buffer, 0, sizeof(buffer));
#ifdef UOFM
if (!strcmp(id, "postalAddress") || !strcmp(id, "homePostalAddress") || !strcmp(id, "multiLineDescription") || !strcmp(id, "vacationMessage"))
#else
if (!strcmp(id, "postalAddress") || !strcmp(id, "homePostalAddress"))
#endif
multiline = 1;
printf("\n %s:\n", prompt);
/* fetch lines */
for (;;) {
if (multiline)
printf(" %1d: ", count);
else
printf(" > ");
fflush(stdout);
fetch_buffer(line, sizeof(line), stdin);
if (line[0] == '\0')
break;
#ifdef UOFM
/*
* Screen out dangerous e-mail addresses of the form:
*
* user@umich.edu
*
* and addresses that have no '@' symbol at all.
*/
if (!strcmp(id, "mail")) {
int i;
char *tmp, *tmp2;
/* if this is a group, don't worry */
if (isgroup())
goto mail_is_good;
/* if this address is not @umich.edu, don't worry */
/* ...unless there is no '@' at all! */
tmp = strdup(line);
if ((tmp2 = strrchr(tmp, '@')) == NULL) {
printf("\n");
format("The address you entered is not a valid e-mail address. E-mail addresses should be of the form \"local@domain\", e.g. bjensen@b.imap.itd.umich.edu", 75, 2 );
goto mail_is_bad;
}
*tmp2 = '\0';
tmp2++;
if (strcasecmp(tmp2, "umich.edu"))
goto mail_is_good;
/* if not of the form uid@umich.edu, don't worry */
if ((i = attr_to_index("uid")) < 0)
goto mail_is_good;
if (strcasecmp(tmp, *(Entry.attrs[i].values)))
goto mail_is_good;
printf("\n");
format("An e-mail address of the form uniqname@umich.edu is not the form that you want registered in the Directory. This form is the one to use on business cards, for example, but the Directory should contain your real e-mail address; that is, the address where you really read your mail.", 75, 2);
mail_is_bad:
printf("\n");
printf(" Please enter a legal e-mail address (or press RETURN to stop)\n");
continue;
}
mail_is_good:
#endif
/*
* If the attribute which we are gathering is a "owner"
* then we should lookup the name. The user is going to
* either have to change the search base before doing the
* modify, or the person is going to have to be within the
* scope of the current search base, or they will need to
* type in a UFN.
*/
if (!strcmp(id, "owner")) {
LDAPMessage *lmp, *elmp;
char *tmp;
lmp = find(line, FALSE);
if (lmp == (LDAPMessage *) NULL) {
printf(" Could not find \"%s\" in the Directory\n", line);
if (verbose)
format("Owners of groups must be valid entries in the X.500 Directory. The name you have typed above could not be found in the X.500 Directory.", 72, 2);
return(NULL);
}
elmp = ldap_first_entry(ld, lmp);
if (lmp == (LDAPMessage *) NULL) {
ldap_perror(ld, "ldap_first_entry");
return(NULL);
}
tmp = ldap_get_dn(ld, elmp);
strcpy(buffer, tmp);
(void) ldap_msgfree(lmp);
break;
}
if (!strcmp(id, "postalAddress") || !strcmp(id, "homePostalAddress")) {
if (strlen(line) > INTL_ADDR_LIMIT) {
printf(" The international standard for addresses only allows for 30-character lines\n");
printf(" Please re-enter your last line.\n");
continue;
}
}
/*
* Separate lines of multiline attribute values with
* dollar signs. Copy this line into the buffer we
* use to collect up all of the user-supplied input
* lines. If this is not a multiline attribute, we
* are done.
*/
if (count++ > 1)
(void) strcat(buffer, "$");
(void) strcat(buffer, line);
if (!multiline)
break;
if ((count > MAX_LINES) && (!strcmp(id, "postalAddress") || !strcmp(id, "homePostalAddress"))) {
printf(" The international standard for addresses only allows for six lines\n");
break;
}
#ifdef UOFM
if ((count > MAX_DESC_LINES) && !strcmp(id, "multiLineDescription")) {
printf(" We only allow %d lines of description\n", MAX_DESC_LINES);
break;
}
#endif
}
if (buffer[0] == '\0')
return(NULL);
#ifdef DEBUG
if (debug & D_MODIFY)
printf(" Value is [%s]\n", buffer);
#endif
cp = (char *) Malloc((unsigned) (strlen(buffer) + 1));
strcpy(cp, buffer);
return(cp);
}
void set_boolean(who, attr)
char *who; /* DN of entry we are changing */
struct attribute attr; /* boolean attribute to change */
{
char *cp, *s;
extern char * fetch_boolean_value();
static char response[16];
static char *newsetting[2] = { NULL, NULL };
LDAPMod mod, *mods[2];
#ifdef DEBUG
if (debug & D_TRACE)
printf("->set_boolean(%s, %s)\n", who, attr.quipu_name);
#endif
mods[0] = &mod;
mods[1] = (LDAPMod *) NULL;
mod.mod_op = LDAP_MOD_REPLACE;
mod.mod_type = attr.quipu_name;
mod.mod_values = newsetting;
/* fetch the current setting */
if ((cp = fetch_boolean_value(who, attr)) == NULL)
return;
if (!strcmp(cp, "TRUE"))
newsetting[0] = "FALSE";
else if (!strcmp(cp, "FALSE"))
newsetting[0] = "TRUE";
else {
printf(" This field needs to be set to either TRUE or to FALSE.\n");
printf(" \"%s\" is not a legal value. Please set this field to either TRUE or to FALSE.\n", cp);
newsetting[0] = "FALSE";
}
/* see if they want to change it */
printf("\n");
printf(" The current value of this field is %s.\n", cp);
printf(" Should I change the value of this field to %s?\n",
newsetting[0]);
printf(" Please enter Y for yes, N for no, or RETURN to cancel: ");
fflush(stdout);
(void) fetch_buffer(response, sizeof(response), stdin);
for (s = response; isspace(*s); s++)
;
if ((*s == 'y') || (*s == 'Y')) {
if (ldap_modify_s(ld, who, mods)) {
mod_perror(ld);
return;
}
else if (verbose)
printf(" Setting has been changed\n");
ldap_uncache_entry(ld, who);
return;
}
if (verbose)
printf(" Setting has not been changed\n");
}
#ifdef UOFM
void set_updates(who)
char *who;
{
char *cp, *s;
extern char * fetch_boolean_value();
static char response[16];
static char value[6];
static char *newsetting[2] = { value, NULL };
LDAPMod mod, *mods[2];
struct attribute attr;
#ifdef DEBUG
if (debug & D_TRACE)
printf("->set_updates(%s)\n", who);
#endif
mods[0] = &mod;
mods[1] = (LDAPMod *) NULL;
mod.mod_op = LDAP_MOD_REPLACE;
mod.mod_type = "noBatchUpdates";
mod.mod_values = newsetting;
/* explain what the implications are */
if (verbose) {
printf("\n By default, updates that are received from the Personnel\n");
printf(" Office and the Office of the Registrar are applied to all\n");
printf(" entries in the X.500 database each month. Sometimes this\n");
printf(" feature is undesirable. For example, if you maintain your\n");
printf(" entry in the X.500 database manually, you may not want to\n");
printf(" have these updates applied to your entry, possibly overwriting\n");
printf(" correct information with out-dated information.\n\n");
}
/* fetch the current setting */
attr.quipu_name = "noBatchUpdates";
if ((cp = fetch_boolean_value(who, attr)) == NULL)
return;
if (!strcmp(cp, "TRUE"))
printf(" Automatic updates are currently turned OFF\n");
else if (!strcmp(cp, "FALSE"))
printf(" Automatic updates are currently turned ON\n");
else {
fprintf(stderr, " Unknown update flag -> [%s]\n", cp);
return;
}
/* see if they want to change it */
printf("\n Change this setting [no]? ");
fflush(stdout);
(void) fetch_buffer(response, sizeof(response), stdin);
for (s = response; isspace(*s); s++)
;
if ((*s == 'y') || (*s == 'Y')) {
if (!strcmp(cp, "TRUE"))
strcpy(value, "FALSE");
else
strcpy(value, "TRUE");
if (ldap_modify_s(ld, who, mods)) {
mod_perror(ld);
return;
}
else if (verbose)
printf(" Setting has been changed\n");
ldap_uncache_entry( ld, who );
return;
}
if (verbose)
printf(" Setting has not been changed\n");
}
#endif
print_mod_list(group)
int group;
{
register int i, j = 1;
extern struct attribute attrlist[];
if (group == TRUE) {
for (i = 0; attrlist[i].quipu_name != NULL; i++) {
if (attrlist[i].flags & ATTR_FLAG_GROUP_MOD) {
printf(" %2d -> %s\n", j, attrlist[i].output_string);
j++;
}
}
} else {
for (i = 0; attrlist[i].quipu_name != NULL; i++) {
if (attrlist[i].flags & ATTR_FLAG_PERSON_MOD) {
printf(" %2d -> %s\n", j, attrlist[i].output_string);
j++;
}
}
}
printf(" ? -> Print this list\n\n");
printf(" Press the RETURN key without typing a number to quit.\n");
#ifdef UOFM
if (group == FALSE)
printf(" To add nicknames, send mail to x500-nicknames@umich.edu\n");
#endif
}
perform_action(choice, dn, group)
char choice[];
char *dn;
int group;
{
int selection;
register int i, j = 1;
extern struct attribute attrlist[];
extern void mod_addrDN(), change_field(), set_boolean();
selection = atoi(choice);
if (selection < 1) {
printf("\n Choices are:\n");
printf(" -----------------------\n");
print_mod_list(group);
return(1);
/* NOTREACHED */
}
if (group == TRUE) {
for (i = 0; attrlist[i].quipu_name != NULL; i++) {
if (attrlist[i].flags & ATTR_FLAG_GROUP_MOD) {
if (j == selection)
break;
j++;
}
}
} else {
for (i = 0; attrlist[i].quipu_name != NULL; i++) {
if (attrlist[i].flags & ATTR_FLAG_PERSON_MOD) {
if (j == selection)
break;
j++;
}
}
}
if (attrlist[i].quipu_name == NULL) {
printf("\n Choices are:\n");
printf(" -----------------------\n");
print_mod_list(group);
return(1);
/* NOTREACHED */
}
if (attrlist[i].mod_func == change_field)
(*attrlist[i].mod_func)(dn, Entry.attrs[attr_to_index(attrlist[i].quipu_name)]);
else if (attrlist[i].mod_func == mod_addrDN)
(*attrlist[i].mod_func)(dn, i);
else if (attrlist[i].mod_func == set_boolean)
(*attrlist[i].mod_func)(dn, Entry.attrs[attr_to_index(attrlist[i].quipu_name)]);
else
(*attrlist[i].mod_func)(dn);
return(0);
}
static char * get_URL()
{
char *rvalue, label[MED_BUF_SIZE], url[MED_BUF_SIZE];
static int check_URL();
extern void * Malloc();
if (verbose) {
printf(" First, enter the URL. (Example: http://www.us.itd.umich.edu/users/).\n");
printf(" The URL may be up to %d characters long.\n", MED_BUF_SIZE);
}
for (;;) {
printf(" URL: ");
fflush(stdout);
(void) fetch_buffer(url, sizeof(url), stdin);
if (*url == '\0')
continue;
if (check_URL(url) == 0)
break;
printf(" A URL may not have any spaces or tabs in it. Please re-enter your URL.\n\n");
}
if (verbose)
printf("\n Now please enter a descriptive label for this URL\n");
do {
printf(" Label: ");
fflush(stdout);
(void) fetch_buffer(label, sizeof(label), stdin);
} while (label[0] == '\0');
rvalue = (char *) Malloc((unsigned) (strlen(url) + 2 + strlen(label)));
sprintf(rvalue, "%s %s", url, label);
return((char *) rvalue);
}
static check_URL(url)
char *url;
{
register char *cp;
for (cp = url; *cp != '\n' && *cp != '\0'; cp++) {
if (isspace(*cp))
return(-1);
/*NOTREACHED*/
}
*cp = '\0';
return(0);
}
mod_perror( LDAP *ld )
{
if ( ld == NULL || ( ld->ld_errno != LDAP_UNAVAILABLE &&
ld->ld_errno != LDAP_UNWILLING_TO_PERFORM )) {
ldap_perror( ld, "modify" );
return;
}
fprintf( stderr, "\n modify: failed because part of the online directory is not able\n" );
fprintf( stderr, " to be modified right now" );
if ( ld->ld_errno == LDAP_UNAVAILABLE ) {
fprintf( stderr, " or is temporarily unavailable" );
}
fprintf( stderr, ".\n Please try again later.\n" );
}

View file

@ -1,653 +0,0 @@
/*
* Copyright (c) 1991, 1993
* Regents of the University of Michigan. All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to the University of Michigan at Ann Arbor. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#ifndef __STDC__
#include <memory.h>
#endif
#include <time.h>
#include <lber.h>
#include <ldap.h>
#include "ud.h"
#ifdef DEBUG
extern int debug;
#endif
struct entry Entry;
extern LDAP *ld;
extern void * Malloc();
extern void Free();
extern char * my_ldap_dn2ufn();
/*
* When displaying entries, display only these attributes, and in this
* order.
*/
static char *person_attr_print_order[] = {
"cn",
"mail",
"telephoneNumber",
"facsimileTelephoneNumber",
"pager",
"postalAddress",
"title",
"uid",
"multiLineDescription",
"homePhone",
"homePostalAddress",
"drink",
"labeledURL",
"onVacation",
"vacationMessage",
"memberOfGroup",
"lastModifiedBy",
"lastModifiedTime",
NULL
};
static char *group_attr_print_order[] = {
"cn",
"facsimileTelephoneNumber",
"telephoneNumber",
"postalAddress",
"multiLineDescription",
"joinable",
"associatedDomain",
"owner",
"moderator",
"ErrorsTo",
"rfc822ErrorsTo",
"RequestsTo",
"rfc822RequestsTo",
"member",
"mail",
"labeledURL",
"lastModifiedBy",
"lastModifiedTime",
NULL
};
parse_answer(s)
LDAPMessage *s;
{
int idx;
char **rdns;
BerElement *cookie;
register LDAPMessage *ep;
register char *ap;
void clear_entry();
#ifdef DEBUG
if (debug & D_TRACE)
printf("->parse_answer(%x)\n", s);
#endif
clear_entry();
#ifdef DEBUG
if (debug & D_PARSE)
printf(" Done clearing entry\n");
#endif
for (ep = ldap_first_entry(ld, s); ep != NULL; ep = ldap_next_entry(ld, ep)) {
#ifdef DEBUG
if (debug & D_PARSE)
printf(" Determining DN and name\n");
#endif
Entry.DN = ldap_get_dn(ld, ep);
#ifdef DEBUG
if (debug & D_PARSE)
printf(" DN = %s\n", Entry.DN);
#endif
rdns = ldap_explode_dn(Entry.DN, TRUE);
#ifdef DEBUG
if (debug & D_PARSE)
printf(" Name = %s\n", *rdns);
#endif
Entry.name = strdup(*rdns);
ldap_value_free(rdns);
for (ap = ldap_first_attribute(ld, ep, &cookie); ap != NULL; ap = ldap_next_attribute(ld, ep, cookie)) {
#ifdef DEBUG
if (debug & D_PARSE)
printf("parsing ap = %s\n", ap);
#endif
if ((idx = attr_to_index(ap)) < 0) {
printf(" Unknown attribute \"%s\"\n", ap);
continue;
}
add_value(&(Entry.attrs[idx]), ep, ap);
}
}
#ifdef DEBUG
if (debug & D_PARSE)
printf(" Done parsing entry\n");
#endif
}
add_value(attr, ep, ap)
struct attribute *attr;
LDAPMessage *ep;
char *ap;
{
register int i = 0;
char **vp, **tp, **avp;
#ifdef DEBUG
if (debug & D_TRACE)
printf("->add_value(%x, %x, %s)\n", attr, ep, ap);
#endif
vp = (char **) ldap_get_values(ld, ep, ap);
/*
* Fill in the attribute structure for this attribute. This
* stores away the values (using strdup()) and the count. Terminate
* the list with a NULL pointer.
*
* attr->quipu_name has already been set during initialization.
*/
if ((attr->number_of_values = ldap_count_values(vp)) > 0) {
attr->values = (char **) Malloc((unsigned) ((attr->number_of_values + 1) * sizeof(char *)));
avp = attr->values;
for (i = 1, tp = vp; *tp != NULL; i++, tp++) {
#ifdef DEBUG
if (debug & D_PARSE)
printf(" value #%d %s\n", i, *tp);
#endif
/*
* The 'name' field of the Entry structure already has
* has the first part of the DN copied into it. Thus,
* we don't need to save it away here again. Also, by
* tossing it away here, we make printing this info out
* a bit easier later.
*/
if (!strcmp(ap, "cn") && !strcmp(*tp, Entry.name)) {
attr->number_of_values--;
continue;
}
*avp++ = strdup(*tp);
}
*avp = NULL;
}
ldap_value_free(vp);
}
print_an_entry()
{
int n = 0, i, idx;
char is_a_group, **order;
char *sub_list[MAX_VALUES], buf[SMALL_BUF_SIZE];
extern int col_size, isaurl(), isadn();
static char *time2text();
#ifdef DEBUG
if (debug & D_TRACE)
printf("->print_an_entry()\n");
#endif
printf(" \"%s\"\n", Entry.name);
/*
* If the entry is a group, find all of the subscribers to that
* group. A subscriber is an entry that *points* to a group entry,
* and a member is an entry that is included as part of a group
* entry.
*
* We also need to select the appropriate output format here.
*/
is_a_group = isgroup();
if (is_a_group) {
order = (char **) group_attr_print_order;
n = find_all_subscribers(sub_list, Entry.DN);
#ifdef DEBUG
if (debug & D_PRINT)
printf(" Group \"%s\" has %d subscribers\n",
Entry.name, n);
#endif
}
else
order = (char **) person_attr_print_order;
for (i = 0; order[i] != NULL; i++) {
idx = attr_to_index(order[i]);
#ifdef DEBUG
if (debug & D_PRINT) {
printf(" ATTR #%2d = %s [%s] (%d values)\n", i + 1,
Entry.attrs[idx].output_string,
Entry.attrs[idx].quipu_name,
Entry.attrs[idx].number_of_values);
}
#endif
if (idx < 0)
continue;
if (Entry.attrs[idx].number_of_values == 0)
continue;
if (isadn(order[i]))
print_DN(Entry.attrs[idx]);
else if (isaurl(order[i]))
print_URL(Entry.attrs[idx]);
else if (isadate(order[i])) {
/* fix time and date, then call usual routine */
Entry.attrs[idx].values[0] =
time2text(Entry.attrs[idx].values[0], FALSE);
print_values(Entry.attrs[idx]);
}
else
print_values(Entry.attrs[idx]);
}
/*
* If it is a group, then we should print the subscriber list (if
* there are any). If there are a lot of them, prompt the user
* before printing them.
*/
if (is_a_group && (n > 0)) {
char *label = "Subscribers: ";
if (n > TOO_MANY_TO_PRINT) {
printf(" There are %d subscribers. Print them? ", n);
fflush(stdout);
fetch_buffer(buf, sizeof(buf), stdin);
if (!((buf[0] == 'y') || (buf[0] == 'Y')))
return;
}
format2((char *) my_ldap_dn2ufn(sub_list[n - 1]), label, (char *) NULL, 2,
2 + strlen(label) + 1, col_size);
for (n--; n > 0; n--)
format2((char *) my_ldap_dn2ufn(sub_list[n - 1]), (char *) NULL,
(char *) NULL, 2 + strlen(label),
2 + strlen(label) + 2, col_size);
}
return;
}
#define OUT_LABEL_LEN 20
/* prints the values associated with an attribute */
print_values(A)
struct attribute A;
{
register int i, k;
register char *cp, **vp;
char out_buf[MED_BUF_SIZE], *padding = NULL;
int lead;
#ifdef DEBUG
if (debug & D_TRACE)
printf("->print_values(%x)\n", A);
#endif
if (A.number_of_values == 0)
return;
if ((vp = A.values) == NULL)
return;
/*
* Pad out the output string label so that it fills the
* whole field of length OUT_LABEL_LEN.
*/
out_buf[0] = '\0';
i = OUT_LABEL_LEN - strlen(A.output_string);
if (i < 0) {
printf("Output string for \"%s\" is too long. Maximum length is %d characters\n", A.quipu_name, OUT_LABEL_LEN);
return;
}
if (isgroup() && !strcmp(A.quipu_name, "mail") && (Entry.attrs[attr_to_index("member")].number_of_values == 0)) {
A.output_string = "Members";
i = OUT_LABEL_LEN - strlen(A.output_string);
padding = (char *) Malloc((unsigned) (i + 1));
(void) memset(padding, ' ', i);
*(padding + i) = '\0';
sprintf(out_buf, "%s:%s", A.output_string, padding);
}
else if (!(isgroup() && !strcmp(A.quipu_name, "mail") && (Entry.attrs[attr_to_index("member")].number_of_values > 0))) {
padding = (char *) Malloc((unsigned) (i + 1));
(void) memset(padding, ' ', i);
*(padding + i) = '\0';
sprintf(out_buf, "%s:%s", A.output_string, padding);
}
/*
* If this happens to be a group, then do not print the output
* string if we have already printed out some members.
*/
else if (isgroup() && !strcmp(A.quipu_name, "mail") && (Entry.attrs[attr_to_index("member")].number_of_values > 0)) {
padding = (char *) Malloc((unsigned) (OUT_LABEL_LEN + 2));
(void) memset(padding, ' ', OUT_LABEL_LEN + 1);
*(padding + OUT_LABEL_LEN + 1) = '\0';
sprintf(out_buf, "%s", padding);
}
lead = strlen(out_buf) + 2;
printf(" %s", out_buf);
for (i = 0; *vp != NULL; i++, vp++) {
if (i > 0) {
if (!strncmp(A.output_string, "Home a", 6) || !strncmp(A.output_string, "Business a", 10)) {
printf(" %s", out_buf);
}
else {
for (k = lead; k > 0; k--)
putchar(' ');
}
}
for (cp = *vp; *cp != '\0'; cp++) {
switch (*cp) {
case '$' :
if (!strncmp(A.output_string, "Home a", 6) || !strncmp(A.output_string, "Business a", 10) || !strcmp(A.quipu_name, "multiLineDescription")) {
putchar('\n');
for (k = lead; k > 0; k--)
putchar(' ');
while (isspace(*(cp + 1)))
cp++;
}
else
putchar(*cp);
break;
case '\n' :
putchar('%');
putchar('\n');
break;
default:
putchar(*cp);
}
}
putchar('\n');
}
if (padding != NULL)
Free(padding);
return;
}
/* prints the DN's associated with an attribute */
print_DN(A)
struct attribute A;
{
int i, lead;
register char **vp;
char out_buf[MED_BUF_SIZE], *padding = NULL;
extern int col_size;
#ifdef DEBUG
if (debug & D_TRACE)
printf("->print_DN(%x)\n", A);
#endif
if (A.number_of_values == 0)
return;
/*
* Pad out the output string label so that it fills the
* whole field of length OUT_LABEL_LEN.
*/
i = OUT_LABEL_LEN - strlen(A.output_string);
if (i > 0) {
padding = (char *) Malloc((unsigned) (i + 1));
(void) memset(padding, ' ', i);
*(padding + i) = '\0';
sprintf(out_buf, "%s:%s", A.output_string, padding);
(void) Free(padding);
}
lead = strlen(out_buf) + 2;
vp = A.values;
format2((char *) my_ldap_dn2ufn(*vp), out_buf, (char *) NULL, 2, lead + 1, col_size);
for (vp++; *vp != NULL; vp++) {
format2((char *) my_ldap_dn2ufn(*vp), (char *) NULL, (char *) NULL, lead,
lead + 1, col_size);
}
return;
}
void clear_entry()
{
register int i;
extern struct attribute attrlist[];
#ifdef DEBUG
if (debug & D_TRACE)
printf("->clear_entry()\n");
if ((debug & D_PRINT) && (Entry.name != NULL))
printf(" Clearing entry \"%s\"\n", Entry.name);
#endif
if (Entry.DN != NULL)
Free(Entry.DN);
if (Entry.name != NULL)
Free(Entry.name);
Entry.may_join = FALSE;
Entry.subscriber_count = -1;
Entry.DN = Entry.name = NULL;
/* clear all of the values associated with all attributes */
for (i = 0; attrlist[i].quipu_name != NULL; i++) {
#ifdef DEBUG
if (debug & D_PRINT)
printf(" Clearing attribute \"%s\" -- ",
Entry.attrs[i].quipu_name);
#endif
if (Entry.attrs[i].values == NULL) {
#ifdef DEBUG
if (debug & D_PRINT)
printf(" no values, skipping\n");
#endif
continue;
}
#ifdef DEBUG
if (debug & D_PRINT)
printf(" freeing %d values\n",
Entry.attrs[i].number_of_values);
#endif
Entry.attrs[i].number_of_values = 0;
ldap_value_free(Entry.attrs[i].values);
Entry.attrs[i].values = (char **) NULL;
/*
* Note: We do not clear either of the char * fields
* since they will always be applicable.
*/
}
}
attr_to_index(s)
char *s;
{
register int i;
extern struct attribute attrlist[];
for (i = 0; attrlist[i].quipu_name != NULL; i++)
if (!strcasecmp(s, attrlist[i].quipu_name))
return(i);
return(-1);
}
void initialize_attribute_strings()
{
register int i;
extern struct entry Entry;
extern struct attribute attrlist[];
for (i = 0; attrlist[i].quipu_name != NULL; i++)
Entry.attrs[i].quipu_name = attrlist[i].quipu_name;
for (i = 0; attrlist[i].quipu_name != NULL; i++)
Entry.attrs[i].output_string = attrlist[i].output_string;
}
/* prints the URL/label pairs associated with an attribute */
print_URL(A)
struct attribute A;
{
int i, lead;
register char **vp;
char out_buf[MED_BUF_SIZE], *padding = NULL;
#ifdef DEBUG
if (debug & D_TRACE)
printf("->print_URL(%x)\n", A);
#endif
if (A.number_of_values == 0)
return;
/*
* Pad out the output string label so that it fills the
* whole field of length OUT_LABEL_LEN.
*/
i = OUT_LABEL_LEN - strlen(A.output_string);
if (i > 0) {
padding = (char *) Malloc((unsigned) (i + 1));
(void) memset(padding, ' ', i);
*(padding + i) = '\0';
sprintf(out_buf, "%s:%s", A.output_string, padding);
}
lead = strlen(out_buf) + 2;
vp = A.values;
print_one_URL(*vp, 2, out_buf, lead);
for (vp++; *vp != NULL; vp++)
print_one_URL(*vp, lead, (char *) NULL, lead);
if (padding != NULL)
Free(padding);
return;
}
print_one_URL(s, label_lead, tag, url_lead)
char *s;
int label_lead;
char *tag;
int url_lead;
{
register int i;
char c, *cp, *url;
extern int col_size;
extern void Free();
for (cp = s; !isspace(*cp) && (*cp != '\0'); cp++)
;
c = *cp;
*cp = '\0';
url = strdup(s);
*cp = c;
if (*cp != '\0') {
for (cp++; isspace(*cp); cp++)
;
}
else
cp = "(no description available)";
format2(cp, tag, (char *) NULL, label_lead, label_lead + 1, col_size);
for (i = url_lead + 2; i > 0; i--)
printf(" ");
printf("%s\n", url);
Free(url);
}
#define GET2BYTENUM( p ) (( *p - '0' ) * 10 + ( *(p+1) - '0' ))
static char *
time2text( char *ldtimestr, int dateonly )
{
struct tm t;
char *p, *timestr, zone, *fmterr = "badly formatted time";
time_t gmttime;
static long gtime();
memset( (char *)&t, 0, sizeof( struct tm ));
if ( strlen( ldtimestr ) < 13 ) {
return( fmterr );
}
for ( p = ldtimestr; p - ldtimestr < 12; ++p ) {
if ( !isdigit( *p )) {
return( fmterr );
}
}
p = ldtimestr;
t.tm_year = GET2BYTENUM( p ); p += 2;
t.tm_mon = GET2BYTENUM( p ) - 1; p += 2;
t.tm_mday = GET2BYTENUM( p ); p += 2;
t.tm_hour = GET2BYTENUM( p ); p += 2;
t.tm_min = GET2BYTENUM( p ); p += 2;
t.tm_sec = GET2BYTENUM( p ); p += 2;
if (( zone = *p ) == 'Z' ) { /* GMT */
zone = '\0'; /* no need to indicate on screen, so we make it null */
}
gmttime = gtime( &t );
timestr = ctime( &gmttime );
timestr[ strlen( timestr ) - 1 ] = zone; /* replace trailing newline */
if ( dateonly ) {
strcpy( timestr + 11, timestr + 20 );
}
Free ( ldtimestr );
return( strdup( timestr ) );
}
/* gtime.c - inverse gmtime */
#if !defined( MACOS ) && !defined( _WIN32 ) && !defined( DOS )
#include <sys/time.h>
#endif /* !MACOS */
/* gtime(): the inverse of localtime().
This routine was supplied by Mike Accetta at CMU many years ago.
*/
int dmsize[] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
#define dysize(y) \
(((y) % 4) ? 365 : (((y) % 100) ? 366 : (((y) % 400) ? 365 : 366)))
#define YEAR(y) ((y) >= 100 ? (y) : (y) + 1900)
/* */
static long gtime ( struct tm *tm )
{
register int i,
sec,
mins,
hour,
mday,
mon,
year;
register long result;
if ((sec = tm -> tm_sec) < 0 || sec > 59
|| (mins = tm -> tm_min) < 0 || mins > 59
|| (hour = tm -> tm_hour) < 0 || hour > 24
|| (mday = tm -> tm_mday) < 1 || mday > 31
|| (mon = tm -> tm_mon + 1) < 1 || mon > 12)
return ((long) -1);
if (hour == 24) {
hour = 0;
mday++;
}
year = YEAR (tm -> tm_year);
result = 0L;
for (i = 1970; i < year; i++)
result += dysize (i);
if (dysize (year) == 366 && mon >= 3)
result++;
while (--mon)
result += dmsize[mon - 1];
result += mday - 1;
result = 24 * result + hour;
result = 60 * result + mins;
result = 60 * result + sec;
return result;
}

View file

@ -1,158 +0,0 @@
/*
* Copyright (c) 1991, 1992, 1993
* Regents of the University of Michigan. All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to the University of Michigan at Ann Arbor. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
*/
#ifdef DOS
#include "protoud.h"
#define strncasecmp(a, b, n) strnicmp(a, b, n)
#define strcasecmp(a, b) stricmp(a, b)
#define MAX_VALUES 8
#else
#define MAX_VALUES 1000
#endif /* end of DOS ifdef */
/*****************************************************************************
**
** Limits which ud imposes. Also subject to change.
**
*****************************************************************************/
/*
* Names are parsed somewhat like 'awk' parses them. This is the
* maximum number of components we store away.
*
* The isnamesepartor() macro should return TRUE if x is equal to one of the
* characters that delimits name fields. The ignorechar() macro should
* return TRUE if it is equal to a character that should be ignored when
* parsing names.
*/
#define MAX_NAME_COMPS 8
#define isnamesepartor(x) (isspace(x))
#define isignorechar(x) (((x) == '.') || ((x) == '_'))
/*
* Quite often a search will turn up more than one match. When it does we
* print out a list of the matches, and ask the user to select the one that
* s/he wants. This defines how many we will save and show.
*/
#define MAX_NUM_NAMES 128
/*
* When a user displays a group, we will automatically print out this many
* members and subscribers. If the number is greater than this, we will
* prompt the user before printing them.
*/
#define TOO_MANY_TO_PRINT 16
/*
* This is the default size of a tty if we can't figure out the actual size.
*/
#define DEFAULT_TTY_HEIGHT 24
#define DEFAULT_TTY_WIDTH 80
/*
* The number of attributes we know about must be less than this number.
* Don't add lots of attributes to the list in globals.c without checking
* this number too.
*/
#define MAX_ATTRS 64
/*****************************************************************************
**
** No user servicable parts beyond this point.
**
*****************************************************************************/
/*
* Generic buffer sizes.
*/
#define SMALL_BUF_SIZE 16
#define MED_BUF_SIZE 128
#define LARGE_BUF_SIZE 512
/*
* Used to specify the operation in x_group().
*/
#define G_JOIN 0
#define G_RESIGN 1
/*
* Authentication method we will be using.
*/
#ifdef KERBEROS
#define UD_AUTH_METHOD LDAP_AUTH_KRBV4
#else
#define UD_AUTH_METHOD LDAP_AUTH_SIMPLE
#endif
/*
* TRUE and FALSE - just in case we need them.
*/
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
/*
* Bound status.
*/
#define UD_NOT_BOUND 0 /* bound only as the default defined above */
#define UD_BOUND 1 /* bound as an actual Directory entity */
/*
* Debug masks.
*/
#define D_TRACE 0x0001
#define D_FIND 0x0002
#define D_GROUPS 0x0004
#define D_MODIFY 0x0008
#define D_PARSE 0x0010
#define D_PRINT 0x0020
#define D_AUTHENTICAT 0x0040
#define D_INITIALIZE 0x0080
/*
* Used in the flags field of an attribute structure.
*/
#define ATTR_FLAG_NONE 0x0000
#define ATTR_FLAG_PERSON 0x0001
#define ATTR_FLAG_GROUP 0x0002
#define ATTR_FLAG_PERSON_MOD 0x0010
#define ATTR_FLAG_GROUP_MOD 0x0020
#define ATTR_FLAG_MAY_EDIT 0x0040
#define ATTR_FLAG_SEARCH 0x0100
#define ATTR_FLAG_READ 0x0200
#define ATTR_FLAG_IS_A_DATE 0x0800
#define ATTR_FLAG_IS_A_DN 0x1000
#define ATTR_FLAG_IS_A_URL 0x2000
#define ATTR_FLAG_IS_A_BOOL 0x4000
#define ATTR_FLAG_IS_MULTILINE 0x8000
/*
* These are the structures we use when parsing an answer we get from the LDAP
* server.
*/
struct attribute {
char *quipu_name;
char *output_string;
void (*mod_func)();
unsigned short flags;
int number_of_values;
char **values;
};
struct entry {
char may_join;
int subscriber_count;
char *DN;
char *name;
struct attribute attrs[MAX_ATTRS];
};

View file

@ -1,662 +0,0 @@
/*
* Copyright (c) 1992, 1993 Regents of the University of Michigan.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to the University of Michigan at Ann Arbor. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
*/
#include <stdio.h>
#include <signal.h>
#include <string.h>
#ifdef DOS
#include <malloc.h>
#endif
#include <memory.h>
#if defined( NeXT )
#include <stdlib.h>
#endif
#include <ctype.h>
#include <errno.h>
#include <lber.h>
#include <ldap.h>
#include <ldapconfig.h>
#if !defined(DOS) && !defined( VMS)
#include <sys/types.h>
#endif
#include "portable.h"
#ifdef USE_TERMIOS
#include <termios.h>
#else /* USE_TERMIOS */
#include <sgtty.h>
#endif /* USE_TERMIOS */
#include "ud.h"
#if defined(VMS)
#define getch getchar
#endif
#ifdef DEBUG
extern int debug;
#endif
char * mygetpass(prompt)
char *prompt;
{
#if defined(DOS) || defined(VMS)
static char buf[256];
int i, c;
#ifdef DEBUG
if (debug & D_TRACE)
printf("->mygetpass(%s)\n", prompt);
#endif
printf("%s", prompt);
i = 0;
while ( (c = getch()) != EOF && c != '\n' && c != '\r' )
buf[i++] = c;
if ( c == EOF )
return( NULL );
buf[i] = '\0';
return (buf);
#else
int no_pass = 0;
char i, j, k;
TERMIO_TYPE ttyb;
TERMFLAG_TYPE flags;
static char pbuf[513];
register char *p;
register int c;
FILE *fi;
SIG_FN (*sig)();
#ifdef DEBUG
if (debug & D_TRACE)
printf("->mygetpass(%s)\n", prompt);
#endif
/*
* Stolen from the getpass() routine. Can't use the plain
* getpass() for two reasons. One is that X.500 passwords
* can be really, really long - much longer than 8 chars.
* The second is that we like to make this client available
* out of inetd via a Merit asynch port, and we need to be
* able to do telnet control codes to turn on and off line
* blanking.
*/
if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL)
fi = stdin;
else
setbuf(fi, (char *)NULL);
sig = signal(SIGINT, SIG_IGN);
if (fi != stdin) {
if (GETATTR(fileno(fi), &ttyb) < 0)
perror("GETATTR");
}
flags = GETFLAGS( ttyb );
SETFLAGS( ttyb, flags & ~ECHO );
if (fi != stdin) {
if (SETATTR(fileno(fi), &ttyb) < 0)
perror("SETATTR");
}
/* blank the line if through Merit */
if (fi == stdin) {
printf("%c%c%c", 255, 251, 1);
fflush(stdout);
(void) scanf("%c%c%c", &i, &j, &k);
fflush(stdin);
}
/* fetch the password */
fprintf(stdout, "%s", prompt);
fflush(stdout);
for (p=pbuf; (c = getc(fi))!='\n' && c!=EOF;) {
if (c == '\r')
break;
if (p < &pbuf[512])
*p++ = c;
}
if (c == EOF)
no_pass = 1;
else {
*p = '\0';
if (*(p - 1) == '\r')
*(p - 1) = '\0';
}
/* unblank the line if through Merit */
if (fi == stdin) {
printf("%c%c%c", 255, 252, 1);
fflush(stdout);
(void) scanf("%c%c%c", &i, &j, &k);
fflush(stdin);
printf("\n"); fflush(stdout);
}
fprintf(stdout, "\n");
fflush(stdout);
/* tidy up */
SETFLAGS( ttyb, flags );
if (fi != stdin) {
if (SETATTR(fileno(fi), &ttyb) < 0)
perror("SETATTR");
}
(void) signal(SIGINT, sig);
if (fi != stdin)
(void) fclose(fi);
else
i = getchar();
if (no_pass)
return(NULL);
return(pbuf);
#endif /* DOS */
}
void printbase(lead, s)
char *lead, *s;
{
register char **cp;
char **rdns;
char * friendly_name();
#ifdef DEBUG
if (debug & D_TRACE)
printf("->printbase(%s, %s)\n", lead, s);
#endif
if (s == NULL) {
printf("%sroot\n", lead);
return;
}
printf("%s", lead);
rdns = ldap_explode_dn(s, TRUE);
for (cp = rdns; ; ) {
printf("%s", friendly_name(*cp));
cp++;
if (*cp == NULL) {
printf("\n");
break;
}
else
printf(", ");
}
ldap_value_free(rdns);
return;
}
fetch_buffer(buffer, length, where)
char *buffer;
int length;
FILE *where;
{
extern LDAP *ld;
register int i;
char *p;
#ifdef DEBUG
if (debug & D_TRACE)
printf("->fetch_buffer(%x, %d, %x)\n", buffer, length, where);
#endif
/*
* Fetch a buffer and strip off any leading or trailing non-printing
* characters, namely newlines and carriage returns.
*/
if (fgets(buffer, length, where) == NULL) {
if (feof(where))
errno = 0; /* so fatal() doesn't bitch */
fatal("fgets");
}
for (i = strlen(buffer) - 1; i >= 0 && !isprint(buffer[i]); i--)
buffer[i] = '\0';
p = buffer;
while ( *p != '\0' ) {
if ( isprint( *p )) {
++p;
} else {
strcpy( p, p + 1 );
}
}
}
fatal(s)
char *s;
{
void exit();
if (errno != 0)
perror(s);
#ifdef KERBEROS
destroy_tickets();
#endif
exit(-1);
}
isgroup()
{
extern struct entry Entry;
char **vp;
register int i;
int group = FALSE;
#ifdef DEBUG
if (debug & D_TRACE)
printf("->isgroup()\n");
#endif
if ((i = attr_to_index("objectClass")) == -1)
return(FALSE);
vp = Entry.attrs[i].values;
for (i = 0; *vp != NULL; vp++) {
#ifdef DEBUG
i++;
if (debug & D_GROUPS)
printf("class #%1d: (%s)\n", i, *vp);
#endif
if (!strcmp(*vp, "rfc822MailGroup"))
group = TRUE;
}
return(group);
}
/*
* Print out the string 's' on a field of 'width' chracters. Each line
* should be indented 'lead' characters.
*/
format(str, width, lead)
char *str;
int width, lead;
{
char *s, *original, *leader = "";
register char *cp;
void * Malloc();
void Free();
#ifdef DEBUG
if (debug & D_TRACE)
printf("->format(%s, %d, %d)\n", str, width, lead);
#endif
if (lead >= width) {
fprintf(stderr, " Cannot format (%s, %d, %d)\n", str, width, lead);
return;
}
if (lead > 0) {
leader = (char *) Malloc((unsigned) (lead + 1));
(void) memset(leader, ' ', lead);
*(leader + lead) = '\0';
}
/*
* Some compilers get really unhappy with this function since it
* fiddles around with the first argument, which could be a string
* constant. We do a strdup() here so we can do whatever the hell
* we want.
*/
s = original = strdup(str);
for (;;) {
if ((strlen(s) + lead) < width) {
printf("%s%s\n", leader, s);
Free(leader);
Free(original);
return;
/*NOTREACHED*/
}
cp = s + width - lead;
while (!isspace(*cp) && (cp != s))
cp--;
*cp = '\0';
while (isspace(*s))
s++;
printf("%s%s\n", leader, s);
s = cp + 1;
}
}
/*
* Print out the string 's' on a field of 'width' chracters. The first line
* should be indented 'first_indent' spaces, then followed by 'first_tag',
* and then followed by the first line of 's'. Subsequent lines should be
* indented 'indent' spaces, then followed by 'tag', and then followed by
* subsequent lines of 's'.
*/
format2(s, first_tag, tag, first_indent, indent, width)
char *s, *first_tag, *tag;
int first_indent, indent, width;
{
char c, *fi, *i;
register char *cp;
void * Malloc();
void Free();
if (first_tag == NULL)
first_tag = "";
if (tag == NULL)
tag = "";
#ifdef DEBUG
if (debug & D_TRACE)
printf("format2(\"%s\", \"%s\", \"%s\", %1d, %1d, %1d)\n", s,
first_tag, tag, first_indent, indent, width);
#endif
/* make sure the indents are sane */
if ((first_indent >= width) || (indent >= width)) {
fprintf(stderr, " Cannot format: indent too large\n");
return;
}
/* make the indentations */
if (first_indent > 0) {
fi = (char *) Malloc((unsigned) (first_indent + 1));
(void) memset(fi, ' ', first_indent);
*(fi + first_indent) = '\0';
}
else
fi = "";
if (indent > 0) {
i = (char *) Malloc((unsigned) (indent + 1));
(void) memset(i, ' ', indent);
*(i + indent) = '\0';
}
else
i = "";
/* now do the first line */
if ((strlen(s) + strlen(first_tag) + first_indent) < width) {
printf("%s%s%s\n", fi, first_tag, s);
Free(fi);
Free(i);
return;
/*NOTREACHED*/
}
/*
* 's' points to the beginning of the string we want to print.
* We point 'cp' to the end of the maximum amount of text we
* can print (i.e., total width less the indentation and the
* length of the tag). Once we have set 'cp' initially we
* back it up to the first space character.
*/
cp = s + width - first_indent - strlen(first_tag);
while (!isspace(*cp) && (cp != s))
cp--;
/*
* Once there, we change that space character to a null, print the
* string, and then restore the space character.
*/
c = *cp;
*cp = '\0';
printf("%s%s%s\n", fi, first_tag, s);
*cp = c;
/*
* Since 'cp' may have been set to a space initially (and so no
* back-tracking was performed), it could have a space after it
* as well. We should gobble up all of these since we don't want
* unexpected leading blanks.
*/
for (s = cp + 1; isspace(*s); s++)
;
/* now do all of the other lines */
for (;;) {
if ((strlen(s) + strlen(tag) + indent) < width) {
printf("%s%s%s\n", i, tag, s);
Free(fi);
Free(i);
return;
/*NOTREACHED*/
}
cp = s + width - indent - strlen(tag);
while (!isspace(*cp) && (cp != s))
cp--;
c = *cp;
*cp = '\0';
printf("%s%s%s\n", i, tag, s);
s = cp + 1;
*cp = c; /* don't mess up 's' */
}
}
#define IN_A_QUOTE 0
#define OUT_OF_QUOTE 1
char * strip_ignore_chars(cp)
char *cp;
{
int had_a_comma = FALSE;
int flag = OUT_OF_QUOTE;
register char *rcp, *cp1;
char *tmp;
void * Malloc();
void Free();
#ifdef DEBUG
if (debug & D_TRACE)
printf("strip_ignore_chars(%s)\n", cp);
#endif
for (rcp = cp; *rcp != '\0'; rcp++)
if (isignorechar(*rcp) || (*rcp == '"'))
break;
if (*rcp == '\0')
return(cp);
cp1 = tmp = (char *) Malloc((unsigned) strlen(cp));
for (rcp = cp; *rcp != '\0'; rcp++) {
/* toss quotes and flip the flag */
if (*rcp == '"')
flag = OUT_OF_QUOTE - flag;
else if (isignorechar(*rcp)) {
if (flag == OUT_OF_QUOTE)
*cp1++ = ' ';
else
*cp1++ = *rcp;
}
else if (*rcp == ',') {
*cp1++ = *rcp;
had_a_comma = TRUE;
}
else
*cp1++ = *rcp;
}
*cp1 = '\0';
/* re-quote the name if it had a comma in it */
if (had_a_comma == TRUE) {
rcp = cp1 = (char *) Malloc((unsigned) (strlen(tmp) + 3));
*rcp++ = '"';
*rcp = '\0';
strcat(rcp, tmp);
strcat(rcp, "\"");
Free(tmp);
tmp = cp1;
}
return(tmp);
}
char * code_to_str(i)
{
switch(i) {
case LDAP_MOD_ADD : return("ADD");
case LDAP_MOD_DELETE : return("DELETE");
case LDAP_MOD_REPLACE : return("REPLACE");
default : return("?????");
}
}
char * friendly_name(s)
char *s;
{
static FriendlyMap *map = NULL;
static char *cp;
cp = ldap_friendly_name(FRIENDLYFILE, s, &map);
if (cp == NULL)
return(s);
return(cp);
}
#ifdef UOFM
/* return TRUE if s has the syntax of a uniqname */
isauniqname(s)
char *s;
{
int i = strlen(s);
if ((i < 3) || (i > 8)) /* uniqnames are 3-8 chars */
return(FALSE);
if (!isalpha(*s)) /* uniqnames begin with a letter */
return(FALSE);
for ( ; *s != '\0'; s++) /* uniqnames are alphanumeric */
if (!isalnum(*s))
return(FALSE);
return(TRUE);
}
#endif
/* return TRUE if this attribute should be printed as a DN */
isadn(s)
char *s;
{
register int i;
extern struct attribute attrlist[];
for (i = 0; attrlist[i].quipu_name != NULL; i++)
if (!strcasecmp(s, attrlist[i].quipu_name))
break;
if (attrlist[i].flags & ATTR_FLAG_IS_A_DN)
return(TRUE);
return(FALSE);
}
char * my_ldap_dn2ufn(s)
char *s;
{
register char **cpp;
static char short_DN[BUFSIZ];
if (strstr(s, UD_BASE) == NULL)
return(ldap_dn2ufn(s));
cpp = ldap_explode_dn(s, TRUE);
sprintf(short_DN, "%s, %s", *cpp, *(cpp + 1));
ldap_value_free(cpp);
return(short_DN);
}
/* return TRUE if this attribute should be printed as a URL */
isaurl(s)
char *s;
{
register int i;
extern struct attribute attrlist[];
for (i = 0; attrlist[i].quipu_name != NULL; i++)
if (!strcasecmp(s, attrlist[i].quipu_name))
break;
if (attrlist[i].flags & ATTR_FLAG_IS_A_URL)
return(TRUE);
return(FALSE);
}
/* return TRUE if this attribute should be printed as a date and time */
isadate(s)
char *s;
{
register int i;
extern struct attribute attrlist[];
for (i = 0; attrlist[i].quipu_name != NULL; i++)
if (!strcasecmp(s, attrlist[i].quipu_name))
break;
if (attrlist[i].flags & ATTR_FLAG_IS_A_DATE)
return(TRUE);
return(FALSE);
}
void * Malloc(size)
unsigned int size;
{
void *void_ptr;
void_ptr = (void *) malloc(size);
if (void_ptr == NULL) {
perror("malloc");
exit(-1);
/*NOTREACHED*/
}
return(void_ptr);
}
void Free(ptr)
char *ptr;
{
extern int free();
if (free(ptr) < 0) {
perror("free");
exit(-1);
/*NOTREACHED*/
}
return;
}
char * nextstr(s)
char *s;
{
while (isspace(*s) && (*s != '\0'))
s++;
if (s == NULL)
return(NULL);
if (*s == '\0')
return(NULL);
return(s);
}
void free_mod_struct(modp)
LDAPMod *modp;
{
void Free();
if (modp->mod_values != NULL)
(void) ldap_value_free(modp->mod_values);
Free(modp->mod_type);
Free(modp);
}
void StrFreeDup(ptr, new_value)
char **ptr, *new_value;
{
void Free();
if (*ptr != NULL)
Free(*ptr);
if (new_value == NULL)
*ptr = NULL;
else
*ptr = strdup(new_value);
}
confirm_action( msg )
char *msg;
{
char tmp[SMALL_BUF_SIZE];
int i;
if ( msg != NULL ) {
putchar( '\n' );
format( msg, 75, 2 );
}
printf("\n Is this OK? ");
fflush(stdout);
tmp[0] = '\0';
fetch_buffer(tmp, sizeof(tmp), stdin);
i = strlen(tmp);
return( i > 0 &&
( !strncasecmp(tmp, "YES", i) || !strncasecmp(tmp, "OK", i)));
}

View file

@ -1,89 +0,0 @@
.TH UD 1 "RELEASEDATE" "OpenLDAP LDVERSION"
.\" $OpenLDAP$
.\" Copyright 1998-2002 The OpenLDAP Foundation All Rights Reserved.
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
.UC 6
.SH NAME
ud \- interactive LDAP Directory Server query program
.SH SYNOPSIS
.B ud
[\c
.BR -Dv ]
.RB [ -s
.IR server ]
.RB [ -d
.IR debug-mask ]
.RB [ -l
.IR ldap-debug-mask ]
.RB [ -f
.IR file ]
.SH DESCRIPTION
.IR ud
is used to interogate a directory server via the Lightweight Directory
Access Protocol (LDAP).
.SH OPTIONS
.TP 1i
.BI \-s \ server
Used to specify the name of an LDAP server to which
.B ud
should connect. If this
flag is omitted, the value specified in the
.B ud
configuration file is used. If
no value is specified in the configuration file, or the configuration
file does not exist, the name
.IR ldap
is used. Of course, it is up to the system administrator to make sure that
the name
.IR ldap
can be resolved (presumably through the use of a CNAME or A record in the DNS
and the appropriate search path specified in the resolver config file).
.TP 1i
.BI \-d \ debug-mask
Sets the
.B ud
debug mask to the value specified.
Values for the mask can be dumped by using the
.IR \-D
flag.
.TP 1i
.BI \-f \ file
Sets the configuration file to the name specified.
.TP 1i
.BI \-l \ ldap-debug-mask
Sets the LDAP debug mask to the value specified.
.TP 1i
.B \-v
Turns on verbose output. Also toggable via the ud
.IR verbose
command.
.TP 1i
.B \-D
Prints out a list of valid ud debug masks.
.SH FILES
.TP
.I ETCDIR/ud.conf
system-wide ud configuration file
.TP
.I $HOME/.udrc
personal ud configuration file, overriding system file
.SH "SEE ALSO"
.BR ud.conf (5),
.BR ldap.conf (5),
.BR ldap (3)
.SH DIAGNOSTICS
.B ud
will try to be nice about error conditions, and in most cases prints a warm
and fuzzy error message when it encounters a problem. Sometimes the error
will be unexpected, and in these cases,
.B ud
uses the ldap_perror() routine to print an informative diagnostic.
.SH BUGS
Too numerous to mention.
.SH AUTHOR
Bryan Beecher, University of Michigan
.SH ACKNOWLEDGEMENTS
.B OpenLDAP
is developed and maintained by The OpenLDAP Project (http://www.openldap.org/).
.B OpenLDAP
is derived from University of Michigan LDAP 3.3 Release.

View file

@ -86,9 +86,7 @@ attribute. The filter "mail=*@terminator.rs.itd.umich.edu" will find
any entries that have a mail attribute ending in the specified string.
To put parentheses in a filter, escape them with a backslash '\\'
character. See RFC 2254 for a more complete description of allowable
filters. See
.BR ldap_getfilter (3)
for routines to help in constructing search filters automatically.
filters.
.LP
\fIAttrs\fP is a null-terminated array of attribute types to return
from entries that match \fIfilter\fP.

View file

@ -1,109 +0,0 @@
.TH UD.CONF 5 "RELEASEDATE" "OpenLDAP LDVERSION"
.\" $OpenLDAP$
.\" Copyright 1998-2002 The OpenLDAP Foundation All Rights Reserved.
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
.UC 6
.SH NAME
ud.conf \- ud configuration file
.SH SYNOPSIS
ETCDIR/ud.conf
.SH DESCRIPTION
The
.I ud
configuration file is used to set system-wide defaults to be applied when
running
.IR ud .
Note that each user may specify an optional configuration file,
.IR .udrc ,
in his/her home directory which will be used instead of the system-wide
configuration file.
.SH OPTIONS
The different configuration options are:
.TP 1i
\fBHOST <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.

View file

@ -1,295 +0,0 @@
.TH MAIL500 8C "RELEASEDATE" "OpenLDAP LDVERSION"
.\" $OpenLDAP$
.\" Copyright 1998-2002 The OpenLDAP Foundation All Rights Reserved.
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
.SH NAME
mail500 \- X.500 capable mailer
.LP
fax500 \- X.500 capable fax delivery agent
.SH SYNOPSIS
.B LIBEXECDIR/mail500 [\-d level] [\-f mailfrom]
.B [\-h hostname] [\-l ldaphost]
.B [\-m address] [\-v vacationhost]
.LP
.B LIBEXECDIR/fax500 [\-d level] [\-f mailfrom]
.B [\-h hostname] [\-l ldaphost]
.B [\-m address]
.SH DESCRIPTION
.B mail500
is an LDAP/X.500-capable mailer, suitable to be invoked from a
mail delivery agent such as
.BR sendmail (8).
It supports mail to both individuals and groups.
.B fax500
is an LDAP/X.500-capable facsimile delivery agent. It utilizes the
Internet remote-printing experiment (tpc.int). For more
information on tpc.int, look in
.B /mrose/tpc
on
.BR ftp.ics.uci.edu ,
or send mail to
.BR tpc-faq@town.hall.org .
.SH OPTIONS
.RB \- d level
Turn on debugging as defined by
.I level.
This option directs
.B mail500/fax500
to produce various debugging output via the
.BR syslog (8)
facility at the LOG_ALERT level.
.TP
.BI \-f " mailfrom"
This option tells
.B mail500/fax500
what to set the envelop from address to when (re)invoking sendmail
to deliver mail.
.I mailfrom
should be a valid email address. Normally, this option is passed
to
.B mail500/fax500
via the sendmail.cf(5) mailer definition, and is set
to something like the $f macro.
.TP
.BI \-l " ldaphost"
Specify an alternate host on which the LDAP server is running.
.TP
.BI \-m " address"
If
.I mail500/fax500
produces a rejection message, this is the
.I address
from which it will com. Normally, this option is passed to
.I mail500/fax500
via the sendmail.cf(5) mailer definition, and is set to something
like $n@$w (typically, mailer-daemon@hostname).
.TP
.BI \-v " vacationhost"
If the vacation facility is operative, this option specifies the
host to which the mail of users who are on vacation should be sent.
.SH HOW MAIL500 AND FAX500 WORK
When mail500/fax500 gets invoked with one or more names to which to
deliver mail, it searches for each name in X.500. Where it searches,
and what kind(s) of search(es) it does are compile-time configurable
by changing the
.B base
array in
.BR main.c .
For example, the configuration we use at U-M is like this:
.LP
.nf
Base base[] =
{ "ou=People, o=University of Michigan, c=US", 0
"uid=%s", "cn=%s", NULL,
"ou=System Groups, ou=Groups, o=University of Michigan, c=US", 1
"(&(cn=%s)(associatedDomain=%h))", NULL, NULL,
"ou=User Groups, ou=Groups, o=University of Michigan, c=US", 1
"(&(cn=%s)(associatedDomain=%h))", NULL, NULL,
NULL
};
.fi
.LP
which means that in delivering mail to "name@umich.edu"
.B mail500/fax500would do the
the following searches, stopping if it finds a match at any step:
.LP
.nf
subtree search of "ou=People, o=University of Michigan, c=US"
for (uid=name)
subtree search of "ou=People, o=University of Michigan, c=US"
for (cn=name)
subtree search of "ou=System Groups, ou=Groups, o=University of Michigan, c=US"
for (&(cn=name)(associatedDomain=umich.edu))
subtree search of "ou=User Groups, ou=Groups, o=University of Michigan, c=US"
for (&(cn=name)(associatedDomain=umich.edu))
.fi
.LP
Notice that when specifying a filter %s is replaced by the name,
or user portion of the address while %h is replaced by whatever is
passed in to
.B mail500/fax500
via the
.RB \- h
option (typically the host portion of the address).
.LP
You can also specify whether you want search results that matched
because the entry's RDN matched the search to be given preference
or not. At U-M, we only give such preference in the mail group
portion of the searches. Beware with this option: the algorithm
used to decide whether an entry's RDN matched the search is very
simple-minded, and may not always be correct.
.LP
There is currently no limit on the number of areas searched (the base
array can be as large as you want), and an arbitrary limit of 2 filters
for each base. If you want more than that, simply changing the 3 in
the typedef for Base should do the trick.
.SH X.500 SUPPORT
In X.500, there are several new attribute types and one new object
class defined that
.B mail500/fax500
uses. At its most basic, for normal
entries
.B mail500
will deliver to the value(s) listed in the
.B mail
attribute of the entry, and
.B fax500
will attempt to deliver a fax to the telephone number listed in the
.B facsimileTelephoneNumber
attribute. For example, at U-M my entry has the attribute
.LP
.nf
mail= tim@terminator.rs.itd.umich.edu
.fi
.LP
So mail sent to tim@umich.edu will be delivered via
.B mail500
to that
address (assuming the
.BR sendmail.cf (5)
file is set up to call
.B mail500
for mail to somebody@umich.edu - see below). If there were multiple
values for the mail attribute, multiple copies of the mail would be sent.
.LP
In the case of
.BR fax500 , if my entry has the attribute
.LP
.nf
facsimileTelephoneNumber= +1 313 764 5140
.fi
.LP
A message sent to tim@fax.umich.edu (assuming the sendmail.cf file
is set up to pass mail @fax.umich.edu to
.BR fax500 \-
see below)
will generate a message to
remote-printer.Timothy_A_Howes@0.4.1.5.4.6.7.3.1.3.1.tpc.int.
.LP
A new object class, rfc822MailGroup, and several new attributes have
been defined to handle email groups/mailing lists. To use this, you
will need to add this to your local
.BR oidtable.oc :
.LP
.nf
# object class for representing rfc 822 mailgroups
rfc822MailGroup: umichObjectClass.2 : \\
top : \\
cn : \\
rfc822Mailbox, member, memberOfGroup, owner, \\
errorsTo, rfc822ErrorsTo, requestsTo, rfc822RequestsTo, \\
joinable, associatedDomain, \\
description, multiLineDescription, \\
userPassword, krbName, \\
telecommunicationAttributeSet, postalAttributeSet
.fi
.LP
And you will need to add these to your local oidtable.at:
.LP
.nf
# attrs for rfc822mailgroups
multiLineDescription: umichAttributeType.2 : CaseIgnoreList
rfc822ErrorsTo: umichAttributeType.26 : CaseIgnoreIA5String
rfc822RequestsTo: umichAttributeType.27 : CaseIgnoreIA5String
joinable: umichAttributeType.28 : Boolean
memberOfGroup: umichAttributeType.29 : DN
errorsTo: umichAttributeType.30 : DN
requestsTo: umichAttributeType.31 : DN
.fi
.LP
The idea was to define a kind of hybrid mail group that could handle
people who were in X.500 or not. So, for example, members of a group
can be specified via the member attribute (for X.500 members) or the
rfc822MailBox attribute (for non-X.500 members). Similarly for the
errorsTo and rfc822ErrorsTo, and the requestsTo and rfc822RequestsTo
attributes.
.LP
To create a real mailing list, with a list maintainer, all you have to
do is create an rfc822MailGroup and fill in the errorsTo or
rfc822ErrorsTo attributes (or both). That will cause any errors
encountered when delivering mail to the group to go to the addresses
listed (or X.500 entry via it's mail attribute).
.LP
If you fill in the requestsTo or rfc822RequestsTo (or both) attributes,
mail sent to groupname-request will be sent to the addresses listed
there. If you fill in the owner attribute, mail sent to
groupname-owner will be sent to the addresses listed there. mail500
does this automatically, so you don't have to explicitly add the
groupname-request or groupname-owner aliases to your group.
.LP
To allow users to join a group, there is the joinable flag. If TRUE,
mail500 will search for entries that have a memberOfGroup attribute
equal to the DN of the group, using the same algorithm it used to find
the group in the first place (i.e. the DNs and filters listed in the
base array). This allows people to join (or subscribe to) a group
without having to modify the group entry directly. If joinable is
FALSE, the search is not done.
.SH SENDMAIL CONFIGURATION
The idea is that you might have a rule like this in your sendmail.cf
file somewhere in rule set 0:
.LP
.nf
R$*<@umich.edu>$* $#mail500$@umich.edu$:<$1>
R$*<@fax.umich.edu>$* $#fax500$@fax.umich.edu$:<$1>
.fi
.LP
These rules say that any address that ends in @umich.edu will cause
the mail500 mailer to be called to deliver the mail, and any address
that ends in @fax.umich.edu will cause the fax500 mailer to
be called. You probably
also want to do something to prevent addresses like terminator!tim@umich.edu
or tim%terminator.rs.itd.umich.edu@umich.edu from being passed to mail500.
At U-M, we do this by adding rules like this to rule set 9 where we
strip off our local names:
.LP
.nf
R<@umich.edu>$*:$* $>10<@>$1:$2
R$+%$+<@umich.edu> $>10$1%$2<@>
R$+!$+<@umich.edu> $>10$1!$2<@>
.fi
.LP
Of course, you would substitute your domain name for umich.edu in the
above examples. See the sample sendmail.cf file in the ldap source
directory clients/mail500/ for more details.
.LP
The mail500 and fax500 mailers should be defined similar to this in the
sendmail.cf file:
.LP
.nf
Mmail500, P=LIBEXECDIR/mail500, F=DFMSmnXuh, A=mail500 -f $f -h $h -m $n@$w $u
Mfax500, P=LIBEXECDIR/fax500, F=DFMSmnXuh, A=fax500 -f $f -h $h -m $n@$w $u
.fi
.LP
This defines how mail500/fax500 will be treated by sendmail and what
arguments it will have when it's called. The various flags specified
by the F=... parameter are explained in your local sendmail book (with
any luck). The arguments to mail500/fax500 are as defined under OPTIONS
above. The final argument $u is used to stand for the addresses to which
to deliver the mail.
.SH NOTES
The default values for several #defines that control how mail500
and fax500 works are configured at compile time in the
include/ldapconfig.h.edit include file. You should edit this
file to suit your site.
.SH BUGS
mail500/fax500 should use the ldap_getfilter(3) facility, instead of
compiling in the search filters to use. This is shameful.
.LP
The support for joinable groups (searching to find members who have
set something in their own entry) is really a hack because we did not
have good enough access control to allow people to add and delete
themselves from the group itself.
.LP
At one point, mail500 and fax500 were exactly the same binary, and
would behave appropriately based on how they were invoked. Unfortunately,
several new features (e.g. vacation support) were added to mail500
but not to fax500.
.SH "SEE ALSO"
.BR ldap (3),
.BR sendmail.cf (5),
.BR sendmail (8)
.SH ACKNOWLEDGEMENTS
.B OpenLDAP
is developed and maintained by The OpenLDAP Project (http://www.openldap.org/).
.B OpenLDAP
is derived from University of Michigan LDAP 3.3 Release.

View file

@ -1 +0,0 @@
fax500.8