1 /* distcache, Distributed Session Caching technology
2  * Copyright (C) 2000-2003  Geoff Thorpe, and Cryptographic Appliances, Inc.
3  * Copyright (C) 2004       The Distcache.org project
4  *
5  * This library is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU Lesser General Public License as published by the Free
7  * Software Foundation; using version 2.1 of the License. The copyright holders
8  * may elect to allow the application of later versions of the License to this
9  * software, please contact the author (geoff@distcache.org) if you wish us to
10  * review any later version released by the Free Software Foundation.
11  *
12  * This library is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
15  * details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this library; if not, write to the Free Software Foundation, Inc.,
19  * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21 #include "swamp.h"
22 
23 /*
24  * returns non-zero on error, zero if otherwise it successfully initialised
25  * the structure.
26  */
init_tokeniser(tokeniser_t * t,const char * string,const char * delimiters)27 int init_tokeniser(tokeniser_t *t, const char *string, const char *delimiters)
28 {
29     /*
30      * I think I'd prefer to see this function allocate a tokeniser_t
31      * structure for itself, with the 'token' bit a part of that
32      * allocation. For now, this system works, however.
33      */
34     if (t) {
35         t->string     = string;
36         t->delimiters = delimiters;
37         t->position   = string;
38 
39         /* A token can't be longer than the length of the string itself */
40         t->token = SYS_malloc(char, strlen(string) + 1);
41         if (!t->token) {
42             free_tokeniser(t);
43             return 1;
44         }
45 	return 0;
46     }
47     return 1;
48 }
49 
free_tokeniser(tokeniser_t * t)50 void free_tokeniser(tokeniser_t *t)
51 {
52     if (t) {
53         t->string     = NULL;
54         t->delimiters = NULL;
55         t->position   = NULL;
56         if (t->token)
57             SYS_free(char, t->token);
58         t->token = NULL;
59     }
60 }
61 
do_tokenising(tokeniser_t * t)62 char *do_tokenising(tokeniser_t *t)
63 {
64     if (t) {
65         const char *p;   /* "Cursor" pointing into the string */
66         int found_token = 0;
67         int i = 0; /* An index into the token string */
68 
69         /*
70          * If 'position' is NULL, this means we've reached the
71          * end of the string
72          */
73         if (t->position == NULL)
74             return NULL;
75 
76         p = t->position;
77         while ( (strchr(t->delimiters, *p)) != NULL && *p != '\0')
78             p++;
79 
80         for (; *p != '\0'; p++) {
81             /*
82              * Check to see if the "cursor" ('p') is over one of the
83              * delimiters, and if so, move forward until a character
84              * is found which *isn't* a delimiter (this also includes
85              * the end of string)
86              */
87             while ( (strchr(t->delimiters, *p)) != NULL && *p != '\0') {
88                 found_token = 1;
89                 p++;
90             }
91 
92 	    /*
93 	     * It's important to let the 'while' loop above find all
94 	     * delimiters, and break out of the 'for' loop afterwards.
95 	     * Otherwise, the strings will be a bit scewed and
96 	     * empty strings will be returned.
97 	     */
98             if (found_token)
99                 break;
100 
101             /*
102              * A character which isn't a delimiter should be stored in
103              * the token buffer.
104              */
105             t->token[i++] = *p;
106         }
107 
108         /*
109          * This seems a bit kludgy. If the last run came across a bunch of
110          * tokens followed by a NULL byte, then nothing was copied into the
111          * token buffer. In this case, we don't want to return an empty buffer,
112          * but instead return with a "no more tokens" indicator.
113          */
114         if (i == 0)
115             return NULL;
116 
117         t->token[i] = '\0'; /* NULL out - reasons should be obvious :-) */
118 
119         /*
120          * If a token was found, update the tokeniser structure's current
121          * position ready for the next run. Otherwise we reached the
122          * end of the string.
123          */
124         if (found_token)
125             t->position = p;
126         else
127             t->position = NULL;
128 
129         /* Return the token to the user. */
130         return t->token;
131     }
132     return NULL;
133 }
134 
135 #ifndef HAVE_STRTOL
strtol(const char * nptr,char ** endptr,int base)136 static long int strtol(const char *nptr, char **endptr, int base)
137 {
138 	int negate = -1; /* not specified, assumed positive */
139 	long toret = 0;
140 	assert(base == 10);
141 	/* Now scan across 'nptr' processing char-by-char */
142 keep_scanning:
143 	if(isdigit(*nptr)) {
144 		toret += ((*nptr) - '0');
145 		if((LONG_MAX / 10) <= toret) {
146 			toret = LONG_MAX;
147 			goto end;
148 		}
149 		toret *= 10;
150 	} else if((*nptr == '-') || (*nptr == '+')) {
151 		if(negate != -1)
152 			/* We've already encountered a plus or minus */
153 			goto end;
154 		negate = ((*nptr == '-') ? 1 : 0);
155 	} else if(!isspace(*nptr)) {
156 		/* We hit something we don't like */
157 		goto end;
158 	}
159 	nptr++;
160 	if(*nptr != '\0')
161 		goto keep_scanning;
162 end:
163 	if(endptr)
164 		*endptr = nptr;
165 	return ((negate == 1) ? -toret : toret);
166 }
167 #endif
168 
169 /* Wrapper for strtol() */
int_strtol(const char * str,long * val)170 int int_strtol(const char *str, long *val)
171 {
172 	char *ptr;
173 	long tmp = strtol(str, &ptr, 10);
174 	if((ptr == str) || (*ptr != '\0'))
175 		/* Doesn't look like a number */
176 		return 0;
177 	*val = tmp;
178 	return 1;
179 }
180 
181 /* Wrapper for strtoul() */
int_strtoul(const char * str,unsigned long * val)182 int int_strtoul(const char *str, unsigned long *val)
183 {
184 	long tmp;
185 	if(!int_strtol(str, &tmp) || (tmp < 0))
186 		return 0;
187 	*val = tmp;
188 	return 1;
189 }
190 
191 /* Versions of the above that allow termination other than '\0' */
int_substrtol(const char * str,long * val,const char * valid_terms)192 int int_substrtol(const char *str, long *val, const char *valid_terms)
193 {
194 	char *ptr;
195 	long tmp = strtol(str, &ptr, 10);
196 	/* FIXME: this check that there was at least *some* numeric content
197 	 * parsed before a non-numeric character is bogus - it forgets possible
198 	 * leading whitespace. */
199 	if((ptr == str) || ((*str == '-') && (str + 1 == ptr)))
200 		/* no numeric characters at all! */
201 		return 0;
202 	*val = tmp;
203 	if(!valid_terms || (*ptr == '\0') || strchr(valid_terms, *ptr))
204 		/* Fine */
205 		return 1;
206 	/* Invalid termination */
207 	return 0;
208 }
209 
int_substrtoul(const char * str,unsigned long * val,const char * valid_terms)210 int int_substrtoul(const char *str, unsigned long *val, const char *valid_terms)
211 {
212 	long tmp;
213 	if(!int_substrtol(str, &tmp, valid_terms) || (tmp < 0))
214 		return 0;
215 	*val = tmp;
216 	return 1;
217 }
218 
219 /* TODO: This could probably be reviewed. Apart from being incomplete, I
220  * wouldn't be surprised if there were "unexpected behaviour conditions". */
util_parse_escaped_string(const char * str_toconvert)221 char *util_parse_escaped_string(const char *str_toconvert)
222 {
223 	char *toreturn, *dest;
224 	int ctrl = 0;
225 
226 	/* Duplicate the input string */
227 	SYS_strdup(&toreturn, str_toconvert);
228 	if(!toreturn) return NULL;
229 	dest = toreturn;
230 	/* Iterate across the input string and output strings in a
231 	 * state-machine to handle control-characters. */
232 	while(*str_toconvert) {
233 		if(!ctrl) {
234 			/* We're not in escaped mode, what's the next char? */
235 			if(*str_toconvert != '\\')
236 				/* A "normal" character */
237 				*(dest++) = *str_toconvert;
238 			else
239 				/* A "\" escape character, switch mode */
240 				ctrl = 1;
241 		} else {
242 			/* We're in escaped mode, check what has been escaped */
243 			switch(*str_toconvert) {
244 			case 'r':
245 				*(dest++) = '\r'; break;
246 			case 'n':
247 				*(dest++) = '\n'; break;
248 			default:
249 				/* If the control command isn't recognised, we
250 				 * literally translate "\x" into "x". */
251 				*(dest++) = *str_toconvert;
252 			}
253 			/* We're no longer in escaped mode */
254 			ctrl = 0;
255 		}
256 		/* In all cases, we increment our "source" string pointer. What
257 		 * we do with our "destination" string pointer varies and is
258 		 * handled (above) case-by-case. */
259 		str_toconvert++;
260 	}
261 	/* NULL-terminate the output string. */
262 	*dest = 0;
263 	return toreturn;
264 }
265 
util_parse_sslmeth(const char * str_toconvert,swamp_sslmeth * val)266 int util_parse_sslmeth(const char *str_toconvert, swamp_sslmeth *val)
267 {
268 	if(!strcmp(str_toconvert, "normal"))
269 		*val = SWAMP_SSLMETH_NORMAL;
270 #if OPENSSL_VERSION_NUMBER < 0x10100000L && !defined(OPENSSL_NO_SSL2)
271 	else if(!strcmp(str_toconvert, "sslv2"))
272 		*val = SWAMP_SSLMETH_SSLv2;
273 #endif
274 #ifndef OPENSSL_NO_SSL3_METHOD
275 	else if(!strcmp(str_toconvert, "sslv3"))
276 		*val = SWAMP_SSLMETH_SSLv3;
277 #endif
278 	else if(!strcmp(str_toconvert, "tlsv1"))
279 		*val = SWAMP_SSLMETH_TLSv1;
280 	else
281 		return 0;
282 	return 1;
283 }
284