2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License, Version 1.0 only
2N/A * (the "License"). You may not use this file except in compliance
2N/A * with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A#pragma ident "%Z%%M% %I% %E% SMI"
2N/A
2N/A#include <stdlib.h>
2N/A#include <syslog.h>
2N/A#include <slp-internal.h>
2N/A
2N/Astruct attr_node {
2N/A char *tag, *val;
2N/A};
2N/A
2N/Astatic SLPError slp_packAttrRqst(slp_handle_impl_t *, const char *,
2N/A const char *);
2N/Astatic int compare_tags(const void *, const void *);
2N/Astatic void collate_attrs(char *, void **, int *, int);
2N/Astatic void parens_attr(char *, void **, int *);
2N/Astatic void merge_attrs(struct attr_node *, char *);
2N/Astatic char *build_attrs_list(void *collator);
2N/Astatic void collect_attrs(void *, VISIT, int, void *);
2N/Astatic SLPBoolean unpackDAAdvert_attr(slp_handle_impl_t *, char *,
2N/A SLPAttrCallback, void *,
2N/A void **, int *);
2N/Astatic SLPBoolean unpackSAAdvert_attr(slp_handle_impl_t *, char *,
2N/A SLPAttrCallback, void *,
2N/A void **, int *);
2N/A
2N/ASLPError SLPFindAttrs(SLPHandle hSLP, const char *pcURL, const char *pcScope,
2N/A const char *pcAttrIds,
2N/A SLPAttrCallback callback, void *pvUser) {
2N/A SLPError err;
2N/A int wantSAAdvert =
2N/A strcasecmp(pcURL, "service:service-agent") == 0;
2N/A int wantDAAdvert =
2N/A strcasecmp(pcURL, "service:directory-agent") == 0;
2N/A int isSpecial = wantSAAdvert || wantDAAdvert;
2N/A SLPMsgReplyCB *unpack_cb;
2N/A
2N/A
2N/A if (!hSLP || !pcURL || !pcScope || (!*pcScope && !isSpecial) ||
2N/A !pcAttrIds || !callback) {
2N/A return (SLP_PARAMETER_BAD);
2N/A }
2N/A
2N/A if ((strlen(pcURL) > SLP_MAX_STRINGLEN) ||
2N/A (strlen(pcScope) > SLP_MAX_STRINGLEN) ||
2N/A (strlen(pcAttrIds) > SLP_MAX_STRINGLEN)) {
2N/A return (SLP_PARAMETER_BAD);
2N/A }
2N/A
2N/A if ((err = slp_start_call(hSLP)) != SLP_OK)
2N/A return (err);
2N/A
2N/A /* Special packer and unpacker for DA and SA solicitations */
2N/A if (wantDAAdvert) {
2N/A unpack_cb = (SLPMsgReplyCB *)unpackDAAdvert_attr;
2N/A err = slp_packSrvRqst(pcURL, "", hSLP);
2N/A ((slp_handle_impl_t *)hSLP)->force_multicast = SLP_TRUE;
2N/A } else if (wantSAAdvert) {
2N/A unpack_cb = (SLPMsgReplyCB *)unpackSAAdvert_attr;
2N/A err = slp_packSrvRqst(pcURL, "", hSLP);
2N/A ((slp_handle_impl_t *)hSLP)->force_multicast = SLP_TRUE;
2N/A } else {
2N/A /* normal service request */
2N/A unpack_cb = (SLPMsgReplyCB *)slp_UnpackAttrReply;
2N/A /* format params into msgBuf */
2N/A err = slp_packAttrRqst(hSLP, pcURL, pcAttrIds);
2N/A }
2N/A
2N/A if (err == SLP_OK)
2N/A err = slp_ua_common(hSLP, pcScope,
2N/A (SLPGenericAppCB *) callback, pvUser,
2N/A unpack_cb);
2N/A
2N/A if (err != SLP_OK)
2N/A slp_end_call(hSLP);
2N/A
2N/A return (err);
2N/A}
2N/A
2N/ASLPBoolean slp_UnpackAttrReply(slp_handle_impl_t *hp, char *reply,
2N/A SLPAttrCallback cb, void *cookie,
2N/A void **collator, int *numResults) {
2N/A char *pcAttrList;
2N/A SLPError errCode;
2N/A unsigned short protoErrCode;
2N/A size_t len, off;
2N/A int maxResults = slp_get_maxResults();
2N/A SLPBoolean cont = SLP_TRUE;
2N/A int auth_cnt;
2N/A size_t tbv_len;
2N/A char *attr_tbv;
2N/A
2N/A if (!reply) {
2N/A /* no more results */
2N/A if (!hp->async) {
2N/A pcAttrList = build_attrs_list(*collator);
2N/A }
2N/A
2N/A if (!hp->async && pcAttrList) {
2N/A cb(hp, pcAttrList, SLP_OK, cookie);
2N/A free(pcAttrList);
2N/A }
2N/A cb(hp, NULL, SLP_LAST_CALL, cookie);
2N/A return (SLP_FALSE);
2N/A }
2N/A
2N/A /* parse reply into params */
2N/A len = slp_get_length(reply);
2N/A off = SLP_HDRLEN + slp_get_langlen(reply);
2N/A /* err code */
2N/A if (slp_get_sht(reply, len, &off, &protoErrCode) != SLP_OK)
2N/A return (SLP_TRUE);
2N/A /* internal errors should have been filtered out by the net code */
2N/A if ((errCode = slp_map_err(protoErrCode)) != SLP_OK) {
2N/A return (cb(hp, NULL, errCode, cookie));
2N/A }
2N/A
2N/A /* attr list */
2N/A attr_tbv = reply + off;
2N/A tbv_len = off;
2N/A if (slp_get_string(reply, len, &off, &pcAttrList) != SLP_OK)
2N/A return (SLP_TRUE);
2N/A tbv_len = off - tbv_len;
2N/A
2N/A /* number of attr auths */
2N/A if (slp_get_byte(reply, len, &off, &auth_cnt) != SLP_OK) {
2N/A goto cleanup;
2N/A }
2N/A
2N/A /* get and verify auth blocks */
2N/A if ((!hp->internal_call && slp_get_security_on()) || auth_cnt > 0) {
2N/A size_t abLen = 0;
2N/A struct iovec iov[1];
2N/A
2N/A iov[0].iov_base = attr_tbv;
2N/A iov[0].iov_len = tbv_len;
2N/A
2N/A if (slp_verify(iov, 1,
2N/A reply + off,
2N/A len - off,
2N/A auth_cnt,
2N/A &abLen) != SLP_OK) {
2N/A goto cleanup;
2N/A }
2N/A }
2N/A
2N/A /* collate */
2N/A if (!hp->async) {
2N/A collate_attrs(pcAttrList, collator, numResults, maxResults);
2N/A } else {
2N/A /* async: invoke cb */
2N/A cont = cb((SLPHandle) hp, pcAttrList, errCode, cookie);
2N/A (*numResults)++;
2N/A }
2N/A
2N/Acleanup:
2N/A free(pcAttrList);
2N/A
2N/A /* check maxResults */
2N/A if (!hp->internal_call && *numResults == maxResults) {
2N/A return (SLP_FALSE);
2N/A }
2N/A
2N/A return (cont);
2N/A}
2N/A
2N/A/*
2N/A * unpackDAAdvert_attr follows the same logic stream as UnpackAttrReply,
2N/A * except that reply contains a DAAdvert.
2N/A */
2N/Astatic SLPBoolean unpackDAAdvert_attr(slp_handle_impl_t *hp, char *reply,
2N/A SLPAttrCallback cb, void *cookie,
2N/A void **collator, int *numResults) {
2N/A char *surl, *scopes, *attrs, *spis;
2N/A SLPBoolean cont = SLP_TRUE;
2N/A SLPError errCode;
2N/A int maxResults = slp_get_maxResults();
2N/A
2N/A if (!reply) {
2N/A /* no more results */
2N/A if (!hp->async) {
2N/A attrs = build_attrs_list(*collator);
2N/A }
2N/A
2N/A if (!hp->async && attrs) {
2N/A cb(hp, attrs, SLP_OK, cookie);
2N/A free(attrs);
2N/A }
2N/A cb(hp, NULL, SLP_LAST_CALL, cookie);
2N/A return (SLP_FALSE);
2N/A }
2N/A
2N/A if (slp_unpackDAAdvert(reply, &surl, &scopes, &attrs, &spis, &errCode)
2N/A != SLP_OK) {
2N/A return (SLP_TRUE);
2N/A }
2N/A if (errCode != SLP_OK) {
2N/A return (cb(hp, NULL, errCode, cookie));
2N/A }
2N/A
2N/A /* collate */
2N/A if (!hp->async) {
2N/A collate_attrs(attrs, collator, numResults, maxResults);
2N/A } else {
2N/A /* async: invoke cb */
2N/A cont = cb((SLPHandle) hp, attrs, errCode, cookie);
2N/A (*numResults)++;
2N/A }
2N/A
2N/A /* cleanup */
2N/A free(surl);
2N/A free(scopes);
2N/A free(attrs);
2N/A free(spis);
2N/A
2N/A /* check maxResults */
2N/A if (!hp->internal_call && *numResults == maxResults) {
2N/A return (SLP_FALSE);
2N/A }
2N/A
2N/A return (cont);
2N/A}
2N/A
2N/A/*
2N/A * unpackSAAdvert_attr follows the same logic stream as UnpackAttrReply,
2N/A * except that reply contains an SAAdvert.
2N/A */
2N/Astatic SLPBoolean unpackSAAdvert_attr(slp_handle_impl_t *hp, char *reply,
2N/A SLPAttrCallback cb, void *cookie,
2N/A void **collator, int *numResults) {
2N/A char *surl, *scopes, *attrs;
2N/A SLPBoolean cont = SLP_TRUE;
2N/A int maxResults = slp_get_maxResults();
2N/A
2N/A if (!reply) {
2N/A /* no more results */
2N/A if (!hp->async) {
2N/A attrs = build_attrs_list(*collator);
2N/A }
2N/A
2N/A if (!hp->async && attrs) {
2N/A cb(hp, attrs, SLP_OK, cookie);
2N/A free(attrs);
2N/A }
2N/A cb(hp, NULL, SLP_LAST_CALL, cookie);
2N/A return (SLP_FALSE);
2N/A }
2N/A
2N/A if (slp_unpackSAAdvert(reply, &surl, &scopes, &attrs) != SLP_OK) {
2N/A return (SLP_TRUE);
2N/A }
2N/A
2N/A /* collate */
2N/A if (!hp->async) {
2N/A collate_attrs(attrs, collator, numResults, maxResults);
2N/A } else {
2N/A /* async: invoke cb */
2N/A cont = cb((SLPHandle) hp, attrs, SLP_OK, cookie);
2N/A (*numResults)++;
2N/A }
2N/A
2N/A /* cleanup */
2N/A free(surl);
2N/A free(scopes);
2N/A free(attrs);
2N/A
2N/A /* check maxResults */
2N/A if (!hp->internal_call && *numResults == maxResults) {
2N/A return (SLP_FALSE);
2N/A }
2N/A
2N/A return (cont);
2N/A}
2N/A
2N/Astatic SLPError slp_packAttrRqst(slp_handle_impl_t *hp, const char *url,
2N/A const char *ids) {
2N/A SLPError err;
2N/A size_t len, tmplen, msgLen;
2N/A slp_msg_t *msg = &(hp->msg);
2N/A char *spi = NULL;
2N/A
2N/A if (slp_get_security_on()) {
2N/A spi = (char *)SLPGetProperty(SLP_CONFIG_SPI);
2N/A }
2N/A
2N/A if (!spi || !*spi) {
2N/A spi = "";
2N/A }
2N/A
2N/A /*
2N/A * Allocate iovec for the messge. An AttrRqst is layed out thus:
2N/A * 0: header
2N/A * 1: prlist length
2N/A * 2: prlist (filled in later by networking code)
2N/A * 3: URL string
2N/A * 4: scopes length
2N/A * 5: scopes (filled in later by networking code)
2N/A * 6: tag list string and SPI string
2N/A */
2N/A if (!(msg->iov = calloc(7, sizeof (*(msg->iov))))) {
2N/A slp_err(LOG_CRIT, 0, "slp_packAttrRqst", "out of memory");
2N/A return (SLP_MEMORY_ALLOC_FAILED);
2N/A }
2N/A msg->iovlen = 7;
2N/A
2N/A /* calculate msg length */
2N/A msgLen = 2 + /* prlist length */
2N/A 2 + strlen(url) + /* URL */
2N/A 2 + /* scope list length */
2N/A 2 + strlen(ids) + /* tag list */
2N/A 2 + strlen(spi); /* SPI string */
2N/A
2N/A if (!(msg->msg = calloc(1, msgLen))) {
2N/A free(msg->iov);
2N/A slp_err(LOG_CRIT, 0, "slp_packAttrRqst", "out of memory");
2N/A return (SLP_MEMORY_ALLOC_FAILED);
2N/A }
2N/A
2N/A /* set pointer to PR list and scope list length spaces */
2N/A msg->prlistlen.iov_base = msg->msg;
2N/A msg->prlistlen.iov_len = 2;
2N/A msg->iov[1].iov_base = msg->msg;
2N/A msg->iov[1].iov_len = 2;
2N/A
2N/A msg->scopeslen.iov_base = msg->msg + 2;
2N/A msg->scopeslen.iov_len = 2;
2N/A msg->iov[4].iov_base = msg->msg + 2;
2N/A msg->iov[4].iov_len = 2;
2N/A
2N/A /* set up the scopes and prlist pointers into iov */
2N/A msg->prlist = &(msg->iov[2]);
2N/A msg->scopes = &(msg->iov[5]);
2N/A
2N/A len = 4;
2N/A
2N/A /* Add URL string */
2N/A msg->iov[3].iov_base = msg->msg + len;
2N/A tmplen = len;
2N/A
2N/A err = slp_add_string(msg->msg, msgLen, url, &len);
2N/A msg->iov[3].iov_len = len - tmplen;
2N/A
2N/A if (err != SLP_OK)
2N/A goto error;
2N/A
2N/A /* Add tag list */
2N/A msg->iov[6].iov_base = msg->msg + len;
2N/A tmplen = len;
2N/A
2N/A err = slp_add_string(msg->msg, msgLen, ids, &len);
2N/A
2N/A if (err != SLP_OK)
2N/A goto error;
2N/A
2N/A /* SPI string */
2N/A err = slp_add_string(msg->msg, msgLen, spi, &len);
2N/A
2N/A msg->iov[6].iov_len = len - tmplen;
2N/A
2N/A hp->fid = ATTRRQST;
2N/A if (err == SLP_OK) {
2N/A return (SLP_OK);
2N/A }
2N/A
2N/A /* else error */
2N/Aerror:
2N/A free(msg->iov);
2N/A free(msg->msg);
2N/A
2N/A return (err);
2N/A}
2N/A
2N/ASLPError slp_packAttrRqst_single(const char *url,
2N/A const char *scopes,
2N/A const char *ids,
2N/A char **msg,
2N/A const char *lang) {
2N/A SLPError err;
2N/A size_t len, msgLen;
2N/A
2N/A msgLen =
2N/A SLP_HDRLEN + strlen(lang) + 2 +
2N/A 2 + strlen(url) +
2N/A 2 + strlen(scopes) +
2N/A 2 + strlen(ids) +
2N/A 2; /* No SPI string for internal calls */
2N/A
2N/A if (!(*msg = calloc(msgLen, 1))) {
2N/A slp_err(LOG_CRIT, 0, "slp_packAttrRqst_single", "out of memory");
2N/A return (SLP_MEMORY_ALLOC_FAILED);
2N/A }
2N/A
2N/A len = 0;
2N/A err = slp_add_header(lang, *msg, msgLen, ATTRRQST, msgLen, &len);
2N/A
2N/A len += 2; /* empty PR list */
2N/A
2N/A if (err == SLP_OK) {
2N/A err = slp_add_string(*msg, msgLen, url, &len);
2N/A }
2N/A if (err == SLP_OK) {
2N/A err = slp_add_string(*msg, msgLen, scopes, &len);
2N/A }
2N/A if (err == SLP_OK) {
2N/A err = slp_add_string(*msg, msgLen, ids, &len);
2N/A }
2N/A /* empty SPI */
2N/A if (err == SLP_OK) {
2N/A err = slp_add_string(*msg, msgLen, "", &len);
2N/A }
2N/A
2N/A return (err);
2N/A}
2N/A
2N/Astatic int compare_tags(const void *n1, const void *n2) {
2N/A return slp_strcasecmp(
2N/A ((struct attr_node *)n1)->tag,
2N/A ((struct attr_node *)n2)->tag);
2N/A}
2N/A
2N/Astatic void merge_attrs(struct attr_node *n, char *vals) {
2N/A char *p, *v;
2N/A
2N/A for (p = v = vals; p; v = p) {
2N/A p = slp_utf_strchr(v, ',');
2N/A if (p)
2N/A *p++ = 0;
2N/A slp_add2list(v, &(n->val), SLP_TRUE);
2N/A }
2N/A}
2N/A
2N/Astatic void parens_attr(char *attr, void **collator, int *numResults) {
2N/A char *open_paren, *close_paren, *equals;
2N/A struct attr_node *n, **res;
2N/A
2N/A open_paren = attr + 1;
2N/A close_paren = slp_utf_strchr(open_paren, ')');
2N/A if (!close_paren)
2N/A return; /* skip bad attr list */
2N/A
2N/A *close_paren = 0;
2N/A if (!(equals = slp_utf_strchr(open_paren, '=')))
2N/A return;
2N/A
2N/A *equals++ = 0;
2N/A
2N/A if (!(n = malloc(sizeof (*n)))) {
2N/A slp_err(LOG_CRIT, 0, "collate_attrs", "out of memory");
2N/A return;
2N/A }
2N/A
2N/A if (!(n->tag = strdup(open_paren))) {
2N/A free(n);
2N/A slp_err(LOG_CRIT, 0, "collate_attrs", "out of memory");
2N/A return;
2N/A }
2N/A n->val = NULL;
2N/A
2N/A res = slp_tsearch(n, collator, compare_tags);
2N/A
2N/A if (*res != n) {
2N/A merge_attrs(*res, equals);
2N/A free(n->tag); free(n);
2N/A } else {
2N/A /* not found; populate new attr node */
2N/A (*numResults)++;
2N/A if (!(n->val = strdup(equals))) {
2N/A slp_err(LOG_CRIT, 0, "collate_attrs", "out of memory");
2N/A return;
2N/A }
2N/A }
2N/A}
2N/A
2N/Astatic void collate_attrs(char *attrs, void **collator,
2N/A int *numResults, int maxResults) {
2N/A char *start, *end;
2N/A struct attr_node *n, **res;
2N/A
2N/A for (start = attrs;
2N/A start &&
2N/A *start &&
2N/A *numResults != maxResults;
2N/A start = end) {
2N/A if (*start == ',') start++;
2N/A if (*start == '(') {
2N/A /* form of (tag=val,val) */
2N/A if (!(end = slp_utf_strchr(start, ')')))
2N/A return; /* skip bad attr */
2N/A parens_attr(start, collator, numResults);
2N/A end++;
2N/A continue;
2N/A }
2N/A end = slp_utf_strchr(start, ',');
2N/A if (end)
2N/A *end++ = 0;
2N/A /* create a new node with the tag only */
2N/A if (!(n = malloc(sizeof (*n)))) {
2N/A slp_err(LOG_CRIT, 0, "collate_attrs", "out of memory");
2N/A return;
2N/A }
2N/A
2N/A if (!(n->tag = strdup(start))) {
2N/A free(n);
2N/A slp_err(LOG_CRIT, 0, "collate_attrs", "out of memory");
2N/A return;
2N/A }
2N/A n->val = NULL;
2N/A res = slp_tsearch(n, collator, compare_tags);
2N/A if (*res != n) {
2N/A /* already in the tree, so just free resources */
2N/A free(n->tag); free(n);
2N/A }
2N/A (*numResults)++;
2N/A }
2N/A}
2N/A
2N/Astatic char *build_attrs_list(void *collator) {
2N/A char *answer = NULL;
2N/A
2N/A if (!collator)
2N/A return (NULL);
2N/A
2N/A slp_twalk(collator, collect_attrs, 0, &answer);
2N/A return (answer);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic void collect_attrs(void *node, VISIT order, int level, void *cookie) {
2N/A struct attr_node *n;
2N/A char *attr, *p, **answer = (char **)cookie;
2N/A
2N/A if (order == endorder || order == leaf) {
2N/A n = *(struct attr_node **)node;
2N/A if (!n->val) {
2N/A /* no values, so no parens */
2N/A if (!(attr = malloc(strlen(n->tag) + 1))) {
2N/A slp_err(LOG_CRIT, 0, "collect_attrs",
2N/A "out of memory");
2N/A return;
2N/A }
2N/A (void) strcpy(attr, n->tag);
2N/A } else {
2N/A if (!(attr = malloc(1 + strlen(n->tag) + 1 +
2N/A strlen(n->val) + 2))) {
2N/A slp_err(LOG_CRIT, 0, "collect_attrs",
2N/A "out of memory");
2N/A return;
2N/A }
2N/A /* build attr string */
2N/A p = attr;
2N/A *p++ = '(';
2N/A (void) strcpy(p, n->tag); p += strlen(n->tag);
2N/A *p++ = '=';
2N/A (void) strcpy(p, n->val); p += strlen(n->val);
2N/A *p++ = ')'; *p = 0;
2N/A }
2N/A
2N/A slp_add2list(attr, answer, SLP_FALSE);
2N/A free(attr);
2N/A free(n->tag); if (n->val) free(n->val); free(n);
2N/A free(node);
2N/A }
2N/A}