1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <stdio.h>
30*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
31*7c478bd9Sstevel@tonic-gate #include <syslog.h>
32*7c478bd9Sstevel@tonic-gate #include <slp-internal.h>
33*7c478bd9Sstevel@tonic-gate 
34*7c478bd9Sstevel@tonic-gate struct surl_node {
35*7c478bd9Sstevel@tonic-gate 	char *surl;
36*7c478bd9Sstevel@tonic-gate 	unsigned short lifetime;
37*7c478bd9Sstevel@tonic-gate };
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate struct caller_bundle {
40*7c478bd9Sstevel@tonic-gate 	SLPSrvURLCallback *cb;
41*7c478bd9Sstevel@tonic-gate 	void *cookie;
42*7c478bd9Sstevel@tonic-gate 	SLPHandle handle;
43*7c478bd9Sstevel@tonic-gate };
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate static int compare_surls(struct surl_node *, struct surl_node *);
46*7c478bd9Sstevel@tonic-gate static char *collate_surls(char *, unsigned short, void **);
47*7c478bd9Sstevel@tonic-gate static void traverse_surls(SLPHandle, SLPSrvURLCallback, void *, void *);
48*7c478bd9Sstevel@tonic-gate static void process_surl_node(void *, VISIT, int, void *);
49*7c478bd9Sstevel@tonic-gate static SLPBoolean unpackDAAdvert_srv(slp_handle_impl_t *, char *,
50*7c478bd9Sstevel@tonic-gate 					SLPSrvURLCallback, void *,
51*7c478bd9Sstevel@tonic-gate 					void **, int *);
52*7c478bd9Sstevel@tonic-gate static SLPBoolean unpackSAAdvert_srv(slp_handle_impl_t *, char *,
53*7c478bd9Sstevel@tonic-gate 					SLPSrvURLCallback, void *,
54*7c478bd9Sstevel@tonic-gate 					void **, int *);
55*7c478bd9Sstevel@tonic-gate 
56*7c478bd9Sstevel@tonic-gate SLPError SLPFindSrvs(SLPHandle hSLP, const char *pcServiceType,
57*7c478bd9Sstevel@tonic-gate 			const char *pcScope, const char *pcSearchFilter,
58*7c478bd9Sstevel@tonic-gate 			SLPSrvURLCallback callback, void *pvUser) {
59*7c478bd9Sstevel@tonic-gate 	SLPError err;
60*7c478bd9Sstevel@tonic-gate 	slp_handle_impl_t *hp = (slp_handle_impl_t *)hSLP;
61*7c478bd9Sstevel@tonic-gate 	int wantSAAdvert =
62*7c478bd9Sstevel@tonic-gate 		strcasecmp(pcServiceType, "service:service-agent") == 0;
63*7c478bd9Sstevel@tonic-gate 	int wantDAAdvert =
64*7c478bd9Sstevel@tonic-gate 		strcasecmp(pcServiceType, "service:directory-agent") == 0;
65*7c478bd9Sstevel@tonic-gate 	int isSpecial = wantSAAdvert || wantDAAdvert;
66*7c478bd9Sstevel@tonic-gate 	SLPMsgReplyCB *unpack_cb;
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate 	if (!hSLP || !pcServiceType || !pcScope || (!*pcScope && !isSpecial) ||
69*7c478bd9Sstevel@tonic-gate 	    !pcSearchFilter || !callback) {
70*7c478bd9Sstevel@tonic-gate 		return (SLP_PARAMETER_BAD);
71*7c478bd9Sstevel@tonic-gate 	}
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate 	if ((strlen(pcServiceType) > SLP_MAX_STRINGLEN) ||
74*7c478bd9Sstevel@tonic-gate 	    (strlen(pcScope) > SLP_MAX_STRINGLEN) ||
75*7c478bd9Sstevel@tonic-gate 	    (strlen(pcSearchFilter) > SLP_MAX_STRINGLEN)) {
76*7c478bd9Sstevel@tonic-gate 	    return (SLP_PARAMETER_BAD);
77*7c478bd9Sstevel@tonic-gate 	}
78*7c478bd9Sstevel@tonic-gate 
79*7c478bd9Sstevel@tonic-gate 	if ((err = slp_start_call(hSLP)) != SLP_OK)
80*7c478bd9Sstevel@tonic-gate 		return (err);
81*7c478bd9Sstevel@tonic-gate 
82*7c478bd9Sstevel@tonic-gate 	/* Special unpacker for DA and SA solicitations */
83*7c478bd9Sstevel@tonic-gate 	if (wantDAAdvert) {
84*7c478bd9Sstevel@tonic-gate 		unpack_cb = (SLPMsgReplyCB *)unpackDAAdvert_srv;
85*7c478bd9Sstevel@tonic-gate 		hp->force_multicast = SLP_TRUE;
86*7c478bd9Sstevel@tonic-gate 	} else if (wantSAAdvert) {
87*7c478bd9Sstevel@tonic-gate 		unpack_cb = (SLPMsgReplyCB *)unpackSAAdvert_srv;
88*7c478bd9Sstevel@tonic-gate 		hp->force_multicast = SLP_TRUE;
89*7c478bd9Sstevel@tonic-gate 	} else {
90*7c478bd9Sstevel@tonic-gate 		/* normal service request */
91*7c478bd9Sstevel@tonic-gate 		unpack_cb = (SLPMsgReplyCB *)slp_unpackSrvReply;
92*7c478bd9Sstevel@tonic-gate 	}
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate 	err = slp_packSrvRqst(pcServiceType, pcSearchFilter, hp);
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate 	if (err == SLP_OK)
97*7c478bd9Sstevel@tonic-gate 		err = slp_ua_common(hSLP, pcScope,
98*7c478bd9Sstevel@tonic-gate 				    (SLPGenericAppCB *) callback, pvUser,
99*7c478bd9Sstevel@tonic-gate 				    unpack_cb);
100*7c478bd9Sstevel@tonic-gate 	if (err != SLP_OK)
101*7c478bd9Sstevel@tonic-gate 		slp_end_call(hSLP);
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate 	return (err);
104*7c478bd9Sstevel@tonic-gate }
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate SLPBoolean slp_unpackSrvReply(slp_handle_impl_t *hp, char *reply,
107*7c478bd9Sstevel@tonic-gate 				SLPSrvURLCallback cb, void *cookie,
108*7c478bd9Sstevel@tonic-gate 				void **collator, int *numResults) {
109*7c478bd9Sstevel@tonic-gate 	SLPError errCode;
110*7c478bd9Sstevel@tonic-gate 	unsigned short urlCount, protoErrCode;
111*7c478bd9Sstevel@tonic-gate 	size_t len, off;
112*7c478bd9Sstevel@tonic-gate 	int i;
113*7c478bd9Sstevel@tonic-gate 	int maxResults = slp_get_maxResults();
114*7c478bd9Sstevel@tonic-gate 	SLPBoolean cont = SLP_TRUE;
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate 	if (!reply) {
117*7c478bd9Sstevel@tonic-gate 		/* no more results */
118*7c478bd9Sstevel@tonic-gate 		/* traverse_surls:invoke cb for sync case,and free resources */
119*7c478bd9Sstevel@tonic-gate 		if (!hp->async) {
120*7c478bd9Sstevel@tonic-gate 		    traverse_surls(hp, cb, cookie, *collator);
121*7c478bd9Sstevel@tonic-gate 		}
122*7c478bd9Sstevel@tonic-gate 		cb(hp, NULL, 0, SLP_LAST_CALL, cookie);
123*7c478bd9Sstevel@tonic-gate 		return (SLP_FALSE);
124*7c478bd9Sstevel@tonic-gate 	}
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate 	len = slp_get_length(reply);
127*7c478bd9Sstevel@tonic-gate 	off = SLP_HDRLEN + slp_get_langlen(reply);
128*7c478bd9Sstevel@tonic-gate 	/* err code */
129*7c478bd9Sstevel@tonic-gate 	if (slp_get_sht(reply, len, &off, &protoErrCode) != SLP_OK)
130*7c478bd9Sstevel@tonic-gate 		return (SLP_TRUE);
131*7c478bd9Sstevel@tonic-gate 	/* internal errors should have been filtered out by the net code */
132*7c478bd9Sstevel@tonic-gate 	if ((errCode = slp_map_err(protoErrCode)) != SLP_OK) {
133*7c478bd9Sstevel@tonic-gate 		return (cb(hp, NULL, 0, errCode, cookie));
134*7c478bd9Sstevel@tonic-gate 	}
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate 	/* url entry count */
137*7c478bd9Sstevel@tonic-gate 	if (slp_get_sht(reply, len, &off, &urlCount) != SLP_OK)
138*7c478bd9Sstevel@tonic-gate 		return (SLP_TRUE);
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate 	/* for each srvRply, unpack and pass to CB */
141*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < urlCount && !hp->cancel; i++) {
142*7c478bd9Sstevel@tonic-gate 		char *pcSrvURL;
143*7c478bd9Sstevel@tonic-gate 		unsigned short sLifetime;
144*7c478bd9Sstevel@tonic-gate 		int nURLAuthBlocks;
145*7c478bd9Sstevel@tonic-gate 		size_t tbv_len;
146*7c478bd9Sstevel@tonic-gate 		char *url_tbv;
147*7c478bd9Sstevel@tonic-gate 
148*7c478bd9Sstevel@tonic-gate 		/* parse URL entry into params */
149*7c478bd9Sstevel@tonic-gate 		off++;	/* skip reserved byte */
150*7c478bd9Sstevel@tonic-gate 		/* lifetime */
151*7c478bd9Sstevel@tonic-gate 		if (slp_get_sht(reply, len, &off, &sLifetime) != SLP_OK)
152*7c478bd9Sstevel@tonic-gate 			return (SLP_TRUE);
153*7c478bd9Sstevel@tonic-gate 		/* URL itself; keep track of it in case we need to verify */
154*7c478bd9Sstevel@tonic-gate 		url_tbv = reply + off;
155*7c478bd9Sstevel@tonic-gate 		tbv_len = off;
156*7c478bd9Sstevel@tonic-gate 		if (slp_get_string(reply, len, &off, &pcSrvURL) != SLP_OK)
157*7c478bd9Sstevel@tonic-gate 			return (SLP_TRUE);
158*7c478bd9Sstevel@tonic-gate 		tbv_len = off - tbv_len;
159*7c478bd9Sstevel@tonic-gate 
160*7c478bd9Sstevel@tonic-gate 		/* number of url auths */
161*7c478bd9Sstevel@tonic-gate 		if (slp_get_byte(reply, len, &off, &nURLAuthBlocks) != SLP_OK)
162*7c478bd9Sstevel@tonic-gate 			goto cleanup;
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate 		/* get and verify auth blocks */
165*7c478bd9Sstevel@tonic-gate 		if ((!hp->internal_call && slp_get_security_on()) ||
166*7c478bd9Sstevel@tonic-gate 		    nURLAuthBlocks > 0) {
167*7c478bd9Sstevel@tonic-gate 			struct iovec iov[1];
168*7c478bd9Sstevel@tonic-gate 			size_t abLen = 0;
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate 			iov[0].iov_base = url_tbv;
171*7c478bd9Sstevel@tonic-gate 			iov[0].iov_len = tbv_len;
172*7c478bd9Sstevel@tonic-gate 
173*7c478bd9Sstevel@tonic-gate 			if (slp_verify(iov, 1,
174*7c478bd9Sstevel@tonic-gate 					reply + off,
175*7c478bd9Sstevel@tonic-gate 					len - off,
176*7c478bd9Sstevel@tonic-gate 					nURLAuthBlocks,
177*7c478bd9Sstevel@tonic-gate 					&abLen) != SLP_OK) {
178*7c478bd9Sstevel@tonic-gate 			    goto cleanup;
179*7c478bd9Sstevel@tonic-gate 			}
180*7c478bd9Sstevel@tonic-gate 			off += abLen;
181*7c478bd9Sstevel@tonic-gate 		}
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate 		/* collate the srv urls for sync behavior */
184*7c478bd9Sstevel@tonic-gate 		if (!hp->async) {
185*7c478bd9Sstevel@tonic-gate 		    pcSrvURL = collate_surls(pcSrvURL, sLifetime, collator);
186*7c478bd9Sstevel@tonic-gate 
187*7c478bd9Sstevel@tonic-gate 		    if (!pcSrvURL)
188*7c478bd9Sstevel@tonic-gate 			continue;
189*7c478bd9Sstevel@tonic-gate 		}
190*7c478bd9Sstevel@tonic-gate 
191*7c478bd9Sstevel@tonic-gate 		(*numResults)++;
192*7c478bd9Sstevel@tonic-gate 		/* invoke cb */
193*7c478bd9Sstevel@tonic-gate 		if (hp->async)
194*7c478bd9Sstevel@tonic-gate 			cont = cb(
195*7c478bd9Sstevel@tonic-gate 				(SLPHandle) hp,
196*7c478bd9Sstevel@tonic-gate 				pcSrvURL,
197*7c478bd9Sstevel@tonic-gate 				sLifetime,
198*7c478bd9Sstevel@tonic-gate 				errCode,
199*7c478bd9Sstevel@tonic-gate 				cookie);
200*7c478bd9Sstevel@tonic-gate 
201*7c478bd9Sstevel@tonic-gate 		/* cleanup */
202*7c478bd9Sstevel@tonic-gate cleanup:
203*7c478bd9Sstevel@tonic-gate 		free(pcSrvURL);
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate 		/* check maxResults */
206*7c478bd9Sstevel@tonic-gate 		if (!hp->internal_call && *numResults == maxResults) {
207*7c478bd9Sstevel@tonic-gate 			cont = SLP_FALSE;
208*7c478bd9Sstevel@tonic-gate 		}
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate 		if (!cont) break;
211*7c478bd9Sstevel@tonic-gate 	}
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate 	return (cont);
214*7c478bd9Sstevel@tonic-gate }
215*7c478bd9Sstevel@tonic-gate 
216*7c478bd9Sstevel@tonic-gate /*
217*7c478bd9Sstevel@tonic-gate  * unpackDAAdvert_srv follows the same same logic flow as slp_unpackSrvReply
218*7c478bd9Sstevel@tonic-gate  * with two differences: the message in reply is a DAAdvert, and
219*7c478bd9Sstevel@tonic-gate  * this function is not used internally, so hp is never NULL. Although
220*7c478bd9Sstevel@tonic-gate  * all info from a DAAdvert is returned by slp_unpackDAAdvert, here
221*7c478bd9Sstevel@tonic-gate  * the recipient (the user-supplied SLPSrvURLCallback) is interested
222*7c478bd9Sstevel@tonic-gate  * only in the DA service URL.
223*7c478bd9Sstevel@tonic-gate  */
224*7c478bd9Sstevel@tonic-gate static SLPBoolean unpackDAAdvert_srv(slp_handle_impl_t *hp, char *reply,
225*7c478bd9Sstevel@tonic-gate 					SLPSrvURLCallback cb, void *cookie,
226*7c478bd9Sstevel@tonic-gate 					void **collator, int *numResults) {
227*7c478bd9Sstevel@tonic-gate 	char *surl, *scopes, *attrs, *spis;
228*7c478bd9Sstevel@tonic-gate 	SLPBoolean cont = SLP_TRUE;
229*7c478bd9Sstevel@tonic-gate 	SLPError errCode;
230*7c478bd9Sstevel@tonic-gate 	int maxResults = slp_get_maxResults();
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate 	if (!reply) {
233*7c478bd9Sstevel@tonic-gate 		/* no more results */
234*7c478bd9Sstevel@tonic-gate 		/* traverse_surls:invoke cb for sync case,and free resources */
235*7c478bd9Sstevel@tonic-gate 		if (!hp->async) {
236*7c478bd9Sstevel@tonic-gate 			traverse_surls(hp, cb, cookie, *collator);
237*7c478bd9Sstevel@tonic-gate 		}
238*7c478bd9Sstevel@tonic-gate 		cb(hp, NULL, 0, SLP_LAST_CALL, cookie);
239*7c478bd9Sstevel@tonic-gate 		return (SLP_FALSE);
240*7c478bd9Sstevel@tonic-gate 	}
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate 	if (slp_unpackDAAdvert(reply, &surl, &scopes, &attrs, &spis, &errCode)
243*7c478bd9Sstevel@tonic-gate 	    != SLP_OK) {
244*7c478bd9Sstevel@tonic-gate 		return (SLP_TRUE);
245*7c478bd9Sstevel@tonic-gate 	}
246*7c478bd9Sstevel@tonic-gate 	if (errCode != SLP_OK) {
247*7c478bd9Sstevel@tonic-gate 		return (cb(hp, NULL, 0, errCode, cookie));
248*7c478bd9Sstevel@tonic-gate 	}
249*7c478bd9Sstevel@tonic-gate 
250*7c478bd9Sstevel@tonic-gate 	/* collate the urls */
251*7c478bd9Sstevel@tonic-gate 	surl = collate_surls(surl, 0, collator);
252*7c478bd9Sstevel@tonic-gate 	if (!surl) {
253*7c478bd9Sstevel@tonic-gate 		return (SLP_TRUE);
254*7c478bd9Sstevel@tonic-gate 	}
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate 	(*numResults)++;
257*7c478bd9Sstevel@tonic-gate 	if (hp->async) {
258*7c478bd9Sstevel@tonic-gate 		cont = cb((SLPHandle)hp, surl, 0, errCode, cookie);
259*7c478bd9Sstevel@tonic-gate 	}
260*7c478bd9Sstevel@tonic-gate 
261*7c478bd9Sstevel@tonic-gate 	/* cleanup */
262*7c478bd9Sstevel@tonic-gate 	free(surl);
263*7c478bd9Sstevel@tonic-gate 	free(scopes);
264*7c478bd9Sstevel@tonic-gate 	free(attrs);
265*7c478bd9Sstevel@tonic-gate 	free(spis);
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate 	/* check maxResults */
268*7c478bd9Sstevel@tonic-gate 	if (!hp->internal_call && *numResults == maxResults) {
269*7c478bd9Sstevel@tonic-gate 		return (SLP_FALSE);
270*7c478bd9Sstevel@tonic-gate 	}
271*7c478bd9Sstevel@tonic-gate 
272*7c478bd9Sstevel@tonic-gate 	return (cont);
273*7c478bd9Sstevel@tonic-gate }
274*7c478bd9Sstevel@tonic-gate /*
275*7c478bd9Sstevel@tonic-gate  * unpackSAAdvert_srv follows the same same logic flow as slp_unpackSrvReply
276*7c478bd9Sstevel@tonic-gate  * with two differences: the message in reply is a SAAdvert, and
277*7c478bd9Sstevel@tonic-gate  * this function is not used internally, so hp is never NULL. Although
278*7c478bd9Sstevel@tonic-gate  * all info from an SAAdvert is returned by slp_unpackSAAdvert, here
279*7c478bd9Sstevel@tonic-gate  * the recipient (the user-supplied SLPSrvURLCallback) is interested
280*7c478bd9Sstevel@tonic-gate  * only in the SA service URL.
281*7c478bd9Sstevel@tonic-gate  */
282*7c478bd9Sstevel@tonic-gate static SLPBoolean unpackSAAdvert_srv(slp_handle_impl_t *hp, char *reply,
283*7c478bd9Sstevel@tonic-gate 					SLPSrvURLCallback cb, void *cookie,
284*7c478bd9Sstevel@tonic-gate 					void **collator, int *numResults) {
285*7c478bd9Sstevel@tonic-gate 	char *surl, *scopes, *attrs;
286*7c478bd9Sstevel@tonic-gate 	SLPBoolean cont = SLP_TRUE;
287*7c478bd9Sstevel@tonic-gate 	int maxResults = slp_get_maxResults();
288*7c478bd9Sstevel@tonic-gate 
289*7c478bd9Sstevel@tonic-gate 	if (!reply) {
290*7c478bd9Sstevel@tonic-gate 		/* no more results */
291*7c478bd9Sstevel@tonic-gate 		/* traverse_surls:invoke cb for sync case,and free resources */
292*7c478bd9Sstevel@tonic-gate 		if (!hp->async) {
293*7c478bd9Sstevel@tonic-gate 			/* sync case */
294*7c478bd9Sstevel@tonic-gate 			traverse_surls(hp, cb, cookie, *collator);
295*7c478bd9Sstevel@tonic-gate 		}
296*7c478bd9Sstevel@tonic-gate 		cb(hp, NULL, 0, SLP_LAST_CALL, cookie);
297*7c478bd9Sstevel@tonic-gate 		return (SLP_FALSE);
298*7c478bd9Sstevel@tonic-gate 	}
299*7c478bd9Sstevel@tonic-gate 
300*7c478bd9Sstevel@tonic-gate 	if (slp_unpackSAAdvert(reply, &surl, &scopes, &attrs) != SLP_OK) {
301*7c478bd9Sstevel@tonic-gate 		return (SLP_TRUE);
302*7c478bd9Sstevel@tonic-gate 	}
303*7c478bd9Sstevel@tonic-gate 
304*7c478bd9Sstevel@tonic-gate 	/* collate the urls */
305*7c478bd9Sstevel@tonic-gate 	surl = collate_surls(surl, 0, collator);
306*7c478bd9Sstevel@tonic-gate 	if (!surl) {
307*7c478bd9Sstevel@tonic-gate 		return (SLP_TRUE);
308*7c478bd9Sstevel@tonic-gate 	}
309*7c478bd9Sstevel@tonic-gate 
310*7c478bd9Sstevel@tonic-gate 	(*numResults)++;
311*7c478bd9Sstevel@tonic-gate 	if (hp->async) {
312*7c478bd9Sstevel@tonic-gate 		cont = cb((SLPHandle)hp, surl, 0, SLP_OK, cookie);
313*7c478bd9Sstevel@tonic-gate 	}
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate 	/* cleanup */
316*7c478bd9Sstevel@tonic-gate 	free(surl);
317*7c478bd9Sstevel@tonic-gate 	free(scopes);
318*7c478bd9Sstevel@tonic-gate 	free(attrs);
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate 	/* check maxResults */
321*7c478bd9Sstevel@tonic-gate 	if (!hp->internal_call && *numResults == maxResults) {
322*7c478bd9Sstevel@tonic-gate 		return (SLP_FALSE);
323*7c478bd9Sstevel@tonic-gate 	}
324*7c478bd9Sstevel@tonic-gate 
325*7c478bd9Sstevel@tonic-gate 	return (cont);
326*7c478bd9Sstevel@tonic-gate }
327*7c478bd9Sstevel@tonic-gate 
328*7c478bd9Sstevel@tonic-gate SLPError slp_packSrvRqst(const char *type,
329*7c478bd9Sstevel@tonic-gate 				const char *filter,
330*7c478bd9Sstevel@tonic-gate 				slp_handle_impl_t *hp) {
331*7c478bd9Sstevel@tonic-gate 	SLPError err;
332*7c478bd9Sstevel@tonic-gate 	size_t len, msgLen, tmplen;
333*7c478bd9Sstevel@tonic-gate 	slp_msg_t *msg = &(hp->msg);
334*7c478bd9Sstevel@tonic-gate 	char *spi = NULL;
335*7c478bd9Sstevel@tonic-gate 
336*7c478bd9Sstevel@tonic-gate 	if (slp_get_security_on()) {
337*7c478bd9Sstevel@tonic-gate 	    spi = (char *)SLPGetProperty(SLP_CONFIG_SPI);
338*7c478bd9Sstevel@tonic-gate 	}
339*7c478bd9Sstevel@tonic-gate 
340*7c478bd9Sstevel@tonic-gate 	if (!spi || !*spi) {
341*7c478bd9Sstevel@tonic-gate 		spi = "";
342*7c478bd9Sstevel@tonic-gate 	}
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate 	/*
345*7c478bd9Sstevel@tonic-gate 	 * Allocate iovec for the messge. A SrvRqst is layed out thus:
346*7c478bd9Sstevel@tonic-gate 	 *  0: header
347*7c478bd9Sstevel@tonic-gate 	 *  1: prlist length
348*7c478bd9Sstevel@tonic-gate 	 *  2: prlist (filled in later by networking code)
349*7c478bd9Sstevel@tonic-gate 	 *  3: service type string
350*7c478bd9Sstevel@tonic-gate 	 *  4: scopes length
351*7c478bd9Sstevel@tonic-gate 	 *  5: scopes (filled in later by networking code)
352*7c478bd9Sstevel@tonic-gate 	 *  6: predicate string and SPI string
353*7c478bd9Sstevel@tonic-gate 	 */
354*7c478bd9Sstevel@tonic-gate 	if (!(msg->iov = calloc(7, sizeof (*(msg->iov))))) {
355*7c478bd9Sstevel@tonic-gate 		slp_err(LOG_CRIT, 0, "slp_packSrvRqst", "out of memory");
356*7c478bd9Sstevel@tonic-gate 		return (SLP_MEMORY_ALLOC_FAILED);
357*7c478bd9Sstevel@tonic-gate 	}
358*7c478bd9Sstevel@tonic-gate 	msg->iovlen = 7;
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate 	/* calculate msg length */
361*7c478bd9Sstevel@tonic-gate 	msgLen = 2 +		/* prlist length */
362*7c478bd9Sstevel@tonic-gate 	    2 + strlen(type) +	/* service type */
363*7c478bd9Sstevel@tonic-gate 	    2 +			/* scope list length */
364*7c478bd9Sstevel@tonic-gate 	    2 + strlen(filter) + /* predicate string */
365*7c478bd9Sstevel@tonic-gate 	    2 + strlen(spi);	/* SPI string */
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate 	if (!(msg->msg = calloc(1, msgLen))) {
368*7c478bd9Sstevel@tonic-gate 		free(msg->iov);
369*7c478bd9Sstevel@tonic-gate 		slp_err(LOG_CRIT, 0, "slp_packSrvRqst", "out of memory");
370*7c478bd9Sstevel@tonic-gate 		return (SLP_MEMORY_ALLOC_FAILED);
371*7c478bd9Sstevel@tonic-gate 	}
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate 	/* set pointer to PR list and scope list length spaces */
374*7c478bd9Sstevel@tonic-gate 	msg->prlistlen.iov_base = msg->msg;
375*7c478bd9Sstevel@tonic-gate 	msg->prlistlen.iov_len = 2;
376*7c478bd9Sstevel@tonic-gate 	msg->iov[1].iov_base = msg->msg;
377*7c478bd9Sstevel@tonic-gate 	msg->iov[1].iov_len = 2;
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate 	msg->scopeslen.iov_base = msg->msg + 2;
380*7c478bd9Sstevel@tonic-gate 	msg->scopeslen.iov_len = 2;
381*7c478bd9Sstevel@tonic-gate 	msg->iov[4].iov_base = msg->msg + 2;
382*7c478bd9Sstevel@tonic-gate 	msg->iov[4].iov_len = 2;
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate 	/* set up the scopes and prlist pointers into iov */
385*7c478bd9Sstevel@tonic-gate 	msg->prlist = &(msg->iov[2]);
386*7c478bd9Sstevel@tonic-gate 	msg->scopes = &(msg->iov[5]);
387*7c478bd9Sstevel@tonic-gate 
388*7c478bd9Sstevel@tonic-gate 	len = 4;
389*7c478bd9Sstevel@tonic-gate 
390*7c478bd9Sstevel@tonic-gate 	/* Add type string */
391*7c478bd9Sstevel@tonic-gate 	msg->iov[3].iov_base = msg->msg + len;
392*7c478bd9Sstevel@tonic-gate 	tmplen = len;
393*7c478bd9Sstevel@tonic-gate 
394*7c478bd9Sstevel@tonic-gate 	err = slp_add_string(msg->msg, msgLen, type, &len);
395*7c478bd9Sstevel@tonic-gate 	msg->iov[3].iov_len = len - tmplen;
396*7c478bd9Sstevel@tonic-gate 
397*7c478bd9Sstevel@tonic-gate 	if (err != SLP_OK)
398*7c478bd9Sstevel@tonic-gate 		goto error;
399*7c478bd9Sstevel@tonic-gate 
400*7c478bd9Sstevel@tonic-gate 	/* Add search filter */
401*7c478bd9Sstevel@tonic-gate 	msg->iov[6].iov_base = msg->msg + len;
402*7c478bd9Sstevel@tonic-gate 	tmplen = len;
403*7c478bd9Sstevel@tonic-gate 
404*7c478bd9Sstevel@tonic-gate 	err = slp_add_string(msg->msg, msgLen, filter, &len);
405*7c478bd9Sstevel@tonic-gate 	if (err != SLP_OK)
406*7c478bd9Sstevel@tonic-gate 		goto error;
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate 	err = slp_add_string(msg->msg, msgLen, spi, &len);
409*7c478bd9Sstevel@tonic-gate 
410*7c478bd9Sstevel@tonic-gate 	msg->iov[6].iov_len = len - tmplen;
411*7c478bd9Sstevel@tonic-gate 
412*7c478bd9Sstevel@tonic-gate 	hp->fid = SRVRQST;
413*7c478bd9Sstevel@tonic-gate 
414*7c478bd9Sstevel@tonic-gate 	if (err == SLP_OK) {
415*7c478bd9Sstevel@tonic-gate 		return (err);
416*7c478bd9Sstevel@tonic-gate 	}
417*7c478bd9Sstevel@tonic-gate 
418*7c478bd9Sstevel@tonic-gate 	/* else error */
419*7c478bd9Sstevel@tonic-gate error:
420*7c478bd9Sstevel@tonic-gate 	free(msg->iov);
421*7c478bd9Sstevel@tonic-gate 	free(msg->msg);
422*7c478bd9Sstevel@tonic-gate 
423*7c478bd9Sstevel@tonic-gate 	return (err);
424*7c478bd9Sstevel@tonic-gate }
425*7c478bd9Sstevel@tonic-gate 
426*7c478bd9Sstevel@tonic-gate /*
427*7c478bd9Sstevel@tonic-gate  * Caller must free msg
428*7c478bd9Sstevel@tonic-gate  */
429*7c478bd9Sstevel@tonic-gate SLPError slp_packSrvRqst_single(const char *type,
430*7c478bd9Sstevel@tonic-gate 				const char *scopes,
431*7c478bd9Sstevel@tonic-gate 				const char *filter,
432*7c478bd9Sstevel@tonic-gate 				char **msg,
433*7c478bd9Sstevel@tonic-gate 				const char *lang) {
434*7c478bd9Sstevel@tonic-gate 	SLPError err;
435*7c478bd9Sstevel@tonic-gate 	size_t len, msgLen;
436*7c478bd9Sstevel@tonic-gate 
437*7c478bd9Sstevel@tonic-gate 	msgLen =
438*7c478bd9Sstevel@tonic-gate 		SLP_HDRLEN + strlen(lang) + 2 +
439*7c478bd9Sstevel@tonic-gate 		2 + strlen(type) +
440*7c478bd9Sstevel@tonic-gate 		2 + strlen(scopes) +
441*7c478bd9Sstevel@tonic-gate 		2 + strlen(filter) +
442*7c478bd9Sstevel@tonic-gate 		2; /* No SPI string for internal calls */
443*7c478bd9Sstevel@tonic-gate 
444*7c478bd9Sstevel@tonic-gate 	if (!(*msg = calloc(msgLen, 1))) {
445*7c478bd9Sstevel@tonic-gate 		slp_err(LOG_CRIT, 0, "slp_packSrvRqst_single",
446*7c478bd9Sstevel@tonic-gate 			"out of memory");
447*7c478bd9Sstevel@tonic-gate 		return (SLP_MEMORY_ALLOC_FAILED);
448*7c478bd9Sstevel@tonic-gate 	}
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 	len = 0;
451*7c478bd9Sstevel@tonic-gate 	err = slp_add_header(lang, *msg, msgLen, SRVRQST, msgLen, &len);
452*7c478bd9Sstevel@tonic-gate 
453*7c478bd9Sstevel@tonic-gate 	len += 2;	/* empty PR list */
454*7c478bd9Sstevel@tonic-gate 
455*7c478bd9Sstevel@tonic-gate 	if (err == SLP_OK)
456*7c478bd9Sstevel@tonic-gate 		err = slp_add_string(*msg, msgLen, type, &len);
457*7c478bd9Sstevel@tonic-gate 	if (err == SLP_OK)
458*7c478bd9Sstevel@tonic-gate 		err = slp_add_string(*msg, msgLen, scopes, &len);
459*7c478bd9Sstevel@tonic-gate 	if (err == SLP_OK)
460*7c478bd9Sstevel@tonic-gate 		err = slp_add_string(*msg, msgLen, filter, &len);
461*7c478bd9Sstevel@tonic-gate 	if (err == SLP_OK)
462*7c478bd9Sstevel@tonic-gate 		/* empty SPI string */
463*7c478bd9Sstevel@tonic-gate 		err = slp_add_string(*msg, msgLen, "", &len);
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate 	return (err);
466*7c478bd9Sstevel@tonic-gate }
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate 
469*7c478bd9Sstevel@tonic-gate static int compare_surls(struct surl_node *s1, struct surl_node *s2) {
470*7c478bd9Sstevel@tonic-gate 	if (s1->lifetime != s2->lifetime)
471*7c478bd9Sstevel@tonic-gate 		return (s1->lifetime - s2->lifetime);
472*7c478bd9Sstevel@tonic-gate 	return (slp_strcasecmp(s1->surl, s2->surl));
473*7c478bd9Sstevel@tonic-gate }
474*7c478bd9Sstevel@tonic-gate 
475*7c478bd9Sstevel@tonic-gate /*
476*7c478bd9Sstevel@tonic-gate  * Using the collator, determine if this URL has already been processed.
477*7c478bd9Sstevel@tonic-gate  * If so, free surl and return NULL, else return the URL.
478*7c478bd9Sstevel@tonic-gate  */
479*7c478bd9Sstevel@tonic-gate static char *collate_surls(char *surl, unsigned short life, void **collator) {
480*7c478bd9Sstevel@tonic-gate 	struct surl_node *n, **res;
481*7c478bd9Sstevel@tonic-gate 
482*7c478bd9Sstevel@tonic-gate 	if (!(n = malloc(sizeof (*n)))) {
483*7c478bd9Sstevel@tonic-gate 		slp_err(LOG_CRIT, 0, "collate_surls", "out of memory");
484*7c478bd9Sstevel@tonic-gate 		return (NULL);
485*7c478bd9Sstevel@tonic-gate 	}
486*7c478bd9Sstevel@tonic-gate 	if (!(n->surl = strdup(surl))) {
487*7c478bd9Sstevel@tonic-gate 		free(n);
488*7c478bd9Sstevel@tonic-gate 		slp_err(LOG_CRIT, 0, "collate_surls", "out of memory");
489*7c478bd9Sstevel@tonic-gate 		return (NULL);
490*7c478bd9Sstevel@tonic-gate 	}
491*7c478bd9Sstevel@tonic-gate 	n->lifetime = life;
492*7c478bd9Sstevel@tonic-gate 	res = slp_tsearch((void *) n, collator,
493*7c478bd9Sstevel@tonic-gate 			(int (*)(const void *, const void *)) compare_surls);
494*7c478bd9Sstevel@tonic-gate 	if (*res == n) {
495*7c478bd9Sstevel@tonic-gate 		/* first time we've encountered this url */
496*7c478bd9Sstevel@tonic-gate 		return (surl);
497*7c478bd9Sstevel@tonic-gate 	}
498*7c478bd9Sstevel@tonic-gate 	/* else  already in tree */
499*7c478bd9Sstevel@tonic-gate 	free(n->surl);
500*7c478bd9Sstevel@tonic-gate 	free(n);
501*7c478bd9Sstevel@tonic-gate 	free(surl);
502*7c478bd9Sstevel@tonic-gate 	return (NULL);
503*7c478bd9Sstevel@tonic-gate }
504*7c478bd9Sstevel@tonic-gate 
505*7c478bd9Sstevel@tonic-gate static void traverse_surls(SLPHandle h, SLPSrvURLCallback cb,
506*7c478bd9Sstevel@tonic-gate 				void *cookie, void *collator) {
507*7c478bd9Sstevel@tonic-gate 	struct caller_bundle caller[1];
508*7c478bd9Sstevel@tonic-gate 
509*7c478bd9Sstevel@tonic-gate 	if (!collator)
510*7c478bd9Sstevel@tonic-gate 		return;
511*7c478bd9Sstevel@tonic-gate 	caller->cb = cb;
512*7c478bd9Sstevel@tonic-gate 	caller->cookie = cookie;
513*7c478bd9Sstevel@tonic-gate 	caller->handle = h;
514*7c478bd9Sstevel@tonic-gate 	slp_twalk(collator, process_surl_node, 0, caller);
515*7c478bd9Sstevel@tonic-gate }
516*7c478bd9Sstevel@tonic-gate 
517*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
518*7c478bd9Sstevel@tonic-gate static void process_surl_node(void *node, VISIT order, int level, void *c) {
519*7c478bd9Sstevel@tonic-gate 	struct surl_node *n;
520*7c478bd9Sstevel@tonic-gate 	SLPSrvURLCallback *cb;
521*7c478bd9Sstevel@tonic-gate 	slp_handle_impl_t *h;
522*7c478bd9Sstevel@tonic-gate 	struct caller_bundle *caller = (struct caller_bundle *)c;
523*7c478bd9Sstevel@tonic-gate 
524*7c478bd9Sstevel@tonic-gate 	if (order == endorder || order == leaf) {
525*7c478bd9Sstevel@tonic-gate 		SLPBoolean cont = SLP_TRUE;
526*7c478bd9Sstevel@tonic-gate 
527*7c478bd9Sstevel@tonic-gate 		cb = caller->cb;
528*7c478bd9Sstevel@tonic-gate 		h = (slp_handle_impl_t *)caller->handle;
529*7c478bd9Sstevel@tonic-gate 		n = *(struct surl_node **)node;
530*7c478bd9Sstevel@tonic-gate 		/* invoke cb */
531*7c478bd9Sstevel@tonic-gate 		if (cont && (!h || !h->async))
532*7c478bd9Sstevel@tonic-gate 			cont = cb(
533*7c478bd9Sstevel@tonic-gate 				h, n->surl,
534*7c478bd9Sstevel@tonic-gate 				n->lifetime,
535*7c478bd9Sstevel@tonic-gate 				SLP_OK,
536*7c478bd9Sstevel@tonic-gate 				caller->cookie);
537*7c478bd9Sstevel@tonic-gate 
538*7c478bd9Sstevel@tonic-gate 		free(n->surl);
539*7c478bd9Sstevel@tonic-gate 		free(n);
540*7c478bd9Sstevel@tonic-gate 		free(node);
541*7c478bd9Sstevel@tonic-gate 	}
542*7c478bd9Sstevel@tonic-gate }
543