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
SLPFindAttrs(SLPHandle hSLP,const char * pcURL,const char * pcScope,const char * pcAttrIds,SLPAttrCallback callback,void * pvUser)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
slp_UnpackAttrReply(slp_handle_impl_t * hp,char * reply,SLPAttrCallback cb,void * cookie,void ** collator,int * numResults)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 */
unpackDAAdvert_attr(slp_handle_impl_t * hp,char * reply,SLPAttrCallback cb,void * cookie,void ** collator,int * numResults)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 */
unpackSAAdvert_attr(slp_handle_impl_t * hp,char * reply,SLPAttrCallback cb,void * cookie,void ** collator,int * numResults)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
slp_packAttrRqst(slp_handle_impl_t * hp,const char * url,const char * ids)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
slp_packAttrRqst_single(const char * url,const char * scopes,const char * ids,char ** msg,const char * lang)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
compare_tags(const void * n1,const void * n2)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
merge_attrs(struct attr_node * n,char * vals)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
parens_attr(char * attr,void ** collator,int * numResults)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
collate_attrs(char * attrs,void ** collator,int * numResults,int maxResults)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
build_attrs_list(void * collator)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*/
collect_attrs(void * node,VISIT order,int level,void * cookie)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