#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <syslog.h>
#include <slp-internal.h>
#define SLP_IANA "iana"
#define SERVICE_PREFIX "service"
typedef struct slp_type {
SLPBoolean isServiceURL;
char *atype;
char *ctype;
char *na;
char *orig;
} slp_type_t;
static SLPError parseType(char *, slp_type_t *);
static int validateTypeChars(char *);
static int validateTransport(char *);
static int checkURLString(char *);
SLPError SLPParseSrvURL(char *pcSrvURL, SLPSrvURL** ppSrvURL) {
char *p, *q, *r;
SLPSrvURL *surl;
slp_type_t type[1];
if (!pcSrvURL || !ppSrvURL) {
return (SLP_PARAMETER_BAD);
}
*ppSrvURL = NULL;
if (!checkURLString((char *)pcSrvURL))
return (SLP_PARSE_ERROR);
if (!(surl = malloc(sizeof (*surl)))) {
slp_err(LOG_CRIT, 0, "SLPParseSrvURL", "out of memory");
return (SLP_MEMORY_ALLOC_FAILED);
}
*ppSrvURL = surl;
surl->s_pcSrvType = "";
surl->s_pcNetFamily = "";
surl->s_pcHost = "";
surl->s_iPort = 0;
surl->s_pcSrvPart = "";
p = strstr(pcSrvURL, ":/");
if (!p)
goto error;
q = pcSrvURL;
*p++ = 0; p++;
r = strdup(q);
if (parseType(r, type) != SLP_OK)
goto error;
free(r);
surl->s_pcSrvType = q;
q = strchr(p, '/');
if (!q)
goto error;
*q++ = 0;
if (!validateTransport(p))
goto error;
surl->s_pcNetFamily = p;
p = strchr(q, ':');
r = strchr(q, '/');
if (!p && !r) {
surl->s_pcHost = q;
return (SLP_OK);
}
if (p && !r) {
int port;
surl->s_pcHost = q;
*p++ = 0;
port = atoi(p);
if (port <= 0)
goto error;
surl->s_iPort = port;
return (SLP_OK);
}
*r++ = 0;
if (!p || p > r) {
surl->s_pcHost = q;
} else {
int port;
surl->s_pcHost = q;
*p++ = 0;
port = atoi(p);
if (port <= 0)
goto error;
surl->s_iPort = port;
}
surl->s_pcSrvPart = r;
return (SLP_OK);
error:
free(surl);
*ppSrvURL = NULL;
return (SLP_PARSE_ERROR);
}
static SLPError parseType(char *typeString, slp_type_t *type) {
char *p, *q;
type->isServiceURL = SLP_FALSE;
type->atype = NULL;
type->ctype = NULL;
type->na = NULL;
type->orig = typeString;
if (!validateTypeChars(typeString))
return (SLP_PARSE_ERROR);
p = strchr(typeString, ':');
if (strncasecmp(
typeString, SERVICE_PREFIX, strlen(SERVICE_PREFIX)) == 0) {
type->isServiceURL = SLP_TRUE;
if (!p)
return (SLP_PARSE_ERROR);
*p++ = 0;
} else {
if (p)
return (SLP_PARSE_ERROR);
p = typeString;
}
q = strchr(p, ':');
if (q) {
type->atype = p;
*q++ = 0;
if (!*p)
return (SLP_PARSE_ERROR);
} else { q = p; }
p = strchr(q, '.');
if (p) {
*p++ = 0;
if (!*p)
return (SLP_PARSE_ERROR);
type->na = p;
}
if (!*q)
return (SLP_PARSE_ERROR);
type->ctype = q;
return (SLP_OK);
}
static int validateTransport(char *t) {
if (*t == 0 ||
strcasecmp(t, "ipx") == 0 ||
strcasecmp(t, "at") == 0)
return (1);
return (0);
}
static int checkURLString(char *s) {
int i;
size_t l = strlen(s);
for (i = 0; i < l; i++) {
if (isalnum(s[i]) ||
s[i] == '/' || s[i] == ':' || s[i] == '-' ||
s[i] == ':' || s[i] == '.' || s[i] == '%' ||
s[i] == '_' || s[i] == '\''|| s[i] == '*' ||
s[i] == '(' || s[i] == ')' || s[i] == '$' ||
s[i] == '!' || s[i] == ',' || s[i] == '+' ||
s[i] == '\\'|| s[i] == ';' || s[i] == '@' ||
s[i] == '?' || s[i] == '&' || s[i] == '=')
continue;
return (0);
}
return (1);
}
static int validateTypeChars(char *s) {
int i;
size_t l = strlen(s);
for (i = 0; i < l; i++)
if (!isalnum(s[i]) &&
s[i] != '-' &&
s[i] != '+' &&
s[i] != '.' &&
s[i] != ':')
return (0);
return (1);
}