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 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 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 */ 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 */ 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 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 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 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 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 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 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 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*/ 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