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 (c) 1999 by Sun Microsystems, Inc.
24  * All rights reserved.
25  */
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <ctype.h>
30 #include <string.h>
31 #include <syslog.h>
32 #include <slp-internal.h>
33 
34 /*
35  * URL parsing
36  */
37 
38 #define	SLP_IANA	"iana"
39 #define	SERVICE_PREFIX	"service"
40 
41 /* service type struct */
42 typedef struct slp_type {
43 	SLPBoolean isServiceURL;
44 	char *atype;
45 	char *ctype;
46 	char *na;
47 	char *orig;
48 } slp_type_t;
49 
50 static SLPError parseType(char *, slp_type_t *);
51 static int validateTypeChars(char *);
52 static int validateTransport(char *);
53 static int checkURLString(char *);
54 
SLPParseSrvURL(char * pcSrvURL,SLPSrvURL ** ppSrvURL)55 SLPError SLPParseSrvURL(char *pcSrvURL, SLPSrvURL** ppSrvURL) {
56 	char *p, *q, *r;
57 	SLPSrvURL *surl;
58 	slp_type_t type[1];
59 
60 	if (!pcSrvURL || !ppSrvURL) {
61 		return (SLP_PARAMETER_BAD);
62 	}
63 
64 	*ppSrvURL = NULL;
65 	if (!checkURLString((char *)pcSrvURL))
66 		return (SLP_PARSE_ERROR);
67 
68 	if (!(surl = malloc(sizeof (*surl)))) {
69 		slp_err(LOG_CRIT, 0, "SLPParseSrvURL", "out of memory");
70 		return (SLP_MEMORY_ALLOC_FAILED);
71 	}
72 	*ppSrvURL = surl;
73 	surl->s_pcSrvType = "";
74 	surl->s_pcNetFamily = "";
75 	surl->s_pcHost = "";
76 	surl->s_iPort = 0;
77 	surl->s_pcSrvPart = "";
78 
79 	/* parse type */
80 	p = strstr(pcSrvURL, ":/");
81 	if (!p)
82 		goto error;
83 	q = pcSrvURL;
84 	*p++ = 0; p++;
85 	r = strdup(q);
86 	if (parseType(r, type) != SLP_OK)
87 	goto error;
88 	free(r);
89 	/* no need to free type since it is on the stack */
90 	surl->s_pcSrvType = q;
91 
92 	/* do we have a transport? */
93 	q = strchr(p, '/');
94 	if (!q)
95 		goto error;
96 	*q++ = 0;
97 	if (!validateTransport(p))
98 		goto error;
99 	surl->s_pcNetFamily = p;	/* may be \0 */
100 
101 	/* host part */
102 	/* do we have a port #? */
103 	p = strchr(q, ':');
104 	r = strchr(q, '/');
105 	if (!p && !r) {	/* only host part */
106 		surl->s_pcHost = q;
107 		return (SLP_OK);
108 	}
109 	if (p && !r) {	/* host + port, no URL part */
110 		int port;
111 		surl->s_pcHost = q;
112 		*p++ = 0;
113 		port = atoi(p);
114 		if (port <= 0)
115 			goto error;
116 		surl->s_iPort = port;
117 		return (SLP_OK);
118 	}
119 	*r++ = 0;
120 	if (!p || p > r) {	/* no port */
121 		surl->s_pcHost = q;
122 	} else {		/* host + port + url part */
123 		int port;
124 		surl->s_pcHost = q;
125 		*p++ = 0;
126 		port = atoi(p);
127 		if (port <= 0)
128 			goto error;
129 		surl->s_iPort = port;
130 	}
131 
132 	/* r now points to the URL part */
133 	surl->s_pcSrvPart = r;
134 
135 	return (SLP_OK);
136 
137 error:
138 	free(surl);
139 	*ppSrvURL = NULL;
140 	return (SLP_PARSE_ERROR);
141 }
142 
143 /*
144  * typeString contains only the service type part of an URL. It should
145  * point to a string which parseType can destructively modify.
146  */
parseType(char * typeString,slp_type_t * type)147 static SLPError parseType(char *typeString, slp_type_t *type) {
148 	char *p, *q;
149 
150 	/* Initialize type structure */
151 	type->isServiceURL = SLP_FALSE;
152 	type->atype = NULL;
153 	type->ctype = NULL;
154 	type->na = NULL;
155 	type->orig = typeString;
156 
157 	if (!validateTypeChars(typeString))
158 		return (SLP_PARSE_ERROR);
159 
160 	/* Is this a service: URL? */
161 	p = strchr(typeString, ':');
162 	if (strncasecmp(
163 		typeString, SERVICE_PREFIX, strlen(SERVICE_PREFIX)) == 0) {
164 		type->isServiceURL = SLP_TRUE;
165 		if (!p)
166 			return (SLP_PARSE_ERROR);
167 		*p++ = 0;
168 	} else {
169 		if (p)	/* can't have an abstract type in a non-service url */
170 			return (SLP_PARSE_ERROR);
171 		p = typeString;
172 	}
173 
174 	/* p now points to the beginning of the type */
175 	/* is this an abstract type? */
176 	q = strchr(p, ':');
177 	if (q) {
178 		type->atype = p;
179 		*q++ = 0;
180 		if (!*p)
181 			return (SLP_PARSE_ERROR);
182 	} else { q = p; }
183 
184 	/* q should now point to the concrete type */
185 	/* is there a naming authority? */
186 	p = strchr(q, '.');
187 	if (p) {
188 		*p++ = 0;
189 		if (!*p)
190 			return (SLP_PARSE_ERROR);
191 		type->na = p;
192 	}
193 	if (!*q)
194 		return (SLP_PARSE_ERROR);
195 	type->ctype = q;
196 
197 	return (SLP_OK);
198 }
199 
validateTransport(char * t)200 static int validateTransport(char *t) {
201 	if (*t == 0 ||
202 	    strcasecmp(t, "ipx") == 0 ||
203 	    strcasecmp(t, "at") == 0)
204 		return (1);
205 	return (0);
206 }
207 
checkURLString(char * s)208 static int checkURLString(char *s) {
209 	int i;
210 	size_t l = strlen(s);
211 	for (i = 0; i < l; i++) {
212 		if (isalnum(s[i]) ||
213 		    s[i] == '/' || s[i] == ':' || s[i] == '-' ||
214 		    s[i] == ':' || s[i] == '.' || s[i] == '%' ||
215 		    s[i] == '_' || s[i] == '\''|| s[i] == '*' ||
216 		    s[i] == '(' || s[i] == ')' || s[i] == '$' ||
217 		    s[i] == '!' || s[i] == ',' || s[i] == '+' ||
218 		    s[i] == '\\'|| s[i] == ';' || s[i] == '@' ||
219 		    s[i] == '?' || s[i] == '&' || s[i] == '=')
220 			continue;
221 		return (0);
222 	}
223 
224 	return (1);
225 }
226 
227 
validateTypeChars(char * s)228 static int validateTypeChars(char *s) {
229 	int i;
230 	size_t l = strlen(s);
231 	for (i = 0; i < l; i++)
232 		if (!isalnum(s[i]) &&
233 		    s[i] != '-' &&
234 		    s[i] != '+' &&
235 		    s[i] != '.' &&
236 		    s[i] != ':')
237 			return (0);
238 	return (1);
239 }
240