2 * NeoSoft Tcl client extensions to Lightweight Directory Access Protocol.
4 * Copyright (c) 1998-1999 NeoSoft, Inc.
7 * This software may be used, modified, copied, distributed, and sold,
8 * in both source and binary form provided that these copyrights are
9 * retained and their terms are followed.
11 * Under no circumstances are the authors or NeoSoft Inc. responsible
12 * for the proper functioning of this software, nor do the authors
13 * assume any liability for damages incurred with its use.
15 * Redistribution and use in source and binary forms are permitted
16 * provided that this notice is preserved and that due credit is given
19 * NeoSoft, Inc. may not be used to endorse or promote products derived
20 * from this software without specific prior written permission. This
21 * software is provided ``as is'' without express or implied warranty.
23 * Requests for permission may be sent to NeoSoft Inc, 1770 St. James Place,
24 * Suite 500, Houston, TX, 77056.
26 * $Id: neoXldap.c,v 1.5 1999/02/05 18:45:14 kunkee Exp $
31 * This code was originally developed by Karl Lehenbauer to work with
32 * Umich-3.3 LDAP. It was debugged against the Netscape LDAP server
33 * and their much more reliable SDK, and again backported to the
34 * Umich-3.3 client code. The UMICH_LDAP define is used to include
35 * code that will work with the Umich-3.3 LDAP, but not with Netscape's
36 * SDK. OpenLDAP may support some of these, but they have not been tested.
37 * Current support is by Randy Kunkee.
40 #include "tclExtend.h"
47 * Macros to do string compares. They pre-check the first character before
48 * checking of the strings are equal.
51 #define STREQU(str1, str2) \
52 (((str1) [0] == (str2) [0]) && (strcmp (str1, str2) == 0))
55 * The following section defines some common macros used by the rest
56 * of the code. It's ugly, and can use some work. This code was
57 * originally developed to work with Umich-3.3 LDAP. It was debugged
58 * against the Netscape LDAP server and the much more reliable SDK,
59 * and then again backported to the Umich-3.3 client code.
62 #if defined(LDAP_API_VERSION)
63 /* LDAP_API_VERSION must be defined per the current draft spec
64 ** it's value will be assigned RFC number. However, as
65 ** no RFC is defined, it's value is currently implementation
66 ** specific (though I would hope it's value is greater than 1823).
67 ** In OpenLDAP 2.x-devel, its 2000 + the draft number, ie 2002.
68 ** This section is for OPENLDAP.
70 #define ldap_attributefree(p) ldap_memfree(p)
71 #define LDAP_ERR_STRING(ld) \
72 ldap_err2string(ldap_get_lderrno(ldap))
73 #elif defined( LDAP_OPT_SIZELIMIT )
75 ** Netscape SDK w/ ldap_set_option, ldap_get_option
77 #define ldap_attributefree(p) ldap_memfree(p)
78 #define LDAP_ERR_STRING(ld) \
79 ldap_err2string(ldap_get_lderrno(ldap, (char**)NULL, (char**)NULL))
81 /* U-Mich/OpenLDAP 1.x API */
82 /* RFC-1823 w/ changes */
84 #define ldap_memfree(p) free(p)
85 #define ldap_ber_free(p, n) ber_free(p, n)
86 #define ldap_get_lderrno(ld, dummy1, dummy2) (ld->ld_errno)
87 #define ldap_value_free_len(bvals) ber_bvecfree(bvals)
88 #define ldap_attributefree(p)
89 #define LDAP_ERR_STRING(ld) \
90 ldap_err2string(ldap_get_lderrno(ldap))
93 #if defined(LDAP_API_VERSION)
94 #ifdef LDAP_OPT_ERROR_NUMBER
95 static int ldap_get_lderrno(LDAP *ld)
98 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, (void*)&ld_errno);
106 /*-----------------------------------------------------------------------------
107 * LDAP_ProcessOneSearchResult --
109 * Process one result return from an LDAP search.
112 * o interp - Tcl interpreter; Errors are returned in result.
113 * o ldap - LDAP structure pointer.
114 * o entry - LDAP message pointer.
115 * o destArrayNameObj - Name of Tcl array in which to store attributes.
116 * o evalCodeObj - Tcl_Obj pointer to code to eval against this result.
118 * o TCL_OK if processing succeeded..
119 * o TCL_ERROR if an error occured, with error message in interp.
120 *-----------------------------------------------------------------------------
123 LDAP_ProcessOneSearchResult (interp, ldap, entry, destArrayNameObj, evalCodeObj)
127 Tcl_Obj *destArrayNameObj;
128 Tcl_Obj *evalCodeObj;
131 Tcl_Obj *attributeNameObj;
132 Tcl_Obj *attributeDataObj;
135 struct berval **bvals;
138 Tcl_UnsetVar (interp, Tcl_GetStringFromObj (destArrayNameObj, NULL), 0);
140 dn = ldap_get_dn(ldap, entry);
142 if (Tcl_SetVar2(interp, /* set dn */
143 Tcl_GetStringFromObj(destArrayNameObj, NULL),
146 TCL_LEAVE_ERR_MSG) == NULL)
150 for (attributeName = ldap_first_attribute (ldap, entry, &ber);
151 attributeName != NULL;
152 attributeName = ldap_next_attribute(ldap, entry, ber)) {
154 bvals = ldap_get_values_len(ldap, entry, attributeName);
157 /* Note here that the U.of.M. ldap will return a null bvals
158 when the last attribute value has been deleted, but still
159 retains the attributeName. Even though this is documented
160 as an error, we ignore it to present a consistent interface
161 with Netscape's server
163 attributeNameObj = Tcl_NewStringObj (attributeName, -1);
164 Tcl_IncrRefCount (attributeNameObj);
165 attributeDataObj = Tcl_NewObj();
166 for (i = 0; bvals[i] != NULL; i++) {
167 Tcl_Obj *singleAttributeValueObj;
169 singleAttributeValueObj = Tcl_NewStringObj (bvals[i]->bv_val, -1);
170 if (Tcl_ListObjAppendElement (interp,
172 singleAttributeValueObj)
178 ldap_value_free_len(bvals);
180 if (Tcl_ObjSetVar2 (interp,
184 TCL_LEAVE_ERR_MSG) == NULL) {
187 Tcl_DecrRefCount (attributeNameObj);
189 ldap_attributefree(attributeName);
191 return Tcl_EvalObj (interp, evalCodeObj);
194 /*-----------------------------------------------------------------------------
195 * LDAP_PerformSearch --
197 * Perform an LDAP search.
200 * o interp - Tcl interpreter; Errors are returned in result.
201 * o ldap - LDAP structure pointer.
202 * o base - Base DN from which to perform search.
203 * o scope - LDAP search scope, must be one of LDAP_SCOPE_BASE,
204 * LDAP_SCOPE_ONELEVEL, or LDAP_SCOPE_SUBTREE.
205 * o attrs - Pointer to array of char * pointers of desired
206 * attribute names, or NULL for all attributes.
207 * o filtpatt LDAP filter pattern.
208 * o value Value to get sprintf'ed into filter pattern.
209 * o destArrayNameObj - Name of Tcl array in which to store attributes.
210 * o evalCodeObj - Tcl_Obj pointer to code to eval against this result.
212 * o TCL_OK if processing succeeded..
213 * o TCL_ERROR if an error occured, with error message in interp.
214 *-----------------------------------------------------------------------------
217 LDAP_PerformSearch (interp, ldap, base, scope, attrs, filtpatt, value, destArrayNameObj, evalCodeObj)
225 Tcl_Obj *destArrayNameObj;
226 Tcl_Obj *evalCodeObj;
232 int tclResult = TCL_OK;
234 LDAPMessage *resultMessage;
235 LDAPMessage *entryMessage;
240 resultObj = Tcl_GetObjResult (interp);
242 sprintf(filter, filtpatt, value);
244 if ((msgid = ldap_search (ldap, base, scope, filter, attrs, 0)) == -1) {
245 Tcl_AppendStringsToObj (resultObj,
246 "LDAP start search error: ",
247 LDAP_ERR_STRING(ldap),
253 while ((resultCode = ldap_result (ldap,
257 &resultMessage)) == LDAP_RES_SEARCH_ENTRY) {
259 entryMessage = ldap_first_entry(ldap, resultMessage);
261 tclResult = LDAP_ProcessOneSearchResult (interp,
266 ldap_msgfree(resultMessage);
267 if (tclResult != TCL_OK) {
268 if (tclResult == TCL_CONTINUE) {
270 } else if (tclResult == TCL_BREAK) {
274 } else if (tclResult == TCL_ERROR) {
276 sprintf(msg, "\n (\"search\" body line %d)",
278 Tcl_AddObjErrorInfo(interp, msg, -1);
289 ldap_abandon(ldap, msgid);
291 if (resultCode == LDAP_RES_SEARCH_RESULT) {
292 if ((errorCode = ldap_result2error (ldap, resultMessage, 0))
294 Tcl_AppendStringsToObj (resultObj,
295 "LDAP search error: ",
296 ldap_err2string(errorCode),
298 ldap_msgfree(resultMessage);
304 if (resultCode == -1) {
305 Tcl_AppendStringsToObj (resultObj,
306 "LDAP result search error: ",
307 LDAP_ERR_STRING(ldap),
311 ldap_msgfree(resultMessage);
317 /*-----------------------------------------------------------------------------
318 * NeoX_LdapTargetObjCmd --
320 * Implements the body of commands created by Neo_LdapObjCmd.
323 * A standard Tcl result.
326 * See the user documentation.
327 *-----------------------------------------------------------------------------
330 NeoX_LdapTargetObjCmd (clientData, interp, objc, objv)
331 ClientData clientData;
334 Tcl_Obj *CONST objv[];
338 LDAP *ldap = (LDAP *)clientData;
341 int is_add_or_modify = 0;
343 char *m, *s, *errmsg;
346 Tcl_Obj *resultObj = Tcl_GetObjResult (interp);
349 return TclX_WrongArgs (interp,
351 "subcommand [args...]");
353 command = Tcl_GetStringFromObj (objv[0], NULL);
354 subCommand = Tcl_GetStringFromObj (objv[1], NULL);
356 /* object bind authtype name password */
357 if (STREQU (subCommand, "bind")) {
361 char *ldap_authString;
365 return TclX_WrongArgs (interp, objv [0], "bind authtype dn passwd");
367 ldap_authString = Tcl_GetStringFromObj (objv[2], NULL);
369 if (STREQU (ldap_authString, "simple")) {
370 ldap_authInt = LDAP_AUTH_SIMPLE;
373 else if (STREQU (ldap_authString, "kerberos_ldap")) {
374 ldap_authInt = LDAP_AUTH_KRBV41;
375 } else if (STREQU (ldap_authString, "kerberos_dsa")) {
376 ldap_authInt = LDAP_AUTH_KRBV42;
377 } else if (STREQU (ldap_authString, "kerberos_both")) {
378 ldap_authInt = LDAP_AUTH_KRBV4;
382 Tcl_AppendStringsToObj (resultObj,
388 "\" authtype must be one of \"simple\", ",
389 "\"kerberos_ldap\", \"kerberos_dsa\" ",
390 "or \"kerberos_both\"",
392 "\" authtype must be \"simple\", ",
398 binddn = Tcl_GetStringFromObj (objv[3], &stringLength);
399 if (stringLength == 0)
402 passwd = Tcl_GetStringFromObj (objv[4], &stringLength);
403 if (stringLength == 0)
406 /* ldap_bind_s(ldap, dn, pw, method) */
409 #define LDAP_BIND(ldap, dn, pw, method) \
410 ldap_bind_s(ldap, dn, pw, method)
412 #define LDAP_BIND(ldap, dn, pw, method) \
413 ldap_simple_bind_s(ldap, dn, pw)
415 if ((errcode = LDAP_BIND (ldap,
418 ldap_authInt)) != LDAP_SUCCESS) {
420 Tcl_AppendStringsToObj (resultObj,
422 ldap_err2string(errcode),
429 if (STREQU (subCommand, "unbind")) {
431 return TclX_WrongArgs (interp, objv [0], "unbind");
433 return Tcl_DeleteCommand(interp, Tcl_GetStringFromObj(objv[0], NULL));
436 /* object delete dn */
437 if (STREQU (subCommand, "delete")) {
439 return TclX_WrongArgs (interp, objv [0], "delete dn");
441 dn = Tcl_GetStringFromObj (objv [2], NULL);
442 if ((errcode = ldap_delete_s(ldap, dn)) != LDAP_SUCCESS) {
443 Tcl_AppendStringsToObj (resultObj,
444 "LDAP delete error: ",
445 ldap_err2string(errcode),
452 /* object rename_rdn dn rdn */
453 /* object modify_rdn dn rdn */
454 if (STREQU (subCommand, "rename_rdn") || STREQU (subCommand, "modify_rdn")) {
459 return TclX_WrongArgs (interp,
461 "delete_rdn|modify_rdn dn rdn");
463 dn = Tcl_GetStringFromObj (objv [2], NULL);
464 rdn = Tcl_GetStringFromObj (objv [3], NULL);
466 deleteOldRdn = (*subCommand == 'r');
468 if ((errcode = ldap_modrdn2_s (ldap, dn, rdn, deleteOldRdn)) != LDAP_SUCCESS) {
469 Tcl_AppendStringsToObj (resultObj,
473 ldap_err2string(errcode),
480 /* object add dn attributePairList */
481 /* object add_attributes dn attributePairList */
482 /* object replace_attributes dn attributePairList */
483 /* object delete_attributes dn attributePairList */
485 if (STREQU (subCommand, "add")) {
487 is_add_or_modify = 1;
490 if (STREQU (subCommand, "add_attributes")) {
491 is_add_or_modify = 1;
492 mod_op = LDAP_MOD_ADD;
493 } else if (STREQU (subCommand, "replace_attributes")) {
494 is_add_or_modify = 1;
495 mod_op = LDAP_MOD_REPLACE;
496 } else if (STREQU (subCommand, "delete_attributes")) {
497 is_add_or_modify = 1;
498 mod_op = LDAP_MOD_DELETE;
502 if (is_add_or_modify) {
506 char **valPtrs = NULL;
508 Tcl_Obj **attribObjv;
510 Tcl_Obj **valuesObjv;
515 Tcl_Obj *resultObj = Tcl_GetObjResult (interp);
518 Tcl_AppendStringsToObj (resultObj,
520 Tcl_GetStringFromObj (objv [0], NULL),
523 " dn attributePairList",
528 dn = Tcl_GetStringFromObj (objv [2], NULL);
530 if (Tcl_ListObjGetElements (interp, objv [3], &attribObjc, &attribObjv)
535 if (attribObjc & 1) {
536 Tcl_AppendStringsToObj (resultObj,
537 "attribute list does not contain an ",
538 "even number of key-value elements",
543 nPairs = attribObjc / 2;
545 modArray = (LDAPMod **)ckalloc (sizeof(LDAPMod *) * (nPairs + 1));
546 modArray[nPairs] = (LDAPMod *) NULL;
548 for (i = 0; i < nPairs; i++) {
549 mod = modArray[i] = (LDAPMod *) ckalloc (sizeof(LDAPMod));
550 mod->mod_op = mod_op;
551 mod->mod_type = Tcl_GetStringFromObj (attribObjv [i * 2], NULL);
553 if (Tcl_ListObjGetElements (interp, attribObjv [i * 2 + 1], &valuesObjc, &valuesObjv) == TCL_ERROR) {
554 /* FIX: cleanup memory here */
558 valPtrs = mod->mod_vals.modv_strvals = \
559 (char **)ckalloc (sizeof (char *) * (valuesObjc + 1));
560 valPtrs[valuesObjc] = (char *)NULL;
562 for (j = 0; j < valuesObjc; j++) {
563 valPtrs [j] = Tcl_GetStringFromObj (valuesObjv[j], NULL);
565 /* If it's "delete" and value is an empty string, make
566 * value be NULL to indicate entire attribute is to be
568 if ((*valPtrs [j] == '\0')
569 && (mod->mod_op == LDAP_MOD_DELETE)) {
576 result = ldap_add_s (ldap, dn, modArray);
578 result = ldap_modify_s (ldap, dn, modArray);
581 /* free the modArray elements, then the modArray itself. */
582 for (i = 0; i < nPairs; i++) {
583 ckfree ((char *) modArray[i]->mod_vals.modv_strvals);
584 ckfree ((char *) modArray[i]);
586 ckfree ((char *) modArray);
588 /* FIX: memory cleanup required all over the place here */
589 if (result != LDAP_SUCCESS) {
590 Tcl_AppendStringsToObj (resultObj,
594 ldap_err2string(result),
601 /* object search controlArray dn pattern */
602 if (STREQU (subCommand, "search")) {
603 char *controlArrayName;
604 Tcl_Obj *controlArrayNameObj;
614 char **attributesArray;
615 char *attributesString;
618 char *filterPatternString;
620 Tcl_Obj *destArrayNameObj;
621 Tcl_Obj *evalCodeObj;
624 return TclX_WrongArgs (interp,
626 "search controlArray destArray code");
628 controlArrayNameObj = objv [2];
629 controlArrayName = Tcl_GetStringFromObj (controlArrayNameObj, NULL);
631 destArrayNameObj = objv [3];
633 evalCodeObj = objv [4];
635 baseString = Tcl_GetVar2 (interp,
640 if (baseString == (char *)NULL) {
641 Tcl_AppendStringsToObj (resultObj,
642 "required element \"base\" ",
643 "is missing from ldap control array \"",
650 filterPatternString = Tcl_GetVar2 (interp,
654 if (filterPatternString == (char *)NULL) {
655 Tcl_AppendStringsToObj (resultObj,
656 "required element \"filter\" ",
657 "is missing from ldap control array \"",
665 /* Fetch scope setting from control array.
666 * If it doesn't exist, default to subtree scoping.
668 scopeString = Tcl_GetVar2 (interp, controlArrayName, "scope", 0);
669 if (scopeString == NULL) {
670 scope = LDAP_SCOPE_SUBTREE;
672 if (STREQU(scopeString, "base"))
673 scope = LDAP_SCOPE_BASE;
674 else if (STREQU(scopeString, "onelevel"))
675 scope = LDAP_SCOPE_ONELEVEL;
676 else if (STREQU(scopeString, "subtree"))
677 scope = LDAP_SCOPE_SUBTREE;
679 Tcl_AppendStringsToObj (resultObj,
680 "\"scope\" element of \"",
682 "\" array is not one of ",
683 "\"base\", \"one_level\", ",
690 /* Fetch dereference control setting from control array.
691 * If it doesn't exist, default to never dereference. */
692 derefString = Tcl_GetVar2 (interp,
697 if (derefString == (char *)NULL) {
698 deref = LDAP_DEREF_NEVER;
700 if (STREQU(derefString, "never"))
701 deref = LDAP_DEREF_NEVER;
702 else if (STREQU(derefString, "search"))
703 deref = LDAP_DEREF_SEARCHING;
704 else if (STREQU(derefString, "find") == 0)
705 deref = LDAP_DEREF_FINDING;
706 else if (STREQU(derefString, "always"))
707 deref = LDAP_DEREF_ALWAYS;
709 Tcl_AppendStringsToObj (resultObj,
710 "\"deref\" element of \"",
712 "\" array is not one of ",
713 "\"never\", \"search\", \"find\", ",
720 /* Fetch list of attribute names from control array.
721 * If entry doesn't exist, default to NULL (all).
723 attributesString = Tcl_GetVar2 (interp,
727 if (attributesString == (char *)NULL) {
728 attributesArray = NULL;
730 if ((Tcl_SplitList (interp,
733 &attributesArray)) != TCL_OK) {
739 ldap->ld_deref = deref;
740 ldap->ld_timelimit = 0;
741 ldap->ld_sizelimit = 0;
742 ldap->ld_options = 0;
745 return LDAP_PerformSearch (interp,
757 if (STREQU (subCommand, "cache")) {
762 return TclX_WrongArgs (interp,
764 "cache command [args...]");
766 cacheCommand = Tcl_GetStringFromObj (objv [2], NULL);
768 if (STREQU (cacheCommand, "uncache")) {
772 return TclX_WrongArgs (interp,
776 dn = Tcl_GetStringFromObj (objv [3], NULL);
777 ldap_uncache_entry (ldap, dn);
781 if (STREQU (cacheCommand, "enable")) {
786 return TclX_WrongArgs (interp,
788 "cache enable timeout maxmem");
790 if (Tcl_GetLongFromObj (interp, objv [3], &timeout) == TCL_ERROR)
793 if (Tcl_GetLongFromObj (interp, objv [4], &maxmem) == TCL_ERROR)
796 if (ldap_enable_cache (ldap, timeout, maxmem) == -1) {
797 Tcl_AppendStringsToObj (resultObj,
798 "LDAP cache enable error: ",
799 LDAP_ERR_STRING(ldap),
806 if (objc != 3) goto badargs;
808 if (STREQU (cacheCommand, "disable")) {
809 ldap_disable_cache (ldap);
813 if (STREQU (cacheCommand, "destroy")) {
814 ldap_destroy_cache (ldap);
818 if (STREQU (cacheCommand, "flush")) {
819 ldap_flush_cache (ldap);
823 if (STREQU (cacheCommand, "no_errors")) {
824 ldap_set_cache_options (ldap, LDAP_CACHE_OPT_CACHENOERRS);
828 if (STREQU (cacheCommand, "all_errors")) {
829 ldap_set_cache_options (ldap, LDAP_CACHE_OPT_CACHEALLERRS);
833 if (STREQU (cacheCommand, "size_errors")) {
834 ldap_set_cache_options (ldap, 0);
837 Tcl_AppendStringsToObj (resultObj,
843 " must be one of \"enable\", ",
845 "\"destroy\", \"flush\", \"uncache\", ",
846 "\"no_errors\", \"size_errors\",",
847 " or \"all_errors\"",
853 if (STREQU (subCommand, "debug")) {
855 Tcl_AppendStringsToObj(resultObj, "Wrong # of arguments",
859 return Tcl_GetIntFromObj(interp, objv[2], &ldap_debug);
863 /* FIX: this needs to enumerate all the possibilities */
864 Tcl_AppendStringsToObj (resultObj,
867 "\" must be one of \"add\", ",
868 "\"add_attributes\", ",
869 "\"bind\", \"cache\", \"delete\", ",
870 "\"delete_attributes\", \"modify\", ",
871 "\"modify_rdn\", \"rename_rdn\", ",
872 "\"replace_attributes\", ",
873 "\"search\" or \"unbind\".",
879 * Delete and LDAP command object
883 NeoX_LdapObjDeleteCmd(clientData)
884 ClientData clientData;
886 LDAP *ldap = (LDAP *)clientData;
891 /*-----------------------------------------------------------------------------
894 * Implements the `ldap' command:
895 * ldap open newObjName host [port]
896 * ldap init newObjName host [port]
899 * A standard Tcl result.
902 * See the user documentation.
903 *-----------------------------------------------------------------------------
906 NeoX_LdapObjCmd (clientData, interp, objc, objv)
907 ClientData clientData;
910 Tcl_Obj *CONST objv[];
919 Tcl_Obj *resultObj = Tcl_GetObjResult (interp);
921 if (objc < 3 || objc > 5)
922 return TclX_WrongArgs (interp, objv [0],
923 "(open|init) new_command host [port]|explode dn");
925 subCommand = Tcl_GetStringFromObj (objv[1], NULL);
927 if (STREQU(subCommand, "explode")) {
931 char **exploded, **p;
933 param = Tcl_GetStringFromObj (objv[2], NULL);
934 if (param[0] == '-') {
935 if (STREQU(param, "-nonames")) {
937 } else if (STREQU(param, "-list")) {
940 return TclX_WrongArgs (interp, objv [0], "explode ?-nonames|-list? dn");
944 param = Tcl_GetStringFromObj (objv[3], NULL);
945 exploded = ldap_explode_dn(param, nonames);
946 for (p = exploded; *p; p++) {
948 char *q = strchr(*p, '=');
950 Tcl_SetObjLength(resultObj, 0);
951 Tcl_AppendStringsToObj(resultObj, "rdn ", *p,
952 " missing '='", NULL);
953 ldap_value_free(exploded);
957 if (Tcl_ListObjAppendElement(interp, resultObj,
958 Tcl_NewStringObj(*p, -1)) != TCL_OK ||
959 Tcl_ListObjAppendElement(interp, resultObj,
960 Tcl_NewStringObj(q+1, -1)) != TCL_OK) {
961 ldap_value_free(exploded);
965 if (Tcl_ListObjAppendElement(interp, resultObj,
966 Tcl_NewStringObj(*p, -1))) {
967 ldap_value_free(exploded);
972 ldap_value_free(exploded);
977 if (STREQU(subCommand, "friendly")) {
978 char *friendly = ldap_dn2ufn(Tcl_GetStringFromObj(objv[2], NULL));
979 Tcl_SetStringObj(resultObj, friendly, -1);
985 newCommand = Tcl_GetStringFromObj (objv[2], NULL);
986 ldapHost = Tcl_GetStringFromObj (objv[3], NULL);
989 if (Tcl_GetIntFromObj (interp, objv [4], &ldapPort) == TCL_ERROR) {
990 Tcl_AppendStringsToObj (resultObj,
991 "LDAP port number is non-numeric",
997 if (STREQU (subCommand, "open")) {
998 ldap = ldap_open (ldapHost, ldapPort);
999 } else if (STREQU (subCommand, "init")) {
1000 ldap = ldap_init (ldapHost, ldapPort);
1002 Tcl_AppendStringsToObj (resultObj,
1003 "option was not \"open\" or \"init\"");
1007 if (ldap == (LDAP *)NULL) {
1008 Tcl_SetErrno(errno);
1009 Tcl_AppendStringsToObj (resultObj,
1010 Tcl_PosixError (interp),
1016 ldap->ld_deref = LDAP_DEREF_NEVER; /* Turn off alias dereferencing */
1019 Tcl_CreateObjCommand (interp,
1021 NeoX_LdapTargetObjCmd,
1023 NeoX_LdapObjDeleteCmd);
1027 /*-----------------------------------------------------------------------------
1029 * Initialize the LDAP interface.
1030 *-----------------------------------------------------------------------------
1033 Ldaptcl_Init (interp)
1036 Tcl_CreateObjCommand (interp,
1040 (Tcl_CmdDeleteProc*) NULL);
1041 Tcl_PkgProvide(interp, "Ldaptcl", "1.1");