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