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