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