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.
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.
41 * Add timeout to controlArray to set timeout for ldap_result.
45 #include "tclExtend.h"
54 * Macros to do string compares. They pre-check the first character before
55 * checking of the strings are equal.
58 #define STREQU(str1, str2) \
59 (((str1) [0] == (str2) [0]) && (strcmp (str1, str2) == 0))
62 * The following section defines some common macros used by the rest
63 * of the code. It's ugly, and can use some work. This code was
64 * originally developed to work with Umich-3.3 LDAP. It was debugged
65 * against the Netscape LDAP server and the much more reliable SDK,
66 * and then again backported to the Umich-3.3 client code.
69 #if defined(OPEN_LDAP)
70 /* LDAP_API_VERSION must be defined per the current draft spec
71 ** it's value will be assigned RFC number. However, as
72 ** no RFC is defined, it's value is currently implementation
73 ** specific (though I would hope it's value is greater than 1823).
74 ** In OpenLDAP 2.x-devel, its 2000 + the draft number, ie 2002.
75 ** This section is for OPENLDAP.
77 #define ldap_attributefree(p) ldap_memfree(p)
78 #define ldap_memfree(p) free(p)
79 #define LDAP_ERR_STRING(ld) \
80 ldap_err2string(ldap->ld_errno)
81 #elif defined( LDAP_OPT_SIZELIMIT )
83 ** Netscape SDK w/ ldap_set_option, ldap_get_option
85 #define ldap_attributefree(p) ldap_memfree(p)
86 #define LDAP_ERR_STRING(ld) \
87 ldap_err2string(ldap_get_lderrno(ldap))
89 /* U-Mich/OpenLDAP 1.x API */
90 /* RFC-1823 w/ changes */
92 #define ldap_memfree(p) free(p)
93 #define ldap_ber_free(p, n) ber_free(p, n)
94 #define ldap_value_free_len(bvals) ber_bvecfree(bvals)
95 #define ldap_attributefree(p)
96 #define LDAP_ERR_STRING(ld) \
97 ldap_err2string(ld->ld_errno)
102 /*-----------------------------------------------------------------------------
103 * LDAP_ProcessOneSearchResult --
105 * Process one result return from an LDAP search.
108 * o interp - Tcl interpreter; Errors are returned in result.
109 * o ldap - LDAP structure pointer.
110 * o entry - LDAP message pointer.
111 * o destArrayNameObj - Name of Tcl array in which to store attributes.
112 * o evalCodeObj - Tcl_Obj pointer to code to eval against this result.
114 * o TCL_OK if processing succeeded..
115 * o TCL_ERROR if an error occured, with error message in interp.
116 *-----------------------------------------------------------------------------
119 LDAP_ProcessOneSearchResult (interp, ldap, entry, destArrayNameObj, evalCodeObj)
123 Tcl_Obj *destArrayNameObj;
124 Tcl_Obj *evalCodeObj;
127 Tcl_Obj *attributeNameObj;
128 Tcl_Obj *attributeDataObj;
131 struct berval **bvals;
134 Tcl_UnsetVar (interp, Tcl_GetStringFromObj (destArrayNameObj, NULL), 0);
136 dn = ldap_get_dn(ldap, entry);
138 if (Tcl_SetVar2(interp, /* set dn */
139 Tcl_GetStringFromObj(destArrayNameObj, NULL),
142 TCL_LEAVE_ERR_MSG) == NULL)
146 for (attributeName = ldap_first_attribute (ldap, entry, &ber);
147 attributeName != NULL;
148 attributeName = ldap_next_attribute(ldap, entry, ber)) {
150 bvals = ldap_get_values_len(ldap, entry, attributeName);
153 /* Note here that the U.of.M. ldap will return a null bvals
154 when the last attribute value has been deleted, but still
155 retains the attributeName. Even though this is documented
156 as an error, we ignore it to present a consistent interface
157 with Netscape's server
159 attributeNameObj = Tcl_NewStringObj (attributeName, -1);
160 Tcl_IncrRefCount (attributeNameObj);
161 attributeDataObj = Tcl_NewObj();
162 for (i = 0; bvals[i] != NULL; i++) {
163 Tcl_Obj *singleAttributeValueObj;
165 singleAttributeValueObj = Tcl_NewStringObj (bvals[i]->bv_val, -1);
166 if (Tcl_ListObjAppendElement (interp,
168 singleAttributeValueObj)
174 ldap_value_free_len(bvals);
176 if (Tcl_ObjSetVar2 (interp,
180 TCL_LEAVE_ERR_MSG) == NULL) {
183 Tcl_DecrRefCount (attributeNameObj);
185 ldap_attributefree(attributeName);
187 return Tcl_EvalObj (interp, evalCodeObj);
190 /*-----------------------------------------------------------------------------
191 * LDAP_PerformSearch --
193 * Perform an LDAP search.
196 * o interp - Tcl interpreter; Errors are returned in result.
197 * o ldap - LDAP structure pointer.
198 * o base - Base DN from which to perform search.
199 * o scope - LDAP search scope, must be one of LDAP_SCOPE_BASE,
200 * LDAP_SCOPE_ONELEVEL, or LDAP_SCOPE_SUBTREE.
201 * o attrs - Pointer to array of char * pointers of desired
202 * attribute names, or NULL for all attributes.
203 * o filtpatt LDAP filter pattern.
204 * o value Value to get sprintf'ed into filter pattern.
205 * o destArrayNameObj - Name of Tcl array in which to store attributes.
206 * o evalCodeObj - Tcl_Obj pointer to code to eval against this result.
208 * o TCL_OK if processing succeeded..
209 * o TCL_ERROR if an error occured, with error message in interp.
210 *-----------------------------------------------------------------------------
213 LDAP_PerformSearch (interp, ldap, base, scope, attrs, filtpatt, value, destArrayNameObj, evalCodeObj, timeout_p)
221 Tcl_Obj *destArrayNameObj;
222 Tcl_Obj *evalCodeObj;
223 struct timeval *timeout_p;
229 int tclResult = TCL_OK;
231 LDAPMessage *resultMessage;
232 LDAPMessage *entryMessage;
237 resultObj = Tcl_GetObjResult (interp);
239 sprintf(filter, filtpatt, value);
241 if ((msgid = ldap_search (ldap, base, scope, filter, attrs, 0)) == -1) {
242 Tcl_AppendStringsToObj (resultObj,
243 "LDAP start search error: ",
244 LDAP_ERR_STRING(ldap),
250 while ((resultCode = ldap_result (ldap,
254 &resultMessage)) == LDAP_RES_SEARCH_ENTRY) {
256 entryMessage = ldap_first_entry(ldap, resultMessage);
258 tclResult = LDAP_ProcessOneSearchResult (interp,
263 ldap_msgfree(resultMessage);
264 if (tclResult != TCL_OK) {
265 if (tclResult == TCL_CONTINUE) {
267 } else if (tclResult == TCL_BREAK) {
271 } else if (tclResult == TCL_ERROR) {
273 sprintf(msg, "\n (\"search\" body line %d)",
275 Tcl_AddObjErrorInfo(interp, msg, -1);
284 if (abandon || resultCode == 0) {
285 ldap_abandon(ldap, msgid);
286 if (resultCode == 0) {
287 Tcl_SetErrorCode (interp, "TIMEOUT", (char*) NULL);
288 Tcl_SetStringObj (resultObj, "LDAP timeout retrieving results", -1);
292 if (resultCode == LDAP_RES_SEARCH_RESULT) {
293 if ((errorCode = ldap_result2error (ldap, resultMessage, 0))
295 Tcl_AppendStringsToObj (resultObj,
296 "LDAP search error: ",
297 ldap_err2string(errorCode),
299 ldap_msgfree(resultMessage);
305 if (resultCode == -1) {
306 Tcl_AppendStringsToObj (resultObj,
307 "LDAP result search error: ",
308 LDAP_ERR_STRING(ldap),
312 ldap_msgfree(resultMessage);
318 /*-----------------------------------------------------------------------------
319 * NeoX_LdapTargetObjCmd --
321 * Implements the body of commands created by Neo_LdapObjCmd.
324 * A standard Tcl result.
327 * See the user documentation.
328 *-----------------------------------------------------------------------------
331 NeoX_LdapTargetObjCmd (clientData, interp, objc, objv)
332 ClientData clientData;
335 Tcl_Obj *CONST objv[];
339 LDAP *ldap = (LDAP *)clientData;
342 int is_add_or_modify = 0;
344 char *m, *s, *errmsg;
347 Tcl_Obj *resultObj = Tcl_GetObjResult (interp);
350 return TclX_WrongArgs (interp,
352 "subcommand [args...]");
354 command = Tcl_GetStringFromObj (objv[0], NULL);
355 subCommand = Tcl_GetStringFromObj (objv[1], NULL);
357 /* object bind authtype name password */
358 if (STREQU (subCommand, "bind")) {
362 char *ldap_authString;
366 return TclX_WrongArgs (interp, objv [0], "bind authtype dn passwd");
368 ldap_authString = Tcl_GetStringFromObj (objv[2], NULL);
370 if (STREQU (ldap_authString, "simple")) {
371 ldap_authInt = LDAP_AUTH_SIMPLE;
374 else if (STREQU (ldap_authString, "kerberos_ldap")) {
375 ldap_authInt = LDAP_AUTH_KRBV41;
376 } else if (STREQU (ldap_authString, "kerberos_dsa")) {
377 ldap_authInt = LDAP_AUTH_KRBV42;
378 } else if (STREQU (ldap_authString, "kerberos_both")) {
379 ldap_authInt = LDAP_AUTH_KRBV4;
383 Tcl_AppendStringsToObj (resultObj,
389 "\" authtype must be one of \"simple\", ",
390 "\"kerberos_ldap\", \"kerberos_dsa\" ",
391 "or \"kerberos_both\"",
393 "\" authtype must be \"simple\", ",
399 binddn = Tcl_GetStringFromObj (objv[3], &stringLength);
400 if (stringLength == 0)
403 passwd = Tcl_GetStringFromObj (objv[4], &stringLength);
404 if (stringLength == 0)
407 /* ldap_bind_s(ldap, dn, pw, method) */
410 #define LDAP_BIND(ldap, dn, pw, method) \
411 ldap_bind_s(ldap, dn, pw, method)
413 #define LDAP_BIND(ldap, dn, pw, method) \
414 ldap_simple_bind_s(ldap, dn, pw)
416 if ((errcode = LDAP_BIND (ldap,
419 ldap_authInt)) != LDAP_SUCCESS) {
421 Tcl_AppendStringsToObj (resultObj,
423 ldap_err2string(errcode),
430 if (STREQU (subCommand, "unbind")) {
432 return TclX_WrongArgs (interp, objv [0], "unbind");
434 return Tcl_DeleteCommand(interp, Tcl_GetStringFromObj(objv[0], NULL));
437 /* object delete dn */
438 if (STREQU (subCommand, "delete")) {
440 return TclX_WrongArgs (interp, objv [0], "delete dn");
442 dn = Tcl_GetStringFromObj (objv [2], NULL);
443 if ((errcode = ldap_delete_s(ldap, dn)) != LDAP_SUCCESS) {
444 Tcl_AppendStringsToObj (resultObj,
445 "LDAP delete error: ",
446 ldap_err2string(errcode),
453 /* object rename_rdn dn rdn */
454 /* object modify_rdn dn rdn */
455 if (STREQU (subCommand, "rename_rdn") || STREQU (subCommand, "modify_rdn")) {
460 return TclX_WrongArgs (interp,
462 "delete_rdn|modify_rdn dn rdn");
464 dn = Tcl_GetStringFromObj (objv [2], NULL);
465 rdn = Tcl_GetStringFromObj (objv [3], NULL);
467 deleteOldRdn = (*subCommand == 'r');
469 if ((errcode = ldap_modrdn2_s (ldap, dn, rdn, deleteOldRdn)) != LDAP_SUCCESS) {
470 Tcl_AppendStringsToObj (resultObj,
474 ldap_err2string(errcode),
481 /* object add dn attributePairList */
482 /* object add_attributes dn attributePairList */
483 /* object replace_attributes dn attributePairList */
484 /* object delete_attributes dn attributePairList */
486 if (STREQU (subCommand, "add")) {
488 is_add_or_modify = 1;
491 if (STREQU (subCommand, "add_attributes")) {
492 is_add_or_modify = 1;
493 mod_op = LDAP_MOD_ADD;
494 } else if (STREQU (subCommand, "replace_attributes")) {
495 is_add_or_modify = 1;
496 mod_op = LDAP_MOD_REPLACE;
497 } else if (STREQU (subCommand, "delete_attributes")) {
498 is_add_or_modify = 1;
499 mod_op = LDAP_MOD_DELETE;
503 if (is_add_or_modify) {
507 char **valPtrs = NULL;
509 Tcl_Obj **attribObjv;
511 Tcl_Obj **valuesObjv;
516 Tcl_Obj *resultObj = Tcl_GetObjResult (interp);
519 Tcl_AppendStringsToObj (resultObj,
521 Tcl_GetStringFromObj (objv [0], NULL),
524 " dn attributePairList",
529 dn = Tcl_GetStringFromObj (objv [2], NULL);
531 if (Tcl_ListObjGetElements (interp, objv [3], &attribObjc, &attribObjv)
536 if (attribObjc & 1) {
537 Tcl_AppendStringsToObj (resultObj,
538 "attribute list does not contain an ",
539 "even number of key-value elements",
544 nPairs = attribObjc / 2;
546 modArray = (LDAPMod **)ckalloc (sizeof(LDAPMod *) * (nPairs + 1));
547 modArray[nPairs] = (LDAPMod *) NULL;
549 for (i = 0; i < nPairs; i++) {
550 mod = modArray[i] = (LDAPMod *) ckalloc (sizeof(LDAPMod));
551 mod->mod_op = mod_op;
552 mod->mod_type = Tcl_GetStringFromObj (attribObjv [i * 2], NULL);
554 if (Tcl_ListObjGetElements (interp, attribObjv [i * 2 + 1], &valuesObjc, &valuesObjv) == TCL_ERROR) {
555 /* FIX: cleanup memory here */
559 valPtrs = mod->mod_vals.modv_strvals = \
560 (char **)ckalloc (sizeof (char *) * (valuesObjc + 1));
561 valPtrs[valuesObjc] = (char *)NULL;
563 for (j = 0; j < valuesObjc; j++) {
564 valPtrs [j] = Tcl_GetStringFromObj (valuesObjv[j], NULL);
566 /* If it's "delete" and value is an empty string, make
567 * value be NULL to indicate entire attribute is to be
569 if ((*valPtrs [j] == '\0')
570 && (mod->mod_op == LDAP_MOD_DELETE)) {
577 result = ldap_add_s (ldap, dn, modArray);
579 result = ldap_modify_s (ldap, dn, modArray);
582 /* free the modArray elements, then the modArray itself. */
583 for (i = 0; i < nPairs; i++) {
584 ckfree ((char *) modArray[i]->mod_vals.modv_strvals);
585 ckfree ((char *) modArray[i]);
587 ckfree ((char *) modArray);
589 /* FIX: memory cleanup required all over the place here */
590 if (result != LDAP_SUCCESS) {
591 Tcl_AppendStringsToObj (resultObj,
595 ldap_err2string(result),
602 /* object search controlArray dn pattern */
603 if (STREQU (subCommand, "search")) {
604 char *controlArrayName;
605 Tcl_Obj *controlArrayNameObj;
615 char **attributesArray;
616 char *attributesString;
619 char *filterPatternString;
623 struct timeval timeout, *timeout_p;
625 Tcl_Obj *destArrayNameObj;
626 Tcl_Obj *evalCodeObj;
629 return TclX_WrongArgs (interp,
631 "search controlArray destArray code");
633 controlArrayNameObj = objv [2];
634 controlArrayName = Tcl_GetStringFromObj (controlArrayNameObj, NULL);
636 destArrayNameObj = objv [3];
638 evalCodeObj = objv [4];
640 baseString = Tcl_GetVar2 (interp,
645 if (baseString == (char *)NULL) {
646 Tcl_AppendStringsToObj (resultObj,
647 "required element \"base\" ",
648 "is missing from ldap control array \"",
655 filterPatternString = Tcl_GetVar2 (interp,
659 if (filterPatternString == (char *)NULL) {
660 Tcl_AppendStringsToObj (resultObj,
661 "required element \"filter\" ",
662 "is missing from ldap control array \"",
670 /* Fetch scope setting from control array.
671 * If it doesn't exist, default to subtree scoping.
673 scopeString = Tcl_GetVar2 (interp, controlArrayName, "scope", 0);
674 if (scopeString == NULL) {
675 scope = LDAP_SCOPE_SUBTREE;
677 if (STREQU(scopeString, "base"))
678 scope = LDAP_SCOPE_BASE;
679 else if (STREQU(scopeString, "onelevel"))
680 scope = LDAP_SCOPE_ONELEVEL;
681 else if (STREQU(scopeString, "subtree"))
682 scope = LDAP_SCOPE_SUBTREE;
684 Tcl_AppendStringsToObj (resultObj,
685 "\"scope\" element of \"",
687 "\" array is not one of ",
688 "\"base\", \"one_level\", ",
695 /* Fetch dereference control setting from control array.
696 * If it doesn't exist, default to never dereference. */
697 derefString = Tcl_GetVar2 (interp,
702 if (derefString == (char *)NULL) {
703 deref = LDAP_DEREF_NEVER;
705 if (STREQU(derefString, "never"))
706 deref = LDAP_DEREF_NEVER;
707 else if (STREQU(derefString, "search"))
708 deref = LDAP_DEREF_SEARCHING;
709 else if (STREQU(derefString, "find") == 0)
710 deref = LDAP_DEREF_FINDING;
711 else if (STREQU(derefString, "always"))
712 deref = LDAP_DEREF_ALWAYS;
714 Tcl_AppendStringsToObj (resultObj,
715 "\"deref\" element of \"",
717 "\" array is not one of ",
718 "\"never\", \"search\", \"find\", ",
725 /* Fetch list of attribute names from control array.
726 * If entry doesn't exist, default to NULL (all).
728 attributesString = Tcl_GetVar2 (interp,
732 if (attributesString == (char *)NULL) {
733 attributesArray = NULL;
735 if ((Tcl_SplitList (interp,
738 &attributesArray)) != TCL_OK) {
743 /* Fetch timeout value if there is one
745 timeoutString = Tcl_GetVar2 (interp,
750 if (timeoutString == (char *)NULL) {
754 if (Tcl_GetDouble(interp, timeoutString, &timeoutTime) != TCL_OK)
756 timeout.tv_sec = floor(timeoutTime);
757 timeout.tv_usec = (timeoutTime-timeout.tv_sec) * 1000000;
758 timeout_p = &timeout;
762 ldap->ld_deref = deref;
763 ldap->ld_timelimit = 0;
764 ldap->ld_sizelimit = 0;
765 ldap->ld_options = 0;
768 return LDAP_PerformSearch (interp,
781 if (STREQU (subCommand, "cache")) {
786 return TclX_WrongArgs (interp,
788 "cache command [args...]");
790 cacheCommand = Tcl_GetStringFromObj (objv [2], NULL);
792 if (STREQU (cacheCommand, "uncache")) {
796 return TclX_WrongArgs (interp,
800 dn = Tcl_GetStringFromObj (objv [3], NULL);
801 ldap_uncache_entry (ldap, dn);
805 if (STREQU (cacheCommand, "enable")) {
810 return TclX_WrongArgs (interp,
812 "cache enable timeout maxmem");
814 if (Tcl_GetLongFromObj (interp, objv [3], &timeout) == TCL_ERROR)
817 if (Tcl_GetLongFromObj (interp, objv [4], &maxmem) == TCL_ERROR)
820 if (ldap_enable_cache (ldap, timeout, maxmem) == -1) {
821 Tcl_AppendStringsToObj (resultObj,
822 "LDAP cache enable error: ",
823 LDAP_ERR_STRING(ldap),
830 if (objc != 3) goto badargs;
832 if (STREQU (cacheCommand, "disable")) {
833 ldap_disable_cache (ldap);
837 if (STREQU (cacheCommand, "destroy")) {
838 ldap_destroy_cache (ldap);
842 if (STREQU (cacheCommand, "flush")) {
843 ldap_flush_cache (ldap);
847 if (STREQU (cacheCommand, "no_errors")) {
848 ldap_set_cache_options (ldap, LDAP_CACHE_OPT_CACHENOERRS);
852 if (STREQU (cacheCommand, "all_errors")) {
853 ldap_set_cache_options (ldap, LDAP_CACHE_OPT_CACHEALLERRS);
857 if (STREQU (cacheCommand, "size_errors")) {
858 ldap_set_cache_options (ldap, 0);
861 Tcl_AppendStringsToObj (resultObj,
867 " must be one of \"enable\", ",
869 "\"destroy\", \"flush\", \"uncache\", ",
870 "\"no_errors\", \"size_errors\",",
871 " or \"all_errors\"",
877 if (STREQU (subCommand, "debug")) {
879 Tcl_AppendStringsToObj(resultObj, "Wrong # of arguments",
883 return Tcl_GetIntFromObj(interp, objv[2], &ldap_debug);
887 /* FIX: this needs to enumerate all the possibilities */
888 Tcl_AppendStringsToObj (resultObj,
891 "\" must be one of \"add\", ",
892 "\"add_attributes\", ",
893 "\"bind\", \"cache\", \"delete\", ",
894 "\"delete_attributes\", \"modify\", ",
895 "\"modify_rdn\", \"rename_rdn\", ",
896 "\"replace_attributes\", ",
897 "\"search\" or \"unbind\".",
903 * Delete and LDAP command object
907 NeoX_LdapObjDeleteCmd(clientData)
908 ClientData clientData;
910 LDAP *ldap = (LDAP *)clientData;
915 /*-----------------------------------------------------------------------------
918 * Implements the `ldap' command:
919 * ldap open newObjName host [port]
920 * ldap init newObjName host [port]
923 * A standard Tcl result.
926 * See the user documentation.
927 *-----------------------------------------------------------------------------
930 NeoX_LdapObjCmd (clientData, interp, objc, objv)
931 ClientData clientData;
934 Tcl_Obj *CONST objv[];
943 Tcl_Obj *resultObj = Tcl_GetObjResult (interp);
945 if (objc < 3 || objc > 5)
946 return TclX_WrongArgs (interp, objv [0],
947 "(open|init) new_command host [port]|explode dn");
949 subCommand = Tcl_GetStringFromObj (objv[1], NULL);
951 if (STREQU(subCommand, "explode")) {
955 char **exploded, **p;
957 param = Tcl_GetStringFromObj (objv[2], NULL);
958 if (param[0] == '-') {
959 if (STREQU(param, "-nonames")) {
961 } else if (STREQU(param, "-list")) {
964 return TclX_WrongArgs (interp, objv [0], "explode ?-nonames|-list? dn");
968 param = Tcl_GetStringFromObj (objv[3], NULL);
969 exploded = ldap_explode_dn(param, nonames);
970 for (p = exploded; *p; p++) {
972 char *q = strchr(*p, '=');
974 Tcl_SetObjLength(resultObj, 0);
975 Tcl_AppendStringsToObj(resultObj, "rdn ", *p,
976 " missing '='", NULL);
977 ldap_value_free(exploded);
981 if (Tcl_ListObjAppendElement(interp, resultObj,
982 Tcl_NewStringObj(*p, -1)) != TCL_OK ||
983 Tcl_ListObjAppendElement(interp, resultObj,
984 Tcl_NewStringObj(q+1, -1)) != TCL_OK) {
985 ldap_value_free(exploded);
989 if (Tcl_ListObjAppendElement(interp, resultObj,
990 Tcl_NewStringObj(*p, -1))) {
991 ldap_value_free(exploded);
996 ldap_value_free(exploded);
1001 if (STREQU(subCommand, "friendly")) {
1002 char *friendly = ldap_dn2ufn(Tcl_GetStringFromObj(objv[2], NULL));
1003 Tcl_SetStringObj(resultObj, friendly, -1);
1009 newCommand = Tcl_GetStringFromObj (objv[2], NULL);
1010 ldapHost = Tcl_GetStringFromObj (objv[3], NULL);
1013 if (Tcl_GetIntFromObj (interp, objv [4], &ldapPort) == TCL_ERROR) {
1014 Tcl_AppendStringsToObj (resultObj,
1015 "LDAP port number is non-numeric",
1021 if (STREQU (subCommand, "open")) {
1022 ldap = ldap_open (ldapHost, ldapPort);
1023 } else if (STREQU (subCommand, "init")) {
1024 ldap = ldap_init (ldapHost, ldapPort);
1026 Tcl_AppendStringsToObj (resultObj,
1027 "option was not \"open\" or \"init\"");
1031 if (ldap == (LDAP *)NULL) {
1032 Tcl_SetErrno(errno);
1033 Tcl_AppendStringsToObj (resultObj,
1034 Tcl_PosixError (interp),
1040 ldap->ld_deref = LDAP_DEREF_NEVER; /* Turn off alias dereferencing */
1043 Tcl_CreateObjCommand (interp,
1045 NeoX_LdapTargetObjCmd,
1047 NeoX_LdapObjDeleteCmd);
1051 /*-----------------------------------------------------------------------------
1053 * Initialize the LDAP interface.
1054 *-----------------------------------------------------------------------------
1057 Ldaptcl_Init (interp)
1060 Tcl_CreateObjCommand (interp,
1064 (Tcl_CmdDeleteProc*) NULL);
1065 Tcl_PkgProvide(interp, "Ldaptcl", "1.1");