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