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
SLPFindSrvs(SLPHandle hSLP,const char * pcServiceType,const char * pcScope,const char * pcSearchFilter,SLPSrvURLCallback callback,void * pvUser)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
slp_unpackSrvReply(slp_handle_impl_t * hp,char * reply,SLPSrvURLCallback cb,void * cookie,void ** collator,int * numResults)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 */
unpackDAAdvert_srv(slp_handle_impl_t * hp,char * reply,SLPSrvURLCallback cb,void * cookie,void ** collator,int * numResults)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 */
unpackSAAdvert_srv(slp_handle_impl_t * hp,char * reply,SLPSrvURLCallback cb,void * cookie,void ** collator,int * numResults)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
slp_packSrvRqst(const char * type,const char * filter,slp_handle_impl_t * hp)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 */
slp_packSrvRqst_single(const char * type,const char * scopes,const char * filter,char ** msg,const char * lang)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
compare_surls(struct surl_node * s1,struct surl_node * s2)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 */
collate_surls(char * surl,unsigned short life,void ** collator)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
traverse_surls(SLPHandle h,SLPSrvURLCallback cb,void * cookie,void * collator)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*/
process_surl_node(void * node,VISIT order,int level,void * c)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