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