mirror of
https://git.openldap.org/openldap/openldap.git
synced 2025-12-24 00:29:35 -05:00
Update documentation. Add support for caching, sorting, enabling "all"
in searches, and experimental "trap" subcommand.
This commit is contained in:
parent
4c7739e6e5
commit
222962d249
2 changed files with 164 additions and 45 deletions
|
|
@ -26,7 +26,7 @@ A new command by the name of \fIcommand\fR will be created to access
|
|||
the LDAP database at \fIhostlist\fR. \fIhostlist\fR may contain elements
|
||||
of the format \fBhost:port\fR if a port other than the default LDAP port
|
||||
of 389 is required. The LDAP library will attempt to connect to each
|
||||
host in turn until it succeeds.
|
||||
host in turn until it succeeds or exhausts the list.
|
||||
.PP
|
||||
The \fBexplode\fR form provides a means (via ldap_explode(3)) to explode a DN
|
||||
into its component parts. \fB-nonames\fR strips off the attribute names,
|
||||
|
|
@ -64,9 +64,6 @@ deferred until we actually try to do something.
|
|||
For the purposes of this example, we're going to assume that "foo" is the
|
||||
command created by opening a connection using "ldap open".
|
||||
|
||||
Note: Karl is particularly dissatisfied with the syntax of this option,
|
||||
so it is one of the most likely things to change in a subsequent release.
|
||||
|
||||
.SH BINDING
|
||||
|
||||
After a connection is made to an LDAP server, an LDAP bind operation must
|
||||
|
|
@ -74,11 +71,10 @@ be performed before other operations can be attempted over the connection.
|
|||
|
||||
Both simple authentication and kerberos authentication are available.
|
||||
LDAP version 3 supports many new "SSL"-style authentication and encryption
|
||||
systems, which are not currently supported by the UMich server, and hence
|
||||
by this interface package.
|
||||
systems, which are not currently supported by the OpenLDAP v1.2 server, and
|
||||
hence by this interface package.
|
||||
|
||||
Currently simple authentication, and kerberos-based authentication, are
|
||||
supported.
|
||||
Currently simple and kerberos-based authentication, are supported.
|
||||
|
||||
To use LDAP and still have reasonable security in a networked,
|
||||
Internet/Intranet environment, secure shell can be used to setup
|
||||
|
|
@ -140,17 +136,19 @@ This creates a new distinguished name and defines zero or more attributes.
|
|||
|
||||
"attributePairList" is a list of key-value pairs, the same as would
|
||||
be returned by "array get" if an array had been set up containing the
|
||||
key-value pairs. Note that, right now, the sort of lowest-level pair
|
||||
of the DN must also appear in the attributePairList, as in:
|
||||
key-value pairs.
|
||||
|
||||
foo add "cn=karl, ou=People, o=NeoSoft Inc, c=US" {cn karl ...}
|
||||
|
||||
Some directory servers and/or their client SDKs will automatically
|
||||
add the leaf attribute value for you.
|
||||
|
||||
Here is a more precise description of how an attributePairList looks:
|
||||
|
||||
{cn {karl {Karl Lehenbauer}} telephone 713-968-5800}
|
||||
|
||||
Note here that two cn values, "karl" and "Karl Lehenbauer", are added.
|
||||
A command error is to write
|
||||
Is it an error to write:
|
||||
|
||||
{cn {Karl Lehenbauer}}
|
||||
|
||||
|
|
@ -161,11 +159,11 @@ typing hard-coded lists.
|
|||
|
||||
We have noticed that the Netscape server will automatically add the
|
||||
left-most rdn portion of the DN (ie. cn=karl), whereas the University
|
||||
of Michigan version does not.
|
||||
of Michigan and OpenLDAP 1.2 versions do not.
|
||||
|
||||
.SH ADDING, DELETING, AND REPLACING OBJECT ATTRIBUTES
|
||||
|
||||
You can have multiple occurrences of the same attribute in a record.
|
||||
You can have multiple values for a given attribute in an LDAP object.
|
||||
These are represented in search results, through the Tcl interface,
|
||||
as a list.
|
||||
|
||||
|
|
@ -173,21 +171,23 @@ as a list.
|
|||
|
||||
This adds key-value pairs to an existing DN. If an attribute being
|
||||
added already exists, the new value will be appended to the list.
|
||||
If a particular value being added to an attribute already exists in
|
||||
the object a Tcl error is raised.
|
||||
|
||||
foo replace_attributes dn attributePairList
|
||||
|
||||
This replaces specified key-value pairs in an existing DN, leaving
|
||||
unnamed ones untouched.
|
||||
This replaces the specified attributes in an existing DN, leaving
|
||||
unnamed ones untouched. Any previous values for the supplied attributes
|
||||
(if any) are discarded.
|
||||
|
||||
foo delete_attributes dn attributePairList
|
||||
|
||||
This deletes attributes in the list. If a pair is "foo {bar snap}" and
|
||||
you delete "foo bar", "foo" will still have "snap".
|
||||
This deletes attributes in the list. If an attribute "foo" has the
|
||||
value list {bar snap}, and you delete using the attributePairList "foo bar",
|
||||
"foo" will still have "snap".
|
||||
|
||||
If you provide an empty string ("") for the value part of the key-value
|
||||
pair, the entire attribute will be deleted. To reiterate, if you provide
|
||||
a non-empty string for the value part, only that value will be removed
|
||||
from the value list.
|
||||
If you provide an empty string ("") for the value list,
|
||||
the entire attribute will be deleted.
|
||||
|
||||
.SH SEARCHING
|
||||
|
||||
|
|
@ -233,8 +233,8 @@ version.
|
|||
|
||||
.SH CACHING (Note: Netscape clients do not have caching interfaces).
|
||||
|
||||
The UMich LDAP library offers the client application fairly fine-
|
||||
grained control of caching of results retrieved from searches,
|
||||
The UMich and OpenLDAP client libraries offers the client application fairly
|
||||
fine-grained control of caching of results retrieved from searches,
|
||||
offering significant performance improvement and reduced
|
||||
network traffic.
|
||||
|
||||
|
|
@ -272,7 +272,10 @@ To enable caching of data received from an LDAP connection,
|
|||
|
||||
This should be used, for example, after doing an add_attributes,
|
||||
delete_attributes, or replace_attributes (ldap_modify(3))
|
||||
involving the requested DN.
|
||||
involving the requested DN. Generally this should not be needed,
|
||||
as the Tcl interface automatically performs this operation on
|
||||
any dn that is modified (add,replace,delete) while caching is
|
||||
enabled.
|
||||
|
||||
foo cache no_errors
|
||||
|
||||
|
|
@ -295,7 +298,8 @@ Because we used the new "Tcl object" C interfaces, this package only works
|
|||
with Tcl 8.0 or above.
|
||||
|
||||
This package interfaces with the University of Michigan LDAP protocol
|
||||
package, version 3.3, an implementation of version 2 of the LDAP protocol.
|
||||
package, version 3.3, and OpenLDAP version 1.2, both of which are
|
||||
implementations of version 2 of the LDAP protocol.
|
||||
|
||||
Although an LDAP client (or server) could be written in native Tcl 8.0,
|
||||
as Tcl 8.0 and above can do binary I/O, and Tcl 8 and above have strings
|
||||
|
|
@ -334,8 +338,8 @@ related to LDAP services.
|
|||
|
||||
.SH AUTHORS
|
||||
It was written by Karl Lehenbauer, of NeoSoft, Inc., in August and
|
||||
September of 1997. Ldap explode, and numerous bug fixes by Randy
|
||||
Kunkee, also of NeoSoft, Inc., in 1998.
|
||||
September of 1997. Ldap explode, and numerous bug fixes and extensions
|
||||
by Randy Kunkee, also of NeoSoft, Inc., in 1998-1999.
|
||||
|
||||
.SH KEYWORDS
|
||||
element, join, list, separator
|
||||
|
|
|
|||
|
|
@ -107,6 +107,8 @@ typedef struct ldaptclobj {
|
|||
int caching; /* flag 1/0 if caching is enabled */
|
||||
long timeout; /* timeout from last cache enable */
|
||||
long maxmem; /* maxmem from last cache enable */
|
||||
Tcl_Obj *trapCmdObj; /* error handler */
|
||||
int *traplist; /* list of errorCodes to trap */
|
||||
int flags;
|
||||
} LDAPTCL;
|
||||
|
||||
|
|
@ -118,7 +120,7 @@ typedef struct ldaptclobj {
|
|||
static
|
||||
LDAP_SetErrorCode(LDAPTCL *ldaptcl, int code, Tcl_Interp *interp)
|
||||
{
|
||||
char shortbuf[6];
|
||||
char shortbuf[16];
|
||||
char *errp;
|
||||
int lderrno;
|
||||
|
||||
|
|
@ -132,6 +134,33 @@ LDAP_SetErrorCode(LDAPTCL *ldaptcl, int code, Tcl_Interp *interp)
|
|||
errp = ldaptclerrorcode[code];
|
||||
|
||||
Tcl_SetErrorCode(interp, errp, NULL);
|
||||
if (ldaptcl->trapCmdObj) {
|
||||
int *i;
|
||||
Tcl_Obj *cmdObj;
|
||||
if (ldaptcl->traplist != NULL) {
|
||||
for (i = ldaptcl->traplist; *i && *i != code; i++)
|
||||
;
|
||||
if (*i == 0) return;
|
||||
}
|
||||
(void) Tcl_EvalObj(interp, ldaptcl->trapCmdObj);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
LDAP_ErrorStringToCode(Tcl_Interp *interp, char *s)
|
||||
{
|
||||
int offset;
|
||||
int code;
|
||||
|
||||
offset = (strncasecmp(s, "LDAP_", 5) == 0) ? 0 : 5;
|
||||
for (code = 0; code < LDAPTCL_MAXERR; code++) {
|
||||
if (!ldaptclerrorcode[code]) continue;
|
||||
if (strcasecmp(s, ldaptclerrorcode[code]+offset) == 0)
|
||||
return code;
|
||||
}
|
||||
Tcl_ResetResult(interp);
|
||||
Tcl_AppendResult(interp, s, " is an invalid code", (char *) NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
|
|
@ -179,6 +208,8 @@ LDAP_ProcessOneSearchResult (interp, ldap, entry, destArrayNameObj, evalCodeObj)
|
|||
return TCL_ERROR;
|
||||
ldap_memfree(dn);
|
||||
}
|
||||
attributeNameObj = Tcl_NewObj();
|
||||
Tcl_IncrRefCount (attributeNameObj);
|
||||
for (attributeName = ldap_first_attribute (ldap, entry, &ber);
|
||||
attributeName != NULL;
|
||||
attributeName = ldap_next_attribute(ldap, entry, ber)) {
|
||||
|
|
@ -192,13 +223,12 @@ LDAP_ProcessOneSearchResult (interp, ldap, entry, destArrayNameObj, evalCodeObj)
|
|||
as an error, we ignore it to present a consistent interface
|
||||
with Netscape's server
|
||||
*/
|
||||
attributeNameObj = Tcl_NewStringObj (attributeName, -1);
|
||||
Tcl_IncrRefCount (attributeNameObj);
|
||||
attributeDataObj = Tcl_NewObj();
|
||||
Tcl_SetStringObj(attributeNameObj, attributeName, -1);
|
||||
for (i = 0; bvals[i] != NULL; i++) {
|
||||
Tcl_Obj *singleAttributeValueObj;
|
||||
|
||||
singleAttributeValueObj = Tcl_NewStringObj (bvals[i]->bv_val, -1);
|
||||
singleAttributeValueObj = Tcl_NewStringObj(bvals[i]->bv_val, bvals[i]->bv_len);
|
||||
if (Tcl_ListObjAppendElement (interp,
|
||||
attributeDataObj,
|
||||
singleAttributeValueObj)
|
||||
|
|
@ -217,9 +247,9 @@ LDAP_ProcessOneSearchResult (interp, ldap, entry, destArrayNameObj, evalCodeObj)
|
|||
TCL_LEAVE_ERR_MSG) == NULL) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
Tcl_DecrRefCount (attributeNameObj);
|
||||
}
|
||||
}
|
||||
Tcl_DecrRefCount (attributeNameObj);
|
||||
return Tcl_EvalObj (interp, evalCodeObj);
|
||||
}
|
||||
|
||||
|
|
@ -268,8 +298,8 @@ LDAP_PerformSearch (interp, ldaptcl, base, scope, attrs, filtpatt, value,
|
|||
int abandon;
|
||||
int tclResult = TCL_OK;
|
||||
int msgid;
|
||||
LDAPMessage *resultMessage;
|
||||
LDAPMessage *entryMessage;
|
||||
LDAPMessage *resultMessage = 0;
|
||||
LDAPMessage *entryMessage = 0;
|
||||
char *sortKey;
|
||||
|
||||
Tcl_Obj *resultObj;
|
||||
|
|
@ -334,10 +364,13 @@ LDAP_PerformSearch (interp, ldaptcl, base, scope, attrs, filtpatt, value,
|
|||
}
|
||||
if (resultCode == LDAP_RES_SEARCH_RESULT || all)
|
||||
break;
|
||||
if (resultMessage)
|
||||
ldap_msgfree(resultMessage);
|
||||
resultMessage = NULL;
|
||||
}
|
||||
if (abandon) {
|
||||
ldap_msgfree(resultMessage);
|
||||
if (resultMessage)
|
||||
ldap_msgfree(resultMessage);
|
||||
if (resultCode == LDAP_RES_SEARCH_ENTRY)
|
||||
ldap_abandon(ldap, msgid);
|
||||
return tclResult;
|
||||
|
|
@ -367,10 +400,13 @@ LDAP_PerformSearch (interp, ldaptcl, base, scope, attrs, filtpatt, value,
|
|||
"LDAP search error: ",
|
||||
ldap_err2string(errorCode),
|
||||
(char *)NULL);
|
||||
ldap_msgfree(resultMessage);
|
||||
if (resultMessage)
|
||||
ldap_msgfree(resultMessage);
|
||||
LDAP_SetErrorCode(ldaptcl, errorCode, interp);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if (resultMessage)
|
||||
ldap_msgfree(resultMessage);
|
||||
return tclResult;
|
||||
}
|
||||
|
||||
|
|
@ -607,11 +643,11 @@ NeoX_LdapTargetObjCmd (clientData, interp, objc, objv)
|
|||
|
||||
nPairs = attribObjc / 2;
|
||||
|
||||
modArray = (LDAPMod **)ckalloc (sizeof(LDAPMod *) * (nPairs + 1));
|
||||
modArray = (LDAPMod **)malloc (sizeof(LDAPMod *) * (nPairs + 1));
|
||||
modArray[nPairs] = (LDAPMod *) NULL;
|
||||
|
||||
for (i = 0; i < nPairs; i++) {
|
||||
mod = modArray[i] = (LDAPMod *) ckalloc (sizeof(LDAPMod));
|
||||
mod = modArray[i] = (LDAPMod *) malloc (sizeof(LDAPMod));
|
||||
mod->mod_op = mod_op;
|
||||
mod->mod_type = Tcl_GetStringFromObj (attribObjv [i * 2], NULL);
|
||||
|
||||
|
|
@ -621,7 +657,7 @@ NeoX_LdapTargetObjCmd (clientData, interp, objc, objv)
|
|||
}
|
||||
|
||||
valPtrs = mod->mod_vals.modv_strvals = \
|
||||
(char **)ckalloc (sizeof (char *) * (valuesObjc + 1));
|
||||
(char **)malloc (sizeof (char *) * (valuesObjc + 1));
|
||||
valPtrs[valuesObjc] = (char *)NULL;
|
||||
|
||||
for (j = 0; j < valuesObjc; j++) {
|
||||
|
|
@ -631,7 +667,7 @@ NeoX_LdapTargetObjCmd (clientData, interp, objc, objv)
|
|||
* value be NULL to indicate entire attribute is to be
|
||||
* deleted */
|
||||
if ((*valPtrs [j] == '\0')
|
||||
&& (mod->mod_op == LDAP_MOD_DELETE)) {
|
||||
&& (mod->mod_op == LDAP_MOD_DELETE || mod->mod_op == LDAP_MOD_REPLACE)) {
|
||||
valPtrs [j] = NULL;
|
||||
}
|
||||
}
|
||||
|
|
@ -647,10 +683,10 @@ NeoX_LdapTargetObjCmd (clientData, interp, objc, objv)
|
|||
|
||||
/* free the modArray elements, then the modArray itself. */
|
||||
for (i = 0; i < nPairs; i++) {
|
||||
ckfree ((char *) modArray[i]->mod_vals.modv_strvals);
|
||||
ckfree ((char *) modArray[i]);
|
||||
free ((char *) modArray[i]->mod_vals.modv_strvals);
|
||||
free ((char *) modArray[i]);
|
||||
}
|
||||
ckfree ((char *) modArray);
|
||||
free ((char *) modArray);
|
||||
|
||||
/* FIX: memory cleanup required all over the place here */
|
||||
if (result != LDAP_SUCCESS) {
|
||||
|
|
@ -848,6 +884,7 @@ NeoX_LdapTargetObjCmd (clientData, interp, objc, objv)
|
|||
/* Caching control within the search: if the "cache" control array */
|
||||
/* value is set, disable/enable caching accordingly */
|
||||
|
||||
#if 0
|
||||
if (cacheThis >= 0 && ldaptcl->caching != cacheThis) {
|
||||
if (cacheThis) {
|
||||
if (ldaptcl->timeout == 0) {
|
||||
|
|
@ -859,6 +896,7 @@ NeoX_LdapTargetObjCmd (clientData, interp, objc, objv)
|
|||
else
|
||||
ldap_disable_cache(ldap);
|
||||
}
|
||||
#endif
|
||||
tclResult = LDAP_PerformSearch (interp,
|
||||
ldaptcl,
|
||||
baseString,
|
||||
|
|
@ -873,12 +911,14 @@ NeoX_LdapTargetObjCmd (clientData, interp, objc, objv)
|
|||
sortattr);
|
||||
/* Following the search, if we changed the caching behavior, change */
|
||||
/* it back. */
|
||||
#if 0
|
||||
if (cacheThis >= 0 && ldaptcl->caching != cacheThis) {
|
||||
if (cacheThis)
|
||||
ldap_disable_cache(ldap);
|
||||
else
|
||||
ldap_enable_cache(ldap, ldaptcl->timeout, ldaptcl->maxmem);
|
||||
}
|
||||
#endif
|
||||
return tclResult;
|
||||
}
|
||||
|
||||
|
|
@ -993,6 +1033,75 @@ NeoX_LdapTargetObjCmd (clientData, interp, objc, objv)
|
|||
return TCL_ERROR;
|
||||
}
|
||||
#endif
|
||||
if (STREQU (subCommand, "trap")) {
|
||||
Tcl_Obj *listObj, *resultObj;
|
||||
int *p, l, i, code;
|
||||
|
||||
if (objc > 4)
|
||||
return TclX_WrongArgs (interp, objv [0],
|
||||
"trap command ?errorCode-list?");
|
||||
if (objc == 2) {
|
||||
if (!ldaptcl->trapCmdObj)
|
||||
return TCL_OK;
|
||||
resultObj = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(interp, resultObj, ldaptcl->trapCmdObj);
|
||||
if (ldaptcl->traplist) {
|
||||
listObj = Tcl_NewObj();
|
||||
for (p = ldaptcl->traplist; *p; p++) {
|
||||
Tcl_ListObjAppendElement(interp, listObj,
|
||||
Tcl_NewStringObj(ldaptclerrorcode[*p], -1));
|
||||
}
|
||||
Tcl_ListObjAppendElement(interp, resultObj, listObj);
|
||||
}
|
||||
Tcl_SetObjResult(interp, resultObj);
|
||||
return TCL_OK;
|
||||
}
|
||||
if (ldaptcl->trapCmdObj) {
|
||||
Tcl_DecrRefCount (ldaptcl->trapCmdObj);
|
||||
ldaptcl->trapCmdObj = NULL;
|
||||
}
|
||||
if (ldaptcl->traplist) {
|
||||
free(ldaptcl->traplist);
|
||||
ldaptcl->traplist = NULL;
|
||||
}
|
||||
Tcl_GetStringFromObj(objv[2], &l);
|
||||
if (l == 0)
|
||||
return TCL_OK; /* just turn off trap */
|
||||
ldaptcl->trapCmdObj = objv[2];
|
||||
Tcl_IncrRefCount (ldaptcl->trapCmdObj);
|
||||
if (objc < 4)
|
||||
return TCL_OK; /* no code list */
|
||||
if (Tcl_ListObjLength(interp, objv[3], &l) != TCL_OK)
|
||||
return TCL_ERROR;
|
||||
if (l == 0)
|
||||
return TCL_OK; /* empty code list */
|
||||
ldaptcl->traplist = malloc(sizeof(int) * (l + 1));
|
||||
ldaptcl->traplist[l] = 0;
|
||||
for (i = 0; i < l; i++) {
|
||||
Tcl_ListObjIndex(interp, objv[3], i, &resultObj);
|
||||
code = LDAP_ErrorStringToCode(interp, Tcl_GetStringFromObj(resultObj));
|
||||
if (code == -1) {
|
||||
free(ldaptcl->traplist);
|
||||
ldaptcl->traplist = NULL;
|
||||
return TCL_ERROR;
|
||||
}
|
||||
ldaptcl->traplist[i] = code;
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
if (STREQU (subCommand, "trapcodes")) {
|
||||
int code;
|
||||
Tcl_Obj *resultObj;
|
||||
Tcl_Obj *stringObj;
|
||||
resultObj = Tcl_GetObjResult(interp);
|
||||
|
||||
for (code = 0; code < LDAPTCL_MAXERR; code++) {
|
||||
if (!ldaptclerrorcode[code]) continue;
|
||||
Tcl_ListObjAppendElement(interp, resultObj,
|
||||
Tcl_NewStringObj(ldaptclerrorcode[code], -1));
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
#ifdef LDAP_DEBUG
|
||||
if (STREQU (subCommand, "debug")) {
|
||||
if (objc != 3) {
|
||||
|
|
@ -1030,8 +1139,12 @@ NeoX_LdapObjDeleteCmd(clientData)
|
|||
LDAPTCL *ldaptcl = (LDAPTCL *)clientData;
|
||||
LDAP *ldap = ldaptcl->ldap;
|
||||
|
||||
if (ldaptcl->trapCmdObj)
|
||||
Tcl_DecrRefCount (ldaptcl->trapCmdObj);
|
||||
if (ldaptcl->traplist)
|
||||
free(ldaptcl->traplist);
|
||||
ldap_unbind(ldap);
|
||||
ckfree((char*) ldaptcl);
|
||||
free((char*) ldaptcl);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
|
|
@ -1163,11 +1276,13 @@ NeoX_LdapObjCmd (clientData, interp, objc, objv)
|
|||
ldap->ld_deref = LDAP_DEREF_NEVER; /* Turn off alias dereferencing */
|
||||
#endif
|
||||
|
||||
ldaptcl = (LDAPTCL *) ckalloc(sizeof(LDAPTCL));
|
||||
ldaptcl = (LDAPTCL *) malloc(sizeof(LDAPTCL));
|
||||
ldaptcl->ldap = ldap;
|
||||
ldaptcl->caching = 0;
|
||||
ldaptcl->timeout = 0;
|
||||
ldaptcl->maxmem = 0;
|
||||
ldaptcl->trapCmdObj = NULL;
|
||||
ldaptcl->traplist = NULL;
|
||||
ldaptcl->flags = 0;
|
||||
|
||||
Tcl_CreateObjCommand (interp,
|
||||
|
|
|
|||
Loading…
Reference in a new issue