comparison modules/ldap/eldap.c @ 996:25e260cb7994

[xemacs-hg @ 2002-09-10 15:27:02 by james] Enable unloading of dynamic modules. Create the first two internal XEmacs modules: LDAP and postgreSQL. Update the sample directory to contain a sample internal XEmacs module and a sample external XEmacs module. Improve support for autoloading modules. Make internal module code compile into the XEmacs binary if XEmacs is configured without module support. Make the internal module directories self-contained so that they can be distributed separately from XEmacs.
author james
date Tue, 10 Sep 2002 15:27:39 +0000
parents 3ecd8885ac67
children 848225013a08
comparison
equal deleted inserted replaced
995:4575a219af58 996:25e260cb7994
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */ 19 Boston, MA 02111-1307, USA. */
20 20
21 /* Synched up with: Not in FSF. */ 21 /* Synched up with: Not in FSF. */
22 22
23 /* Author: Oscar Figueiredo */ 23 /* Author: Oscar Figueiredo with lots of support from Hrvoje Niksic */
24 24
25 /* This file provides lisp primitives for access to an LDAP library 25 /* This file provides lisp primitives for access to an LDAP library
26 conforming to the API defined in RFC 1823. 26 conforming to the API defined in RFC 1823.
27 It has been tested with: 27 It has been tested with:
28 - UMich LDAP 3.3 (http://www.umich.edu/~dirsvcs/ldap/) 28 - UMich LDAP 3.3 (http://www.umich.edu/~dirsvcs/ldap/)
29 - Netscape's LDAP SDK 1.0 (http://developer.netscape.com) */ 29 - OpenLDAP 1.2 (http://www.openldap.org/)
30 30 - Netscape's LDAP SDK (http://developer.netscape.com/) */
31 #include <emodules.h> 31
32 32
33 #if defined (HAVE_LDAP) 33 #include <config.h>
34 /* The entire file is within this conditional */ 34 #include "lisp.h"
35 #include "opaque.h"
36 #include "sysdep.h"
37 #include "buffer.h"
38 #include "process.h" /* for report_process_error */
39
40 #include <errno.h>
35 41
36 #include "eldap.h" 42 #include "eldap.h"
37 #include <lber.h> 43
38 #include <ldap.h> 44 static Fixnum ldap_default_port;
39
40 #ifdef HAVE_NS_LDAP
41 #define HAVE_LDAP_SET_OPTION 1
42 #define HAVE_LDAP_GET_ERRNO 1
43 #else
44 #undef HAVE_LDAP_SET_OPTION
45 #undef HAVE_LDAP_GET_ERRNO
46 #endif
47
48 static Lisp_Object Vldap_default_base; 45 static Lisp_Object Vldap_default_base;
49 static Lisp_Object Vldap_default_host; 46
50 47 static Lisp_Object Qeldap;
51 /* ldap-search-internal plist keywords */ 48
52 static Lisp_Object Qhost, Qfilter, Qattributes, Qattrsonly, Qbase, Qscope, 49 /* Needed by the lrecord definition */
53 Qauth, Qbinddn, Qpasswd, Qderef, Qtimelimit, Qsizelimit; 50 Lisp_Object Qldapp;
51
52 /* ldap-open plist keywords */
53 static Lisp_Object Qport, Qauth, Qbinddn, Qpasswd, Qderef, Qtimelimit, Qsizelimit;
54 /* Search scope limits */ 54 /* Search scope limits */
55 static Lisp_Object Qbase, Qonelevel, Qsubtree; 55 static Lisp_Object Qbase, Qonelevel, Qsubtree;
56 /* Authentication methods */ 56 /* Authentication methods */
57 #ifdef LDAP_AUTH_KRBV41 57 static Lisp_Object Qkrbv41, Qkrbv42;
58 static Lisp_Object Qkrbv41;
59 #endif
60 #ifdef LDAP_AUTH_KRBV42
61 static Lisp_Object Qkrbv42;
62 #endif
63 /* Deref policy */ 58 /* Deref policy */
64 static Lisp_Object Qnever, Qalways, Qfind; 59 static Lisp_Object Qnever, Qalways, Qfind;
65 60 /* Modification types (Qdelete is defined in general.c) */
66 DEFUN ("ldap-search-internal", Fldap_search_internal, 1, 1, 0, /* 61 static Lisp_Object Qadd, Qreplace;
67 Perform a search on a LDAP server. 62
68 SEARCH-PLIST is a property list describing the search request. 63
64 /************************************************************************/
65 /* Utility Functions */
66 /************************************************************************/
67
68 static void
69 signal_ldap_error (LDAP *ld, LDAPMessage *res, int ldap_err)
70 {
71 if (ldap_err <= 0)
72 {
73 #if defined HAVE_LDAP_PARSE_RESULT
74 int err;
75 ldap_err = ldap_parse_result (ld, res,
76 &err,
77 NULL, NULL, NULL, NULL, 0);
78 if (ldap_err == LDAP_SUCCESS)
79 ldap_err = err;
80 #elif defined HAVE_LDAP_GET_LDERRNO
81 ldap_err = ldap_get_lderrno (ld, NULL, NULL);
82 #elif defined HAVE_LDAP_RESULT2ERROR
83 ldap_err = ldap_result2error (ld, res, 0);
84 #else
85 ldap_err = ld->ld_errno;
86 #endif
87 }
88 invalid_operation ("LDAP error",
89 build_string (ldap_err2string (ldap_err)));
90 }
91
92
93 /************************************************************************/
94 /* ldap lrecord basic functions */
95 /************************************************************************/
96
97 static Lisp_Object
98 make_ldap (Lisp_LDAP *ldap)
99 {
100 return wrap_ldap (ldap);
101 }
102
103 #ifdef USE_KKCC
104 static const struct lrecord_description ldap_description [] = {
105 { XD_LISP_OBJECT, offsetof (struct Lisp_LDAP, host) },
106 { XD_END }
107 };
108 #endif /* USE_KKCC */
109
110 static Lisp_Object
111 mark_ldap (Lisp_Object obj)
112 {
113 return XLDAP (obj)->host;
114 }
115
116 static void
117 print_ldap (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
118 {
119 Lisp_LDAP *ldap = XLDAP (obj);
120
121 if (print_readably)
122 printing_unreadable_object ("#<ldap %s>", XSTRING_DATA (ldap->host));
123
124 write_fmt_string_lisp (printcharfun, "#<ldap %S", 1, ldap->host);
125 if (!ldap->ld)
126 write_c_string (printcharfun,"(dead) ");
127 write_fmt_string (printcharfun, " 0x%lx>", (long)ldap);
128 }
129
130 static Lisp_LDAP *
131 allocate_ldap (void)
132 {
133 Lisp_LDAP *ldap = alloc_lcrecord_type (Lisp_LDAP, &lrecord_ldap);
134
135 ldap->ld = NULL;
136 ldap->host = Qnil;
137 return ldap;
138 }
139
140 static void
141 finalize_ldap (void *header, int for_disksave)
142 {
143 Lisp_LDAP *ldap = (Lisp_LDAP *) header;
144
145 if (for_disksave)
146 invalid_operation ("Can't dump an emacs containing LDAP objects",
147 make_ldap (ldap));
148
149 if (ldap->ld)
150 ldap_unbind (ldap->ld);
151 ldap->ld = NULL;
152 }
153
154 #ifdef USE_KKCC
155 DEFINE_LRECORD_IMPLEMENTATION ("ldap", ldap,
156 0, /*dumpable-flag*/
157 mark_ldap, print_ldap, finalize_ldap,
158 NULL, NULL, ldap_description, Lisp_LDAP);
159 #else /* not USE_KKCC */
160 DEFINE_LRECORD_IMPLEMENTATION ("ldap", ldap,
161 mark_ldap, print_ldap, finalize_ldap,
162 NULL, NULL, 0, Lisp_LDAP);
163 #endif /* not USE_KKCC */
164
165
166
167 /************************************************************************/
168 /* Basic ldap accessors */
169 /************************************************************************/
170
171 /* ###autoload */
172 DEFUN ("ldapp", Fldapp, 1, 1, 0, /*
173 Return t if OBJECT is a LDAP connection.
174 */
175 (object))
176 {
177 return LDAPP (object) ? Qt : Qnil;
178 }
179
180 DEFUN ("ldap-host", Fldap_host, 1, 1, 0, /*
181 Return the server host of the connection LDAP, as a string.
182 */
183 (ldap))
184 {
185 CHECK_LDAP (ldap);
186 return (XLDAP (ldap))->host;
187 }
188
189 DEFUN ("ldap-live-p", Fldap_live_p, 1, 1, 0, /*
190 Return t if LDAP is an active LDAP connection.
191 */
192 (ldap))
193 {
194 CHECK_LDAP (ldap);
195 return (XLDAP (ldap))->ld ? Qt : Qnil;
196 }
197
198 /************************************************************************/
199 /* Opening/Closing a LDAP connection */
200 /************************************************************************/
201
202
203 /* ###autoload */
204 DEFUN ("ldap-open", Fldap_open, 1, 2, 0, /*
205 Open a LDAP connection to HOST.
206 PLIST is a plist containing additional parameters for the connection.
69 Valid keys in that list are: 207 Valid keys in that list are:
70 `host' is a string naming one or more (blank separated) LDAP servers to 208 `port' the TCP port to use for the connection if different from
71 to try to connect to. Each host name may optionally be of the form host:port. 209 `ldap-default-port'.
72 `filter' is a filter string for the search as described in RFC 1558
73 `attributes' is a list of strings indicating which attributes to retrieve
74 for each matching entry. If nil return all available attributes.
75 `attrsonly' if non-nil indicates that only the attributes are retrieved, not
76 the associated values.
77 `base' is the base for the search as described in RFC 1779.
78 `scope' is one of the three symbols `subtree', `base' or `onelevel'.
79 `auth' is the authentication method to use, possible values depend on 210 `auth' is the authentication method to use, possible values depend on
80 the LDAP library XEmacs was compiled with: `simple', `krbv41' and `krbv42'. 211 the LDAP library XEmacs was compiled with: `simple', `krbv41' and `krbv42'.
81 `binddn' is the distinguished name of the user to bind as (in RFC 1779 syntax). 212 `binddn' is the distinguished name of the user to bind as (in RFC 1779 syntax).
82 `passwd' is the password to use for simple authentication. 213 `passwd' is the password to use for simple authentication.
83 `deref' is one of the symbols `never', `always', `search' or `find'. 214 `deref' is one of the symbols `never', `always', `search' or `find'.
84 `timelimit' is the timeout limit for the connection in seconds. 215 `timelimit' is the timeout limit for the connection in seconds.
85 `sizelimit' is the maximum number of matches to return. 216 `sizelimit' is the maximum number of matches to return.
86 The function returns a list of matching entries. Each entry is itself
87 an alist of attribute/values.
88 */ 217 */
89 (search_plist)) 218 (host, plist))
90 { 219 {
91 /* This function calls lisp */ 220 /* This function can GC */
92 221 Lisp_LDAP *ldap;
93 /* Vars for query */
94 LDAP *ld; 222 LDAP *ld;
95 LDAPMessage *res, *e; 223 int ldap_port = 0;
96 BerElement *ptr;
97 char *a;
98 int i, rc, err;
99
100 char *ldap_host = NULL;
101 char *ldap_filter = NULL;
102 char **ldap_attributes = NULL;
103 int ldap_attrsonly = 0;
104 char *ldap_base = NULL;
105 int ldap_scope = LDAP_SCOPE_SUBTREE;
106 int ldap_auth = LDAP_AUTH_SIMPLE; 224 int ldap_auth = LDAP_AUTH_SIMPLE;
107 char *ldap_binddn = NULL; 225 char *ldap_binddn = NULL;
108 char *ldap_passwd = NULL; 226 char *ldap_passwd = NULL;
109 int ldap_deref = LDAP_DEREF_NEVER; 227 int ldap_deref = LDAP_DEREF_NEVER;
110 int ldap_timelimit = 0; 228 int ldap_timelimit = 0;
111 int ldap_sizelimit = 0; 229 int ldap_sizelimit = 0;
112 230 int err;
113 char **vals = NULL; 231
114 int matches; 232 CHECK_STRING (host);
115 233
116 Lisp_Object list, entry, result, keyword, value; 234 {
117 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; 235 EXTERNAL_PROPERTY_LIST_LOOP_3 (keyword, value, plist)
118 236 {
119 list = entry = result = keyword = value = Qnil; 237 /* TCP Port */
120 GCPRO5 (list, entry, result, keyword, value); 238 if (EQ (keyword, Qport))
121 239 {
122 240 CHECK_INT (value);
123 EXTERNAL_PROPERTY_LIST_LOOP(list, keyword, value, search_plist) 241 ldap_port = XINT (value);
124 { 242 }
125 /* Host */ 243 /* Authentication method */
126 if (EQ (keyword, Qhost)) 244 if (EQ (keyword, Qauth))
127 { 245 {
128 CHECK_STRING (value); 246 if (EQ (value, Qsimple))
129 ldap_host = alloca (XSTRING_LENGTH (value) + 1); 247 ldap_auth = LDAP_AUTH_SIMPLE;
130 strcpy (ldap_host, (char *)XSTRING_DATA (value));
131 }
132 /* Filter */
133 else if (EQ (keyword, Qfilter))
134 {
135 CHECK_STRING (value);
136 ldap_filter = alloca (XSTRING_LENGTH (value) + 1);
137 strcpy (ldap_filter, (char *)XSTRING_DATA (value));
138 }
139 /* Attributes */
140 else if (EQ (keyword, Qattributes))
141 {
142 if (! NILP (value))
143 {
144 Lisp_Object attr_left = value;
145 struct gcpro ngcpro1;
146
147 NGCPRO1 (attr_left);
148 CHECK_CONS (value);
149
150 ldap_attributes = alloca ((XINT (Flength (value)) + 1)*sizeof (char *));
151
152 for (i=0; !NILP (attr_left); i++) {
153 CHECK_STRING (XCAR (attr_left));
154 ldap_attributes[i] = alloca (XSTRING_LENGTH (XCAR (attr_left)) + 1);
155 strcpy(ldap_attributes[i],
156 (char *)(XSTRING_DATA( XCAR (attr_left))));
157 attr_left = XCDR (attr_left);
158 }
159 ldap_attributes[i] = NULL;
160 NUNGCPRO;
161 }
162 }
163 /* Attributes Only */
164 else if (EQ (keyword, Qattrsonly))
165 {
166 CHECK_SYMBOL (value);
167 ldap_attrsonly = NILP (value) ? 0 : 1;
168 }
169 /* Base */
170 else if (EQ (keyword, Qbase))
171 {
172 if (!NILP (value))
173 {
174 CHECK_STRING (value);
175 ldap_base = alloca (XSTRING_LENGTH (value) + 1);
176 strcpy (ldap_base, (char *)XSTRING_DATA (value));
177 }
178 }
179 /* Scope */
180 else if (EQ (keyword, Qscope))
181 {
182 CHECK_SYMBOL (value);
183
184 if (EQ (value, Qbase))
185 ldap_scope = LDAP_SCOPE_BASE;
186 else if (EQ (value, Qonelevel))
187 ldap_scope = LDAP_SCOPE_ONELEVEL;
188 else if (EQ (value, Qsubtree))
189 ldap_scope = LDAP_SCOPE_SUBTREE;
190 else
191 signal_simple_error ("Invalid scope", value);
192 }
193 /* Authentication method */
194 else if (EQ (keyword, Qauth))
195 {
196 CHECK_SYMBOL (value);
197
198 if (EQ (value, Qsimple))
199 ldap_auth = LDAP_AUTH_SIMPLE;
200 #ifdef LDAP_AUTH_KRBV41 248 #ifdef LDAP_AUTH_KRBV41
201 else if (EQ (value, Qkrbv41)) 249 else if (EQ (value, Qkrbv41))
202 ldap_auth = LDAP_AUTH_KRBV41; 250 ldap_auth = LDAP_AUTH_KRBV41;
203 #endif 251 #endif
204 #ifdef LDAP_AUTH_KRBV42 252 #ifdef LDAP_AUTH_KRBV42
205 else if (EQ (value, Qkrbv42)) 253 else if (EQ (value, Qkrbv42))
206 ldap_auth = LDAP_AUTH_KRBV42; 254 ldap_auth = LDAP_AUTH_KRBV42;
207 #endif 255 #endif
208 else 256 else
209 signal_simple_error ("Invalid authentication method", value); 257 invalid_constant ("Invalid authentication method", value);
210 } 258 }
211 /* Bind DN */ 259 /* Bind DN */
212 else if (EQ (keyword, Qbinddn)) 260 else if (EQ (keyword, Qbinddn))
213 { 261 {
214 if (!NILP (value)) 262 CHECK_STRING (value);
215 { 263 LISP_STRING_TO_EXTERNAL (value, ldap_binddn, Qnative);
216 CHECK_STRING (value); 264 }
217 ldap_binddn = alloca (XSTRING_LENGTH (value) + 1); 265 /* Password */
218 strcpy (ldap_binddn, (char *)XSTRING_DATA (value)); 266 else if (EQ (keyword, Qpasswd))
219 } 267 {
220 } 268 CHECK_STRING (value);
221 /* Password */ 269 LISP_STRING_TO_EXTERNAL (value, ldap_passwd, Qnative);
222 else if (EQ (keyword, Qpasswd)) 270 }
223 { 271 /* Deref */
224 if (!NILP (value)) 272 else if (EQ (keyword, Qderef))
225 { 273 {
226 CHECK_STRING (value); 274 if (EQ (value, Qnever))
227 ldap_passwd = alloca (XSTRING_LENGTH (value) + 1); 275 ldap_deref = LDAP_DEREF_NEVER;
228 strcpy (ldap_passwd, (char *)XSTRING_DATA (value)); 276 else if (EQ (value, Qsearch))
229 } 277 ldap_deref = LDAP_DEREF_SEARCHING;
230 } 278 else if (EQ (value, Qfind))
231 /* Deref */ 279 ldap_deref = LDAP_DEREF_FINDING;
232 else if (EQ (keyword, Qderef)) 280 else if (EQ (value, Qalways))
233 { 281 ldap_deref = LDAP_DEREF_ALWAYS;
234 CHECK_SYMBOL (value); 282 else
235 if (EQ (value, Qnever)) 283 invalid_constant ("Invalid deref value", value);
236 ldap_deref = LDAP_DEREF_NEVER; 284 }
237 else if (EQ (value, Qsearch)) 285 /* Timelimit */
238 ldap_deref = LDAP_DEREF_SEARCHING; 286 else if (EQ (keyword, Qtimelimit))
239 else if (EQ (value, Qfind)) 287 {
240 ldap_deref = LDAP_DEREF_FINDING; 288 CHECK_INT (value);
241 else if (EQ (value, Qalways)) 289 ldap_timelimit = XINT (value);
242 ldap_deref = LDAP_DEREF_ALWAYS; 290 }
243 else 291 /* Sizelimit */
244 signal_simple_error ("Invalid deref value", value); 292 else if (EQ (keyword, Qsizelimit))
245 } 293 {
246 /* Timelimit */ 294 CHECK_INT (value);
247 else if (EQ (keyword, Qtimelimit)) 295 ldap_sizelimit = XINT (value);
248 { 296 }
249 if (!NILP (value)) 297 }
250 { 298 }
251 CHECK_INT (value); 299
252 ldap_timelimit = XINT (value); 300 if (ldap_port == 0)
253 } 301 {
254 } 302 ldap_port = ldap_default_port;
255 /* Sizelimit */ 303 }
256 else if (EQ (keyword, Qsizelimit))
257 {
258 if (!NILP (value))
259 {
260 CHECK_INT (value);
261 ldap_sizelimit = XINT (value);
262 }
263 }
264 }
265
266 /* Use ldap-default-base if no default base was given */
267 if (ldap_base == NULL && !NILP (Vldap_default_base))
268 {
269 CHECK_STRING (Vldap_default_base);
270 ldap_base = alloca (XSTRING_LENGTH (Vldap_default_base) + 1);
271 strcpy (ldap_base, (char *)XSTRING_DATA (Vldap_default_base));
272 }
273
274 /* Use ldap-default-host if no host was given */
275 if (ldap_host == NULL && !NILP (Vldap_default_host))
276 {
277 CHECK_STRING (Vldap_default_host);
278 ldap_host = alloca (XSTRING_LENGTH (Vldap_default_host) + 1);
279 strcpy (ldap_host, (char *)XSTRING_DATA (Vldap_default_host));
280 }
281
282 if (ldap_filter == NULL)
283 error ("Empty search filter");
284
285 /* Garbage collect before connecting (if using UMich lib).
286 This is ugly, I know, but without this, the UMich LDAP library 3.3
287 frequently reports "Can't contact LDAP server". I really need to
288 check what happens inside that lib. Anyway this should be harmless to
289 XEmacs and makes things work. */
290 #if defined (HAVE_UMICH_LDAP)
291 garbage_collect_1 ();
292 #endif
293 304
294 /* Connect to the server and bind */ 305 /* Connect to the server and bind */
295 message ("Connecting to %s...", ldap_host); 306 slow_down_interrupts ();
296 if ( (ld = ldap_open (ldap_host, LDAP_PORT)) == NULL ) 307 ld = ldap_open ((char *) XSTRING_DATA (host), ldap_port);
297 signal_simple_error ("Failed connecting to host", 308 speed_up_interrupts ();
298 build_string (ldap_host)); 309
299 310 if (ld == NULL )
300 #if HAVE_LDAP_SET_OPTION 311 report_process_error ("Failed connecting to host", host);
301 if (ldap_set_option (ld, LDAP_OPT_DEREF, (void *)&ldap_deref) != LDAP_SUCCESS) 312
302 error ("Failed to set deref option"); 313 #ifdef HAVE_LDAP_SET_OPTION
303 if (ldap_set_option (ld, LDAP_OPT_TIMELIMIT, (void *)&ldap_timelimit) != LDAP_SUCCESS) 314 if ((err = ldap_set_option (ld, LDAP_OPT_DEREF,
304 error ("Failed to set timelimit option"); 315 (void *)&ldap_deref)) != LDAP_SUCCESS)
305 if (ldap_set_option (ld, LDAP_OPT_SIZELIMIT, (void *)&ldap_sizelimit) != LDAP_SUCCESS) 316 signal_ldap_error (ld, NULL, err);
306 error ("Failed to set sizelimit option"); 317 if ((err = ldap_set_option (ld, LDAP_OPT_TIMELIMIT,
307 if (ldap_set_option (ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON) != LDAP_SUCCESS) 318 (void *)&ldap_timelimit)) != LDAP_SUCCESS)
308 error ("Failed to set referral option"); 319 signal_ldap_error (ld, NULL, err);
309 #else /* HAVE_LDAP_SET_OPTION */ 320 if ((err = ldap_set_option (ld, LDAP_OPT_SIZELIMIT,
321 (void *)&ldap_sizelimit)) != LDAP_SUCCESS)
322 signal_ldap_error (ld, NULL, err);
323 if ((err = ldap_set_option (ld, LDAP_OPT_REFERRALS,
324 LDAP_OPT_ON)) != LDAP_SUCCESS)
325 signal_ldap_error (ld, NULL, err);
326 if ((err = ldap_set_option (ld, LDAP_OPT_RESTART,
327 LDAP_OPT_ON)) != LDAP_SUCCESS)
328 signal_ldap_error (ld, NULL, err);
329 #else /* not HAVE_LDAP_SET_OPTION */
310 ld->ld_deref = ldap_deref; 330 ld->ld_deref = ldap_deref;
311 ld->ld_timelimit = ldap_timelimit; 331 ld->ld_timelimit = ldap_timelimit;
312 ld->ld_sizelimit = ldap_sizelimit; 332 ld->ld_sizelimit = ldap_sizelimit;
313 #ifdef LDAP_REFERRALS 333 #ifdef LDAP_REFERRALS
314 ld->ld_options = LDAP_OPT_REFERRALS; 334 ld->ld_options = LDAP_OPT_REFERRALS;
315 #else /* LDAP_REFERRALS */ 335 #else /* not LDAP_REFERRALS */
316 ld->ld_options = 0; 336 ld->ld_options = 0;
317 #endif /* LDAP_REFERRALS */ 337 #endif /* not LDAP_REFERRALS */
318 #endif /* HAVE_LDAP_SET_OPTION */ 338 /* XEmacs uses interrupts (SIGIO,SIGALRM), LDAP calls need to ignore them */
319 339 ld->ld_options |= LDAP_OPT_RESTART;
320 message ("Binding to %s...", ldap_host); 340 #endif /* not HAVE_LDAP_SET_OPTION */
321 if ( (err = (ldap_bind_s (ld, ldap_binddn, ldap_passwd, ldap_auth ))) != LDAP_SUCCESS ) 341
322 signal_simple_error ("Failed binding to the server", 342 err = ldap_bind_s (ld, ldap_binddn, ldap_passwd, ldap_auth);
323 build_string (ldap_err2string (err))); 343 if (err != LDAP_SUCCESS)
344 {
345 Ibyte *interrmess;
346 EXTERNAL_TO_C_STRING (ldap_err2string (err), interrmess, Qnative);
347 signal_error (Qprocess_error, "Failed binding to the server",
348 build_intstring (interrmess));
349 }
350
351 ldap = allocate_ldap ();
352 ldap->ld = ld;
353 ldap->host = host;
354
355 return make_ldap (ldap);
356 }
357
358
359
360 DEFUN ("ldap-close", Fldap_close, 1, 1, 0, /*
361 Close an LDAP connection.
362 */
363 (ldap))
364 {
365 Lisp_LDAP *lldap;
366 CHECK_LIVE_LDAP (ldap);
367 lldap = XLDAP (ldap);
368 ldap_unbind (lldap->ld);
369 lldap->ld = NULL;
370 return Qnil;
371 }
372
373
374
375 /************************************************************************/
376 /* Working on a LDAP connection */
377 /************************************************************************/
378 struct ldap_unwind_struct
379 {
380 LDAPMessage *res;
381 struct berval **vals;
382 };
383
384 static Lisp_Object
385 ldap_search_unwind (Lisp_Object unwind_obj)
386 {
387 struct ldap_unwind_struct *unwind =
388 (struct ldap_unwind_struct *) get_opaque_ptr (unwind_obj);
389 if (unwind->res)
390 ldap_msgfree (unwind->res);
391 if (unwind->vals)
392 ldap_value_free_len (unwind->vals);
393 return Qnil;
394 }
395
396 /* The following function is called `ldap-search-basic' instead of */
397 /* plain `ldap-search' to maintain compatibility with the XEmacs 21.1 */
398 /* API where `ldap-search' was the name of the high-level search */
399 /* function */
400
401 DEFUN ("ldap-search-basic", Fldap_search_basic, 2, 8, 0, /*
402 Perform a search on an open LDAP connection.
403 LDAP is an LDAP connection object created with `ldap-open'.
404 FILTER is a filter string for the search as described in RFC 1558.
405 BASE is the distinguished name at which to start the search.
406 SCOPE is one of the symbols `base', `onelevel' or `subtree' indicating
407 the scope of the search.
408 ATTRS is a list of strings indicating which attributes to retrieve
409 for each matching entry. If nil return all available attributes.
410 If ATTRSONLY is non-nil then only the attributes are retrieved, not
411 the associated values.
412 If WITHDN is non-nil each entry in the result will be prepended with
413 its distinguished name DN.
414 If VERBOSE is non-nil progress messages will be echoed.
415 The function returns a list of matching entries. Each entry is itself
416 an alist of attribute/value pairs optionally preceded by the DN of the
417 entry according to the value of WITHDN.
418 */
419 (ldap, filter, base, scope, attrs, attrsonly, withdn, verbose))
420 {
421 /* This function can GC */
422
423 /* Vars for query */
424 LDAP *ld;
425 LDAPMessage *e;
426 BerElement *ptr;
427 char *a, *dn;
428 int i, rc;
429 int matches;
430 struct ldap_unwind_struct unwind;
431
432 int ldap_scope = LDAP_SCOPE_SUBTREE;
433 char **ldap_attributes = NULL;
434
435 int speccount = specpdl_depth ();
436
437 Lisp_Object list = Qnil;
438 Lisp_Object entry = Qnil;
439 Lisp_Object result = Qnil;
440 struct gcpro gcpro1, gcpro2, gcpro3;
441
442 GCPRO3 (list, entry, result);
443
444 unwind.res = NULL;
445 unwind.vals = NULL;
446
447 /* Do all the parameter checking */
448 CHECK_LIVE_LDAP (ldap);
449 ld = XLDAP (ldap)->ld;
450
451 /* Filter */
452 CHECK_STRING (filter);
453
454 /* Search base */
455 if (NILP (base))
456 {
457 base = Vldap_default_base;
458 }
459 if (!NILP (base))
460 {
461 CHECK_STRING (base);
462 }
463
464 /* Search scope */
465 if (!NILP (scope))
466 {
467 if (EQ (scope, Qbase))
468 ldap_scope = LDAP_SCOPE_BASE;
469 else if (EQ (scope, Qonelevel))
470 ldap_scope = LDAP_SCOPE_ONELEVEL;
471 else if (EQ (scope, Qsubtree))
472 ldap_scope = LDAP_SCOPE_SUBTREE;
473 else
474 invalid_constant ("Invalid scope", scope);
475 }
476
477 /* Attributes to search */
478 if (!NILP (attrs))
479 {
480 CHECK_CONS (attrs);
481 ldap_attributes = alloca_array (char *, 1 + XINT (Flength (attrs)));
482
483 i = 0;
484 EXTERNAL_LIST_LOOP (attrs, attrs)
485 {
486 Lisp_Object current = XCAR (attrs);
487 CHECK_STRING (current);
488 LISP_STRING_TO_EXTERNAL (current, ldap_attributes[i], Qnative);
489 ++i;
490 }
491 ldap_attributes[i] = NULL;
492 }
493
494 /* Attributes only ? */
495 CHECK_SYMBOL (attrsonly);
324 496
325 /* Perform the search */ 497 /* Perform the search */
326 message ("Searching with LDAP on %s...", ldap_host); 498 if (ldap_search (ld,
327 if ( ldap_search (ld, ldap_base, ldap_scope, ldap_filter, 499 NILP (base) ? (char *) "" : (char *) XSTRING_DATA (base),
328 ldap_attributes, ldap_attrsonly) == -1) 500 ldap_scope,
329 { 501 NILP (filter) ? (char *) "" : (char *) XSTRING_DATA (filter),
330 ldap_unbind (ld); 502 ldap_attributes,
331 #if HAVE_LDAP_GET_ERRNO 503 NILP (attrsonly) ? 0 : 1)
332 signal_simple_error ("Error during LDAP search", 504 == -1)
333 build_string (ldap_err2string (ldap_get_lderrno (ld, NULL, NULL)))); 505 {
334 #else 506 signal_ldap_error (ld, NULL, 0);
335 signal_simple_error ("Error during LDAP search", 507 }
336 build_string (ldap_err2string (ld->ld_errno))); 508
337 #endif 509 /* Ensure we don't exit without cleaning up */
338 } 510 record_unwind_protect (ldap_search_unwind,
511 make_opaque_ptr (&unwind));
339 512
340 /* Build the results list */ 513 /* Build the results list */
341 matches = 0; 514 matches = 0;
342 515
343 while ( (rc = ldap_result (ld, LDAP_RES_ANY, 0, NULL, &res)) 516 rc = ldap_result (ld, LDAP_RES_ANY, 0, NULL, &unwind.res);
344 == LDAP_RES_SEARCH_ENTRY ) 517
345 { 518 while (rc == LDAP_RES_SEARCH_ENTRY)
519 {
520 QUIT;
346 matches ++; 521 matches ++;
347 e = ldap_first_entry (ld, res); 522 e = ldap_first_entry (ld, unwind.res);
348 message ("Parsing results... %d", matches); 523 /* #### This call to message() is pretty fascist, because it
524 destroys the current echo area contents, even when invoked
525 from Lisp. It should use echo_area_message() instead, and
526 restore the old echo area contents later. */
527 if (! NILP (verbose))
528 message ("Parsing ldap results... %d", matches);
349 entry = Qnil; 529 entry = Qnil;
530 /* Get the DN if required */
531 if (! NILP (withdn))
532 {
533 dn = ldap_get_dn (ld, e);
534 if (dn == NULL)
535 signal_ldap_error (ld, e, 0);
536 entry = Fcons (build_ext_string (dn, Qnative), Qnil);
537 }
350 for (a= ldap_first_attribute (ld, e, &ptr); 538 for (a= ldap_first_attribute (ld, e, &ptr);
351 a != NULL; 539 a != NULL;
352 a= ldap_next_attribute (ld, e, ptr) ) 540 a = ldap_next_attribute (ld, e, ptr) )
353 { 541 {
354 list = Fcons (build_string (a), Qnil); 542 list = Fcons (build_ext_string (a, Qnative), Qnil);
355 vals = ldap_get_values (ld, e, a); 543 unwind.vals = ldap_get_values_len (ld, e, a);
356 if (vals != NULL) 544 if (unwind.vals != NULL)
357 { 545 {
358 for (i=0; vals[i]!=NULL; i++) 546 for (i = 0; unwind.vals[i] != NULL; i++)
359 { 547 {
360 list = Fcons (build_string (vals[i]), 548 list = Fcons (make_ext_string ((Extbyte *) unwind.vals[i]->bv_val,
549 unwind.vals[i]->bv_len,
550 Qnative),
361 list); 551 list);
362 } 552 }
363 } 553 }
364 entry = Fcons (Fnreverse (list), 554 entry = Fcons (Fnreverse (list),
365 entry); 555 entry);
366 ldap_value_free (vals); 556 ldap_value_free_len (unwind.vals);
557 unwind.vals = NULL;
367 } 558 }
368 result = Fcons (Fnreverse (entry), 559 result = Fcons (Fnreverse (entry),
369 result); 560 result);
370 ldap_msgfree (res); 561 ldap_msgfree (unwind.res);
371 } 562 unwind.res = NULL;
563
564 rc = ldap_result (ld, LDAP_RES_ANY, 0, NULL, &(unwind.res));
565 }
566
567 #if defined HAVE_LDAP_PARSE_RESULT
568 {
569 int rc2 = ldap_parse_result (ld, unwind.res,
570 &rc,
571 NULL, NULL, NULL, NULL, 0);
572 if (rc2 != LDAP_SUCCESS)
573 rc = rc2;
574 }
575 #else
576 if (rc == 0)
577 signal_ldap_error (ld, NULL, LDAP_TIMELIMIT_EXCEEDED);
372 578
373 if (rc == -1) 579 if (rc == -1)
374 { 580 signal_ldap_error (ld, unwind.res, (unwind.res==NULL) ? ld->ld_errno : 0);
375 #if HAVE_LDAP_GET_ERRNO 581
376 signal_simple_error ("Error retrieving result", 582 #if defined HAVE_LDAP_RESULT2ERROR
377 build_string (ldap_err2string (ldap_get_lderrno (ld, NULL, NULL)))); 583 rc = ldap_result2error (ld, unwind.res, 0);
378 #else
379 signal_simple_error ("Error retrieving result",
380 build_string (ldap_err2string (ld->ld_errno)));
381 #endif 584 #endif
382 }
383
384 if ((rc = ldap_result2error (ld, res, 0)) != LDAP_SUCCESS)
385 {
386 #if HAVE_LDAP_GET_ERRNO
387 signal_simple_error ("Error on result",
388 build_string (ldap_err2string (ldap_get_lderrno (ld, NULL, NULL))));
389 #else
390 signal_simple_error ("Error on result",
391 build_string (ldap_err2string (ld->ld_errno)));
392 #endif 585 #endif
393 } 586
394 587 if (rc != LDAP_SUCCESS)
395 ldap_msgfree (res); 588 signal_ldap_error (ld, NULL, rc);
396 ldap_unbind (ld); 589
397 message ("Done."); 590 ldap_msgfree (unwind.res);
398 591 unwind.res = (LDAPMessage *)NULL;
399 result = Fnreverse (result); 592
400 clear_message (); 593 /* #### See above for calling message(). */
401 594 if (! NILP (verbose))
595 message ("Parsing ldap results... done");
596
597 unbind_to (speccount);
402 UNGCPRO; 598 UNGCPRO;
403 return result; 599 return Fnreverse (result);
600 }
601
602 DEFUN ("ldap-add", Fldap_add, 3, 3, 0, /*
603 Add an entry to an LDAP directory.
604 LDAP is an LDAP connection object created with `ldap-open'.
605 DN is the distinguished name of the entry to add.
606 ENTRY is an entry specification, i.e., a list of cons cells
607 containing attribute/value string pairs.
608 */
609 (ldap, dn, entry))
610 {
611 LDAP *ld;
612 LDAPMod *ldap_mods, **ldap_mods_ptrs;
613 struct berval *bervals;
614 int rc;
615 int i, j;
616 Elemcount len;
617
618 Lisp_Object current = Qnil;
619 Lisp_Object values = Qnil;
620 struct gcpro gcpro1, gcpro2;
621
622 GCPRO2 (current, values);
623
624 /* Do all the parameter checking */
625 CHECK_LIVE_LDAP (ldap);
626 ld = XLDAP (ldap)->ld;
627
628 /* Check the DN */
629 CHECK_STRING (dn);
630
631 /* Check the entry */
632 CHECK_CONS (entry);
633 if (NILP (entry))
634 invalid_operation ("Cannot add void entry", entry);
635
636 /* Build the ldap_mods array */
637 len = (Elemcount) XINT (Flength (entry));
638 ldap_mods = alloca_array (LDAPMod, len);
639 ldap_mods_ptrs = alloca_array (LDAPMod *, 1 + len);
640 i = 0;
641 EXTERNAL_LIST_LOOP (entry, entry)
642 {
643 current = XCAR (entry);
644 CHECK_CONS (current);
645 CHECK_STRING (XCAR (current));
646 ldap_mods_ptrs[i] = &(ldap_mods[i]);
647 LISP_STRING_TO_EXTERNAL (XCAR (current), ldap_mods[i].mod_type, Qnative);
648 ldap_mods[i].mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
649 values = XCDR (current);
650 if (CONSP (values))
651 {
652 len = (Elemcount) XINT (Flength (values));
653 bervals = alloca_array (struct berval, len);
654 ldap_mods[i].mod_vals.modv_bvals =
655 alloca_array (struct berval *, 1 + len);
656 j = 0;
657 EXTERNAL_LIST_LOOP (values, values)
658 {
659 current = XCAR (values);
660 CHECK_STRING (current);
661 ldap_mods[i].mod_vals.modv_bvals[j] = &(bervals[j]);
662 TO_EXTERNAL_FORMAT (LISP_STRING, current,
663 ALLOCA, (bervals[j].bv_val,
664 bervals[j].bv_len),
665 Qnative);
666 j++;
667 }
668 ldap_mods[i].mod_vals.modv_bvals[j] = NULL;
669 }
670 else
671 {
672 CHECK_STRING (values);
673 bervals = alloca_array (struct berval, 1);
674 ldap_mods[i].mod_vals.modv_bvals = alloca_array (struct berval *, 2);
675 ldap_mods[i].mod_vals.modv_bvals[0] = &(bervals[0]);
676 TO_EXTERNAL_FORMAT (LISP_STRING, values,
677 ALLOCA, (bervals[0].bv_val,
678 bervals[0].bv_len),
679 Qnative);
680 ldap_mods[i].mod_vals.modv_bvals[1] = NULL;
681 }
682 i++;
683 }
684 ldap_mods_ptrs[i] = NULL;
685 rc = ldap_add_s (ld, (char *) XSTRING_DATA (dn), ldap_mods_ptrs);
686 if (rc != LDAP_SUCCESS)
687 signal_ldap_error (ld, NULL, rc);
688
689 UNGCPRO;
690 return Qnil;
691 }
692
693 DEFUN ("ldap-modify", Fldap_modify, 3, 3, 0, /*
694 Add an entry to an LDAP directory.
695 LDAP is an LDAP connection object created with `ldap-open'.
696 DN is the distinguished name of the entry to modify.
697 MODS is a list of modifications to apply.
698 A modification is a list of the form (MOD-OP ATTR VALUE1 VALUE2 ...)
699 MOD-OP and ATTR are mandatory, VALUEs are optional depending on MOD-OP.
700 MOD-OP is the type of modification, one of the symbols `add', `delete'
701 or `replace'. ATTR is the LDAP attribute type to modify.
702 */
703 (ldap, dn, mods))
704 {
705 LDAP *ld;
706 LDAPMod *ldap_mods, **ldap_mods_ptrs;
707 struct berval *bervals;
708 int i, j, rc;
709 Lisp_Object mod_op;
710 Elemcount len;
711
712 Lisp_Object current = Qnil;
713 Lisp_Object values = Qnil;
714 struct gcpro gcpro1, gcpro2;
715
716 /* Do all the parameter checking */
717 CHECK_LIVE_LDAP (ldap);
718 ld = XLDAP (ldap)->ld;
719
720 /* Check the DN */
721 CHECK_STRING (dn);
722
723 /* Check the entry */
724 CHECK_CONS (mods);
725 if (NILP (mods))
726 return Qnil;
727
728 /* Build the ldap_mods array */
729 len = (Elemcount) XINT (Flength (mods));
730 ldap_mods = alloca_array (LDAPMod, len);
731 ldap_mods_ptrs = alloca_array (LDAPMod *, 1 + len);
732 i = 0;
733
734 GCPRO2 (current, values);
735 EXTERNAL_LIST_LOOP (mods, mods)
736 {
737 current = XCAR (mods);
738 CHECK_CONS (current);
739 CHECK_SYMBOL (XCAR (current));
740 mod_op = XCAR (current);
741 ldap_mods_ptrs[i] = &(ldap_mods[i]);
742 ldap_mods[i].mod_op = LDAP_MOD_BVALUES;
743 if (EQ (mod_op, Qadd))
744 ldap_mods[i].mod_op |= LDAP_MOD_ADD;
745 else if (EQ (mod_op, Qdelete))
746 ldap_mods[i].mod_op |= LDAP_MOD_DELETE;
747 else if (EQ (mod_op, Qreplace))
748 ldap_mods[i].mod_op |= LDAP_MOD_REPLACE;
749 else
750 invalid_constant ("Invalid LDAP modification type", mod_op);
751 current = XCDR (current);
752 CHECK_STRING (XCAR (current));
753 LISP_STRING_TO_EXTERNAL (XCAR (current), ldap_mods[i].mod_type, Qnative);
754 values = XCDR (current);
755 len = (Elemcount) XINT (Flength (values));
756 bervals = alloca_array (struct berval, len);
757 ldap_mods[i].mod_vals.modv_bvals =
758 alloca_array (struct berval *, 1 + len);
759 j = 0;
760 EXTERNAL_LIST_LOOP (values, values)
761 {
762 current = XCAR (values);
763 CHECK_STRING (current);
764 ldap_mods[i].mod_vals.modv_bvals[j] = &(bervals[j]);
765 TO_EXTERNAL_FORMAT (LISP_STRING, current,
766 ALLOCA, (bervals[j].bv_val,
767 bervals[j].bv_len),
768 Qnative);
769 j++;
770 }
771 ldap_mods[i].mod_vals.modv_bvals[j] = NULL;
772 i++;
773 }
774 ldap_mods_ptrs[i] = NULL;
775 rc = ldap_modify_s (ld, (char *) XSTRING_DATA (dn), ldap_mods_ptrs);
776 if (rc != LDAP_SUCCESS)
777 signal_ldap_error (ld, NULL, rc);
778
779 UNGCPRO;
780 return Qnil;
781 }
782
783
784 DEFUN ("ldap-delete", Fldap_delete, 2, 2, 0, /*
785 Delete an entry to an LDAP directory.
786 LDAP is an LDAP connection object created with `ldap-open'.
787 DN is the distinguished name of the entry to delete.
788 */
789 (ldap, dn))
790 {
791 LDAP *ld;
792 int rc;
793
794 /* Check parameters */
795 CHECK_LIVE_LDAP (ldap);
796 ld = XLDAP (ldap)->ld;
797 CHECK_STRING (dn);
798
799 rc = ldap_delete_s (ld, (char *) XSTRING_DATA (dn));
800 if (rc != LDAP_SUCCESS)
801 signal_ldap_error (ld, NULL, rc);
802
803 return Qnil;
404 } 804 }
405 805
406 void 806 void
407 syms_of_ldap (void) 807 syms_of_eldap (void)
408 { 808 {
409 DEFSUBR(Fldap_search_internal); 809 INIT_LRECORD_IMPLEMENTATION (ldap);
410 810
411 defsymbol (&Qhost, "host"); 811 DEFSYMBOL (Qeldap);
412 defsymbol (&Qfilter, "filter"); 812 DEFSYMBOL (Qldapp);
413 defsymbol (&Qattributes, "attributes"); 813 DEFSYMBOL (Qport);
414 defsymbol (&Qattrsonly, "attrsonly"); 814 DEFSYMBOL (Qauth);
415 defsymbol (&Qbase, "base"); 815 DEFSYMBOL (Qbinddn);
416 defsymbol (&Qscope, "scope"); 816 DEFSYMBOL (Qpasswd);
417 defsymbol (&Qauth, "auth"); 817 DEFSYMBOL (Qderef);
418 defsymbol (&Qbinddn, "binddn"); 818 DEFSYMBOL (Qtimelimit);
419 defsymbol (&Qpasswd, "passwd"); 819 DEFSYMBOL (Qsizelimit);
420 defsymbol (&Qderef, "deref"); 820 DEFSYMBOL (Qbase);
421 defsymbol (&Qtimelimit, "timelimit"); 821 DEFSYMBOL (Qonelevel);
422 defsymbol (&Qsizelimit, "sizelimit"); 822 DEFSYMBOL (Qsubtree);
423 defsymbol (&Qbase, "base"); 823 DEFSYMBOL (Qkrbv41);
424 defsymbol (&Qonelevel, "onelevel"); 824 DEFSYMBOL (Qkrbv42);
425 defsymbol (&Qsubtree, "subtree"); 825 DEFSYMBOL (Qnever);
426 #ifdef LDAP_AUTH_KRBV41 826 DEFSYMBOL (Qalways);
427 defsymbol (&Qkrbv41, "krbv41"); 827 DEFSYMBOL (Qfind);
428 #endif 828 DEFSYMBOL (Qadd);
429 #ifdef LDAP_AUTH_KRBV42 829 DEFSYMBOL (Qreplace);
430 defsymbol (&Qkrbv42, "krbv42"); 830
431 #endif 831 DEFSUBR (Fldapp);
432 defsymbol (&Qnever, "never"); 832 DEFSUBR (Fldap_host);
433 defsymbol (&Qalways, "always"); 833 DEFSUBR (Fldap_live_p);
434 defsymbol (&Qfind, "find"); 834 DEFSUBR (Fldap_open);
835 DEFSUBR (Fldap_close);
836 DEFSUBR (Fldap_search_basic);
837 DEFSUBR (Fldap_add);
838 DEFSUBR (Fldap_modify);
839 DEFSUBR (Fldap_delete);
435 } 840 }
436 841
437 void 842 void
438 vars_of_ldap (void) 843 vars_of_eldap (void)
439 { 844 {
440 Fprovide (intern ("ldap-internal")); 845
441 846 Fprovide (Qeldap);
442 DEFVAR_LISP ("ldap-default-host", &Vldap_default_host /* 847
443 Default LDAP host. 848 ldap_default_port = LDAP_PORT;
849 Vldap_default_base = Qnil;
850
851 DEFVAR_INT ("ldap-default-port", &ldap_default_port /*
852 Default TCP port for LDAP connections.
853 Initialized from the LDAP library. Default value is 389.
444 */ ); 854 */ );
445 855
446 DEFVAR_LISP ("ldap-default-base", &Vldap_default_base /* 856 DEFVAR_LISP ("ldap-default-base", &Vldap_default_base /*
447 Default base for LDAP searches. 857 Default base for LDAP searches.
448 This is a string using the syntax of RFC 1779. 858 This is a string using the syntax of RFC 1779.
449 For instance, "o=ACME, c=US" limits the search to the 859 For instance, "o=ACME, c=US" limits the search to the
450 Acme organization in the United States. 860 Acme organization in the United States.
451 */ ); 861 */ );
452 862
453 Vldap_default_host = Qnil; 863 }
454 Vldap_default_base = Qnil; 864
455 } 865 #ifdef HAVE_SHLIB
456 866 void
457 #endif /* HAVE_LDAP */ 867 unload_eldap (void)
868 {
869 /* Remove defined types */
870 UNDEF_LRECORD_IMPLEMENTATION (ldap);
871
872 /* Remove staticpro'ing of symbols */
873 unstaticpro_nodump (&Qeldap);
874 unstaticpro_nodump (&Qldapp);
875 unstaticpro_nodump (&Qport);
876 unstaticpro_nodump (&Qauth);
877 unstaticpro_nodump (&Qbinddn);
878 unstaticpro_nodump (&Qpasswd);
879 unstaticpro_nodump (&Qderef);
880 unstaticpro_nodump (&Qtimelimit);
881 unstaticpro_nodump (&Qsizelimit);
882 unstaticpro_nodump (&Qbase);
883 unstaticpro_nodump (&Qonelevel);
884 unstaticpro_nodump (&Qsubtree);
885 unstaticpro_nodump (&Qkrbv41);
886 unstaticpro_nodump (&Qkrbv42);
887 unstaticpro_nodump (&Qnever);
888 unstaticpro_nodump (&Qalways);
889 unstaticpro_nodump (&Qfind);
890 unstaticpro_nodump (&Qadd);
891 unstaticpro_nodump (&Qreplace);
892 }
893 #endif /* HAVE_SHLIB */