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