1/*
2 * Copyright (c) 2010 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1.  Redistributions of source code must retain the above copyright
11 *     notice, this list of conditions and the following disclaimer.
12 * 2.  Redistributions in binary form must reproduce the above copyright
13 *     notice, this list of conditions and the following disclaimer in the
14 *     documentation and/or other materials provided with the distribution.
15 * 3.  Neither the name of Apple Inc. ("Apple") nor the names of its
16 *     contributors may be used to endorse or promote products derived from
17 *     this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * Portions of this software have been released under the following terms:
31 *
32 * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC.
33 * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY
34 * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION
35 *
36 * To anyone who acknowledges that this file is provided "AS IS"
37 * without any express or implied warranty:
38 * permission to use, copy, modify, and distribute this file for any
39 * purpose is hereby granted without fee, provided that the above
40 * copyright notices and this notice appears in all source code copies,
41 * and that none of the names of Open Software Foundation, Inc., Hewlett-
42 * Packard Company or Digital Equipment Corporation be used
43 * in advertising or publicity pertaining to distribution of the software
44 * without specific, written prior permission.  Neither Open Software
45 * Foundation, Inc., Hewlett-Packard Company nor Digital
46 * Equipment Corporation makes any representations about the suitability
47 * of this software for any purpose.
48 *
49 * Copyright (c) 2007, Novell, Inc. All rights reserved.
50 * Redistribution and use in source and binary forms, with or without
51 * modification, are permitted provided that the following conditions
52 * are met:
53 *
54 * 1.  Redistributions of source code must retain the above copyright
55 *     notice, this list of conditions and the following disclaimer.
56 * 2.  Redistributions in binary form must reproduce the above copyright
57 *     notice, this list of conditions and the following disclaimer in the
58 *     documentation and/or other materials provided with the distribution.
59 * 3.  Neither the name of Novell Inc. nor the names of its contributors
60 *     may be used to endorse or promote products derived from this
61 *     this software without specific prior written permission.
62 *
63 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
64 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
65 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
66 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
67 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
68 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
69 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
70 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
71 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
72 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
73 *
74 * @APPLE_LICENSE_HEADER_END@
75 */
76
77/*
78**
79**  NAME:
80**
81**      nsldap.c
82**
83**  FACILITY:
84**
85**      LDAP RPC locator
86**
87**  ABSTRACT:
88**
89**  This module supports locating RPC servers in LDAP directories.
90**  Note: only a portion of the RPC NS API is implemented, and
91**  this support is presently experimental.
92**
93*/
94
95#if HAVE_CONFIG_H
96#include <config.h>
97#endif
98
99/* #define BUILD_RPC_NS_LDAP 1  */
100
101#ifdef BUILD_RPC_NS_LDAP
102
103#include <commonp.h>    /* Common declarations for all RPC runtime */
104#include <com.h>        /* Common communications services */
105#include <comp.h>       /* Private communications services */
106
107#include <lber.h>
108#include <ldap.h>
109
110typedef struct rpc_ns_handle_s_t
111{
112	unsigned32 cursor;
113	unsigned32 count;
114	unsigned_char_p_t *bindings;
115} rpc_ns_handle_rep_t, *rpc_ns_handle_rep_p_t;
116
117/*
118 * Turn a DCE name into an LDAP distinguished name.
119 * This needs to be fixed to support DCE CDS style
120 * names.
121 */
122static void rpc_ns__ldap_crack_name(unsigned32 entry_name_syntax,
123	unsigned_char_p_t entry_name,
124	unsigned_char_p_t *dn,
125	unsigned32 *status)
126{
127	switch (entry_name_syntax) {
128		/* /DC=com/DC=padl/DC=nt/CN=RpcServices/CN=foo */
129		case rpc_c_ns_syntax_x500: {
130			char *tmp;
131
132			tmp = ldap_dcedn2dn(entry_name);
133			if (tmp == NULL) {
134				*status = rpc_s_invalid_name_syntax;
135			} else {
136				*status = rpc_s_ok;
137				*dn = rpc_stralloc(tmp);
138			}
139		}
140		/* CN=foo,CN=RpcServices,DC=nt,DC=padl,DC=com */
141		case rpc_c_ns_syntax_ldap:
142			*dn = rpc_stralloc(entry_name);
143			break;
144		/*
145		 * /.:/foo or
146		 * /.../nt.padl.com/foo
147		 */
148		case rpc_c_ns_syntax_default:
149		case rpc_c_ns_syntax_dce:
150			/* need to do something about cell-relative names */
151		default:
152			*status = rpc_s_unsupported_name_syntax;
153			break;
154	}
155}
156
157/*
158 * Create a new connection to the LDAP server.
159 */
160static void rpc_ns__ldap_connect_to_server(LDAP **ld,
161	unsigned32 *status)
162{
163	if (ldap_initialize(ld, "ldapi://") != LDAP_SUCCESS) {
164		*status = rpc_s_name_service_unavailable;
165	} else {
166		*status = rpc_s_ok;
167	}
168
169	if (*status == rpc_s_ok) {
170		if (ldap_sasl_bind_s(*ld, NULL, "EXTERNAL",
171			NULL, NULL, NULL, NULL) != LDAP_SUCCESS)
172			*status = rpc_s_name_service_unavailable;
173	}
174}
175
176/*
177 * Create an LDAP server container entry.
178 */
179static void rpc_ns__ldap_export_server(LDAP *ld,
180	char *dn,
181	rpc_if_handle_t if_spec,
182	unsigned32 *status
183	)
184{
185	unsigned_char_p_t uuid = NULL;
186	rpc_if_id_t if_id;
187	LDAPMod *modV[4];
188	LDAPMod modRpcNsObjectID, modObjectClass;
189	char *valueRpcNsObjectID[2], *valueObjectClass[3];
190
191	rpc_if_inq_id(if_spec, &if_id, status);
192	if (*status != rpc_s_ok) {
193		return;
194	}
195
196	uuid_to_string(&if_id.uuid, &uuid, status);
197	if (*status != rpc_s_ok) {
198		return;
199	}
200
201	valueRpcNsObjectID[0] = uuid;
202	valueRpcNsObjectID[1] = NULL;
203
204	modRpcNsObjectID.mod_op = LDAP_MOD_ADD;
205	modRpcNsObjectID.mod_type = "rpcNsObjectID";
206	modRpcNsObjectID.mod_values = valueRpcNsObjectID;
207
208	valueObjectClass[0] = "rpcServer";
209	valueObjectClass[1] = "rpcEntry";
210	valueObjectClass[2] = "top";
211
212	modObjectClass.mod_op = LDAP_MOD_ADD;
213	modObjectClass.mod_type = "objectClass";
214	modObjectClass.mod_values = valueObjectClass;
215
216	modV[0] = &modRpcNsObjectID;
217	modV[1] = &modObjectClass;
218	modV[2] = NULL;
219
220	if (ldap_add_s(ld, dn, modV) != LDAP_SUCCESS) {
221		*status = rpc_s_update_failed;
222	} else {
223		*status = rpc_s_ok;
224	}
225
226	rpc_string_free(&uuid, status);
227}
228
229/*
230 * Create or update an LDAP server binding entry.
231 */
232static void rpc_ns__ldap_export_server_element_ext(LDAP *ld,
233	char *dn,
234	rpc_if_handle_t if_spec,
235	rpc_binding_vector_p_t vec,
236	int modop,
237	unsigned32 *status
238	)
239{
240	unsigned_char_p_t uuid = NULL;
241	unsigned_char_p_t interfaceID = NULL;
242	rpc_if_id_t if_id;
243	LDAPMod *modV[4];
244	LDAPMod modRpcNsInterfaceID, modRpcNsBindings, modObjectClass;
245	char **valueRpcNsBindings = NULL;
246	char *valueRpcNsInterfaceID[2], *valueObjectClass[3];
247	int rc;
248	unsigned i;
249
250	rpc_if_inq_id(if_spec, &if_id, status);
251	if (*status != rpc_s_ok) {
252		goto out;
253	}
254
255	/* Get the interface ID */
256	uuid_to_string(&if_id.uuid, &uuid, status);
257	if (*status != rpc_s_ok) {
258		goto out;
259	}
260
261	RPC_MEM_ALLOC(interfaceID, unsigned_char_p_t,
262		strlen(uuid) + sizeof(",65535.65535"),
263		RPC_C_MEM_NSRESOLUTION, RPC_C_MEM_WAITOK);
264
265	sprintf(interfaceID, "%s,%hu.%hu", uuid,
266		if_id.vers_major, if_id.vers_minor);
267
268	valueRpcNsInterfaceID[0] = interfaceID;
269	valueRpcNsInterfaceID[1] = NULL;
270
271	modRpcNsInterfaceID.mod_op = LDAP_MOD_ADD;
272	modRpcNsInterfaceID.mod_type = "rpcNsInterfaceID";
273	modRpcNsInterfaceID.mod_values = valueRpcNsInterfaceID;
274
275	RPC_MEM_ALLOC(valueRpcNsBindings, char **,
276		(vec->count * sizeof(char *)),
277		RPC_C_MEM_NSRESOLUTION, RPC_C_MEM_WAITOK);
278	memset(valueRpcNsBindings, 0, (vec->count * sizeof(unsigned_char_p_t)));
279
280	for (i = 0; i < vec->count; i++) {
281		rpc_binding_to_string_binding(vec->binding_h[i],
282			(unsigned_char_p_t *)&valueRpcNsBindings[i], status);
283		if (*status != rpc_s_ok) {
284			goto out;
285		}
286	}
287	valueRpcNsBindings[vec->count] = NULL;
288
289	modRpcNsBindings.mod_op = modop;
290	modRpcNsBindings.mod_type = "rpcNsBindings";
291	modRpcNsBindings.mod_values = valueRpcNsBindings;
292
293	valueObjectClass[0] = "rpcServerElement";
294	valueObjectClass[1] = "rpcEntry";
295	valueObjectClass[2] = "top";
296
297	modObjectClass.mod_op = modop;
298	modObjectClass.mod_type = "objectClass";
299	modObjectClass.mod_values = valueObjectClass;
300
301	modV[0] = &modRpcNsInterfaceID;
302	modV[1] = &modRpcNsBindings;
303	modV[2] = &modObjectClass;
304	modV[3] = NULL;
305
306	if (modop == LDAP_MOD_ADD) {
307		rc = ldap_add_s(ld, dn, modV);
308	} else {
309		rc = ldap_modify_s(ld, dn, modV);
310	}
311	*status = (rc == LDAP_SUCCESS) ? rpc_s_ok : rpc_s_update_failed;
312
313out:
314	if (uuid != NULL)
315		free(uuid);
316	if (interfaceID != NULL)
317		free(interfaceID);
318	if (valueRpcNsBindings != NULL) {
319		char **p;
320
321		for (p = valueRpcNsBindings; *valueRpcNsBindings != NULL; p++) {
322			unsigned_char_p_t tmp = (unsigned_char_p_t)*p;
323
324			rpc_string_free(&tmp, status);
325		}
326		RPC_MEM_FREE(valueRpcNsBindings, RPC_C_MEM_NSRESOLUTION);
327	}
328}
329
330/*
331 * Create a new named server binding entry.
332 */
333static void rpc_ns__ldap_export_server_element(LDAP *ld,
334	char *serverDN,
335	rpc_if_handle_t if_spec,
336	rpc_binding_vector_p_t vec,
337	unsigned32 *status
338	)
339{
340	unsigned_char_p_t dn = NULL, rdn = NULL;
341	idl_uuid_t rdnUuid;
342
343	/* Just create an arbitary UUID to name this entry. */
344	uuid_create(&rdnUuid, status);
345	if (*status != rpc_s_ok) {
346		goto out;
347	}
348
349	uuid_to_string(&rdnUuid, &rdn, status);
350	if (*status != rpc_s_ok) {
351		goto out;
352	}
353
354	RPC_MEM_ALLOC(dn, unsigned_char_p_t,
355		strlen(serverDN) + strlen(rdn) + sizeof("CN=,"),
356		RPC_C_MEM_NSRESOLUTION, RPC_C_MEM_WAITOK);
357
358	sprintf(dn, "CN=%s,%s", rdn, serverDN);
359
360	rpc_ns__ldap_export_server_element_ext(ld, dn, if_spec,
361		vec, LDAP_MOD_ADD, status);
362
363out:
364	if (dn != NULL) {
365		RPC_MEM_FREE(dn, RPC_C_MEM_NSRESOLUTION);
366	}
367
368	if (rdn != NULL) {
369		rpc_string_free(&rdn, status);
370	}
371}
372
373static void rpc_ns__ldap_lookup_server_element(LDAP *ld,
374	unsigned_char_p_t serverDN,
375	rpc_if_handle_t if_spec,
376	unsigned_char_p_t *dn,
377	unsigned32 *status)
378{
379	unsigned_char_p_t filter = NULL;
380	unsigned_char_p_t uuid = NULL;
381	rpc_if_id_t if_id;
382	LDAPMessage *msg = NULL, *e;
383	char *_dn;
384	size_t len;
385
386	rpc_if_inq_id(if_spec, &if_id, status);
387	if (*status != rpc_s_ok) {
388		goto out;
389	}
390
391	/* Get the interface ID */
392	uuid_to_string(&if_id.uuid, &uuid, status);
393	if (*status != rpc_s_ok) {
394		goto out;
395	}
396
397	len = strlen(uuid);
398	len += sizeof("(&(objectClass=rpcServerElement)(rpcNsInterfaceID=,65535.65535))");
399
400	RPC_MEM_ALLOC(filter, unsigned_char_p_t, len,
401		RPC_C_MEM_NSRESOLUTION, RPC_C_MEM_WAITOK);
402
403	sprintf(filter, "(&(objectClass=rpcServerElement)(rpcNsInterfaceID=%s,%hu.%hu))",
404		uuid, if_id.vers_major, if_id.vers_minor);
405
406	if (ldap_search_s(ld, serverDN, LDAP_SCOPE_ONELEVEL,
407		filter, NULL, 0, &msg) != LDAP_SUCCESS) {
408		*status = rpc_s_not_found;
409		goto out;
410	}
411
412	e = ldap_first_entry(ld, msg);
413	if (e == NULL) {
414		*status = rpc_s_not_found;
415		goto out;
416	}
417
418	_dn = ldap_get_dn(ld, e);
419	if (dn == NULL) {
420		*status = rpc_s_not_found;
421		goto out;
422	}
423
424	*dn = rpc_stralloc(_dn);
425	ldap_memfree(_dn);
426
427out:
428	if (filter != NULL) {
429		RPC_MEM_FREE(filter, RPC_C_MEM_NSRESOLUTION);
430	}
431
432	if (msg != NULL) {
433		ldap_msgfree(msg);
434	}
435
436	if (uuid != NULL) {
437		rpc_string_free(&uuid, status);
438	}
439}
440
441void rpc_ns_binding_export(
442	/* [in] */ unsigned32 entry_name_syntax,
443	/* [in] */ unsigned_char_p_t entry_name,
444	/* [in] */ rpc_if_handle_t if_spec,
445	/* [in] */ rpc_binding_vector_p_t binding_vector,
446	/* [in] */ uuid_vector_p_t object_uuid_vector ATTRIBUTE_UNUSED,
447	/* [out] */ unsigned32 *status
448)
449{
450	LDAP *ld = NULL;
451	unsigned_char_p_t elementDN = NULL;
452	unsigned_char_p_t serverDN = NULL;
453
454	rpc_ns__ldap_connect_to_server(&ld, status);
455	if (*status != rpc_s_ok) {
456		goto out;
457	}
458
459	rpc_ns__ldap_crack_name(entry_name_syntax, entry_name, &serverDN, status);
460	if (*status != rpc_s_ok) {
461		goto out;
462	}
463
464	rpc_ns__ldap_lookup_server_element(ld, serverDN, if_spec, &elementDN, status);
465	if (*status != rpc_s_ok) {
466		rpc_ns__ldap_export_server(ld, serverDN, if_spec, status);
467		if (*status == rpc_s_ok) {
468			rpc_ns__ldap_export_server_element(ld, serverDN,
469				if_spec, binding_vector, status);
470			}
471	} else {
472		rpc_ns__ldap_export_server_element_ext(ld, elementDN, if_spec,
473			binding_vector, LDAP_MOD_REPLACE, status);
474	}
475
476out:
477	if (ld != NULL) {
478		ldap_unbind(ld);
479	}
480	if (elementDN != NULL) {
481		RPC_MEM_FREE(elementDN, RPC_C_MEM_NSRESOLUTION);
482	}
483	if (serverDN != NULL) {
484		RPC_MEM_FREE(serverDN, RPC_C_MEM_NSRESOLUTION);
485	}
486}
487
488static void rpc_ns__ldap_import_server_element(LDAP *ld,
489	unsigned_char_p_t serverDN,
490	rpc_if_handle_t if_spec,
491	rpc_ns_handle_t *ctx,
492	unsigned32 *status
493	)
494{
495	unsigned_char_p_t filter = NULL;
496	unsigned_char_p_t uuid = NULL;
497	rpc_if_id_t if_id;
498	LDAPMessage *msg = NULL, *e;
499	rpc_ns_handle_rep_t *rep;
500	unsigned_char_p_t *bindings;
501	size_t len;
502
503	rpc_if_inq_id(if_spec, &if_id, status);
504	if (*status != rpc_s_ok) {
505		goto out;
506	}
507
508	/* Get the interface ID */
509	uuid_to_string(&if_id.uuid, &uuid, status);
510	if (*status != rpc_s_ok) {
511		goto out;
512	}
513
514	len = strlen(uuid);
515	len += sizeof("(&(objectClass=rpcServerElement)(rpcNsInterfaceID=,65535.65535))");
516	RPC_MEM_ALLOC(filter, unsigned_char_p_t, len,
517		RPC_C_MEM_NSRESOLUTION, RPC_C_MEM_WAITOK);
518
519	sprintf(filter, "(&(objectClass=rpcServerElement)(rpcNsInterfaceID=%s,%hu.%hu))",
520		uuid, if_id.vers_major, if_id.vers_minor);
521
522	if (ldap_search_s(ld, serverDN, LDAP_SCOPE_ONELEVEL,
523		filter, NULL, 0, &msg) != LDAP_SUCCESS) {
524		*status = rpc_s_not_found;
525		goto out;
526	}
527
528	e = ldap_first_entry(ld, msg);
529	if (e == NULL) {
530		*status = rpc_s_not_found;
531		goto out;
532	}
533
534	bindings = (unsigned_char_p_t *)ldap_get_values(ld, e, "rpcNsBindings");
535	if (bindings == NULL) {
536		*status = rpc_s_not_found;
537		goto out;
538	}
539
540	RPC_MEM_ALLOC(rep, rpc_ns_handle_rep_p_t,
541		sizeof(*rep),
542		RPC_C_MEM_NSRESOLUTION, RPC_C_MEM_WAITOK);
543
544	rep->count = ldap_count_values((char **)bindings);
545	rep->bindings = bindings;
546	rep->cursor = 0;
547
548	*ctx = (rpc_ns_handle_t)rep;
549	*status = rpc_s_ok;
550
551out:
552	if (filter != NULL) {
553		RPC_MEM_FREE(filter, RPC_C_MEM_NSRESOLUTION);
554	}
555
556	if (msg != NULL) {
557		ldap_msgfree(msg);
558	}
559}
560
561void
562rpc_ns_binding_import_begin(
563    /* [in] */ unsigned32 entry_name_syntax,
564    /* [in] */ unsigned_char_p_t entry_name,
565    /* [in] */ rpc_if_handle_t if_spec,
566    /* [in] */ uuid_p_t object_uuid ATTRIBUTE_UNUSED,
567    /* [out] */ rpc_ns_handle_t *import_context,
568    /* [out] */ unsigned32 *status
569)
570{
571	unsigned_char_p_t serverDN = NULL;
572	LDAP *ld;
573
574	rpc_ns__ldap_connect_to_server(&ld, status);
575	if (*status != rpc_s_ok) {
576		goto out;
577	}
578
579	rpc_ns__ldap_crack_name(entry_name_syntax, entry_name, &serverDN, status);
580	if (*status != rpc_s_ok) {
581		goto out;
582	}
583
584	rpc_ns__ldap_import_server_element(ld, serverDN, if_spec, import_context, status);
585
586out:
587	if (serverDN != NULL) {
588		RPC_MEM_FREE(serverDN, RPC_C_MEM_NSRESOLUTION);
589	}
590	if (ld != NULL) {
591		ldap_unbind(ld);
592	}
593}
594
595void
596rpc_ns_binding_import_done(
597    /* [in, out] */ rpc_ns_handle_t *import_context,
598    /* [out] */ unsigned32 *status
599)
600{
601	rpc_ns_handle_rep_t *rep = (rpc_ns_handle_rep_t *)import_context;
602
603	if (rep != NULL) {
604		unsigned_char_p_t *p;
605
606		for (p = rep->bindings; *p != NULL; p++) {
607			RPC_MEM_FREE(*p, RPC_C_MEM_NSRESOLUTION);
608		}
609		RPC_MEM_FREE(rep, RPC_C_MEM_NSRESOLUTION);
610	}
611	*status = rpc_s_ok;
612}
613
614void
615rpc_ns_mgmt_handle_set_exp_age(
616    /* [in] */ rpc_ns_handle_t ns_handle ATTRIBUTE_UNUSED,
617    /* [in] */ unsigned32 expiration_age ATTRIBUTE_UNUSED,
618    /* [out] */ unsigned32 *status
619
620)
621{
622	*status = rpc_s_ok;
623}
624
625void
626rpc_ns_binding_import_next(
627    /* [in] */ rpc_ns_handle_t import_context,
628    /* [out] */ rpc_binding_handle_t *binding,
629    /* [out] */ unsigned32 *status
630	       )
631{
632	rpc_ns_handle_rep_t *rep = (rpc_ns_handle_rep_t *)import_context;
633
634	if (rep->cursor < rep->count) {
635		rpc_binding_from_string_binding(rep->bindings[rep->cursor],
636			binding, status);
637		rep->cursor++;
638	} else {
639		*status = rpc_s_no_more_bindings;
640	}
641}
642
643void rpc_ns_binding_lookup_begin
644(
645	unsigned32              entry_name_syntax,
646	unsigned_char_p_t       entry_name,
647	rpc_if_handle_t         if_spec,
648	uuid_p_t                object_uuid,
649	unsigned32              binding_max_count ATTRIBUTE_UNUSED,
650	rpc_ns_handle_t         *lookup_context,
651	unsigned32              *status
652)
653{
654	rpc_ns_binding_import_begin(entry_name_syntax,
655		entry_name,
656		if_spec,
657		object_uuid,
658		lookup_context,
659		status);
660}
661
662void rpc_ns_binding_lookup_done
663(
664	rpc_ns_handle_t         *lookup_context,
665	unsigned32              *status
666)
667{
668	rpc_ns_binding_import_done(lookup_context, status);
669}
670
671void rpc_ns_binding_lookup_next
672(
673	rpc_ns_handle_t         lookup_context,
674	rpc_binding_vector_p_t  *binding_vector,
675	unsigned32              *status
676)
677{
678	rpc_ns_handle_rep_t *rep = (rpc_ns_handle_rep_t *) lookup_context;
679
680	if (rep->cursor == 0) {
681		unsigned32 size, i;
682
683		size = sizeof(rpc_binding_vector_t);
684		size += (rep->count - 1) * sizeof(rpc_binding_handle_t);
685		RPC_MEM_ALLOC(*binding_vector, rpc_binding_vector_p_t,
686			size, RPC_C_MEM_BINDING_VEC, RPC_C_MEM_WAITOK);
687
688		for (i = 0; i < rep->count; i++) {
689			rpc_binding_from_string_binding(rep->bindings[i],
690				&((*binding_vector)->binding_h[i]), status);
691		}
692	} else {
693		*status = rpc_s_no_more_bindings;
694	}
695}
696
697void rpc_ns_binding_unexport
698(
699	unsigned32              entry_name_syntax,
700	unsigned_char_p_t       entry_name,
701	rpc_if_handle_t         if_spec,
702	uuid_vector_p_t         object_uuid_vector ATTRIBUTE_UNUSED,
703	unsigned32              *status
704)
705{
706	LDAP *ld = NULL;
707	unsigned_char_p_t elementDN = NULL;
708	unsigned_char_p_t serverDN = NULL;
709
710	rpc_ns__ldap_connect_to_server(&ld, status);
711	if (*status != rpc_s_ok) {
712		goto out;
713	}
714
715	rpc_ns__ldap_crack_name(entry_name_syntax, entry_name, &serverDN, status);
716	if (*status != rpc_s_ok) {
717		goto out;
718	}
719
720	rpc_ns__ldap_lookup_server_element(ld, serverDN, if_spec, &elementDN, status);
721	if (*status == rpc_s_ok) {
722		if (ldap_delete_s(ld, elementDN) != LDAP_SUCCESS) {
723			*status = rpc_s_update_failed;
724			goto out;
725		}
726	}
727	if (ldap_delete_s(ld, serverDN) != LDAP_SUCCESS) {
728		*status = rpc_s_update_failed;
729		goto out;
730	}
731
732	*status = rpc_s_ok;
733
734out:
735	if (ld != NULL) {
736		ldap_unbind(ld);
737	}
738	if (elementDN != NULL) {
739		RPC_MEM_FREE(elementDN, RPC_C_MEM_NSRESOLUTION);
740	}
741	if (serverDN != NULL) {
742		RPC_MEM_FREE(serverDN, RPC_C_MEM_NSRESOLUTION);
743	}
744}
745
746#endif /* BUILD_RPC_NS_LDAP */
747