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 <stdio.h> 30 #include <stdlib.h> 31 #include <syslog.h> 32 #include <slp-internal.h> 33 34 struct surl_node { 35 char *surl; 36 unsigned short lifetime; 37 }; 38 39 struct caller_bundle { 40 SLPSrvURLCallback *cb; 41 void *cookie; 42 SLPHandle handle; 43 }; 44 45 static int compare_surls(struct surl_node *, struct surl_node *); 46 static char *collate_surls(char *, unsigned short, void **); 47 static void traverse_surls(SLPHandle, SLPSrvURLCallback, void *, void *); 48 static void process_surl_node(void *, VISIT, int, void *); 49 static SLPBoolean unpackDAAdvert_srv(slp_handle_impl_t *, char *, 50 SLPSrvURLCallback, void *, 51 void **, int *); 52 static SLPBoolean unpackSAAdvert_srv(slp_handle_impl_t *, char *, 53 SLPSrvURLCallback, void *, 54 void **, int *); 55 56 SLPError SLPFindSrvs(SLPHandle hSLP, const char *pcServiceType, 57 const char *pcScope, const char *pcSearchFilter, 58 SLPSrvURLCallback callback, void *pvUser) { 59 SLPError err; 60 slp_handle_impl_t *hp = (slp_handle_impl_t *)hSLP; 61 int wantSAAdvert = 62 strcasecmp(pcServiceType, "service:service-agent") == 0; 63 int wantDAAdvert = 64 strcasecmp(pcServiceType, "service:directory-agent") == 0; 65 int isSpecial = wantSAAdvert || wantDAAdvert; 66 SLPMsgReplyCB *unpack_cb; 67 68 if (!hSLP || !pcServiceType || !pcScope || (!*pcScope && !isSpecial) || 69 !pcSearchFilter || !callback) { 70 return (SLP_PARAMETER_BAD); 71 } 72 73 if ((strlen(pcServiceType) > SLP_MAX_STRINGLEN) || 74 (strlen(pcScope) > SLP_MAX_STRINGLEN) || 75 (strlen(pcSearchFilter) > SLP_MAX_STRINGLEN)) { 76 return (SLP_PARAMETER_BAD); 77 } 78 79 if ((err = slp_start_call(hSLP)) != SLP_OK) 80 return (err); 81 82 /* Special unpacker for DA and SA solicitations */ 83 if (wantDAAdvert) { 84 unpack_cb = (SLPMsgReplyCB *)unpackDAAdvert_srv; 85 hp->force_multicast = SLP_TRUE; 86 } else if (wantSAAdvert) { 87 unpack_cb = (SLPMsgReplyCB *)unpackSAAdvert_srv; 88 hp->force_multicast = SLP_TRUE; 89 } else { 90 /* normal service request */ 91 unpack_cb = (SLPMsgReplyCB *)slp_unpackSrvReply; 92 } 93 94 err = slp_packSrvRqst(pcServiceType, pcSearchFilter, hp); 95 96 if (err == SLP_OK) 97 err = slp_ua_common(hSLP, pcScope, 98 (SLPGenericAppCB *) callback, pvUser, 99 unpack_cb); 100 if (err != SLP_OK) 101 slp_end_call(hSLP); 102 103 return (err); 104 } 105 106 SLPBoolean slp_unpackSrvReply(slp_handle_impl_t *hp, char *reply, 107 SLPSrvURLCallback cb, void *cookie, 108 void **collator, int *numResults) { 109 SLPError errCode; 110 unsigned short urlCount, protoErrCode; 111 size_t len, off; 112 int i; 113 int maxResults = slp_get_maxResults(); 114 SLPBoolean cont = SLP_TRUE; 115 116 if (!reply) { 117 /* no more results */ 118 /* traverse_surls:invoke cb for sync case,and free resources */ 119 if (!hp->async) { 120 traverse_surls(hp, cb, cookie, *collator); 121 } 122 cb(hp, NULL, 0, SLP_LAST_CALL, cookie); 123 return (SLP_FALSE); 124 } 125 126 len = slp_get_length(reply); 127 off = SLP_HDRLEN + slp_get_langlen(reply); 128 /* err code */ 129 if (slp_get_sht(reply, len, &off, &protoErrCode) != SLP_OK) 130 return (SLP_TRUE); 131 /* internal errors should have been filtered out by the net code */ 132 if ((errCode = slp_map_err(protoErrCode)) != SLP_OK) { 133 return (cb(hp, NULL, 0, errCode, cookie)); 134 } 135 136 /* url entry count */ 137 if (slp_get_sht(reply, len, &off, &urlCount) != SLP_OK) 138 return (SLP_TRUE); 139 140 /* for each srvRply, unpack and pass to CB */ 141 for (i = 0; i < urlCount && !hp->cancel; i++) { 142 char *pcSrvURL; 143 unsigned short sLifetime; 144 int nURLAuthBlocks; 145 size_t tbv_len; 146 char *url_tbv; 147 148 /* parse URL entry into params */ 149 off++; /* skip reserved byte */ 150 /* lifetime */ 151 if (slp_get_sht(reply, len, &off, &sLifetime) != SLP_OK) 152 return (SLP_TRUE); 153 /* URL itself; keep track of it in case we need to verify */ 154 url_tbv = reply + off; 155 tbv_len = off; 156 if (slp_get_string(reply, len, &off, &pcSrvURL) != SLP_OK) 157 return (SLP_TRUE); 158 tbv_len = off - tbv_len; 159 160 /* number of url auths */ 161 if (slp_get_byte(reply, len, &off, &nURLAuthBlocks) != SLP_OK) 162 goto cleanup; 163 164 /* get and verify auth blocks */ 165 if ((!hp->internal_call && slp_get_security_on()) || 166 nURLAuthBlocks > 0) { 167 struct iovec iov[1]; 168 size_t abLen = 0; 169 170 iov[0].iov_base = url_tbv; 171 iov[0].iov_len = tbv_len; 172 173 if (slp_verify(iov, 1, 174 reply + off, 175 len - off, 176 nURLAuthBlocks, 177 &abLen) != SLP_OK) { 178 goto cleanup; 179 } 180 off += abLen; 181 } 182 183 /* collate the srv urls for sync behavior */ 184 if (!hp->async) { 185 pcSrvURL = collate_surls(pcSrvURL, sLifetime, collator); 186 187 if (!pcSrvURL) 188 continue; 189 } 190 191 (*numResults)++; 192 /* invoke cb */ 193 if (hp->async) 194 cont = cb( 195 (SLPHandle) hp, 196 pcSrvURL, 197 sLifetime, 198 errCode, 199 cookie); 200 201 /* cleanup */ 202 cleanup: 203 free(pcSrvURL); 204 205 /* check maxResults */ 206 if (!hp->internal_call && *numResults == maxResults) { 207 cont = SLP_FALSE; 208 } 209 210 if (!cont) break; 211 } 212 213 return (cont); 214 } 215 216 /* 217 * unpackDAAdvert_srv follows the same same logic flow as slp_unpackSrvReply 218 * with two differences: the message in reply is a DAAdvert, and 219 * this function is not used internally, so hp is never NULL. Although 220 * all info from a DAAdvert is returned by slp_unpackDAAdvert, here 221 * the recipient (the user-supplied SLPSrvURLCallback) is interested 222 * only in the DA service URL. 223 */ 224 static SLPBoolean unpackDAAdvert_srv(slp_handle_impl_t *hp, char *reply, 225 SLPSrvURLCallback cb, void *cookie, 226 void **collator, int *numResults) { 227 char *surl, *scopes, *attrs, *spis; 228 SLPBoolean cont = SLP_TRUE; 229 SLPError errCode; 230 int maxResults = slp_get_maxResults(); 231 232 if (!reply) { 233 /* no more results */ 234 /* traverse_surls:invoke cb for sync case,and free resources */ 235 if (!hp->async) { 236 traverse_surls(hp, cb, cookie, *collator); 237 } 238 cb(hp, NULL, 0, SLP_LAST_CALL, cookie); 239 return (SLP_FALSE); 240 } 241 242 if (slp_unpackDAAdvert(reply, &surl, &scopes, &attrs, &spis, &errCode) 243 != SLP_OK) { 244 return (SLP_TRUE); 245 } 246 if (errCode != SLP_OK) { 247 return (cb(hp, NULL, 0, errCode, cookie)); 248 } 249 250 /* collate the urls */ 251 surl = collate_surls(surl, 0, collator); 252 if (!surl) { 253 return (SLP_TRUE); 254 } 255 256 (*numResults)++; 257 if (hp->async) { 258 cont = cb((SLPHandle)hp, surl, 0, errCode, cookie); 259 } 260 261 /* cleanup */ 262 free(surl); 263 free(scopes); 264 free(attrs); 265 free(spis); 266 267 /* check maxResults */ 268 if (!hp->internal_call && *numResults == maxResults) { 269 return (SLP_FALSE); 270 } 271 272 return (cont); 273 } 274 /* 275 * unpackSAAdvert_srv follows the same same logic flow as slp_unpackSrvReply 276 * with two differences: the message in reply is a SAAdvert, and 277 * this function is not used internally, so hp is never NULL. Although 278 * all info from an SAAdvert is returned by slp_unpackSAAdvert, here 279 * the recipient (the user-supplied SLPSrvURLCallback) is interested 280 * only in the SA service URL. 281 */ 282 static SLPBoolean unpackSAAdvert_srv(slp_handle_impl_t *hp, char *reply, 283 SLPSrvURLCallback cb, void *cookie, 284 void **collator, int *numResults) { 285 char *surl, *scopes, *attrs; 286 SLPBoolean cont = SLP_TRUE; 287 int maxResults = slp_get_maxResults(); 288 289 if (!reply) { 290 /* no more results */ 291 /* traverse_surls:invoke cb for sync case,and free resources */ 292 if (!hp->async) { 293 /* sync case */ 294 traverse_surls(hp, cb, cookie, *collator); 295 } 296 cb(hp, NULL, 0, SLP_LAST_CALL, cookie); 297 return (SLP_FALSE); 298 } 299 300 if (slp_unpackSAAdvert(reply, &surl, &scopes, &attrs) != SLP_OK) { 301 return (SLP_TRUE); 302 } 303 304 /* collate the urls */ 305 surl = collate_surls(surl, 0, collator); 306 if (!surl) { 307 return (SLP_TRUE); 308 } 309 310 (*numResults)++; 311 if (hp->async) { 312 cont = cb((SLPHandle)hp, surl, 0, SLP_OK, cookie); 313 } 314 315 /* cleanup */ 316 free(surl); 317 free(scopes); 318 free(attrs); 319 320 /* check maxResults */ 321 if (!hp->internal_call && *numResults == maxResults) { 322 return (SLP_FALSE); 323 } 324 325 return (cont); 326 } 327 328 SLPError slp_packSrvRqst(const char *type, 329 const char *filter, 330 slp_handle_impl_t *hp) { 331 SLPError err; 332 size_t len, msgLen, tmplen; 333 slp_msg_t *msg = &(hp->msg); 334 char *spi = NULL; 335 336 if (slp_get_security_on()) { 337 spi = (char *)SLPGetProperty(SLP_CONFIG_SPI); 338 } 339 340 if (!spi || !*spi) { 341 spi = ""; 342 } 343 344 /* 345 * Allocate iovec for the messge. A SrvRqst is layed out thus: 346 * 0: header 347 * 1: prlist length 348 * 2: prlist (filled in later by networking code) 349 * 3: service type string 350 * 4: scopes length 351 * 5: scopes (filled in later by networking code) 352 * 6: predicate string and SPI string 353 */ 354 if (!(msg->iov = calloc(7, sizeof (*(msg->iov))))) { 355 slp_err(LOG_CRIT, 0, "slp_packSrvRqst", "out of memory"); 356 return (SLP_MEMORY_ALLOC_FAILED); 357 } 358 msg->iovlen = 7; 359 360 /* calculate msg length */ 361 msgLen = 2 + /* prlist length */ 362 2 + strlen(type) + /* service type */ 363 2 + /* scope list length */ 364 2 + strlen(filter) + /* predicate string */ 365 2 + strlen(spi); /* SPI string */ 366 367 if (!(msg->msg = calloc(1, msgLen))) { 368 free(msg->iov); 369 slp_err(LOG_CRIT, 0, "slp_packSrvRqst", "out of memory"); 370 return (SLP_MEMORY_ALLOC_FAILED); 371 } 372 373 /* set pointer to PR list and scope list length spaces */ 374 msg->prlistlen.iov_base = msg->msg; 375 msg->prlistlen.iov_len = 2; 376 msg->iov[1].iov_base = msg->msg; 377 msg->iov[1].iov_len = 2; 378 379 msg->scopeslen.iov_base = msg->msg + 2; 380 msg->scopeslen.iov_len = 2; 381 msg->iov[4].iov_base = msg->msg + 2; 382 msg->iov[4].iov_len = 2; 383 384 /* set up the scopes and prlist pointers into iov */ 385 msg->prlist = &(msg->iov[2]); 386 msg->scopes = &(msg->iov[5]); 387 388 len = 4; 389 390 /* Add type string */ 391 msg->iov[3].iov_base = msg->msg + len; 392 tmplen = len; 393 394 err = slp_add_string(msg->msg, msgLen, type, &len); 395 msg->iov[3].iov_len = len - tmplen; 396 397 if (err != SLP_OK) 398 goto error; 399 400 /* Add search filter */ 401 msg->iov[6].iov_base = msg->msg + len; 402 tmplen = len; 403 404 err = slp_add_string(msg->msg, msgLen, filter, &len); 405 if (err != SLP_OK) 406 goto error; 407 408 err = slp_add_string(msg->msg, msgLen, spi, &len); 409 410 msg->iov[6].iov_len = len - tmplen; 411 412 hp->fid = SRVRQST; 413 414 if (err == SLP_OK) { 415 return (err); 416 } 417 418 /* else error */ 419 error: 420 free(msg->iov); 421 free(msg->msg); 422 423 return (err); 424 } 425 426 /* 427 * Caller must free msg 428 */ 429 SLPError slp_packSrvRqst_single(const char *type, 430 const char *scopes, 431 const char *filter, 432 char **msg, 433 const char *lang) { 434 SLPError err; 435 size_t len, msgLen; 436 437 msgLen = 438 SLP_HDRLEN + strlen(lang) + 2 + 439 2 + strlen(type) + 440 2 + strlen(scopes) + 441 2 + strlen(filter) + 442 2; /* No SPI string for internal calls */ 443 444 if (!(*msg = calloc(msgLen, 1))) { 445 slp_err(LOG_CRIT, 0, "slp_packSrvRqst_single", 446 "out of memory"); 447 return (SLP_MEMORY_ALLOC_FAILED); 448 } 449 450 len = 0; 451 err = slp_add_header(lang, *msg, msgLen, SRVRQST, msgLen, &len); 452 453 len += 2; /* empty PR list */ 454 455 if (err == SLP_OK) 456 err = slp_add_string(*msg, msgLen, type, &len); 457 if (err == SLP_OK) 458 err = slp_add_string(*msg, msgLen, scopes, &len); 459 if (err == SLP_OK) 460 err = slp_add_string(*msg, msgLen, filter, &len); 461 if (err == SLP_OK) 462 /* empty SPI string */ 463 err = slp_add_string(*msg, msgLen, "", &len); 464 465 return (err); 466 } 467 468 469 static int compare_surls(struct surl_node *s1, struct surl_node *s2) { 470 if (s1->lifetime != s2->lifetime) 471 return (s1->lifetime - s2->lifetime); 472 return (slp_strcasecmp(s1->surl, s2->surl)); 473 } 474 475 /* 476 * Using the collator, determine if this URL has already been processed. 477 * If so, free surl and return NULL, else return the URL. 478 */ 479 static char *collate_surls(char *surl, unsigned short life, void **collator) { 480 struct surl_node *n, **res; 481 482 if (!(n = malloc(sizeof (*n)))) { 483 slp_err(LOG_CRIT, 0, "collate_surls", "out of memory"); 484 return (NULL); 485 } 486 if (!(n->surl = strdup(surl))) { 487 free(n); 488 slp_err(LOG_CRIT, 0, "collate_surls", "out of memory"); 489 return (NULL); 490 } 491 n->lifetime = life; 492 res = slp_tsearch((void *) n, collator, 493 (int (*)(const void *, const void *)) compare_surls); 494 if (*res == n) { 495 /* first time we've encountered this url */ 496 return (surl); 497 } 498 /* else already in tree */ 499 free(n->surl); 500 free(n); 501 free(surl); 502 return (NULL); 503 } 504 505 static void traverse_surls(SLPHandle h, SLPSrvURLCallback cb, 506 void *cookie, void *collator) { 507 struct caller_bundle caller[1]; 508 509 if (!collator) 510 return; 511 caller->cb = cb; 512 caller->cookie = cookie; 513 caller->handle = h; 514 slp_twalk(collator, process_surl_node, 0, caller); 515 } 516 517 /*ARGSUSED*/ 518 static void process_surl_node(void *node, VISIT order, int level, void *c) { 519 struct surl_node *n; 520 SLPSrvURLCallback *cb; 521 slp_handle_impl_t *h; 522 struct caller_bundle *caller = (struct caller_bundle *)c; 523 524 if (order == endorder || order == leaf) { 525 SLPBoolean cont = SLP_TRUE; 526 527 cb = caller->cb; 528 h = (slp_handle_impl_t *)caller->handle; 529 n = *(struct surl_node **)node; 530 /* invoke cb */ 531 if (cont && (!h || !h->async)) 532 cont = cb( 533 h, n->surl, 534 n->lifetime, 535 SLP_OK, 536 caller->cookie); 537 538 free(n->surl); 539 free(n); 540 free(node); 541 } 542 } 543