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