1 #include <stdio.h>
2 #include <assert.h>
3 #include <ctype.h>
4 #include <errno.h>
5 #include <string.h>
6 #include <stdlib.h>
7 #include <stdarg.h>
8 
9 #include "memcached.h"
10 
11 static char *uriencode_map[256];
12 static char uriencode_str[768];
13 
uriencode_init(void)14 void uriencode_init(void) {
15     int x;
16     char *str = uriencode_str;
17     for (x = 0; x < 256; x++) {
18         if (isalnum(x) || x == '-' || x == '.' || x == '_' || x == '~') {
19             uriencode_map[x] = NULL;
20         } else {
21             snprintf(str, 4, "%%%02hhX", (unsigned char)x);
22             uriencode_map[x] = str;
23             str += 3; /* lobbing off the \0 is fine */
24         }
25     }
26 }
27 
uriencode(const char * src,char * dst,const size_t srclen,const size_t dstlen)28 bool uriencode(const char *src, char *dst, const size_t srclen, const size_t dstlen) {
29     int x;
30     size_t d = 0;
31     for (x = 0; x < srclen; x++) {
32         if (d + 4 > dstlen)
33             return false;
34         if (uriencode_map[(unsigned char) src[x]] != NULL) {
35             memcpy(&dst[d], uriencode_map[(unsigned char) src[x]], 3);
36             d += 3;
37         } else {
38             dst[d] = src[x];
39             d++;
40         }
41     }
42     dst[d] = '\0';
43     return true;
44 }
45 
46 /* Avoid warnings on solaris, where isspace() is an index into an array, and gcc uses signed chars */
47 #define xisspace(c) isspace((unsigned char)c)
48 
safe_strtoull(const char * str,uint64_t * out)49 bool safe_strtoull(const char *str, uint64_t *out) {
50     assert(out != NULL);
51     errno = 0;
52     *out = 0;
53     char *endptr;
54     unsigned long long ull = strtoull(str, &endptr, 10);
55     if ((errno == ERANGE) || (str == endptr)) {
56         return false;
57     }
58 
59     if (xisspace(*endptr) || (*endptr == '\0' && endptr != str)) {
60         if ((long long) ull < 0) {
61             /* only check for negative signs in the uncommon case when
62              * the unsigned number is so big that it's negative as a
63              * signed number. */
64             if (memchr(str, '-', endptr - str) != NULL) {
65                 return false;
66             }
67         }
68         *out = ull;
69         return true;
70     }
71     return false;
72 }
73 
74 /* Could macro this. Decided to keep this unrolled for safety rather than add
75  * the base parameter to all callers. Very few places need to parse a number
76  * outside of base 10, currently exactly once, so splitting this up should
77  * help avoid typo bugs.
78  */
safe_strtoull_hex(const char * str,uint64_t * out)79 bool safe_strtoull_hex(const char *str, uint64_t *out) {
80     assert(out != NULL);
81     errno = 0;
82     *out = 0;
83     char *endptr;
84     unsigned long long ull = strtoull(str, &endptr, 16);
85     if ((errno == ERANGE) || (str == endptr)) {
86         return false;
87     }
88 
89     if (xisspace(*endptr) || (*endptr == '\0' && endptr != str)) {
90         if ((long long) ull < 0) {
91             /* only check for negative signs in the uncommon case when
92              * the unsigned number is so big that it's negative as a
93              * signed number. */
94             if (memchr(str, '-', endptr - str) != NULL) {
95                 return false;
96             }
97         }
98         *out = ull;
99         return true;
100     }
101     return false;
102 }
103 
safe_strtoll(const char * str,int64_t * out)104 bool safe_strtoll(const char *str, int64_t *out) {
105     assert(out != NULL);
106     errno = 0;
107     *out = 0;
108     char *endptr;
109     long long ll = strtoll(str, &endptr, 10);
110     if ((errno == ERANGE) || (str == endptr)) {
111         return false;
112     }
113 
114     if (xisspace(*endptr) || (*endptr == '\0' && endptr != str)) {
115         *out = ll;
116         return true;
117     }
118     return false;
119 }
120 
safe_strtoul(const char * str,uint32_t * out)121 bool safe_strtoul(const char *str, uint32_t *out) {
122     char *endptr = NULL;
123     unsigned long l = 0;
124     assert(out);
125     assert(str);
126     *out = 0;
127     errno = 0;
128 
129     l = strtoul(str, &endptr, 10);
130     if ((errno == ERANGE) || (str == endptr)) {
131         return false;
132     }
133 
134     if (xisspace(*endptr) || (*endptr == '\0' && endptr != str)) {
135         if ((long) l < 0) {
136             /* only check for negative signs in the uncommon case when
137              * the unsigned number is so big that it's negative as a
138              * signed number. */
139             if (memchr(str, '-', endptr - str) != NULL) {
140                 return false;
141             }
142         }
143         *out = l;
144         return true;
145     }
146 
147     return false;
148 }
149 
safe_strtol(const char * str,int32_t * out)150 bool safe_strtol(const char *str, int32_t *out) {
151     assert(out != NULL);
152     errno = 0;
153     *out = 0;
154     char *endptr;
155     long l = strtol(str, &endptr, 10);
156     if ((errno == ERANGE) || (str == endptr)) {
157         return false;
158     }
159 
160     if (xisspace(*endptr) || (*endptr == '\0' && endptr != str)) {
161         *out = l;
162         return true;
163     }
164     return false;
165 }
166 
safe_strtod(const char * str,double * out)167 bool safe_strtod(const char *str, double *out) {
168     assert(out != NULL);
169     errno = 0;
170     *out = 0;
171     char *endptr;
172     double d = strtod(str, &endptr);
173     if ((errno == ERANGE) || (str == endptr)) {
174         return false;
175     }
176 
177     if (xisspace(*endptr) || (*endptr == '\0' && endptr != str)) {
178         *out = d;
179         return true;
180     }
181     return false;
182 }
183 
184 // slow, safe function for copying null terminated buffers.
185 // ensures null terminator set on destination buffer. copies at most dstmax-1
186 // non-null bytes.
187 // Explicitly avoids over-reading src while looking for the null byte.
188 // returns true if src was fully copied.
189 // returns false if src was truncated into dst.
safe_strcpy(char * dst,const char * src,const size_t dstmax)190 bool safe_strcpy(char *dst, const char *src, const size_t dstmax) {
191    size_t x;
192 
193    for (x = 0; x < dstmax - 1 && src[x] != '\0'; x++) {
194         dst[x] = src[x];
195    }
196 
197    dst[x] = '\0';
198 
199    if (src[x] == '\0') {
200        return true;
201    } else {
202        return false;
203    }
204 }
205 
safe_memcmp(const void * a,const void * b,size_t len)206 bool safe_memcmp(const void *a, const void *b, size_t len) {
207     const volatile unsigned char *ua = (const volatile unsigned char *)a;
208     const volatile unsigned char *ub = (const volatile unsigned char *)b;
209     int delta = 0;
210     size_t x;
211 
212     for (x = 0; x < len; x++) {
213         delta |= ua[x] ^ ub[x];
214     }
215 
216     if (delta == 0) {
217         return true;
218     } else {
219         return false;
220     }
221 }
222 
vperror(const char * fmt,...)223 void vperror(const char *fmt, ...) {
224     int old_errno = errno;
225     char buf[1024];
226     va_list ap;
227 
228     va_start(ap, fmt);
229     if (vsnprintf(buf, sizeof(buf), fmt, ap) == -1) {
230         buf[sizeof(buf) - 1] = '\0';
231     }
232     va_end(ap);
233 
234     errno = old_errno;
235 
236     perror(buf);
237 }
238 
239 #ifndef HAVE_HTONLL
mc_swap64(uint64_t in)240 static uint64_t mc_swap64(uint64_t in) {
241 #ifdef ENDIAN_LITTLE
242     /* Little endian, flip the bytes around until someone makes a faster/better
243     * way to do this. */
244     int64_t rv = 0;
245     int i = 0;
246      for(i = 0; i<8; i++) {
247         rv = (rv << 8) | (in & 0xff);
248         in >>= 8;
249      }
250     return rv;
251 #else
252     /* big-endian machines don't need byte swapping */
253     return in;
254 #endif
255 }
256 
ntohll(uint64_t val)257 uint64_t ntohll(uint64_t val) {
258    return mc_swap64(val);
259 }
260 
htonll(uint64_t val)261 uint64_t htonll(uint64_t val) {
262    return mc_swap64(val);
263 }
264 #endif
265 
266