.SH SYNOPSIS
\fBldap \fBopen \fR \fIcommand\fR \fIhostlist\fR
.br
-\fBldap \fBinit \fR \fIcommand\fR \fIhostlist\fR
+\fBldap \fBinit \fR \fIcommand\fR \fIhostlist\fR ?protocol_version [2|3]?
.br
\fBldap \fBexplode ?-nonames|-list?\fR \fIdn\fR
.br
Same as above, foo is created, but for "init", opening the connection is
deferred until we actually try to do something.
+The init command also allows some optional values to be set for the connection.
+Currently, the only useful option is \fBprotocol_version\fR which take a
+single argument to specify to use LDAP protocol 2 or 3. This may be required
+when connecting to older LDAP server.
+
For the purposes of this example, we're going to assume that "foo" is the
command created by opening a connection using "ldap open".
If you provide an empty string ("") for the value list,
the entire attribute will be deleted.
+In Ldaptcl version 2.0, multiple operations may be combined into a single
+transaction, ie. as in:
+
+ foo add_attributes dn attributePairList replace attributePairList \
+ delete attributePairList
+
.SH SEARCHING
The Tcl interface to searching takes a control array, which contains
The "code" part is executed repeatedly, once for each DN matching the
search criteria.
+.nf
foo search controlArray destArray code
Using data in the control array, a search is performed of the
controlArray(timeout) a timeout value in seconds (may contain
fractional values -- extremely very small values are useful
for forcing timeout conditions to test timeouts).
+.fi
- For each matching record, destArray is populated with none,
- some or all attribute-value pairs.
+For each matching record, destArray is populated with none,
+some or all attribute-value pairs as determined by the request and
+access control lists on the server.
Note: There are some additional parameters that can be set, such as
how long the synchronous version of the routines should wait before
timing out, the interfaces for which are not available in the current
version.
+.SH COMPARE
+
+ foo compare dn attribute value
+
+Interface to the ldap_compare_s() command.
+Compares the value of \fIattribute\fR in the object at \fIdn\fR to the
+\fIvalue\fR given in the command line. Returns an error if \fIdn\fR
+does not exist. Otherwise, a
+
.SH CACHING (Note: Netscape clients do not have caching interfaces).
The UMich and OpenLDAP client libraries offers the client application fairly
** In OpenLDAP 2.x-devel, its 2000 + the draft number, ie 2002.
** This section is for OPENLDAP.
*/
+#ifndef LDAP_API_FEATURE_X_OPENLDAP
#define ldap_memfree(p) free(p)
+#endif
#ifdef LDAP_OPT_ERROR_NUMBER
#define ldap_get_lderrno(ld) (ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &lderrno), lderrno)
#else
char *m, *s, *errmsg;
int errcode;
int tclResult;
+ int lderrno; /* might be used by LDAP_ERR_STRING macro */
Tcl_Obj *resultObj = Tcl_GetObjResult (interp);
- if (objc < 2)
- return TclX_WrongArgs (interp,
- objv [0],
- "subcommand [args...]");
+ if (objc < 2) {
+ Tcl_WrongNumArgs (interp, 1, objv, "subcommand [args...]");
+ return TCL_ERROR;
+ }
command = Tcl_GetStringFromObj (objv[0], NULL);
subCommand = Tcl_GetStringFromObj (objv[1], NULL);
char *ldap_authString;
int ldap_authInt;
- if (objc != 5)
- return TclX_WrongArgs (interp, objv [0], "bind authtype dn passwd");
+ if (objc != 5) {
+ Tcl_WrongNumArgs (interp, 2, objv, "authtype dn passwd");
+ return TCL_ERROR;
+ }
ldap_authString = Tcl_GetStringFromObj (objv[2], NULL);
}
if (STREQU (subCommand, "unbind")) {
- if (objc != 2)
- return TclX_WrongArgs (interp, objv [0], "unbind");
+ if (objc != 2) {
+ Tcl_WrongNumArgs (interp, 2, objv, "");
+ return TCL_ERROR;
+ }
return Tcl_DeleteCommand(interp, Tcl_GetStringFromObj(objv[0], NULL));
}
/* object delete dn */
if (STREQU (subCommand, "delete")) {
- if (objc != 3)
- return TclX_WrongArgs (interp, objv [0], "delete dn");
+ if (objc != 3) {
+ Tcl_WrongNumArgs (interp, 2, objv, "dn");
+ return TCL_ERROR;
+ }
dn = Tcl_GetStringFromObj (objv [2], NULL);
if ((errcode = ldap_delete_s(ldap, dn)) != LDAP_SUCCESS) {
char *rdn;
int deleteOldRdn;
- if (objc != 4)
- return TclX_WrongArgs (interp,
- objv [0],
- "delete_rdn|modify_rdn dn rdn");
+ if (objc != 4) {
+ Tcl_WrongNumArgs (interp, 2, objv, "dn rdn");
+ return TCL_ERROR;
+ }
dn = Tcl_GetStringFromObj (objv [2], NULL);
rdn = Tcl_GetStringFromObj (objv [3], NULL);
Tcl_Obj **attribObjv;
int valuesObjc;
Tcl_Obj **valuesObjv;
- int nPairs;
+ int nPairs, allPairs;
int i;
int j;
+ int pairIndex;
+ int modIndex;
Tcl_Obj *resultObj = Tcl_GetObjResult (interp);
- if (objc != 4) {
+ if (objc < 4 || objc > 4 && is_add || is_add == 0 && objc&1) {
Tcl_AppendStringsToObj (resultObj,
"wrong # args: ",
Tcl_GetStringFromObj (objv [0], NULL),
subCommand,
" dn attributePairList",
(char *)NULL);
+ if (!is_add)
+ Tcl_AppendStringsToObj (resultObj,
+ " ?[add|delete|replace] attributePairList ...?", (char *)NULL);
return TCL_ERROR;
}
dn = Tcl_GetStringFromObj (objv [2], NULL);
- if (Tcl_ListObjGetElements (interp, objv [3], &attribObjc, &attribObjv)
- == TCL_ERROR) {
- return TCL_ERROR;
+ allPairs = 0;
+ for (i = 3; i < objc; i += 2) {
+ if (Tcl_ListObjLength (interp, objv[i], &j) == TCL_ERROR)
+ return TCL_ERROR;
+ if (j & 1) {
+ Tcl_AppendStringsToObj (resultObj,
+ "attribute list does not contain an ",
+ "even number of key-value elements",
+ (char *)NULL);
+ return TCL_ERROR;
+ }
+ allPairs += j / 2;
}
- if (attribObjc & 1) {
- Tcl_AppendStringsToObj (resultObj,
- "attribute list does not contain an ",
- "even number of key-value elements",
- (char *)NULL);
- return TCL_ERROR;
+ modArray = (LDAPMod **)malloc (sizeof(LDAPMod *) * (allPairs + 1));
+
+ pairIndex = 3;
+ modIndex = 0;
+
+ do {
+
+ if (Tcl_ListObjGetElements (interp, objv [pairIndex], &attribObjc, &attribObjv)
+ == TCL_ERROR) {
+ mod_op = -1;
+ goto badop;
}
nPairs = attribObjc / 2;
- modArray = (LDAPMod **)malloc (sizeof(LDAPMod *) * (nPairs + 1));
- modArray[nPairs] = (LDAPMod *) NULL;
-
for (i = 0; i < nPairs; i++) {
- mod = modArray[i] = (LDAPMod *) malloc (sizeof(LDAPMod));
+ mod = modArray[modIndex++] = (LDAPMod *) malloc (sizeof(LDAPMod));
mod->mod_op = mod_op;
mod->mod_type = Tcl_GetStringFromObj (attribObjv [i * 2], NULL);
if (Tcl_ListObjGetElements (interp, attribObjv [i * 2 + 1], &valuesObjc, &valuesObjv) == TCL_ERROR) {
/* FIX: cleanup memory here */
- return TCL_ERROR;
+ mod_op = -1;
+ goto badop;
}
valPtrs = mod->mod_vals.modv_strvals = \
}
}
- if (is_add) {
+ pairIndex += 2;
+ if (mod_op != -1 && pairIndex < objc) {
+ subCommand = Tcl_GetStringFromObj (objv[pairIndex - 1], NULL);
+ mod_op = -1;
+ if (STREQU (subCommand, "add")) {
+ mod_op = LDAP_MOD_ADD;
+ } else if (STREQU (subCommand, "replace")) {
+ mod_op = LDAP_MOD_REPLACE;
+ } else if (STREQU (subCommand, "delete")) {
+ mod_op = LDAP_MOD_DELETE;
+ }
+ if (mod_op == -1) {
+ Tcl_SetStringObj (resultObj,
+ "Additional operators must be one of"
+ " add, replace, or delete", -1);
+ mod_op = -1;
+ goto badop;
+ }
+ }
+
+ } while (mod_op != -1 && pairIndex < objc);
+ modArray[modIndex] = (LDAPMod *) NULL;
+
+ if (is_add) {
result = ldap_add_s (ldap, dn, modArray);
} else {
result = ldap_modify_s (ldap, dn, modArray);
}
/* free the modArray elements, then the modArray itself. */
- for (i = 0; i < nPairs; i++) {
+badop:
+ for (i = 0; i < modIndex; i++) {
free ((char *) modArray[i]->mod_vals.modv_strvals);
free ((char *) modArray[i]);
}
free ((char *) modArray);
+ /* after modArray is allocated, mod_op = -1 upon error for cleanup */
+ if (mod_op == -1)
+ return TCL_ERROR;
+
/* FIX: memory cleanup required all over the place here */
if (result != LDAP_SUCCESS) {
Tcl_AppendStringsToObj (resultObj,
Tcl_Obj *destArrayNameObj;
Tcl_Obj *evalCodeObj;
- if (objc != 5)
- return TclX_WrongArgs (interp,
- objv [0],
- "search controlArray destArray code");
+ if (objc != 5) {
+ Tcl_WrongNumArgs (interp, 2, objv,
+ "controlArray destArray code");
+ return TCL_ERROR;
+ }
controlArrayNameObj = objv [2];
controlArrayName = Tcl_GetStringFromObj (controlArrayNameObj, NULL);
}
}
+#ifdef LDAP_OPT_DEREF
/* Fetch dereference control setting from control array.
* If it doesn't exist, default to never dereference. */
derefString = Tcl_GetVar2 (interp,
controlArrayName,
"deref",
0);
-
if (derefString == (char *)NULL) {
deref = LDAP_DEREF_NEVER;
} else {
return TCL_ERROR;
}
}
+#endif
/* Fetch list of attribute names from control array.
* If entry doesn't exist, default to NULL (all).
}
#endif
+#ifdef LDAP_OPT_DEREF
ldap_set_option(ldap, LDAP_OPT_DEREF, &deref);
+#endif
tclResult = LDAP_PerformSearch (interp,
ldaptcl,
else
ldap_enable_cache(ldap, ldaptcl->timeout, ldaptcl->maxmem);
}
+#ifdef LDAP_OPT_DEREF
deref = LDAP_DEREF_NEVER;
ldap_set_option(ldap, LDAP_OPT_DEREF, &deref);
+#endif
#endif
return tclResult;
}
int result;
int lderrno;
- if (objc != 5)
- return TclX_WrongArgs (interp,
- objv [0],
- "compare dn attribute value");
+ if (objc != 5) {
+ Tcl_WrongNumArgs (interp,
+ 2, objv,
+ "dn attribute value");
+ return TCL_ERROR;
+ }
dn = Tcl_GetStringFromObj (objv[2], NULL);
attr = Tcl_GetStringFromObj (objv[3], NULL);
result = ldap_compare_s (ldap, dn, attr, value);
if (result == LDAP_COMPARE_TRUE || result == LDAP_COMPARE_FALSE) {
- Tcl_SetIntObj(resultObj, result == LDAP_COMPARE_TRUE);
+ Tcl_SetBooleanObj(resultObj, result == LDAP_COMPARE_TRUE);
return TCL_OK;
}
LDAP_SetErrorCode(ldaptcl, result, interp);
return TCL_ERROR;
}
-#if defined(UMICH_LDAP) || (defined(OPEN_LDAP) && !defined(LDAP_API_VERSION))
if (STREQU (subCommand, "cache")) {
+#if defined(UMICH_LDAP) || (defined(OPEN_LDAP) && !defined(LDAP_API_VERSION))
char *cacheCommand;
- if (objc < 3)
+ if (objc < 3) {
badargs:
- return TclX_WrongArgs (interp,
- objv [0],
- "cache command [args...]");
+ Tcl_WrongNumArgs (interp, 2, objv [0], "command [args...]");
+ return TCL_ERROR;
+ }
cacheCommand = Tcl_GetStringFromObj (objv [2], NULL);
if (STREQU (cacheCommand, "uncache")) {
char *dn;
- if (objc != 4)
- return TclX_WrongArgs (interp,
- objv [0],
- "cache uncache dn");
+ if (objc != 4) {
+ Tcl_WrongNumArgs (interp,
+ 3, objv,
+ "dn");
+ return TCL_ERROR;
+ }
dn = Tcl_GetStringFromObj (objv [3], NULL);
ldap_uncache_entry (ldap, dn);
long timeout = ldaptcl->timeout;
long maxmem = ldaptcl->maxmem;
- if (objc > 5)
- return TclX_WrongArgs (interp,
- objv [0],
- "cache enable ?timeout? ?maxmem?");
+ if (objc > 5) {
+ Tcl_WrongNumArgs (interp, 3, objv, "?timeout? ?maxmem?");
+ return TCL_ERROR;
+ }
if (objc > 3) {
if (Tcl_GetLongFromObj (interp, objv [3], &timeout) == TCL_ERROR)
" or \"all_errors\"",
(char *)NULL);
return TCL_ERROR;
- }
+#else
+ return TCL_OK;
#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 > 4) {
+ Tcl_WrongNumArgs (interp, 2, objv,
+ "command ?errorCode-list?");
+ return TCL_ERROR;
+ }
if (objc == 2) {
if (!ldaptcl->trapCmdObj)
return TCL_OK;
char *subCommand;
char *newCommand;
char *ldapHost;
- int ldapPort = 389;
+ int ldapPort = LDAP_PORT;
LDAP *ldap;
LDAPTCL *ldaptcl;
Tcl_Obj *resultObj = Tcl_GetObjResult (interp);
- if (objc < 3 || objc > 5)
- return TclX_WrongArgs (interp, objv [0],
+ if (objc < 3) {
+ Tcl_WrongNumArgs (interp, 1, objv,
"(open|init) new_command host [port]|explode dn");
+ return TCL_ERROR;
+ }
subCommand = Tcl_GetStringFromObj (objv[1], NULL);
} else if (STREQU(param, "-list")) {
list = 1;
} else {
- return TclX_WrongArgs (interp, objv [0], "explode ?-nonames|-list? dn");
+ Tcl_WrongNumArgs (interp, 1, objv, "explode ?-nonames|-list? dn");
+ return TCL_ERROR;
}
}
if (nonames || list)
if (STREQU (subCommand, "open")) {
ldap = ldap_open (ldapHost, ldapPort);
} else if (STREQU (subCommand, "init")) {
+ int version = -1;
+ int i;
+ int value;
+ char *subOption;
+ char *subValue;
+
+#if LDAPTCL_PROTOCOL_VERSION_DEFAULT
+ version = LDAPTCL_PROTOCOL_VERSION_DEFAULT;
+#endif
+
+ for (i = 6; i < objc; i += 2) {
+ subOption = Tcl_GetStringFromObj(objv[i-1], NULL);
+ if (STREQU (subOption, "protocol_version")) {
+#ifdef LDAP_OPT_PROTOCOL_VERSION
+ subValue = Tcl_GetStringFromObj(objv[i], NULL);
+ if (STREQU (subValue, "2")) {
+ version = LDAP_VERSION2;
+ }
+ else if (STREQU (subValue, "3")) {
+#ifdef LDAP_VERSION3
+ version = LDAP_VERSION3;
+#else
+ Tcl_SetStringObj (resultObj, "protocol_version 3 not supported", -1);
+ return TCL_ERROR;
+#endif
+ }
+ else {
+ Tcl_SetStringObj (resultObj, "protocol_version must be '2' or '3'", -1);
+ return TCL_ERROR;
+ }
+#else
+ Tcl_SetStringObj (resultObj, "protocol_version not supported", -1);
+ return TCL_ERROR;
+#endif
+ } else if (STREQU (subOption, "port")) {
+ if (Tcl_GetIntFromObj (interp, objv [i], &ldapPort) == TCL_ERROR) {
+ Tcl_AppendStringsToObj (resultObj,
+ "LDAP port number is non-numeric",
+ (char *)NULL);
+ return TCL_ERROR;
+ }
+ } else {
+ Tcl_SetStringObj (resultObj, "valid options: protocol_version, port", -1);
+ return TCL_ERROR;
+ }
+ }
ldap = ldap_init (ldapHost, ldapPort);
+
+#if LDAP_OPT_PROTOCOL_VERSION
+ if (version != -1)
+ ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &version);
+#endif
} else {
Tcl_AppendStringsToObj (resultObj,
"option was not \"open\" or \"init\"");
NeoX_LdapObjCmd,
(ClientData) NULL,
(Tcl_CmdDeleteProc*) NULL);
+ /*
+ if (Neo_initLDAPX(interp) != TCL_OK)
+ return TCL_ERROR;
+ */
Tcl_PkgProvide(interp, "Ldaptcl", VERSION);
return TCL_OK;
}