#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <netdb.h>
#include <unistd.h>
#include <libintl.h>
#include <slp-internal.h>
struct scopes_tree {
void *scopes;
int len;
};
typedef SLPBoolean SLPScopeCallback(SLPHandle, const char *, SLPError, void *);
static SLPSrvURLCallback collate_scopes;
static void collect_scopes(void *, VISIT, int, void *);
static SLPBoolean unpackSAAdvert_scope(slp_handle_impl_t *, char *,
SLPScopeCallback, void *,
void **, int *);
static SLPError SAAdvert_for_scopes(SLPHandle, void **);
static SLPError slp_unescape(const char *, char **, SLPBoolean, const char);
SLPError SLPFindScopes(SLPHandle hSLP, char **ppcScopes) {
SLPError err;
char *reply, *unesc_reply;
void *stree = NULL;
void *collator = NULL;
if (!hSLP || !ppcScopes) {
return (SLP_PARAMETER_BAD);
}
if ((err = slp_administrative_scopes(ppcScopes, SLP_FALSE))
!= SLP_OK) {
return (err);
}
if (*ppcScopes) {
return (SLP_OK);
}
if ((err = slp_find_das("", &reply)) != SLP_OK &&
err != SLP_NETWORK_ERROR)
return (err);
if (reply) {
int numResults = 0;
((slp_handle_impl_t *)hSLP)->internal_call = SLP_TRUE;
(void) slp_unpackSrvReply(
hSLP, reply, collate_scopes,
&stree, &collator, &numResults);
(void) slp_unpackSrvReply(
hSLP, NULL, collate_scopes,
&stree, &collator, &numResults);
free(reply);
((slp_handle_impl_t *)hSLP)->internal_call = SLP_FALSE;
}
if (!stree) {
(void) SAAdvert_for_scopes(hSLP, &stree);
}
if (!stree) {
if (!(*ppcScopes = strdup("default"))) {
slp_err(LOG_CRIT, 0, "SLPFindScopes", "out of memory");
return (SLP_MEMORY_ALLOC_FAILED);
}
return (SLP_OK);
}
slp_twalk(stree, collect_scopes, 0, (void *) ppcScopes);
if ((err = slp_unescape(*ppcScopes, &unesc_reply, SLP_FALSE, '%'))
== SLP_OK) {
free(*ppcScopes);
*ppcScopes = unesc_reply;
} else {
free(unesc_reply);
}
return (err);
}
SLPError slp_administrative_scopes(char **ppcScopes,
SLPBoolean return_default) {
const char *useScopes;
*ppcScopes = NULL;
useScopes = SLPGetProperty(SLP_CONFIG_USESCOPES);
if (useScopes && *useScopes) {
if (!(*ppcScopes = strdup(useScopes))) {
slp_err(LOG_CRIT, 0, "SLPFindScopes", "out of memory");
return (SLP_MEMORY_ALLOC_FAILED);
}
return (SLP_OK);
}
if (return_default && !(*ppcScopes = strdup("default"))) {
slp_err(LOG_CRIT, 0, "SLPFindScopes", "out of memory");
return (SLP_MEMORY_ALLOC_FAILED);
}
return (SLP_OK);
}
static SLPBoolean saadvert_callback(SLPHandle hp, char *scopes,
SLPError err, void **stree) {
char *s, *tstate;
if (err != SLP_OK) {
return (SLP_TRUE);
}
for (
s = strtok_r((char *)scopes, ",", &tstate);
s;
s = strtok_r(NULL, ",", &tstate)) {
char *ascope, **srch;
if (!(ascope = strdup(s))) {
slp_err(LOG_CRIT, 0, "collate_scopes",
"out of memory");
return (SLP_TRUE);
}
srch = slp_tsearch(
(void *) ascope, stree,
(int (*)(const void *, const void *)) slp_strcasecmp);
if (*srch != ascope)
free(ascope);
}
return (SLP_TRUE);
}
static SLPError SAAdvert_for_scopes(SLPHandle hSLP, void **stree) {
SLPError err;
SLPBoolean sync_state;
slp_handle_impl_t *hp = (slp_handle_impl_t *)hSLP;
char *predicate;
const char *type_hint;
if ((type_hint = SLPGetProperty(SLP_CONFIG_TYPEHINT)) != NULL &&
*type_hint != 0) {
size_t hintlen = strlen(type_hint);
size_t predlen = strlen("(service-type=)");
if (hintlen > (SLP_MAX_STRINGLEN - predlen)) {
return (SLP_PARAMETER_BAD);
}
if (!(predicate = malloc(hintlen + predlen + 1))) {
slp_err(LOG_CRIT, 0, "SAAdvert_for_scopes",
"out of memory");
return (SLP_MEMORY_ALLOC_FAILED);
}
(void) strcpy(predicate, "(service-type=");
(void) strcat(predicate, type_hint);
(void) strcat(predicate, ")");
} else {
predicate = "";
type_hint = NULL;
}
sync_state = hp->async;
hp->async = SLP_FALSE;
if ((err = slp_start_call(hp)) != SLP_OK)
return (err);
err = slp_packSrvRqst("service:service-agent", predicate, hp);
if (err == SLP_OK) {
err = slp_ua_common(hSLP, "",
(SLPGenericAppCB *)(uintptr_t)saadvert_callback,
stree,
(SLPMsgReplyCB *)unpackSAAdvert_scope);
}
if (type_hint) {
free(predicate);
}
if (err != SLP_OK)
slp_end_call(hp);
hp->async = sync_state;
return (err);
}
static SLPBoolean unpackSAAdvert_scope(slp_handle_impl_t *hSLP, char *reply,
SLPScopeCallback cb, void *cookie,
void **collator, int *numResults) {
char *surl, *scopes, *attrs;
SLPBoolean cont;
if (!reply) {
cb(hSLP, NULL, SLP_LAST_CALL, cookie);
return (SLP_FALSE);
}
hSLP->internal_call = SLP_TRUE;
if (slp_unpackSAAdvert(reply, &surl, &scopes, &attrs) != SLP_OK) {
return (SLP_TRUE);
}
cont = cb(hSLP, scopes, SLP_OK, cookie);
hSLP->internal_call = SLP_FALSE;
free(surl);
free(scopes);
free(attrs);
return (cont);
}
SLPError slp_find_das(const char *filter, char **reply) {
SLPError err;
char *msg, hostname[MAXHOSTNAMELEN];
if (*reply = slp_find_das_cached(filter)) {
return (SLP_OK);
}
(void) gethostname(hostname, MAXHOSTNAMELEN);
err = slp_packSrvRqst_single(
SLP_SUN_DA_TYPE, hostname, filter, &msg, "en");
if (err == SLP_OK) {
err = slp_send2slpd(msg, reply);
free(msg);
}
if (err == SLP_OK) {
slp_put_das_cached(filter, *reply, slp_get_length(*reply));
}
return (err);
}
static SLPBoolean collate_scopes(SLPHandle h, const char *u,
unsigned short lifetime,
SLPError errCode, void *cookie) {
SLPSrvURL *surl;
char *s, *tstate, *p, *url;
void **collator = cookie;
if (errCode != SLP_OK)
return (SLP_TRUE);
if (!(url = strdup(u))) {
slp_err(LOG_CRIT, 0, "collate_scopes", "out of memory");
return (SLP_FALSE);
}
if (SLPParseSrvURL(url, &surl) != SLP_OK)
return (SLP_TRUE);
if (!(p = strchr(surl->s_pcSrvPart, '='))) {
free(surl);
return (SLP_TRUE);
}
p++;
for (
s = strtok_r(p, ",", &tstate);
s;
s = strtok_r(NULL, ",", &tstate)) {
char *ascope, **srch;
if (!(ascope = strdup(s))) {
slp_err(LOG_CRIT, 0, "collate_scopes",
"out of memory");
free(surl);
return (SLP_TRUE);
}
srch = slp_tsearch(
(void *) ascope, collator,
(int (*)(const void *, const void *)) slp_strcasecmp);
if (*srch != ascope)
free(ascope);
}
free(url);
free(surl);
return (SLP_TRUE);
}
static void collect_scopes(void *node, VISIT order, int level, void *cookie) {
char **scopes = (char **)cookie;
if (order == endorder || order == leaf) {
char *s = *(char **)node;
slp_add2list(s, scopes, SLP_FALSE);
free(s);
free(node);
}
}
void SLPFree(void *pvMem) {
if (pvMem)
free(pvMem);
}
#define isBadTagChar(c) ((c) == '*' || (c) == '_' || \
(c) == '\n' || (c) == '\t' || (c) == '\r')
#define isReserved(c) ((c) <= 31 || (c) == '(' || (c) == ')' || \
(c) == ',' || (c) == '\\' || (c) == '!' || \
(c) == '<' || (c) == '=' || (c) == '>' || \
(c) == '~')
SLPError SLPEscape(const char *pcInbuf, char **ppcOutBuf, SLPBoolean isTag) {
char *buf, *pin, *pout;
if (!pcInbuf || !ppcOutBuf)
return (SLP_PARAMETER_BAD);
if (!(buf = malloc(strlen(pcInbuf) * 3 + 1))) {
slp_err(LOG_CRIT, 0, "SLPEscape", "out of memory");
return (SLP_MEMORY_ALLOC_FAILED);
}
*ppcOutBuf = buf;
for (pin = (char *)pcInbuf, pout = buf; *pin; ) {
int len;
if ((len = mblen(pin, MB_CUR_MAX)) > 1) {
int i;
for (i = 0; i < len && *pin; i++)
*pout++ = *pin++;
continue;
}
if (isTag && isBadTagChar(*pin))
return (SLP_PARSE_ERROR);
if (isReserved(*pin)) {
if (isTag)
return (SLP_PARSE_ERROR);
(void) sprintf(pout, "\\%.2x", *pin);
pout += 3;
pin++;
} else {
*pout++ = *pin++;
}
}
*pout = 0;
return (SLP_OK);
}
SLPError SLPUnescape(const char *pcInbuf, char **ppcOutBuf, SLPBoolean isTag) {
if (!pcInbuf || !ppcOutBuf)
return (SLP_PARAMETER_BAD);
return (slp_unescape(pcInbuf, ppcOutBuf, isTag, '\\'));
}
static SLPError slp_unescape(const char *pcInbuf, char **ppcOutBuf,
SLPBoolean isTag, const char esc_char) {
char *buf, *pin, *pout, conv[3];
if (!(buf = malloc(strlen(pcInbuf) * 3 + 1))) {
slp_err(LOG_CRIT, 0, "SLPEscape", "out of memory");
return (SLP_MEMORY_ALLOC_FAILED);
}
*ppcOutBuf = buf;
conv[2] = 0;
for (pin = (char *)pcInbuf, pout = buf; *pin; ) {
int len;
if ((len = mblen(pin, MB_CUR_MAX)) > 1) {
int i;
for (i = 0; i < len && *pin; i++)
*pout++ = *pin++;
continue;
}
if (*pin == esc_char) {
if (!pin[1] || !pin[2])
return (SLP_PARSE_ERROR);
pin++;
conv[0] = *pin++;
conv[1] = *pin++;
*pout++ = (char)strtol(conv, NULL, 16);
if (isTag && isBadTagChar(*pout))
return (SLP_PARSE_ERROR);
} else {
*pout++ = *pin++;
}
}
*pout = 0;
return (SLP_OK);
}
struct prop_entry {
const char *key, *val;
};
typedef struct prop_entry slp_prop_entry_t;
static void *slp_props = NULL;
static mutex_t prop_table_lock = DEFAULTMUTEX;
static void setDefaults();
static int compare_props(const void *a, const void *b) {
return (strcmp(
((slp_prop_entry_t *)a)->key,
((slp_prop_entry_t *)b)->key));
}
void SLPSetProperty(const char *pcName, const char *pcValue) {
slp_prop_entry_t *pe, **pe2;
if (!slp_props) setDefaults();
if (!pcName || !pcValue) {
return;
}
if (!(pe = malloc(sizeof (*pe)))) {
slp_err(LOG_CRIT, 0, "SLPSetProperty", "out of memory");
return;
}
if (!(pe->key = strdup(pcName))) {
free(pe);
slp_err(LOG_CRIT, 0, "SLPSetProperty", "out of memory");
return;
}
if (!(pe->val = strdup(pcValue))) {
free((void *) pe->key);
free(pe);
slp_err(LOG_CRIT, 0, "SLPSetProperty", "out of memory");
return;
}
(void) mutex_lock(&prop_table_lock);
pe2 = slp_tsearch((void *) pe, &slp_props, compare_props);
if (pe != *pe2) {
free((void *) (*pe2)->val);
(*pe2)->val = pe->val;
free((void *) pe->key);
free(pe);
}
(void) mutex_unlock(&prop_table_lock);
}
const char *SLPGetProperty(const char *pcName) {
slp_prop_entry_t pe[1], **ans;
if (!slp_props) setDefaults();
if (!pcName) {
return (NULL);
}
pe->key = pcName;
(void) mutex_lock(&prop_table_lock);
ans = slp_tfind(pe, &slp_props, compare_props);
(void) mutex_unlock(&prop_table_lock);
if (ans)
return ((*ans)->val);
return (NULL);
}
static void setDefaults() {
slp_prop_entry_t *pe;
static mutex_t lock = DEFAULTMUTEX;
(void) mutex_lock(&lock);
if (slp_props) {
(void) mutex_unlock(&lock);
return;
}
pe = malloc(sizeof (*pe));
pe->key = strdup(SLP_CONFIG_ISBROADCASTONLY);
pe->val = strdup("false");
(void) slp_tsearch((void *) pe, &slp_props, compare_props);
pe = malloc(sizeof (*pe));
pe->key = strdup(SLP_CONFIG_MULTICASTTTL);
pe->val = strdup("255");
(void) slp_tsearch((void *) pe, &slp_props, compare_props);
pe = malloc(sizeof (*pe));
pe->key = strdup(SLP_CONFIG_MULTICASTMAXWAIT);
pe->val = strdup("15000");
(void) slp_tsearch((void *) pe, &slp_props, compare_props);
pe = malloc(sizeof (*pe));
pe->key = strdup(SLP_CONFIG_DATAGRAMTIMEOUTS);
pe->val = strdup("2000,2000,2000");
(void) slp_tsearch((void *) pe, &slp_props, compare_props);
pe = malloc(sizeof (*pe));
pe->key = strdup(SLP_CONFIG_MULTICASTTIMEOUTS);
pe->val = strdup("1000,3000,3000,3000,3000");
(void) slp_tsearch((void *) pe, &slp_props, compare_props);
pe = malloc(sizeof (*pe));
pe->key = SLP_CONFIG_MTU; pe->val = "1400";
(void) slp_tsearch((void *) pe, &slp_props, compare_props);
pe = malloc(sizeof (*pe));
pe->key = strdup(SLP_CONFIG_MAXRESULTS);
pe->val = strdup("-1");
(void) slp_tsearch((void *) pe, &slp_props, compare_props);
pe = malloc(sizeof (*pe));
pe->key = strdup(SLP_CONFIG_SECURITY_ON);
pe->val = strdup("false");
(void) slp_tsearch((void *) pe, &slp_props, compare_props);
pe = malloc(sizeof (*pe));
pe->key = strdup(SLP_CONFIG_BYPASS_AUTH);
pe->val = strdup("false");
(void) slp_tsearch((void *) pe, &slp_props, compare_props);
slp_readConfig();
(void) mutex_unlock(&lock);
}
static const char *error_strings[] = {
"OK",
"Language not supported",
"Parse error",
"Invalid registration",
"Scope not supported",
"Invalid error number",
"Authentication absent",
"Authentication failed",
"Invalid error number",
"Invalid error number",
"Invalid error number",
"Invalid error number",
"Invalid error number",
"Invalid update",
"Invalid error number",
"Invalid error number",
"Invalid error number",
"Not implemented",
"Buffer overflow",
"Network timed out",
"Network init failed",
"Memory alloc failed",
"Parameter bad",
"Network error",
"Internal system error",
"Handle in use",
"Type error"
};
#define SLP_MAX_ERR_CNT 26
const char *slp_strerror(SLPError err) {
int abserr;
const char *str;
if (err == SLP_LAST_CALL) {
str = "Last call";
} else if (err == SLP_SECURITY_UNAVAILABLE) {
str = "Security Implementation Unavailable";
} else {
abserr = abs(err);
if (abserr > SLP_MAX_ERR_CNT) {
str = "Invalid error number";
} else {
str = error_strings[abserr];
}
}
return (dgettext("libslp", str));
}