Merge lp:~rodrigo-moya/couchdb-glib/oauth-signing into lp:couchdb-glib
- oauth-signing
- Merge into trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~rodrigo-moya/couchdb-glib/oauth-signing |
Merge into: | lp:couchdb-glib |
Diff against target: | None lines |
To merge this branch: | bzr merge lp:~rodrigo-moya/couchdb-glib/oauth-signing |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
dobey (community) | Needs Fixing | ||
Review via email: mp+11187@code.launchpad.net |
This proposal has been superseded by a proposal from 2009-09-08.
Commit message
Description of the change
Rodrigo Moya (rodrigo-moya) wrote : | # |
- 90. By Rodrigo Moya
-
Added missing 'return TRUE' in couchdb_
enable_ oauth - 91. By Rodrigo Moya
-
Remove extra ;
dobey (dobey) wrote : | # |
The oauth files will fail to dist here if oauth is not enabled. You should add a OAUTH_FILES variable, and assign OAUTH_SOURCES to it when enabled, and add OAUTH_FILES to extra dist, to ensure the files are always disted.
- 92. By Rodrigo Moya
-
Parse the signed URL returned by oauth_sign_url2 and create the Authorization header with that
- 93. By Rodrigo Moya
-
Decode the signature
- 94. By Rodrigo Moya
-
Make sure OAuth sources get disted
- 95. By Rodrigo Moya
-
No need to decode signature, and removed None keys in Authentication header
- 96. By Rodrigo Moya
-
Simplified URL parsing
- 97. By Rodrigo Moya
-
Added " to all values
- 98. By Rodrigo Moya
-
Added test programs
- 99. By Rodrigo Moya
-
Encode correctly the base_signature
- 100. By Rodrigo Moya
-
Added a better output for test-oauth program
- 101. By Rodrigo Moya
-
Add oauth_verifier and oauth_callback arguments and added couchdb connection code to test-oauth
- 102. By Rodrigo Moya
-
Add OAuth prefix to Authorization header (thanks to Jason Davies)
Unmerged revisions
- 102. By Rodrigo Moya
-
Add OAuth prefix to Authorization header (thanks to Jason Davies)
- 101. By Rodrigo Moya
-
Add oauth_verifier and oauth_callback arguments and added couchdb connection code to test-oauth
- 100. By Rodrigo Moya
-
Added a better output for test-oauth program
- 99. By Rodrigo Moya
-
Encode correctly the base_signature
- 98. By Rodrigo Moya
-
Added test programs
- 97. By Rodrigo Moya
-
Added " to all values
- 96. By Rodrigo Moya
-
Simplified URL parsing
- 95. By Rodrigo Moya
-
No need to decode signature, and removed None keys in Authentication header
- 94. By Rodrigo Moya
-
Make sure OAuth sources get disted
- 93. By Rodrigo Moya
-
Decode the signature
Preview Diff
1 | === modified file 'configure.ac' |
2 | --- configure.ac 2009-08-31 15:48:46 +0000 |
3 | +++ configure.ac 2009-09-04 09:28:53 +0000 |
4 | @@ -18,6 +18,18 @@ |
5 | dnl glib-genmarshal |
6 | AC_PATH_PROG(GLIB_GENMARSHAL, glib-genmarshal) |
7 | |
8 | +dnl Check for oAuth dependencies |
9 | +have_oauth="no" |
10 | +AC_CHECK_HEADERS(unistd.h time.h string.h alloca.h stdio.h stdarg.h math.h openssl/hmac.h, have_oauth_headers="yes", have_oauth_headers="no") |
11 | +AC_CHECK_LIB(crypto, CRYPTO_free, have_oauth_libs="yes", have_oauth_libs="no") |
12 | +if test "x$have_oauth_headers" = "xyes" -a "x$have_oauth_libs" = "xyes"; then |
13 | + AC_DEFINE(HAVE_OAUTH, 1, [Define to build OAUTH signing code]) |
14 | + have_oauth="yes" |
15 | + OAUTH_LIBS="-lm -lcrypto" |
16 | + AC_SUBST(OAUTH_LIBS) |
17 | +fi |
18 | +AM_CONDITIONAL(HAVE_OAUTH, test "x$have_oauth" = "xyes") |
19 | + |
20 | dnl Look for needed modules |
21 | PKG_CHECK_MODULES(COUCHDB_GLIB, glib-2.0 gobject-2.0 json-glib-1.0 >= 0.7.4 libsoup-2.4 libsoup-gnome-2.4 uuid) |
22 | AC_SUBST(COUCHDB_GLIB_CFLAGS) |
23 | @@ -36,3 +48,13 @@ |
24 | couchdb-glib/Makefile |
25 | tests/Makefile |
26 | ]) |
27 | + |
28 | +AC_MSG_NOTICE([ |
29 | + |
30 | + couchdb-glib configured: |
31 | + ------------------------ |
32 | + |
33 | + version: $VERSION |
34 | + oAuth: $have_oauth |
35 | + |
36 | +]) |
37 | \ No newline at end of file |
38 | |
39 | === modified file 'couchdb-glib/Makefile.am' |
40 | --- couchdb-glib/Makefile.am 2009-08-31 15:48:46 +0000 |
41 | +++ couchdb-glib/Makefile.am 2009-09-04 09:28:53 +0000 |
42 | @@ -1,3 +1,11 @@ |
43 | +if HAVE_OAUTH |
44 | +OAUTH_SOURCES = oauth.c oauth.h xmalloc.c xmalloc.h |
45 | +OAUTH_LIBS = |
46 | +else |
47 | +OAUTH_SOURCES = |
48 | +OAUTH_LIBS = |
49 | +endif |
50 | + |
51 | INCLUDES = \ |
52 | $(COUCHDB_GLIB_CFLAGS) |
53 | |
54 | @@ -20,10 +28,12 @@ |
55 | couchdb-types.c \ |
56 | dbwatch.c \ |
57 | dbwatch.h \ |
58 | + $(OAUTH_SOURCES) \ |
59 | utils.c \ |
60 | utils.h |
61 | libcouchdb_glib_1_0_la_LIBADD = \ |
62 | $(COUCHDB_GLIB_LIBS) \ |
63 | + $(OAUTH_LIBS) \ |
64 | -luuid |
65 | libcouchdb_glib_1_0_la_LDFLAGS = \ |
66 | -version-info $(LIBCOUCHDBGLIB_CURRENT):$(LIBCOUCHDBGLIB_REVISION):$(LIBCOUCHDBGLIB_AGE) |
67 | |
68 | === modified file 'couchdb-glib/couchdb-glib.h' |
69 | --- couchdb-glib/couchdb-glib.h 2009-08-31 15:48:46 +0000 |
70 | +++ couchdb-glib/couchdb-glib.h 2009-09-04 09:28:53 +0000 |
71 | @@ -64,6 +64,13 @@ |
72 | |
73 | void couchdb_listen_for_changes (CouchDB *couchdb, const char *dbname); |
74 | |
75 | +gboolean couchdb_enable_oauth (CouchDB *couchdb, |
76 | + const char *consumer_key, |
77 | + const char *consumer_secret, |
78 | + const char *token_key, |
79 | + const char *token_secret); |
80 | +void couchdb_disable_oauth (CouchDB *couchdb); |
81 | + |
82 | /* |
83 | * Documents API |
84 | */ |
85 | |
86 | === modified file 'couchdb-glib/couchdb.c' |
87 | --- couchdb-glib/couchdb.c 2009-08-31 15:48:46 +0000 |
88 | +++ couchdb-glib/couchdb.c 2009-09-04 09:28:53 +0000 |
89 | @@ -49,6 +49,13 @@ |
90 | g_free (couchdb->hostname); |
91 | g_object_unref (couchdb->http_session); |
92 | |
93 | +#ifdef HAVE_OAUTH |
94 | + g_free (couchdb->oauth_consumer_key); |
95 | + g_free (couchdb->oauth_consumer_secret); |
96 | + g_free (couchdb->oauth_token_key); |
97 | + g_free (couchdb->oauth_token_secret); |
98 | +#endif |
99 | + |
100 | G_OBJECT_CLASS (couchdb_parent_class)->finalize (object); |
101 | } |
102 | |
103 | @@ -375,3 +382,42 @@ |
104 | /* Free memory */ |
105 | couchdb_database_info_unref (db_info); |
106 | } |
107 | + |
108 | +/** |
109 | + * couchdb_enable_oauth: |
110 | + * @couchdb: A #CouchDB object |
111 | + * @consumer_key: Consumer key to use |
112 | + * @consumer_secret: Consumer secret to use |
113 | + * @token_key: Token key to use |
114 | + * @token_secret: Token secret to use |
115 | + * |
116 | + * Enables oAuth signing of all requests for the given #CouchDB object. |
117 | + * |
118 | + * Return value: TRUE if oAuth is enabled in the library or FALSE if not. |
119 | + */ |
120 | +gboolean |
121 | +couchdb_enable_oauth (CouchDB *couchdb, |
122 | + const char *consumer_key, |
123 | + const char *consumer_secret, |
124 | + const char *token_key, |
125 | + const char *token_secret) |
126 | +{ |
127 | + g_return_val_if_fail (COUCHDB_IS (couchdb), FALSE); |
128 | + |
129 | +#ifdef HAVE_OAUTH |
130 | + if (couchdb->oauth_enabled) { |
131 | + g_free (couchdb->oauth_consumer_key); |
132 | + g_free (couchdb->oauth_consumer_secret); |
133 | + g_free (couchdb->oauth_token_key); |
134 | + g_free (couchdb->oauth_token_secret); |
135 | + } |
136 | + |
137 | + couchdb->oauth_consumer_key = g_strdup (consumer_key); |
138 | + couchdb->oauth_consumer_secret = g_strdup (consumer_secret); |
139 | + couchdb->oauth_token_key = g_strdup (token_key); |
140 | + couchdb->oauth_token_secret = g_strdup (token_secret); |
141 | + couchdb->oauth_enabled = TRUE; |
142 | +#else |
143 | + return FALSE; |
144 | +#endif |
145 | +} |
146 | |
147 | === added file 'couchdb-glib/oauth.c' |
148 | --- couchdb-glib/oauth.c 1970-01-01 00:00:00 +0000 |
149 | +++ couchdb-glib/oauth.c 2009-09-04 09:28:53 +0000 |
150 | @@ -0,0 +1,955 @@ |
151 | +/* |
152 | + * oAuth string functions in POSIX-C. |
153 | + * |
154 | + * Copyright 2007, 2008, 2009 Robin Gareus <robin@gareus.org> |
155 | + * |
156 | + * The base64 functions are by Jan-Henrik Haukeland, <hauk@tildeslash.com> |
157 | + * and un/escape_url() was inspired by libcurl's curl_escape under ISC-license |
158 | + * many thanks to Daniel Stenberg <daniel@haxx.se>. |
159 | + * |
160 | + * Permission is hereby granted, free of charge, to any person obtaining a copy |
161 | + * of this software and associated documentation files (the "Software"), to deal |
162 | + * in the Software without restriction, including without limitation the rights |
163 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
164 | + * copies of the Software, and to permit persons to whom the Software is |
165 | + * furnished to do so, subject to the following conditions: |
166 | + * |
167 | + * The above copyright notice and this permission notice shall be included in |
168 | + * all copies or substantial portions of the Software. |
169 | + * |
170 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
171 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
172 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
173 | + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
174 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
175 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
176 | + * THE SOFTWARE. |
177 | + * |
178 | + */ |
179 | +#if HAVE_CONFIG_H |
180 | +# include <config.h> |
181 | +#endif |
182 | + |
183 | +#define WIPE_MEMORY ///< overwrite sensitve data before free()ing it. |
184 | + |
185 | +#include <stdio.h> |
186 | +#include <stdarg.h> |
187 | +#include <stdlib.h> |
188 | +#include <string.h> |
189 | +#include <time.h> |
190 | +#include <math.h> |
191 | +#include <ctype.h> // isxdigit |
192 | +#include <openssl/hmac.h> |
193 | + |
194 | +#include "xmalloc.h" |
195 | +#include "oauth.h" |
196 | + |
197 | +#ifndef WIN // getpid() on POSIX systems |
198 | +#include <sys/types.h> |
199 | +#include <unistd.h> |
200 | +#endif |
201 | + |
202 | +/** |
203 | + * Base64 encode one byte |
204 | + */ |
205 | +char oauth_b64_encode(unsigned char u) { |
206 | + if(u < 26) return 'A'+u; |
207 | + if(u < 52) return 'a'+(u-26); |
208 | + if(u < 62) return '0'+(u-52); |
209 | + if(u == 62) return '+'; |
210 | + return '/'; |
211 | +} |
212 | + |
213 | +/** |
214 | + * Decode a single base64 character. |
215 | + */ |
216 | +unsigned char oauth_b64_decode(char c) { |
217 | + if(c >= 'A' && c <= 'Z') return(c - 'A'); |
218 | + if(c >= 'a' && c <= 'z') return(c - 'a' + 26); |
219 | + if(c >= '0' && c <= '9') return(c - '0' + 52); |
220 | + if(c == '+') return 62; |
221 | + return 63; |
222 | +} |
223 | + |
224 | +/** |
225 | + * Return TRUE if 'c' is a valid base64 character, otherwise FALSE |
226 | + */ |
227 | +int oauth_b64_is_base64(char c) { |
228 | + if((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || |
229 | + (c >= '0' && c <= '9') || (c == '+') || |
230 | + (c == '/') || (c == '=')) { |
231 | + return 1; |
232 | + } |
233 | + return 0; |
234 | +} |
235 | + |
236 | +/** |
237 | + * Base64 encode and return size data in 'src'. The caller must free the |
238 | + * returned string. |
239 | + * |
240 | + * @param size The size of the data in src |
241 | + * @param src The data to be base64 encode |
242 | + * @return encoded string otherwise NULL |
243 | + */ |
244 | +char *oauth_encode_base64(int size, const unsigned char *src) { |
245 | + int i; |
246 | + char *out, *p; |
247 | + |
248 | + if(!src) return NULL; |
249 | + if(!size) size= strlen((char *)src); |
250 | + out= (char*) xcalloc(sizeof(char), size*4/3+4); |
251 | + p= out; |
252 | + |
253 | + for(i=0; i<size; i+=3) { |
254 | + unsigned char b1=0, b2=0, b3=0, b4=0, b5=0, b6=0, b7=0; |
255 | + b1= src[i]; |
256 | + if(i+1<size) b2= src[i+1]; |
257 | + if(i+2<size) b3= src[i+2]; |
258 | + |
259 | + b4= b1>>2; |
260 | + b5= ((b1&0x3)<<4)|(b2>>4); |
261 | + b6= ((b2&0xf)<<2)|(b3>>6); |
262 | + b7= b3&0x3f; |
263 | + |
264 | + *p++= oauth_b64_encode(b4); |
265 | + *p++= oauth_b64_encode(b5); |
266 | + |
267 | + if(i+1<size) *p++= oauth_b64_encode(b6); |
268 | + else *p++= '='; |
269 | + |
270 | + if(i+2<size) *p++= oauth_b64_encode(b7); |
271 | + else *p++= '='; |
272 | + } |
273 | + return out; |
274 | +} |
275 | + |
276 | +/** |
277 | + * Decode the base64 encoded string 'src' into the memory pointed to by |
278 | + * 'dest'. |
279 | + * |
280 | + * @param dest Pointer to memory for holding the decoded string. |
281 | + * Must be large enough to recieve the decoded string. |
282 | + * @param src A base64 encoded string. |
283 | + * @return the length of the decoded string if decode |
284 | + * succeeded otherwise 0. |
285 | + */ |
286 | +int oauth_decode_base64(unsigned char *dest, const char *src) { |
287 | + if(src && *src) { |
288 | + unsigned char *p= dest; |
289 | + int k, l= strlen(src)+1; |
290 | + unsigned char *buf= (unsigned char*) xcalloc(sizeof(unsigned char), l); |
291 | + |
292 | + /* Ignore non base64 chars as per the POSIX standard */ |
293 | + for(k=0, l=0; src[k]; k++) { |
294 | + if(oauth_b64_is_base64(src[k])) { |
295 | + buf[l++]= src[k]; |
296 | + } |
297 | + } |
298 | + |
299 | + for(k=0; k<l; k+=4) { |
300 | + char c1='A', c2='A', c3='A', c4='A'; |
301 | + unsigned char b1=0, b2=0, b3=0, b4=0; |
302 | + c1= buf[k]; |
303 | + |
304 | + if(k+1<l) c2= buf[k+1]; |
305 | + if(k+2<l) c3= buf[k+2]; |
306 | + if(k+3<l) c4= buf[k+3]; |
307 | + |
308 | + b1= oauth_b64_decode(c1); |
309 | + b2= oauth_b64_decode(c2); |
310 | + b3= oauth_b64_decode(c3); |
311 | + b4= oauth_b64_decode(c4); |
312 | + |
313 | + *p++=((b1<<2)|(b2>>4) ); |
314 | + |
315 | + if(c3 != '=') *p++=(((b2&0xf)<<4)|(b3>>2) ); |
316 | + if(c4 != '=') *p++=(((b3&0x3)<<6)|b4 ); |
317 | + } |
318 | + free(buf); |
319 | + dest[p-dest]='\0'; |
320 | + return(p-dest); |
321 | + } |
322 | + return 0; |
323 | +} |
324 | + |
325 | +/** |
326 | + * Escape 'string' according to RFC3986 and |
327 | + * http://oauth.net/core/1.0/#encoding_parameters. |
328 | + * |
329 | + * @param string The data to be encoded |
330 | + * @return encoded string otherwise NULL |
331 | + * The caller must free the returned string. |
332 | + */ |
333 | +char *oauth_url_escape(const char *string) { |
334 | + size_t alloc, newlen; |
335 | + char *ns = NULL, *testing_ptr = NULL; |
336 | + unsigned char in; |
337 | + size_t strindex=0; |
338 | + size_t length; |
339 | + |
340 | + if (!string) return xstrdup(""); |
341 | + |
342 | + alloc = strlen(string)+1; |
343 | + newlen = alloc; |
344 | + |
345 | + ns = (char*) xmalloc(alloc); |
346 | + |
347 | + length = alloc-1; |
348 | + while(length--) { |
349 | + in = *string; |
350 | + |
351 | + switch(in){ |
352 | + case '0': case '1': case '2': case '3': case '4': |
353 | + case '5': case '6': case '7': case '8': case '9': |
354 | + case 'a': case 'b': case 'c': case 'd': case 'e': |
355 | + case 'f': case 'g': case 'h': case 'i': case 'j': |
356 | + case 'k': case 'l': case 'm': case 'n': case 'o': |
357 | + case 'p': case 'q': case 'r': case 's': case 't': |
358 | + case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': |
359 | + case 'A': case 'B': case 'C': case 'D': case 'E': |
360 | + case 'F': case 'G': case 'H': case 'I': case 'J': |
361 | + case 'K': case 'L': case 'M': case 'N': case 'O': |
362 | + case 'P': case 'Q': case 'R': case 'S': case 'T': |
363 | + case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': |
364 | + case '_': case '~': case '.': case '-': |
365 | + ns[strindex++]=in; |
366 | + break; |
367 | + default: |
368 | + newlen += 2; /* this'll become a %XX */ |
369 | + if(newlen > alloc) { |
370 | + alloc *= 2; |
371 | + testing_ptr = (char*) xrealloc(ns, alloc); |
372 | + ns = testing_ptr; |
373 | + } |
374 | + snprintf(&ns[strindex], 4, "%%%02X", in); |
375 | + strindex+=3; |
376 | + break; |
377 | + } |
378 | + string++; |
379 | + } |
380 | + ns[strindex]=0; |
381 | + return ns; |
382 | +} |
383 | + |
384 | +#ifndef ISXDIGIT |
385 | +# define ISXDIGIT(x) (isxdigit((int) ((unsigned char)x))) |
386 | +#endif |
387 | + |
388 | +/** |
389 | + * Parse RFC3986 encoded 'string' back to unescaped version. |
390 | + * |
391 | + * @param string The data to be unescaped |
392 | + * @param olen unless NULL the length of the returned string is stored there. |
393 | + * @return decoded string or NULL |
394 | + * The caller must free the returned string. |
395 | + */ |
396 | +char *oauth_url_unescape(const char *string, size_t *olen) { |
397 | + size_t alloc, strindex=0; |
398 | + char *ns = NULL; |
399 | + unsigned char in; |
400 | + long hex; |
401 | + |
402 | + if (!string) return NULL; |
403 | + alloc = strlen(string)+1; |
404 | + ns = (char*) xmalloc(alloc); |
405 | + |
406 | + while(--alloc > 0) { |
407 | + in = *string; |
408 | + if(('%' == in) && ISXDIGIT(string[1]) && ISXDIGIT(string[2])) { |
409 | + char hexstr[3]; // '%XX' |
410 | + hexstr[0] = string[1]; |
411 | + hexstr[1] = string[2]; |
412 | + hexstr[2] = 0; |
413 | + hex = strtol(hexstr, NULL, 16); |
414 | + in = (unsigned char)hex; /* hex is always < 256 */ |
415 | + string+=2; |
416 | + alloc-=2; |
417 | + } |
418 | + ns[strindex++] = in; |
419 | + string++; |
420 | + } |
421 | + ns[strindex]=0; |
422 | + if(olen) *olen = strindex; |
423 | + return ns; |
424 | +} |
425 | + |
426 | +/** |
427 | + * returns base64 encoded HMAC-SHA1 signature for |
428 | + * given message and key. |
429 | + * both data and key need to be urlencoded. |
430 | + * |
431 | + * the returned string needs to be freed by the caller |
432 | + * |
433 | + * @param m message to be signed |
434 | + * @param k key used for signing |
435 | + * @return signature string. |
436 | + */ |
437 | +char *oauth_sign_hmac_sha1 (const char *m, const char *k) { |
438 | + return(oauth_sign_hmac_sha1_raw (m, strlen(m), k, strlen(k))); |
439 | +} |
440 | + |
441 | +char *oauth_sign_hmac_sha1_raw (const char *m, const size_t ml, const char *k, const size_t kl) { |
442 | + unsigned char result[EVP_MAX_MD_SIZE]; |
443 | + unsigned int resultlen = 0; |
444 | + |
445 | + HMAC(EVP_sha1(), k, kl, |
446 | + (unsigned char*) m, ml, |
447 | + result, &resultlen); |
448 | + |
449 | + return(oauth_encode_base64(resultlen, result)); |
450 | +} |
451 | + |
452 | +/** |
453 | + * returns plaintext signature for the given key. |
454 | + * |
455 | + * the returned string needs to be freed by the caller |
456 | + * |
457 | + * @param m message to be signed |
458 | + * @param k key used for signing |
459 | + * @return signature string |
460 | + */ |
461 | +char *oauth_sign_plaintext (const char *m, const char *k) { |
462 | + return(oauth_url_escape(k)); |
463 | +} |
464 | + |
465 | +#include <openssl/evp.h> |
466 | +#include <openssl/x509.h> |
467 | +#include <openssl/x509v3.h> |
468 | +#include <openssl/ssl.h> |
469 | + |
470 | +/** |
471 | + * returns RSA-SHA1 signature for given data. |
472 | + * the returned signature needs to be freed by the caller. |
473 | + * |
474 | + * @param m message to be signed |
475 | + * @param k private-key PKCS and Base64-encoded |
476 | + * @return base64 encoded signature string. |
477 | + */ |
478 | +char *oauth_sign_rsa_sha1 (const char *m, const char *k) { |
479 | + unsigned char *sig = NULL; |
480 | + unsigned char *passphrase = NULL; |
481 | + unsigned int len=0; |
482 | + EVP_MD_CTX md_ctx; |
483 | + |
484 | + EVP_PKEY *pkey; |
485 | + BIO *in; |
486 | + in = BIO_new_mem_buf((unsigned char*) k, strlen(k)); |
487 | + pkey = PEM_read_bio_PrivateKey(in, NULL, 0, passphrase); // generate sign |
488 | + BIO_free(in); |
489 | + |
490 | + if (pkey == NULL) { |
491 | + //fprintf(stderr, "liboauth/ssl: can not read private key\n"); |
492 | + return xstrdup("liboauth/ssl: can not read private key"); |
493 | + } |
494 | + |
495 | + len = EVP_PKEY_size(pkey); |
496 | + sig = xmalloc((len+1)*sizeof(char)); |
497 | + |
498 | + EVP_SignInit(&md_ctx, EVP_sha1()); |
499 | + EVP_SignUpdate(&md_ctx, m, strlen(m)); |
500 | + if (EVP_SignFinal (&md_ctx, sig, &len, pkey)) { |
501 | + char *tmp; |
502 | + sig[len] = '\0'; |
503 | + tmp = oauth_encode_base64(len,sig); |
504 | + OPENSSL_free(sig); |
505 | + EVP_PKEY_free(pkey); |
506 | + return tmp; |
507 | + } |
508 | + return xstrdup("liboauth/ssl: rsa-sha1 signing failed"); |
509 | +} |
510 | + |
511 | +/** |
512 | + * verify RSA-SHA1 signature. |
513 | + * |
514 | + * returns the output of EVP_VerifyFinal() for a given message, |
515 | + * cert/pubkey and signature |
516 | + * |
517 | + * @param m message to be verified |
518 | + * @param c public-key or x509 certificate |
519 | + * @param s base64 encoded signature |
520 | + * @return 1 for a correct signature, 0 for failure and -1 if some other error occurred |
521 | + */ |
522 | +int oauth_verify_rsa_sha1 (const char *m, const char *c, const char *s) { |
523 | + EVP_MD_CTX md_ctx; |
524 | + EVP_PKEY *pkey; |
525 | + BIO *in; |
526 | + X509 *cert = NULL; |
527 | + unsigned char *b64d; |
528 | + int slen, err; |
529 | + |
530 | + in = BIO_new_mem_buf((unsigned char*)c, strlen(c)); |
531 | + cert = PEM_read_bio_X509(in, NULL, 0, NULL); |
532 | + if (cert) { |
533 | + pkey = (EVP_PKEY *) X509_get_pubkey(cert); |
534 | + X509_free(cert); |
535 | + } else { |
536 | + pkey = PEM_read_bio_PUBKEY(in, NULL, 0, NULL); |
537 | + } |
538 | + BIO_free(in); |
539 | + if (pkey == NULL) { |
540 | + //fprintf(stderr, "could not read cert/pubkey.\n"); |
541 | + return -2; |
542 | + } |
543 | + |
544 | + b64d= (unsigned char*) xmalloc(sizeof(char)*strlen(s)); |
545 | + slen = oauth_decode_base64(b64d, s); |
546 | + |
547 | + EVP_VerifyInit(&md_ctx, EVP_sha1()); |
548 | + EVP_VerifyUpdate(&md_ctx, m, strlen(m)); |
549 | + err = EVP_VerifyFinal(&md_ctx, b64d, slen, pkey); |
550 | + EVP_MD_CTX_cleanup(&md_ctx); |
551 | + EVP_PKEY_free(pkey); |
552 | + free(b64d); |
553 | + return (err); |
554 | +} |
555 | + |
556 | +/** |
557 | + * encode strings and concatenate with '&' separator. |
558 | + * The number of strings to be concatenated must be |
559 | + * given as first argument. |
560 | + * all arguments thereafter must be of type (char *) |
561 | + * |
562 | + * @param len the number of arguments to follow this parameter |
563 | + * @param ... string to escape and added (may be NULL) |
564 | + * |
565 | + * @return pointer to memory holding the concatenated |
566 | + * strings - needs to be free(d) by the caller. or NULL |
567 | + * in case we ran out of memory. |
568 | + */ |
569 | +char *oauth_catenc(int len, ...) { |
570 | + va_list va; |
571 | + int i; |
572 | + char *rv = (char*) xmalloc(sizeof(char)); |
573 | + *rv='\0'; |
574 | + va_start(va, len); |
575 | + for(i=0;i<len;i++) { |
576 | + char *arg = va_arg(va, char *); |
577 | + char *enc; |
578 | + int len; |
579 | + enc = oauth_url_escape(arg); |
580 | + if(!enc) break; |
581 | + len = strlen(enc) + 1 + ((i>0)?1:0); |
582 | + if(rv) len+=strlen(rv); |
583 | + rv=(char*) xrealloc(rv,len*sizeof(char)); |
584 | + |
585 | + if(i>0) strcat(rv, "&"); |
586 | + strcat(rv, enc); |
587 | + free(enc); |
588 | + } |
589 | + va_end(va); |
590 | + return(rv); |
591 | +} |
592 | + |
593 | +/** |
594 | + * splits the given url into a parameter array. |
595 | + * (see \ref oauth_serialize_url and \ref oauth_serialize_url_parameters for the reverse) |
596 | + * |
597 | + * NOTE: Request-parameters-values may include an ampersand character. |
598 | + * However if unescaped this function will use them as parameter delimiter. |
599 | + * If you need to make such a request, this function since version 0.3.5 allows |
600 | + * to use the ASCII SOH (0x01) character as alias for '&' (0x26). |
601 | + * (the motivation is convenience: SOH is /untypeable/ and much more |
602 | + * unlikely to appear than '&' - If you plan to sign fancy URLs you |
603 | + * should not split a query-string, but rather provide the parameter array |
604 | + * directly to \ref oauth_serialize_url) |
605 | + * |
606 | + * @param url the url or query-string to parse. |
607 | + * @param argv pointer to a (char *) array where the results are stored. |
608 | + * The array is re-allocated to match the number of parameters and each |
609 | + * parameter-string is allocated with strdup. - The memory needs to be freed |
610 | + * by the caller. |
611 | + * @param qesc use query parameter escape (vs post-param-escape) - if set |
612 | + * to 1 all '+' are treated as spaces ' ' |
613 | + * |
614 | + * @return number of parameter(s) in array. |
615 | + */ |
616 | +int oauth_split_post_paramters(const char *url, char ***argv, short qesc) { |
617 | + int argc=0; |
618 | + char *token, *tmp, *t1; |
619 | + if (!argv) return 0; |
620 | + if (!url) return 0; |
621 | + t1=xstrdup(url); |
622 | + |
623 | + // '+' represents a space, in a URL query string |
624 | + while ((qesc&1) && (tmp=strchr(t1,'+'))) *tmp=' '; |
625 | + |
626 | + tmp=t1; |
627 | + while((token=strtok(tmp,"&?"))) { |
628 | + if(!strncasecmp("oauth_signature=",token,16)) continue; |
629 | + (*argv)=(char**) xrealloc(*argv,sizeof(char*)*(argc+1)); |
630 | + while (!(qesc&2) && (tmp=strchr(token,'\001'))) *tmp='&'; |
631 | + (*argv)[argc]=oauth_url_unescape(token, NULL); |
632 | + if (argc==0 && strstr(token, ":/")) { |
633 | + // HTTP does not allow empty absolute paths, so the URL |
634 | + // 'http://example.com' is equivalent to 'http://example.com/' and should |
635 | + // be treated as such for the purposes of OAuth signing (rfc2616, section 3.2.1) |
636 | + // see http://groups.google.com/group/oauth/browse_thread/thread/c44b6f061bfd98c?hl=en |
637 | + char *slash=strstr(token, ":/"); |
638 | + while (slash && *(++slash) == '/') ; // skip slashes eg /xxx:[\/]*/ |
639 | +#if 0 |
640 | + // skip possibly unescaped slashes in the userinfo - they're not allowed by RFC2396 but have been seen. |
641 | + // the hostname/IP may only contain alphanumeric characters - so we're safe there. |
642 | + if (slash && strchr(slash,'@')) slash=strchr(slash,'@'); |
643 | +#endif |
644 | + if (slash && !strchr(slash,'/')) { |
645 | +#ifdef DEBUG_OAUTH |
646 | + fprintf(stderr, "\nliboauth: added trailing slash to URL: '%s'\n\n", token); |
647 | +#endif |
648 | + free((*argv)[argc]); |
649 | + (*argv)[argc]= (char*) xmalloc(sizeof(char)*(2+strlen(token))); |
650 | + strcpy((*argv)[argc],token); |
651 | + strcat((*argv)[argc],"/"); |
652 | + } |
653 | + } |
654 | + if (argc==0 && (tmp=strstr((*argv)[argc],":80/"))) { |
655 | + memmove(tmp, tmp+3, strlen(tmp+2)); |
656 | + } |
657 | + tmp=NULL; |
658 | + argc++; |
659 | + } |
660 | + |
661 | + free(t1); |
662 | + return argc; |
663 | +} |
664 | + |
665 | +int oauth_split_url_parameters(const char *url, char ***argv) { |
666 | + return oauth_split_post_paramters(url, argv, 1); |
667 | +} |
668 | + |
669 | +/** |
670 | + * build a url query string from an array. |
671 | + * |
672 | + * @param argc the total number of elements in the array |
673 | + * @param start element in the array at which to start concatenating. |
674 | + * @param argv parameter-array to concatenate. |
675 | + * @return url string needs to be freed by the caller. |
676 | + * |
677 | + */ |
678 | +char *oauth_serialize_url (int argc, int start, char **argv) { |
679 | + return oauth_serialize_url_sep( argc, start, argv, "&"); |
680 | +} |
681 | + |
682 | +/** |
683 | + * encode query parameters from an array. |
684 | + * |
685 | + * @param argc the total number of elements in the array |
686 | + * @param start element in the array at which to start concatenating. |
687 | + * @param argv parameter-array to concatenate. |
688 | + * @param sep separator for parameters (usually "&") |
689 | + * @return url string needs to be freed by the caller. |
690 | + */ |
691 | +char *oauth_serialize_url_sep (int argc, int start, char **argv, char *sep) { |
692 | + char *tmp, *t1; |
693 | + int i; |
694 | + int first=0; |
695 | + int seplen=strlen(sep); |
696 | + char *query = (char*) xmalloc(sizeof(char)); |
697 | + *query='\0'; |
698 | + for(i=start; i< argc; i++) { |
699 | + int len = 0; |
700 | + if (query) len+=strlen(query); |
701 | + |
702 | + if (i==start && i==0 && strstr(argv[i], ":/")) { |
703 | + tmp=xstrdup(argv[i]); |
704 | + len+=strlen(tmp); |
705 | + } else if(!(t1=strchr(argv[i], '='))) { |
706 | + // see http://oauth.net/core/1.0/#anchor14 |
707 | + // escape parameter names and arguments but not the '=' |
708 | + tmp=xstrdup(argv[i]); |
709 | + tmp=(char*) xrealloc(tmp,(strlen(tmp)+2)*sizeof(char)); |
710 | + strcat(tmp,"="); |
711 | + len+=strlen(tmp); |
712 | + } else { |
713 | + *t1=0; |
714 | + tmp = oauth_url_escape(argv[i]); |
715 | + *t1='='; |
716 | + t1 = oauth_url_escape((t1+1)); |
717 | + tmp=(char*) xrealloc(tmp,(strlen(tmp)+strlen(t1)+2)*sizeof(char)); |
718 | + strcat(tmp,"="); |
719 | + strcat(tmp,t1); |
720 | + free(t1); |
721 | + len+=strlen(tmp); |
722 | + } |
723 | + len+=seplen+1; |
724 | + query=(char*) xrealloc(query,len*sizeof(char)); |
725 | + strcat(query, ((i==start||first)?"":sep)); |
726 | + first=0; |
727 | + strcat(query, tmp); |
728 | + if (i==start && i==0 && strstr(tmp, ":/")) { |
729 | + strcat(query, "?"); |
730 | + first=1; |
731 | + } |
732 | + free(tmp); |
733 | + } |
734 | + return (query); |
735 | +} |
736 | + |
737 | +/** |
738 | + * build a query parameter string from an array. |
739 | + * |
740 | + * This function is a shortcut for \ref oauth_serialize_url (argc, 1, argv). |
741 | + * It strips the leading host/path, which is usually the first |
742 | + * element when using oauth_split_url_parameters on an URL. |
743 | + * |
744 | + * @param argc the total number of elements in the array |
745 | + * @param argv parameter-array to concatenate. |
746 | + * @return url string needs to be freed by the caller. |
747 | + */ |
748 | +char *oauth_serialize_url_parameters (int argc, char **argv) { |
749 | + return oauth_serialize_url(argc, 1, argv); |
750 | +} |
751 | + |
752 | +/** |
753 | + * generate a random string between 15 and 32 chars length |
754 | + * and return a pointer to it. The value needs to be freed by the |
755 | + * caller |
756 | + * |
757 | + * @return zero terminated random string. |
758 | + */ |
759 | +char *oauth_gen_nonce() { |
760 | + char *nc; |
761 | + static int rndinit = 1; |
762 | + const char *chars = "abcdefghijklmnopqrstuvwxyz" |
763 | + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789_"; |
764 | + unsigned int max = strlen( chars ); |
765 | + int i, len; |
766 | + |
767 | + if(rndinit) {srand(time(NULL) |
768 | +#ifndef WIN // quick windows check. |
769 | + * getpid() |
770 | +#endif |
771 | + ); rndinit=0;} // seed random number generator - FIXME: we can do better ;) |
772 | + |
773 | + len=15+floor(rand()*16.0/(double)RAND_MAX); |
774 | + nc = (char*) xmalloc((len+1)*sizeof(char)); |
775 | + for(i=0;i<len; i++) { |
776 | + nc[i] = chars[ rand() % max ]; |
777 | + } |
778 | + nc[i]='\0'; |
779 | + return (nc); |
780 | +} |
781 | + |
782 | +/** |
783 | + * string compare function for oauth parameters. |
784 | + * |
785 | + * used with qsort. needed to normalize request parameters. |
786 | + * see http://oauth.net/core/1.0/#anchor14 |
787 | + */ |
788 | +int oauth_cmpstringp(const void *p1, const void *p2) { |
789 | + char *v1,*v2; |
790 | + char *t1,*t2; |
791 | + int rv; |
792 | + // TODO: this is not fast - we should escape the |
793 | + // array elements (once) before sorting. |
794 | + v1=oauth_url_escape(* (char * const *)p1); |
795 | + v2=oauth_url_escape(* (char * const *)p2); |
796 | + |
797 | + // '=' signs are not "%3D" ! |
798 | + if ((t1=strstr(v1,"%3D"))) { |
799 | + t1[0]='\0'; t1[1]='='; t1[2]='='; |
800 | + } |
801 | + if ((t2=strstr(v2,"%3D"))) { |
802 | + t2[0]='\0'; t2[1]='='; t2[2]='='; |
803 | + } |
804 | + |
805 | + // compare parameter names |
806 | + rv=strcmp(v1,v2); |
807 | + if (rv!=0) { |
808 | + if (v1) free(v1); |
809 | + if (v2) free(v2); |
810 | + return rv; |
811 | + } |
812 | + |
813 | + // if parameter names are equal, sort by value. |
814 | + if (t1) t1[0]='='; |
815 | + if (t2) t2[0]='='; |
816 | + rv=strcmp(t1,t2); |
817 | + if (v1) free(v1); |
818 | + if (v2) free(v2); |
819 | + return rv; |
820 | +} |
821 | + |
822 | +/** |
823 | + * search array for parameter key. |
824 | + * @param argv length of array to search |
825 | + * @param argc parameter array to search |
826 | + * @param key key of parameter to check. |
827 | + * |
828 | + * @return FALSE (0) if array does not contain a paramater with given key, TRUE (1) otherwise. |
829 | + */ |
830 | +int oauth_param_exists(char **argv, int argc, char *key) { |
831 | + int i; |
832 | + size_t l= strlen(key); |
833 | + for (i=0;i<argc;i++) |
834 | + if (strlen(argv[i])>l && !strncmp(argv[i],key,l) && argv[i][l] == '=') return 1; |
835 | + return 0; |
836 | +} |
837 | + |
838 | +/** |
839 | + * add query parameter to array |
840 | + * |
841 | + * @param argcp pointer to array length int |
842 | + * @param argvp pointer to array values |
843 | + * @param addparam parameter to add (eg. "foo=bar") |
844 | + */ |
845 | +void oauth_add_param_to_array(int *argcp, char ***argvp, const char *addparam) { |
846 | + (*argvp)=(char**) xrealloc(*argvp,sizeof(char*)*((*argcp)+1)); |
847 | + (*argvp)[(*argcp)++]= (char*) xstrdup(addparam); |
848 | +} |
849 | + |
850 | +/** |
851 | + * |
852 | + */ |
853 | +void oauth_add_protocol(int *argcp, char ***argvp, |
854 | + OAuthMethod method, |
855 | + const char *c_key, //< consumer key - posted plain text |
856 | + const char *t_key //< token key - posted plain text in URL |
857 | + ){ |
858 | + char oarg[1024]; |
859 | + |
860 | + // add oAuth specific arguments |
861 | + if (!oauth_param_exists(*argvp,*argcp,"oauth_nonce")) { |
862 | + char *tmp; |
863 | + snprintf(oarg, 1024, "oauth_nonce=%s", (tmp=oauth_gen_nonce())); |
864 | + oauth_add_param_to_array(argcp, argvp, oarg); |
865 | + free(tmp); |
866 | + } |
867 | + |
868 | + if (!oauth_param_exists(*argvp,*argcp,"oauth_timestamp")) { |
869 | + snprintf(oarg, 1024, "oauth_timestamp=%li", (long int) time(NULL)); |
870 | + oauth_add_param_to_array(argcp, argvp, oarg); |
871 | + } |
872 | + |
873 | + if (t_key) { |
874 | + snprintf(oarg, 1024, "oauth_token=%s", t_key); |
875 | + oauth_add_param_to_array(argcp, argvp, oarg); |
876 | + } |
877 | + |
878 | + snprintf(oarg, 1024, "oauth_consumer_key=%s", c_key); |
879 | + oauth_add_param_to_array(argcp, argvp, oarg); |
880 | + |
881 | + snprintf(oarg, 1024, "oauth_signature_method=%s", |
882 | + method==0?"HMAC-SHA1":method==1?"RSA-SHA1":"PLAINTEXT"); |
883 | + oauth_add_param_to_array(argcp, argvp, oarg); |
884 | + |
885 | + if (!oauth_param_exists(*argvp,*argcp,"oauth_version")) { |
886 | + snprintf(oarg, 1024, "oauth_version=1.0"); |
887 | + oauth_add_param_to_array(argcp, argvp, oarg); |
888 | + } |
889 | + |
890 | +#if 0 // oauth_version 1.0 Rev A |
891 | + if (!oauth_param_exists(argv,argc,"oauth_callback")) { |
892 | + snprintf(oarg, 1024, "oauth_callback=oob"); |
893 | + oauth_add_param_to_array(argcp, argvp, oarg); |
894 | + } |
895 | +#endif |
896 | + |
897 | +} |
898 | + |
899 | +char *oauth_sign_url (const char *url, char **postargs, |
900 | + OAuthMethod method, |
901 | + const char *c_key, //< consumer key - posted plain text |
902 | + const char *c_secret, //< consumer secret - used as 1st part of secret-key |
903 | + const char *t_key, //< token key - posted plain text in URL |
904 | + const char *t_secret //< token secret - used as 2st part of secret-key |
905 | + ) { |
906 | + return oauth_sign_url2(url, postargs, |
907 | + method, NULL, |
908 | + c_key, c_secret, |
909 | + t_key, t_secret); |
910 | +} |
911 | + |
912 | +char *oauth_sign_url2 (const char *url, char **postargs, |
913 | + OAuthMethod method, |
914 | + const char *http_method, //< HTTP request method |
915 | + const char *c_key, //< consumer key - posted plain text |
916 | + const char *c_secret, //< consumer secret - used as 1st part of secret-key |
917 | + const char *t_key, //< token key - posted plain text in URL |
918 | + const char *t_secret //< token secret - used as 2st part of secret-key |
919 | + ) { |
920 | + int argc; |
921 | + char **argv = NULL; |
922 | + char *rv; |
923 | + |
924 | + if (postargs) |
925 | + argc = oauth_split_post_paramters(url, &argv, 0); |
926 | + else |
927 | + argc = oauth_split_url_parameters(url, &argv); |
928 | + |
929 | + rv=oauth_sign_array2(&argc, &argv, postargs, |
930 | + method, http_method, |
931 | + c_key, c_secret, t_key, t_secret); |
932 | + |
933 | + oauth_free_array(&argc, &argv); |
934 | + return(rv); |
935 | +} |
936 | + |
937 | +char *oauth_sign_array (int *argcp, char***argvp, |
938 | + char **postargs, |
939 | + OAuthMethod method, |
940 | + const char *c_key, //< consumer key - posted plain text |
941 | + const char *c_secret, //< consumer secret - used as 1st part of secret-key |
942 | + const char *t_key, //< token key - posted plain text in URL |
943 | + const char *t_secret //< token secret - used as 2st part of secret-key |
944 | + ) { |
945 | + return oauth_sign_array2 (argcp, argvp, |
946 | + postargs, method, |
947 | + NULL, |
948 | + c_key, c_secret, |
949 | + t_key, t_secret); |
950 | +} |
951 | + |
952 | +char *oauth_sign_array2 (int *argcp, char***argvp, |
953 | + char **postargs, |
954 | + OAuthMethod method, |
955 | + const char *http_method, //< HTTP request method |
956 | + const char *c_key, //< consumer key - posted plain text |
957 | + const char *c_secret, //< consumer secret - used as 1st part of secret-key |
958 | + const char *t_key, //< token key - posted plain text in URL |
959 | + const char *t_secret //< token secret - used as 2st part of secret-key |
960 | + ) { |
961 | + char oarg[1024]; |
962 | + char *query; |
963 | + char *okey, *odat, *sign; |
964 | + char *result; |
965 | + char *http_request_method; |
966 | + |
967 | + if (!http_method) { |
968 | + http_request_method = xstrdup(postargs?"POST":"GET"); |
969 | + } else { |
970 | + int i; |
971 | + http_request_method = xstrdup(http_method); |
972 | + for (i=0;i<strlen(http_request_method);i++) |
973 | + http_request_method[i]=toupper(http_request_method[i]); |
974 | + } |
975 | + |
976 | + // add OAuth protocol parameters |
977 | + oauth_add_protocol(argcp, argvp, method, c_key, t_key); |
978 | + |
979 | + // sort parameters |
980 | + qsort(&(*argvp)[1], (*argcp)-1, sizeof(char *), oauth_cmpstringp); |
981 | + |
982 | + // serialize URL |
983 | + query= oauth_serialize_url_parameters(*argcp, *argvp); |
984 | + |
985 | + // generate signature |
986 | + okey = oauth_catenc(2, c_secret, t_secret); |
987 | + odat = oauth_catenc(3, http_request_method, (*argvp)[0], query); |
988 | + free(http_request_method); |
989 | +#ifdef DEBUG_OAUTH |
990 | + fprintf (stderr, "\nliboauth: data to sign='%s'\n\n", odat); |
991 | + fprintf (stderr, "\nliboauth: key='%s'\n\n", okey); |
992 | +#endif |
993 | + switch(method) { |
994 | + case OA_RSA: |
995 | + sign = oauth_sign_rsa_sha1(odat,okey); // XXX okey needs to be RSA key! |
996 | + break; |
997 | + case OA_PLAINTEXT: |
998 | + sign = oauth_sign_plaintext(odat,okey); |
999 | + break; |
1000 | + default: |
1001 | + sign = oauth_sign_hmac_sha1(odat,okey); |
1002 | + } |
1003 | +#ifdef WIPE_MEMORY |
1004 | + memset(okey,0, strlen(okey)); |
1005 | + memset(odat,0, strlen(odat)); |
1006 | +#endif |
1007 | + free(odat); |
1008 | + free(okey); |
1009 | + |
1010 | + // append signature to query args. |
1011 | + snprintf(oarg, 1024, "oauth_signature=%s",sign); |
1012 | + oauth_add_param_to_array(argcp, argvp, oarg); |
1013 | + free(sign); |
1014 | + |
1015 | + // build URL params |
1016 | + result = oauth_serialize_url(*argcp, (postargs?1:0), *argvp); |
1017 | + |
1018 | + if(postargs) { |
1019 | + *postargs = result; |
1020 | + result = xstrdup((*argvp)[0]); |
1021 | + } |
1022 | + |
1023 | + if(query) free(query); |
1024 | + |
1025 | + return result; |
1026 | +} |
1027 | + |
1028 | +/** |
1029 | + * free array args |
1030 | + * |
1031 | + * @param argcp pointer to array length int |
1032 | + * @param argvp pointer to array values to be free()d |
1033 | + */ |
1034 | +void oauth_free_array(int *argcp, char ***argvp) { |
1035 | + int i; |
1036 | + for (i=0;i<(*argcp);i++) { |
1037 | + free((*argvp)[i]); |
1038 | + } |
1039 | + if(*argvp) free(*argvp); |
1040 | +} |
1041 | + |
1042 | +/** |
1043 | + * http://oauth.googlecode.com/svn/spec/ext/body_hash/1.0/drafts/4/spec.html |
1044 | + */ |
1045 | +char *oauth_body_hash_file(char *filename) { |
1046 | + unsigned char fb[BUFSIZ]; |
1047 | + EVP_MD_CTX ctx; |
1048 | + size_t len=0; |
1049 | + unsigned char *md; |
1050 | + FILE *F= fopen(filename, "r"); |
1051 | + if (!F) return NULL; |
1052 | + |
1053 | + EVP_MD_CTX_init(&ctx); |
1054 | + EVP_DigestInit(&ctx,EVP_sha1()); |
1055 | + while (!feof(F) && (len=fread(fb,sizeof(char),BUFSIZ, F))>0) { |
1056 | + EVP_DigestUpdate(&ctx, fb, len); |
1057 | + } |
1058 | + fclose(F); |
1059 | + len=0; |
1060 | + md=(unsigned char*) calloc(EVP_MD_size(EVP_sha1()),sizeof(unsigned char)); |
1061 | + EVP_DigestFinal(&ctx, md, &len); |
1062 | + EVP_MD_CTX_cleanup(&ctx); |
1063 | + return oauth_body_hash_encode(len, md); |
1064 | +} |
1065 | + |
1066 | +char *oauth_body_hash_data(size_t length, const char *data) { |
1067 | + EVP_MD_CTX ctx; |
1068 | + size_t len=0; |
1069 | + unsigned char *md; |
1070 | + md=(unsigned char*) calloc(EVP_MD_size(EVP_sha1()),sizeof(unsigned char)); |
1071 | + EVP_MD_CTX_init(&ctx); |
1072 | + EVP_DigestInit(&ctx,EVP_sha1()); |
1073 | + EVP_DigestUpdate(&ctx, data, length); |
1074 | + EVP_DigestFinal(&ctx, md, &len); |
1075 | + EVP_MD_CTX_cleanup(&ctx); |
1076 | + return oauth_body_hash_encode(len, md); |
1077 | +} |
1078 | + |
1079 | +/** |
1080 | + * base64 encode digest, free it and return a URL parameter |
1081 | + * with the oauth_body_hash |
1082 | + */ |
1083 | +char *oauth_body_hash_encode(size_t len, unsigned char *digest) { |
1084 | + char *sign=oauth_encode_base64(len,digest); |
1085 | + char *sig_url = malloc(17+strlen(sign)); |
1086 | + sprintf(sig_url,"oauth_body_hash=%s", sign); |
1087 | + free(sign); |
1088 | + free(digest); |
1089 | + return sig_url; |
1090 | +} |
1091 | + |
1092 | + |
1093 | +/** |
1094 | + * xep-0235 - TODO |
1095 | + */ |
1096 | +char *oauth_sign_xmpp (const char *xml, |
1097 | + OAuthMethod method, |
1098 | + const char *c_secret, //< consumer secret - used as 1st part of secret-key |
1099 | + const char *t_secret //< token secret - used as 2st part of secret-key |
1100 | + ) { |
1101 | + |
1102 | + return NULL; |
1103 | +} |
1104 | + |
1105 | +// vi: sts=2 sw=2 ts=2 |
1106 | |
1107 | === added file 'couchdb-glib/oauth.h' |
1108 | --- couchdb-glib/oauth.h 1970-01-01 00:00:00 +0000 |
1109 | +++ couchdb-glib/oauth.h 2009-09-04 09:28:53 +0000 |
1110 | @@ -0,0 +1,539 @@ |
1111 | +/** |
1112 | + * @brief oAuth.net implementation in POSIX-C. |
1113 | + * @file oauth.h |
1114 | + * @author Robin Gareus <robin@gareus.org> |
1115 | + * |
1116 | + * Copyright 2007, 2008, 2009 Robin Gareus <robin@gareus.org> |
1117 | + * |
1118 | + * Permission is hereby granted, free of charge, to any person obtaining a copy |
1119 | + * of this software and associated documentation files (the "Software"), to deal |
1120 | + * in the Software without restriction, including without limitation the rights |
1121 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
1122 | + * copies of the Software, and to permit persons to whom the Software is |
1123 | + * furnished to do so, subject to the following conditions: |
1124 | + * |
1125 | + * The above copyright notice and this permission notice shall be included in |
1126 | + * all copies or substantial portions of the Software. |
1127 | + * |
1128 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
1129 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
1130 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
1131 | + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
1132 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
1133 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
1134 | + * THE SOFTWARE. |
1135 | + * |
1136 | + */ |
1137 | +#ifndef _OAUTH_H |
1138 | +#define _OAUTH_H 1 |
1139 | + |
1140 | +#ifndef DOXYGEN_IGNORE |
1141 | +// liboauth version |
1142 | +#define LIBOAUTH_VERSION "0.5.3" |
1143 | +#define LIBOAUTH_VERSION_MAJOR 0 |
1144 | +#define LIBOAUTH_VERSION_MINOR 5 |
1145 | +#define LIBOAUTH_VERSION_MICRO 3 |
1146 | + |
1147 | +//interface revision number |
1148 | +//http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html |
1149 | +#define LIBOAUTH_CUR 3 |
1150 | +#define LIBOAUTH_REV 0 |
1151 | +#define LIBOAUTH_AGE 3 |
1152 | +#endif |
1153 | + |
1154 | +#ifdef __GNUC__ |
1155 | +# define OA_GCC_VERSION_AT_LEAST(x,y) (__GNUC__ > x || __GNUC__ == x && __GNUC_MINOR__ >= y) |
1156 | +#else |
1157 | +# define OA_GCC_VERSION_AT_LEAST(x,y) 0 |
1158 | +#endif |
1159 | + |
1160 | +#ifndef attribute_deprecated |
1161 | +#if OA_GCC_VERSION_AT_LEAST(3,1) |
1162 | +# define attribute_deprecated __attribute__((deprecated)) |
1163 | +#else |
1164 | +# define attribute_deprecated |
1165 | +#endif |
1166 | +#endif |
1167 | + |
1168 | +/** \enum OAuthMethod |
1169 | + * signature method to used for signing the request. |
1170 | + */ |
1171 | +typedef enum { |
1172 | + OA_HMAC=0, ///< use HMAC-SHA1 request signing method |
1173 | + OA_RSA, ///< use RSA signature (not implemented) |
1174 | + OA_PLAINTEXT ///< use plain text signature (for testing only) |
1175 | + } OAuthMethod; |
1176 | + |
1177 | +/** |
1178 | + * Base64 encode and return size data in 'src'. The caller must free the |
1179 | + * returned string. |
1180 | + * |
1181 | + * @param size The size of the data in src |
1182 | + * @param src The data to be base64 encode |
1183 | + * @return encoded string otherwise NULL |
1184 | + */ |
1185 | +char *oauth_encode_base64(int size, const unsigned char *src); |
1186 | + |
1187 | +/** |
1188 | + * Decode the base64 encoded string 'src' into the memory pointed to by |
1189 | + * 'dest'. |
1190 | + * |
1191 | + * @param dest Pointer to memory for holding the decoded string. |
1192 | + * Must be large enough to recieve the decoded string. |
1193 | + * @param src A base64 encoded string. |
1194 | + * @return the length of the decoded string if decode |
1195 | + * succeeded otherwise 0. |
1196 | + */ |
1197 | +int oauth_decode_base64(unsigned char *dest, const char *src); |
1198 | + |
1199 | +/** |
1200 | + * Escape 'string' according to RFC3986 and |
1201 | + * http://oauth.net/core/1.0/#encoding_parameters. |
1202 | + * |
1203 | + * @param string The data to be encoded |
1204 | + * @return encoded string otherwise NULL |
1205 | + * The caller must free the returned string. |
1206 | + */ |
1207 | +char *oauth_url_escape(const char *string); |
1208 | + |
1209 | +/** |
1210 | + * Parse RFC3986 encoded 'string' back to unescaped version. |
1211 | + * |
1212 | + * @param string The data to be unescaped |
1213 | + * @param olen unless NULL the length of the returned string is stored there. |
1214 | + * @return decoded string or NULL |
1215 | + * The caller must free the returned string. |
1216 | + */ |
1217 | +char *oauth_url_unescape(const char *string, size_t *olen); |
1218 | + |
1219 | + |
1220 | +/** |
1221 | + * returns base64 encoded HMAC-SHA1 signature for |
1222 | + * given message and key. |
1223 | + * both data and key need to be urlencoded. |
1224 | + * |
1225 | + * the returned string needs to be freed by the caller |
1226 | + * |
1227 | + * @param m message to be signed |
1228 | + * @param k key used for signing |
1229 | + * @return signature string. |
1230 | + */ |
1231 | +char *oauth_sign_hmac_sha1 (const char *m, const char *k); |
1232 | + |
1233 | +/** |
1234 | + * same as \ref oauth_sign_hmac_sha1 but allows |
1235 | + * to specify length of message and key (in case they contain null chars). |
1236 | + * |
1237 | + * @param m message to be signed |
1238 | + * @param ml length of message |
1239 | + * @param k key used for signing |
1240 | + * @param kl length of key |
1241 | + * @return signature string. |
1242 | + */ |
1243 | +char *oauth_sign_hmac_sha1_raw (const char *m, const size_t ml, const char *k, const size_t kl); |
1244 | + |
1245 | +/** |
1246 | + * returns plaintext signature for the given key. |
1247 | + * |
1248 | + * the returned string needs to be freed by the caller |
1249 | + * |
1250 | + * @param m message to be signed |
1251 | + * @param k key used for signing |
1252 | + * @return signature string |
1253 | + */ |
1254 | +char *oauth_sign_plaintext (const char *m, const char *k); |
1255 | + |
1256 | +/** |
1257 | + * returns RSA-SHA1 signature for given data. |
1258 | + * the returned signature needs to be freed by the caller. |
1259 | + * |
1260 | + * @param m message to be signed |
1261 | + * @param k private-key PKCS and Base64-encoded |
1262 | + * @return base64 encoded signature string. |
1263 | + */ |
1264 | +char *oauth_sign_rsa_sha1 (const char *m, const char *k); |
1265 | + |
1266 | +/** |
1267 | + * verify RSA-SHA1 signature. |
1268 | + * |
1269 | + * returns the output of EVP_VerifyFinal() for a given message, |
1270 | + * cert/pubkey and signature. |
1271 | + * |
1272 | + * @param m message to be verified |
1273 | + * @param c public-key or x509 certificate |
1274 | + * @param s base64 encoded signature |
1275 | + * @return 1 for a correct signature, 0 for failure and -1 if some other error occurred |
1276 | + */ |
1277 | +int oauth_verify_rsa_sha1 (const char *m, const char *c, const char *s); |
1278 | + |
1279 | +/** |
1280 | + * url-escape strings and concatenate with '&' separator. |
1281 | + * The number of strings to be concatenated must be |
1282 | + * given as first argument. |
1283 | + * all arguments thereafter must be of type (char *) |
1284 | + * |
1285 | + * @param len the number of arguments to follow this parameter |
1286 | + * |
1287 | + * @return pointer to memory holding the concatenated |
1288 | + * strings - needs to be free(d) by the caller. or NULL |
1289 | + * in case we ran out of memory. |
1290 | + */ |
1291 | +char *oauth_catenc(int len, ...); |
1292 | + |
1293 | +/** |
1294 | + * splits the given url into a parameter array. |
1295 | + * (see \ref oauth_serialize_url and \ref oauth_serialize_url_parameters for the reverse) |
1296 | + * (see \ref oauth_split_post_paramters for a more generic version) |
1297 | + * |
1298 | + * @param url the url or query-string to parse; may be NULL |
1299 | + * @param argv pointer to a (char *) array where the results are stored. |
1300 | + * The array is re-allocated to match the number of parameters and each |
1301 | + * parameter-string is allocated with strdup. - The memory needs to be freed |
1302 | + * by the caller. |
1303 | + * |
1304 | + * @return number of parameter(s) in array. |
1305 | + */ |
1306 | +int oauth_split_url_parameters(const char *url, char ***argv); |
1307 | + |
1308 | +/** |
1309 | + * splits the given url into a parameter array. |
1310 | + * (see \ref oauth_serialize_url and \ref oauth_serialize_url_parameters for the reverse) |
1311 | + * |
1312 | + * @param url the url or query-string to parse. |
1313 | + * @param argv pointer to a (char *) array where the results are stored. |
1314 | + * The array is re-allocated to match the number of parameters and each |
1315 | + * parameter-string is allocated with strdup. - The memory needs to be freed |
1316 | + * by the caller. |
1317 | + * @param qesc use query parameter escape (vs post-param-escape) - if set |
1318 | + * to 1 all '+' are treated as spaces ' ' |
1319 | + * |
1320 | + * @return number of parameter(s) in array. |
1321 | + */ |
1322 | +int oauth_split_post_paramters(const char *url, char ***argv, short qesc); |
1323 | + |
1324 | +/** |
1325 | + * build a url query string from an array. |
1326 | + * |
1327 | + * @param argc the total number of elements in the array |
1328 | + * @param start element in the array at which to start concatenating. |
1329 | + * @param argv parameter-array to concatenate. |
1330 | + * @return url string needs to be freed by the caller. |
1331 | + * |
1332 | + */ |
1333 | +char *oauth_serialize_url (int argc, int start, char **argv); |
1334 | + |
1335 | +/** |
1336 | + * encode query parameters from an array. |
1337 | + * |
1338 | + * @param argc the total number of elements in the array |
1339 | + * @param start element in the array at which to start concatenating. |
1340 | + * @param argv parameter-array to concatenate. |
1341 | + * @param sep separator for parameters (usually "&") |
1342 | + * @return url string needs to be freed by the caller. |
1343 | + */ |
1344 | +char *oauth_serialize_url_sep (int argc, int start, char **argv, char *sep); |
1345 | + |
1346 | +/** |
1347 | + * build a query parameter string from an array. |
1348 | + * |
1349 | + * This function is a shortcut for \ref oauth_serialize_url (argc, 1, argv). |
1350 | + * It strips the leading host/path, which is usually the first |
1351 | + * element when using oauth_split_url_parameters on an URL. |
1352 | + * |
1353 | + * @param argc the total number of elements in the array |
1354 | + * @param argv parameter-array to concatenate. |
1355 | + * @return url string needs to be freed by the caller. |
1356 | + */ |
1357 | +char *oauth_serialize_url_parameters (int argc, char **argv); |
1358 | + |
1359 | +/** |
1360 | + * generate a random string between 15 and 32 chars length |
1361 | + * and return a pointer to it. The value needs to be freed by the |
1362 | + * caller |
1363 | + * |
1364 | + * @return zero terminated random string. |
1365 | + */ |
1366 | +char *oauth_gen_nonce(); |
1367 | + |
1368 | +/** |
1369 | + * string compare function for oauth parameters. |
1370 | + * |
1371 | + * used with qsort. needed to normalize request parameters. |
1372 | + * see http://oauth.net/core/1.0/#anchor14 |
1373 | + */ |
1374 | +int oauth_cmpstringp(const void *p1, const void *p2); |
1375 | + |
1376 | + |
1377 | +/** |
1378 | + * search array for parameter key. |
1379 | + * @param argv length of array to search |
1380 | + * @param argc parameter array to search |
1381 | + * @param key key of parameter to check. |
1382 | + * |
1383 | + * @return FALSE (0) if array does not contain a paramater with given key, TRUE (1) otherwise. |
1384 | + */ |
1385 | +int oauth_param_exists(char **argv, int argc, char *key); |
1386 | + |
1387 | +/** |
1388 | + * add query parameter to array |
1389 | + * |
1390 | + * @param argcp pointer to array length int |
1391 | + * @param argvp pointer to array values |
1392 | + * @param addparam parameter to add (eg. "foo=bar") |
1393 | + */ |
1394 | +void oauth_add_param_to_array(int *argcp, char ***argvp, const char *addparam); |
1395 | + |
1396 | +/** |
1397 | + * free array args |
1398 | + * |
1399 | + * @param argcp pointer to array length int |
1400 | + * @param argvp pointer to array values to be free()d |
1401 | + */ |
1402 | +void oauth_free_array(int *argcp, char ***argvp); |
1403 | + |
1404 | +/** |
1405 | + * calculate oAuth-signature for a given HTTP request URL, parameters and oauth-tokens. |
1406 | + * |
1407 | + * if 'postargs' is NULL a "GET" request is signed and the |
1408 | + * signed URL is returned. Else this fn will modify 'postargs' |
1409 | + * to point to memory that contains the signed POST-variables |
1410 | + * and returns the base URL. |
1411 | + * |
1412 | + * both, the return value and (if given) 'postargs' need to be freed |
1413 | + * by the caller. |
1414 | + * |
1415 | + * @param url The request URL to be signed. append all GET or POST |
1416 | + * query-parameters separated by either '?' or '&' to this parameter. |
1417 | + * |
1418 | + * @param postargs This parameter points to an area where the return value |
1419 | + * is stored. If 'postargs' is NULL, no value is stored. |
1420 | + * |
1421 | + * @param method specify the signature method to use. It is of type |
1422 | + * \ref OAuthMethod and most likely \ref OA_HMAC. |
1423 | + * |
1424 | + * @param http_method The HTTP request method to use (ie "GET", "PUT",..) |
1425 | + * If NULL is given as 'http_method' this defaults to "GET" when |
1426 | + * 'postargs' is also NULL and when postargs is not NULL "POST" is used. |
1427 | + * |
1428 | + * @param c_key consumer key |
1429 | + * @param c_secret consumer secret |
1430 | + * @param t_key token key |
1431 | + * @param t_secret token secret |
1432 | + * |
1433 | + * @return the signed url or NULL if an error occurred. |
1434 | + * |
1435 | + */ |
1436 | +char *oauth_sign_url2 (const char *url, char **postargs, |
1437 | + OAuthMethod method, |
1438 | + const char *http_method, //< HTTP request method |
1439 | + const char *c_key, //< consumer key - posted plain text |
1440 | + const char *c_secret, //< consumer secret - used as 1st part of secret-key |
1441 | + const char *t_key, //< token key - posted plain text in URL |
1442 | + const char *t_secret //< token secret - used as 2st part of secret-key |
1443 | + ); |
1444 | + |
1445 | +/** |
1446 | + * @deprecated Use oauth_sign_url2() instead. |
1447 | + */ |
1448 | +char *oauth_sign_url (const char *url, char **postargs, |
1449 | + OAuthMethod method, |
1450 | + const char *c_key, //< consumer key - posted plain text |
1451 | + const char *c_secret, //< consumer secret - used as 1st part of secret-key |
1452 | + const char *t_key, //< token key - posted plain text in URL |
1453 | + const char *t_secret //< token secret - used as 2st part of secret-key |
1454 | + ) attribute_deprecated; |
1455 | + |
1456 | +/** |
1457 | + * same as /ref oauth_sign_url |
1458 | + * with the url already split into parameter array |
1459 | + * |
1460 | + * @param argcp pointer to array length int |
1461 | + * @param argvp pointer to array values |
1462 | + * (argv[0]="http://example.org:80/" argv[1]="first=QueryParamater" ..) |
1463 | + * |
1464 | + * @param postargs This parameter points to an area where the return value |
1465 | + * is stored. If 'postargs' is NULL, no value is stored. |
1466 | + * |
1467 | + * @param method specify the signature method to use. It is of type |
1468 | + * \ref OAuthMethod and most likely \ref OA_HMAC. |
1469 | + * |
1470 | + * @param http_method The HTTP request method to use (ie "GET", "PUT",..) |
1471 | + * If NULL is given as 'http_method' this defaults to "GET" when |
1472 | + * 'postargs' is also NULL and when postargs is not NULL "POST" is used. |
1473 | + * |
1474 | + * @param c_key consumer key |
1475 | + * @param c_secret consumer secret |
1476 | + * @param t_key token key |
1477 | + * @param t_secret token secret |
1478 | + * |
1479 | + * @return the signed url or NULL if an error occurred. |
1480 | + */ |
1481 | +char *oauth_sign_array2 (int *argcp, char***argvp, |
1482 | + char **postargs, |
1483 | + OAuthMethod method, |
1484 | + const char *http_method, //< HTTP request method |
1485 | + const char *c_key, //< consumer key - posted plain text |
1486 | + const char *c_secret, //< consumer secret - used as 1st part of secret-key |
1487 | + const char *t_key, //< token key - posted plain text in URL |
1488 | + const char *t_secret //< token secret - used as 2st part of secret-key |
1489 | + ); |
1490 | + |
1491 | +/** |
1492 | + * @deprecated Use oauth_sign_array2() instead. |
1493 | + */ |
1494 | +char *oauth_sign_array (int *argcp, char***argvp, |
1495 | + char **postargs, |
1496 | + OAuthMethod method, |
1497 | + const char *c_key, //< consumer key - posted plain text |
1498 | + const char *c_secret, //< consumer secret - used as 1st part of secret-key |
1499 | + const char *t_key, //< token key - posted plain text in URL |
1500 | + const char *t_secret //< token secret - used as 2st part of secret-key |
1501 | + ) attribute_deprecated; |
1502 | + |
1503 | + |
1504 | +/** |
1505 | + * calculate body hash (sha1sum) of given file and return |
1506 | + * a oauth_body_hash=xxxx parameter to be added to the request. |
1507 | + * The returned string needs to be freed by the calling function. |
1508 | + * |
1509 | + * see |
1510 | + * http://oauth.googlecode.com/svn/spec/ext/body_hash/1.0/drafts/4/spec.html |
1511 | + * |
1512 | + * @param filename the filename to calculate the hash for |
1513 | + * |
1514 | + * @return URL oauth_body_hash parameter string |
1515 | + */ |
1516 | +char *oauth_body_hash_file(char *filename); |
1517 | + |
1518 | +/** |
1519 | + * calculate body hash (sha1sum) of given data and return |
1520 | + * a oauth_body_hash=xxxx parameter to be added to the request. |
1521 | + * The returned string needs to be freed by the calling function. |
1522 | + * The returned string is not yet url-escaped and suitable to be |
1523 | + * passed as argument to \ref oauth_catenc. |
1524 | + * |
1525 | + * see |
1526 | + * http://oauth.googlecode.com/svn/spec/ext/body_hash/1.0/drafts/4/spec.html |
1527 | + * |
1528 | + * @param length length of the data parameter in bytes |
1529 | + * @param data to calculate the hash for |
1530 | + * |
1531 | + * @return URL oauth_body_hash parameter string |
1532 | + */ |
1533 | +char *oauth_body_hash_data(size_t length, const char *data); |
1534 | + |
1535 | +/** |
1536 | + * base64 encode digest, free it and return a URL parameter |
1537 | + * with the oauth_body_hash. The returned hash needs to be freed by the |
1538 | + * calling function. The returned string is not yet url-escaped and |
1539 | + * thus suitable to be passed to \ref oauth_catenc. |
1540 | + * |
1541 | + * @param len length of the digest to encode |
1542 | + * @param digest hash value to encode |
1543 | + * |
1544 | + * @return URL oauth_body_hash parameter string |
1545 | + */ |
1546 | +char *oauth_body_hash_encode(size_t len, unsigned char *digest); |
1547 | + |
1548 | +/** |
1549 | + * xep-0235 - TODO |
1550 | + */ |
1551 | +char *oauth_sign_xmpp (const char *xml, |
1552 | + OAuthMethod method, |
1553 | + const char *c_secret, //< consumer secret - used as 1st part of secret-key |
1554 | + const char *t_secret //< token secret - used as 2st part of secret-key |
1555 | + ); |
1556 | + |
1557 | +/** |
1558 | + * do a HTTP GET request, wait for it to finish |
1559 | + * and return the content of the reply. |
1560 | + * (requires libcurl or a command-line HTTP client) |
1561 | + * |
1562 | + * If compiled <b>without</b> libcurl this function calls |
1563 | + * a command-line executable defined in the environment variable |
1564 | + * OAUTH_HTTP_GET_CMD - it defaults to |
1565 | + * <tt>curl -sA 'liboauth-agent/0.1' '%%u'</tt> |
1566 | + * where %%u is replaced with the URL and query parameters. |
1567 | + * |
1568 | + * bash & wget example: |
1569 | + * <tt>export OAUTH_HTTP_CMD="wget -q -U 'liboauth-agent/0.1' '%%u' "</tt> |
1570 | + * |
1571 | + * WARNING: this is a tentative function. it's convenient and handy for testing |
1572 | + * or developing oAuth code. But don't rely on this function |
1573 | + * to become a stable part of this API. It does not do |
1574 | + * much error checking or handling for one thing.. |
1575 | + * |
1576 | + * NOTE: \a u and \a q are just concatenated with a '?' in between, |
1577 | + * unless \a q is NULL. in which case only \a u will be used. |
1578 | + * |
1579 | + * @param u base url to get |
1580 | + * @param q query string to send along with the HTTP request or NULL. |
1581 | + * @return In case of an error NULL is returned; otherwise a pointer to the |
1582 | + * replied content from HTTP server. latter needs to be freed by caller. |
1583 | + */ |
1584 | +char *oauth_http_get (const char *u, const char *q); |
1585 | + |
1586 | + |
1587 | +/** |
1588 | + * do a HTTP POST request, wait for it to finish |
1589 | + * and return the content of the reply. |
1590 | + * (requires libcurl or a command-line HTTP client) |
1591 | + * |
1592 | + * If compiled <b>without</b> libcurl this function calls |
1593 | + * a command-line executable defined in the environment variable |
1594 | + * OAUTH_HTTP_CMD - it defaults to |
1595 | + * <tt>curl -sA 'liboauth-agent/0.1' -d '%%p' '%%u'</tt> |
1596 | + * where %%p is replaced with the postargs and %%u is replaced with |
1597 | + * the URL. |
1598 | + * |
1599 | + * bash & wget example: |
1600 | + * <tt>export OAUTH_HTTP_CMD="wget -q -U 'liboauth-agent/0.1' --post-data='%%p' '%%u' "</tt> |
1601 | + * |
1602 | + * NOTE: This function uses the curl's default HTTP-POST Content-Type: |
1603 | + * application/x-www-form-urlencoded which is the only option allowed |
1604 | + * by oauth core 1.0 spec. Experimental code can use the Environment variable |
1605 | + * to transmit custom HTTP headers or parameters. |
1606 | + * |
1607 | + * WARNING: this is a tentative function. it's convenient and handy for testing |
1608 | + * or developing oAuth code. But don't rely on this function |
1609 | + * to become a stable part of this API. It does not do |
1610 | + * much error checking for one thing.. |
1611 | + * |
1612 | + * @param u url to query |
1613 | + * @param p postargs to send along with the HTTP request. |
1614 | + * @return replied content from HTTP server. needs to be freed by caller. |
1615 | + */ |
1616 | +char *oauth_http_post (const char *u, const char *p); |
1617 | + |
1618 | +/** |
1619 | + * http post raw data from file. |
1620 | + * the returned string needs to be freed by the caller |
1621 | + * (requires libcurl) |
1622 | + * |
1623 | + * see dislaimer: /ref oauth_http_post |
1624 | + * |
1625 | + * @param u url to retrieve |
1626 | + * @param fn filename of the file to post along |
1627 | + * @param len length of the file in bytes. set to '0' for autodetection |
1628 | + * @param customheader specify custom HTTP header (or NULL for default) |
1629 | + * @return returned HTTP reply or NULL on error |
1630 | + */ |
1631 | +char *oauth_post_file (const char *u, const char *fn, size_t len, const char *customheader); |
1632 | + |
1633 | +/** |
1634 | + * http post raw data |
1635 | + * the returned string needs to be freed by the caller |
1636 | + * (requires libcurl) |
1637 | + * |
1638 | + * see dislaimer: /ref oauth_http_post |
1639 | + * |
1640 | + * @param u url to retrieve |
1641 | + * @param data data to post |
1642 | + * @param len length of the data in bytes. |
1643 | + * @param customheader specify custom HTTP header (or NULL for default) |
1644 | + * @return returned HTTP reply or NULL on error |
1645 | + */ |
1646 | +char *oauth_post_data (const char *u, const char *data, size_t len, const char *customheader); |
1647 | + |
1648 | +#endif |
1649 | +/* vi:set ts=8 sts=2 sw=2: */ |
1650 | |
1651 | === added file 'couchdb-glib/oauth_http.c' |
1652 | --- couchdb-glib/oauth_http.c 1970-01-01 00:00:00 +0000 |
1653 | +++ couchdb-glib/oauth_http.c 2009-09-04 09:28:53 +0000 |
1654 | @@ -0,0 +1,504 @@ |
1655 | +/* |
1656 | + * oAuth string functions in POSIX-C. |
1657 | + * |
1658 | + * Copyright 2007, 2008 Robin Gareus <robin@gareus.org> |
1659 | + * |
1660 | + * Permission is hereby granted, free of charge, to any person obtaining a copy |
1661 | + * of this software and associated documentation files (the "Software"), to deal |
1662 | + * in the Software without restriction, including without limitation the rights |
1663 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
1664 | + * copies of the Software, and to permit persons to whom the Software is |
1665 | + * furnished to do so, subject to the following conditions: |
1666 | + * |
1667 | + * The above copyright notice and this permission notice shall be included in |
1668 | + * all copies or substantial portions of the Software. |
1669 | + * |
1670 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
1671 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
1672 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
1673 | + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
1674 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
1675 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
1676 | + * THE SOFTWARE. |
1677 | + * |
1678 | + */ |
1679 | +#if HAVE_CONFIG_H |
1680 | +# include <config.h> |
1681 | +#endif |
1682 | + |
1683 | +#include <stdio.h> |
1684 | +#include <stdarg.h> |
1685 | +#include <stdlib.h> |
1686 | +#include <string.h> |
1687 | + |
1688 | +#include "xmalloc.h" |
1689 | +#include "oauth.h" |
1690 | + |
1691 | +#define OAUTH_USER_AGENT "liboauth-agent/" VERSION |
1692 | + |
1693 | +#ifdef HAVE_CURL |
1694 | +#include <curl/curl.h> |
1695 | +#include <sys/stat.h> |
1696 | + |
1697 | +struct MemoryStruct { |
1698 | + char *data; |
1699 | + size_t size; |
1700 | +}; |
1701 | + |
1702 | +static size_t |
1703 | +WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data) { |
1704 | + size_t realsize = size * nmemb; |
1705 | + struct MemoryStruct *mem = (struct MemoryStruct *)data; |
1706 | + |
1707 | + mem->data = (char *)xrealloc(mem->data, mem->size + realsize + 1); |
1708 | + if (mem->data) { |
1709 | + memcpy(&(mem->data[mem->size]), ptr, realsize); |
1710 | + mem->size += realsize; |
1711 | + mem->data[mem->size] = 0; |
1712 | + } |
1713 | + return realsize; |
1714 | +} |
1715 | + |
1716 | +static size_t |
1717 | +ReadMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data) { |
1718 | + struct MemoryStruct *mem = (struct MemoryStruct *)data; |
1719 | + size_t realsize = size * nmemb; |
1720 | + if (realsize > mem->size) realsize = mem->size; |
1721 | + memcpy(ptr, mem->data, realsize); |
1722 | + mem->size -= realsize; |
1723 | + mem->data += realsize; |
1724 | + return realsize; |
1725 | +} |
1726 | + |
1727 | +/** |
1728 | + * cURL http post function. |
1729 | + * the returned string (if not NULL) needs to be freed by the caller |
1730 | + * |
1731 | + * @param u url to retrieve |
1732 | + * @param p post parameters |
1733 | + * @return returned HTTP |
1734 | + */ |
1735 | +char *oauth_curl_post (const char *u, const char *p) { |
1736 | + CURL *curl; |
1737 | + CURLcode res; |
1738 | + |
1739 | + struct MemoryStruct chunk; |
1740 | + chunk.data=NULL; |
1741 | + chunk.size = 0; |
1742 | + |
1743 | + curl = curl_easy_init(); |
1744 | + if(!curl) return NULL; |
1745 | + curl_easy_setopt(curl, CURLOPT_URL, u); |
1746 | + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, p); |
1747 | + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk); |
1748 | + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); |
1749 | + curl_easy_setopt(curl, CURLOPT_USERAGENT, OAUTH_USER_AGENT); |
1750 | + res = curl_easy_perform(curl); |
1751 | + if (res) { |
1752 | + return NULL; |
1753 | + } |
1754 | + |
1755 | + curl_easy_cleanup(curl); |
1756 | + return (chunk.data); |
1757 | +} |
1758 | + |
1759 | +/** |
1760 | + * cURL http get function. |
1761 | + * the returned string (if not NULL) needs to be freed by the caller |
1762 | + * |
1763 | + * @param u url to retrieve |
1764 | + * @param q optional query parameters |
1765 | + * @return returned HTTP |
1766 | + */ |
1767 | +char *oauth_curl_get (const char *u, const char *q) { |
1768 | + CURL *curl; |
1769 | + CURLcode res; |
1770 | + char *t1=NULL; |
1771 | + struct MemoryStruct chunk; |
1772 | + |
1773 | + if (q) { |
1774 | + t1=xmalloc(sizeof(char)*(strlen(u)+strlen(q)+2)); |
1775 | + strcat(t1,u); strcat(t1,"?"); strcat(t1,q); |
1776 | + } |
1777 | + |
1778 | + chunk.data=NULL; |
1779 | + chunk.size = 0; |
1780 | + |
1781 | + curl = curl_easy_init(); |
1782 | + if(!curl) return NULL; |
1783 | + curl_easy_setopt(curl, CURLOPT_URL, q?t1:u); |
1784 | + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk); |
1785 | + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); |
1786 | + curl_easy_setopt(curl, CURLOPT_USERAGENT, OAUTH_USER_AGENT); |
1787 | + res = curl_easy_perform(curl); |
1788 | + if (q) free(t1); |
1789 | + if (res) { |
1790 | + return NULL; |
1791 | + } |
1792 | + |
1793 | + curl_easy_cleanup(curl); |
1794 | + return (chunk.data); |
1795 | +} |
1796 | + |
1797 | +/** |
1798 | + * cURL http post raw data from file. |
1799 | + * the returned string needs to be freed by the caller |
1800 | + * |
1801 | + * @param u url to retrieve |
1802 | + * @param fn filename of the file to post along |
1803 | + * @param len length of the file in bytes. set to '0' for autodetection |
1804 | + * @param customheader specify custom HTTP header (or NULL for default) |
1805 | + * @return returned HTTP or NULL on error |
1806 | + */ |
1807 | +char *oauth_curl_post_file (const char *u, const char *fn, size_t len, const char *customheader) { |
1808 | + CURL *curl; |
1809 | + CURLcode res; |
1810 | + struct curl_slist *slist=NULL; |
1811 | + struct MemoryStruct chunk; |
1812 | + FILE *f; |
1813 | + |
1814 | + chunk.data=NULL; |
1815 | + chunk.size=0; |
1816 | + |
1817 | + if (customheader) |
1818 | + slist = curl_slist_append(slist, customheader); |
1819 | + else |
1820 | + slist = curl_slist_append(slist, "Content-Type: image/jpeg;"); |
1821 | + |
1822 | + if (!len) { |
1823 | + struct stat statbuf; |
1824 | + if (stat(fn, &statbuf) == -1) return(NULL); |
1825 | + len = statbuf.st_size; |
1826 | + } |
1827 | + |
1828 | + f = fopen(fn,"r"); |
1829 | + if (!f) return NULL; |
1830 | + |
1831 | + curl = curl_easy_init(); |
1832 | + if(!curl) return NULL; |
1833 | + curl_easy_setopt(curl, CURLOPT_URL, u); |
1834 | + curl_easy_setopt(curl, CURLOPT_POST, 1); |
1835 | + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len); |
1836 | + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist); |
1837 | + curl_easy_setopt(curl, CURLOPT_READDATA, f); |
1838 | + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk); |
1839 | + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); |
1840 | + curl_easy_setopt(curl, CURLOPT_USERAGENT, OAUTH_USER_AGENT); |
1841 | + res = curl_easy_perform(curl); |
1842 | + if (res) { |
1843 | + // error |
1844 | + return NULL; |
1845 | + } |
1846 | + fclose(f); |
1847 | + |
1848 | + curl_easy_cleanup(curl); |
1849 | + return (chunk.data); |
1850 | +} |
1851 | + |
1852 | +/** |
1853 | + * http post raw data. |
1854 | + * the returned string needs to be freed by the caller |
1855 | + * |
1856 | + * more documentation in oauth.h |
1857 | + * |
1858 | + * @param u url to retrieve |
1859 | + * @param data data to post along |
1860 | + * @param len length of the file in bytes. set to '0' for autodetection |
1861 | + * @param customheader specify custom HTTP header (or NULL for default) |
1862 | + * @return returned HTTP reply or NULL on error |
1863 | + */ |
1864 | +char *oauth_curl_post_data (const char *u, const char *data, size_t len, const char *customheader) { |
1865 | + CURL *curl; |
1866 | + CURLcode res; |
1867 | + struct curl_slist *slist=NULL; |
1868 | + struct MemoryStruct chunk; |
1869 | + struct MemoryStruct rdnfo; |
1870 | + |
1871 | + chunk.data=NULL; |
1872 | + chunk.size=0; |
1873 | + rdnfo.data=(char *)data; |
1874 | + rdnfo.size=len; |
1875 | + |
1876 | + if (customheader) |
1877 | + slist = curl_slist_append(slist, customheader); |
1878 | + else |
1879 | + slist = curl_slist_append(slist, "Content-Type: image/jpeg;"); |
1880 | + |
1881 | + curl = curl_easy_init(); |
1882 | + if(!curl) return NULL; |
1883 | + curl_easy_setopt(curl, CURLOPT_URL, u); |
1884 | + curl_easy_setopt(curl, CURLOPT_POST, 1); |
1885 | + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len); |
1886 | + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist); |
1887 | + curl_easy_setopt(curl, CURLOPT_READDATA, (void *)&rdnfo); |
1888 | + curl_easy_setopt(curl, CURLOPT_READFUNCTION, ReadMemoryCallback); |
1889 | + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk); |
1890 | + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); |
1891 | + curl_easy_setopt(curl, CURLOPT_USERAGENT, OAUTH_USER_AGENT); |
1892 | + res = curl_easy_perform(curl); |
1893 | + if (res) { |
1894 | + // error |
1895 | + return NULL; |
1896 | + } |
1897 | + |
1898 | + curl_easy_cleanup(curl); |
1899 | + return (chunk.data); |
1900 | +} |
1901 | +#endif // no cURL. |
1902 | + |
1903 | +// command line presets and ENV variable name |
1904 | +#define _OAUTH_ENV_HTTPCMD "OAUTH_HTTP_CMD" |
1905 | +#define _OAUTH_DEF_HTTPCMD "curl -sA '"OAUTH_USER_AGENT"' -d '%p' '%u' " |
1906 | +// alternative: "wget -q -U 'liboauth-agent/0.1' --post-data='%p' '%u' " |
1907 | + |
1908 | +#define _OAUTH_ENV_HTTPGET "OAUTH_HTTP_GET_CMD" |
1909 | +#define _OAUTH_DEF_HTTPGET "curl -sA '"OAUTH_USER_AGENT"' '%u' " |
1910 | +// alternative: "wget -q -U 'liboauth-agent/0.1' '%u' " |
1911 | + |
1912 | +#include <stdio.h> |
1913 | + |
1914 | +/** |
1915 | + * escape URL for use in String Quotes (aka shell single quotes). |
1916 | + * the returned string needs to be free()d by the calling function |
1917 | + * |
1918 | + * WARNING: this function only escapes single-quotes (') |
1919 | + * |
1920 | + * |
1921 | + * RFC2396 defines the following |
1922 | + * reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | "," |
1923 | + * besides alphanum the following are allowed as unreserved: |
1924 | + * mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")" |
1925 | + * |
1926 | + * checking `echo '-_.!~*()'` it seems we |
1927 | + * just need to escape the tick (') itself from "'" to "'\''" |
1928 | + * |
1929 | + * In C shell, the "!" character may need a backslash before it. |
1930 | + * It depends on the characters next to it. If it is surrounded by spaces, |
1931 | + * you don't need to use a backslash. |
1932 | + * (here: we'd always need to escape it for c shell) |
1933 | + * @todo: escape '!' for c-shell curl/wget commandlines |
1934 | + * |
1935 | + * @param cmd URI string or parameter to be escaped |
1936 | + * @return escaped parameter |
1937 | + */ |
1938 | +char *oauth_escape_shell (const char *cmd) { |
1939 | + char *esc = xstrdup(cmd); |
1940 | + char *tmp = esc; |
1941 | + int idx; |
1942 | + while ((tmp=strchr(tmp,'\''))) { |
1943 | + idx = tmp-esc; |
1944 | + esc=xrealloc(esc,(strlen(esc)+5)*sizeof(char)); |
1945 | + memmove(esc+idx+4,esc+idx+1, strlen(esc+idx)); |
1946 | + esc[idx+1]='\\'; esc[idx+2]='\''; esc[idx+3]='\''; |
1947 | + tmp=esc+(idx+4); |
1948 | + } |
1949 | + |
1950 | +// TODO escape '!' if CSHELL ?! |
1951 | + |
1952 | + return esc; |
1953 | +} |
1954 | + |
1955 | +/** |
1956 | + * execute command via shell and return it's output. |
1957 | + * This is used to call 'curl' or 'wget'. |
1958 | + * the command is uses <em>as is</em> and needs to be propery escaped. |
1959 | + * |
1960 | + * @param cmd the commandline to execute |
1961 | + * @return stdout string that needs to be freed or NULL if there's no output |
1962 | + */ |
1963 | +char *oauth_exec_shell (const char *cmd) { |
1964 | +#ifdef DEBUG_OAUTH |
1965 | + printf("DEBUG: executing: %s\n",cmd); |
1966 | +#endif |
1967 | + FILE *in = popen (cmd, "r"); |
1968 | + size_t len = 0; |
1969 | + size_t alloc = 0; |
1970 | + char *data = NULL; |
1971 | + int rcv = 1; |
1972 | + while (in && rcv > 0 && !feof(in)) { |
1973 | + alloc +=1024; |
1974 | + data = xrealloc(data, alloc * sizeof(char)); |
1975 | + rcv = fread(data, sizeof(char), 1024, in); |
1976 | + len += rcv; |
1977 | + } |
1978 | + pclose(in); |
1979 | +#ifdef DEBUG_OAUTH |
1980 | + printf("DEBUG: read %i bytes\n",len); |
1981 | +#endif |
1982 | + data[len]=0; |
1983 | +#ifdef DEBUG_OAUTH |
1984 | + if (data) printf("DEBUG: return: %s\n",data); |
1985 | + else printf("DEBUG: NULL data\n"); |
1986 | +#endif |
1987 | + return (data); |
1988 | +} |
1989 | + |
1990 | +/** |
1991 | + * send POST via a command line HTTP client, wait for it to finish |
1992 | + * and return the content of the reply. requires a command-line HTTP client |
1993 | + * |
1994 | + * see \ref oauth_http_post |
1995 | + * |
1996 | + * @param u url to query |
1997 | + * @param p postargs to send along with the HTTP request. |
1998 | + * @return In case of an error NULL is returned; otherwise a pointer to the |
1999 | + * replied content from HTTP server. latter needs to be freed by caller. |
2000 | + */ |
2001 | +char *oauth_exec_post (const char *u, const char *p) { |
2002 | + char cmd[BUFSIZ]; |
2003 | + char *t1,*t2; |
2004 | + char *cmdtpl = getenv(_OAUTH_ENV_HTTPCMD); |
2005 | + if (!cmdtpl) cmdtpl = xstrdup (_OAUTH_DEF_HTTPCMD); |
2006 | + else cmdtpl = xstrdup (cmdtpl); // clone getenv() string. |
2007 | + |
2008 | + // add URL and post param - error if no '%p' or '%u' present in definition |
2009 | + t1=strstr(cmdtpl, "%p"); |
2010 | + t2=strstr(cmdtpl, "%u"); |
2011 | + if (!t1 || !t2) { |
2012 | + fprintf(stderr, "\nliboauth: invalid HTTP command. set the '%s' environement variable.\n\n",_OAUTH_ENV_HTTPCMD); |
2013 | + return(NULL); |
2014 | + } |
2015 | + // TODO: check if there are exactly two '%' in cmdtpl |
2016 | + *(++t1)= 's'; *(++t2)= 's'; |
2017 | + if (t1>t2) { |
2018 | + t1=oauth_escape_shell(u); |
2019 | + t2=oauth_escape_shell(p); |
2020 | + } else { |
2021 | + t1=oauth_escape_shell(p); |
2022 | + t2=oauth_escape_shell(u); |
2023 | + } |
2024 | + snprintf(cmd, BUFSIZ, cmdtpl, t1, t2); |
2025 | + free(cmdtpl); |
2026 | + free(t1); free(t2); |
2027 | + return oauth_exec_shell(cmd); |
2028 | +} |
2029 | + |
2030 | +/** |
2031 | + * send GET via a command line HTTP client |
2032 | + * and return the content of the reply.. |
2033 | + * requires a command-line HTTP client. |
2034 | + * |
2035 | + * Note: u and q are just concatenated with a '?' in between unless q is NULL. in which case only u will be used. |
2036 | + * |
2037 | + * see \ref oauth_http_get |
2038 | + * |
2039 | + * @param u base url to get |
2040 | + * @param q query string to send along with the HTTP request. |
2041 | + * @return In case of an error NULL is returned; otherwise a pointer to the |
2042 | + * replied content from HTTP server. latter needs to be freed by caller. |
2043 | + */ |
2044 | +char *oauth_exec_get (const char *u, const char *q) { |
2045 | + char cmd[BUFSIZ]; |
2046 | + char *cmdtpl, *t1, *e1; |
2047 | + |
2048 | + if (!u) return (NULL); |
2049 | + |
2050 | + cmdtpl = getenv(_OAUTH_ENV_HTTPGET); |
2051 | + if (!cmdtpl) cmdtpl = xstrdup (_OAUTH_DEF_HTTPGET); |
2052 | + else cmdtpl = xstrdup (cmdtpl); // clone getenv() string. |
2053 | + |
2054 | + // add URL and post param - error if no '%p' or '%u' present in definition |
2055 | + t1=strstr(cmdtpl, "%u"); |
2056 | + if (!t1) { |
2057 | + fprintf(stderr, "\nliboauth: invalid HTTP command. set the '%s' environement variable.\n\n",_OAUTH_ENV_HTTPGET); |
2058 | + return(NULL); |
2059 | + } |
2060 | + *(++t1)= 's'; |
2061 | + |
2062 | + e1 = oauth_escape_shell(u); |
2063 | + if (q) { |
2064 | + char *e2; |
2065 | + e2 = oauth_escape_shell(q); |
2066 | + t1=xmalloc(sizeof(char)*(strlen(e1)+strlen(e2)+2)); |
2067 | + strcat(t1,e1); strcat(t1,"?"); strcat(t1,e2); |
2068 | + free(e2); |
2069 | + } |
2070 | + snprintf(cmd, BUFSIZ, cmdtpl, q?t1:e1); |
2071 | + free(cmdtpl); |
2072 | + free(e1); |
2073 | + if (q) free(t1); |
2074 | + return oauth_exec_shell(cmd); |
2075 | +} |
2076 | + |
2077 | +/** |
2078 | + * do a HTTP GET request, wait for it to finish |
2079 | + * and return the content of the reply. |
2080 | + * (requires libcurl or a command-line HTTP client) |
2081 | + * |
2082 | + * more documentation in oauth.h |
2083 | + * |
2084 | + * @param u base url to get |
2085 | + * @param q query string to send along with the HTTP request or NULL. |
2086 | + * @return In case of an error NULL is returned; otherwise a pointer to the |
2087 | + * replied content from HTTP server. latter needs to be freed by caller. |
2088 | + */ |
2089 | +char *oauth_http_get (const char *u, const char *q) { |
2090 | +#ifdef HAVE_CURL |
2091 | + return oauth_curl_get(u,q); |
2092 | +#else // no cURL. |
2093 | + return oauth_exec_get(u,q); |
2094 | +#endif |
2095 | +} |
2096 | + |
2097 | +/** |
2098 | + * do a HTTP POST request, wait for it to finish |
2099 | + * and return the content of the reply. |
2100 | + * (requires libcurl or a command-line HTTP client) |
2101 | + * |
2102 | + * more documentation in oauth.h |
2103 | + * |
2104 | + * @param u url to query |
2105 | + * @param p postargs to send along with the HTTP request. |
2106 | + * @return In case of an error NULL is returned; otherwise a pointer to the |
2107 | + * replied content from HTTP server. latter needs to be freed by caller. |
2108 | + */ |
2109 | +char *oauth_http_post (const char *u, const char *p) { |
2110 | +#ifdef HAVE_CURL |
2111 | + return oauth_curl_post(u,p); |
2112 | +#else // no cURL. |
2113 | + return oauth_exec_post(u,p); |
2114 | +#endif |
2115 | +} |
2116 | + |
2117 | +/** |
2118 | + * http post raw data from file. |
2119 | + * the returned string needs to be freed by the caller |
2120 | + * |
2121 | + * more documentation in oauth.h |
2122 | + * |
2123 | + * @param u url to retrieve |
2124 | + * @param fn filename of the file to post along |
2125 | + * @param len length of the file in bytes. set to '0' for autodetection |
2126 | + * @param customheader specify custom HTTP header (or NULL for default) |
2127 | + * @return returned HTTP reply or NULL on error |
2128 | + */ |
2129 | +char *oauth_post_file (const char *u, const char *fn, const size_t len, const char *customheader){ |
2130 | +#ifdef HAVE_CURL |
2131 | + return oauth_curl_post_file (u, fn, len, customheader); |
2132 | +#else |
2133 | + fprintf(stderr, "\nliboauth: oauth_post_file requires libcurl. libcurl is not available.\n\n"); |
2134 | + return (NULL); |
2135 | +#endif |
2136 | +} |
2137 | + |
2138 | +/** |
2139 | + * http post raw data. |
2140 | + * the returned string needs to be freed by the caller |
2141 | + * |
2142 | + * more documentation in oauth.h |
2143 | + * |
2144 | + * @param u url to retrieve |
2145 | + * @param data data to post along |
2146 | + * @param len length of the file in bytes. set to '0' for autodetection |
2147 | + * @param customheader specify custom HTTP header (or NULL for default) |
2148 | + * @return returned HTTP reply or NULL on error |
2149 | + */ |
2150 | +char *oauth_post_data (const char *u, const char *data, size_t len, const char *customheader) { |
2151 | +#ifdef HAVE_CURL |
2152 | + return oauth_curl_post_data (u, data, len, customheader); |
2153 | +#else |
2154 | + fprintf(stderr, "\nliboauth: oauth_post_data requires libcurl. libcurl is not available.\n\n"); |
2155 | + return (NULL); |
2156 | +#endif |
2157 | +} |
2158 | +/* vi:set ts=8 sts=2 sw=2: */ |
2159 | |
2160 | === modified file 'couchdb-glib/utils.c' |
2161 | --- couchdb-glib/utils.c 2009-08-17 22:26:51 +0000 |
2162 | +++ couchdb-glib/utils.c 2009-09-04 09:28:53 +0000 |
2163 | @@ -24,6 +24,10 @@ |
2164 | #include <libsoup/soup-session-async.h> |
2165 | #include "couchdb-glib.h" |
2166 | #include "utils.h" |
2167 | +#ifdef HAVE_OAUTH |
2168 | +#include <time.h> |
2169 | +#include "oauth.h" |
2170 | +#endif |
2171 | |
2172 | static JsonParser * |
2173 | parse_json_response (SoupMessage *http_message, GError **error) |
2174 | @@ -72,6 +76,41 @@ |
2175 | return error; |
2176 | } |
2177 | |
2178 | +#ifdef HAVE_OAUTH |
2179 | +static void |
2180 | +add_oauth_signature (CouchDB *couchdb, SoupMessage *http_message, const char *method, const char *url) |
2181 | +{ |
2182 | + char *signature;; |
2183 | + |
2184 | + signature = oauth_sign_url2 (url, NULL, OA_HMAC, method, |
2185 | + couchdb->oauth_consumer_key, |
2186 | + couchdb->oauth_consumer_secret, |
2187 | + couchdb->oauth_token_key, |
2188 | + couchdb->oauth_token_secret); |
2189 | + if (signature != NULL) { |
2190 | + char *header, *nonce; |
2191 | + |
2192 | + nonce = oauth_gen_nonce (); |
2193 | + header = g_strdup_printf ("OAuth realm = \"\", oauth_version=\"1.0\", " |
2194 | + "oauth_signature=\"%s\", oauth_token=\"%s\", " |
2195 | + "oauth_nonce=\"%s\", oauth_timestamp=\"%ld\", " |
2196 | + "oauth_signature_method=\"HMAC-SHA1\", " |
2197 | + "oauth_consumer_key=\"%s\", oauth_verifier=\"None\", " |
2198 | + "oauth_callback=\"None\"", |
2199 | + signature, |
2200 | + couchdb->oauth_token_key, |
2201 | + nonce, |
2202 | + time (NULL), |
2203 | + couchdb->oauth_consumer_key); |
2204 | + soup_message_headers_append (http_message->request_headers, "Authorization", header); |
2205 | + |
2206 | + g_free (header); |
2207 | + free (nonce); |
2208 | + free (signature); |
2209 | + } |
2210 | +} |
2211 | +#endif |
2212 | + |
2213 | JsonParser * |
2214 | send_message_and_parse (CouchDB *couchdb, const char *method, const char *url, const char *body, GError **error) |
2215 | { |
2216 | @@ -85,12 +124,17 @@ |
2217 | body, strlen (body)); |
2218 | } |
2219 | |
2220 | +#ifdef HAVE_OAUTH |
2221 | + if (couchdb->oauth_enabled) |
2222 | + add_oauth_signature (couchdb, http_message, method, url); |
2223 | +#endif |
2224 | + |
2225 | g_debug ("Sending %s to %s...", method, url); |
2226 | status = soup_session_send_message (couchdb->http_session, http_message); |
2227 | if (SOUP_STATUS_IS_SUCCESSFUL (status)) { |
2228 | parser = parse_json_response (http_message, error); |
2229 | } else { |
2230 | - g_set_error (error, COUCHDB_ERROR, status, http_message->reason_phrase); |
2231 | + g_set_error (error, COUCHDB_ERROR, status, "%s", http_message->reason_phrase); |
2232 | } |
2233 | |
2234 | return parser; |
2235 | |
2236 | === modified file 'couchdb-glib/utils.h' |
2237 | --- couchdb-glib/utils.h 2009-08-31 15:48:46 +0000 |
2238 | +++ couchdb-glib/utils.h 2009-09-04 09:28:53 +0000 |
2239 | @@ -22,6 +22,7 @@ |
2240 | #ifndef __UTILS_H__ |
2241 | #define __UTILS_H__ |
2242 | |
2243 | +#include "config.h" |
2244 | #include <libsoup/soup-session-async.h> |
2245 | #include <json-glib/json-glib.h> |
2246 | |
2247 | @@ -32,6 +33,14 @@ |
2248 | SoupSession *http_session; |
2249 | |
2250 | GHashTable *db_watchlist; |
2251 | + |
2252 | +#ifdef HAVE_OAUTH |
2253 | + gboolean oauth_enabled; |
2254 | + char *oauth_consumer_key; |
2255 | + char *oauth_consumer_secret; |
2256 | + char *oauth_token_key; |
2257 | + char *oauth_token_secret; |
2258 | +#endif |
2259 | }; |
2260 | |
2261 | struct _CouchDBDocument { |
2262 | |
2263 | === added file 'couchdb-glib/xmalloc.c' |
2264 | --- couchdb-glib/xmalloc.c 1970-01-01 00:00:00 +0000 |
2265 | +++ couchdb-glib/xmalloc.c 2009-09-04 09:28:53 +0000 |
2266 | @@ -0,0 +1,151 @@ |
2267 | +/* xmalloc.c -- malloc with out of memory checking |
2268 | + Copyright (C) 1990, 91, 92, 93, 94, 95, 96, 99 Free Software Foundation, Inc. |
2269 | + |
2270 | + This program is free software; you can redistribute it and/or modify |
2271 | + it under the terms of the GNU General Public License as published by |
2272 | + the Free Software Foundation; either version 2, or (at your option) |
2273 | + any later version. |
2274 | + |
2275 | + This program is distributed in the hope that it will be useful, |
2276 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
2277 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2278 | + GNU General Public License for more details. |
2279 | + |
2280 | + You should have received a copy of the GNU General Public License |
2281 | + along with this program; if not, write to the Free Software Foundation, |
2282 | + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
2283 | + |
2284 | +#if HAVE_CONFIG_H |
2285 | +# include <config.h> |
2286 | +#endif |
2287 | + |
2288 | +#ifndef USE_LGPL |
2289 | +// TODO better use #define in header file?! |
2290 | +#include <string.h> |
2291 | +#include <stdlib.h> |
2292 | +void *xmalloc (size_t n) {return malloc(n);} |
2293 | +void *xcalloc (size_t n, size_t s) {return calloc(n,s);} |
2294 | +void *xrealloc (void *p, size_t n) {return realloc(p,n);} |
2295 | +char *xstrdup (const char *p) {return strdup(p);} |
2296 | + |
2297 | +#else // LGPL LICENSED CODE |
2298 | +#if __STDC__ |
2299 | +# define VOID void |
2300 | +#else |
2301 | +# define VOID char |
2302 | +#endif |
2303 | + |
2304 | +#include <stdio.h> /* for stderr */ |
2305 | + |
2306 | +#if STDC_HEADERS |
2307 | + |
2308 | +#include <sys/types.h> |
2309 | +#include <string.h> /* for strlen etc. */ |
2310 | +#include <stdlib.h> |
2311 | + |
2312 | +#else /* !STDC_HEADERS */ |
2313 | + |
2314 | +extern size_t strlen (); |
2315 | +extern char *strcpy (); |
2316 | + |
2317 | +VOID *calloc (); |
2318 | +VOID *malloc (); |
2319 | +VOID *realloc (); |
2320 | +void free (); |
2321 | +#endif |
2322 | + |
2323 | +#if ENABLE_NLS |
2324 | +# include <libintl.h> |
2325 | +# define _(Text) gettext (Text) |
2326 | +#else |
2327 | +# define textdomain(Domain) |
2328 | +# define _(Text) Text |
2329 | +#endif |
2330 | + |
2331 | +/* Prototypes for functions defined here. */ |
2332 | +#if defined (__STDC__) && __STDC__ |
2333 | +static VOID *fixup_null_alloc (size_t n); |
2334 | +VOID *xmalloc (size_t n); |
2335 | +VOID *xcalloc (size_t n, size_t s); |
2336 | +VOID *xrealloc (VOID *p, size_t n); |
2337 | +char *xstrdup (const char *p); |
2338 | +#endif |
2339 | + |
2340 | + |
2341 | +static VOID * |
2342 | +fixup_null_alloc (n) |
2343 | + size_t n; |
2344 | +{ |
2345 | + VOID *p; |
2346 | + |
2347 | + p = 0; |
2348 | + if (n == 0) |
2349 | + p = malloc ((size_t) 1); |
2350 | + if (p == 0) |
2351 | + { |
2352 | + /* possible revisions: release some memory and re-try, print |
2353 | + more information (e.g. line number of input file) */ |
2354 | + fprintf(stderr, _("liboauth: Memory exhausted")); |
2355 | + exit(1); |
2356 | + } |
2357 | + return p; |
2358 | +} |
2359 | + |
2360 | +/* Allocate N bytes of memory dynamically, with error checking. */ |
2361 | + |
2362 | +VOID * |
2363 | +xmalloc (n) |
2364 | + size_t n; |
2365 | +{ |
2366 | + VOID *p; |
2367 | + |
2368 | + p = malloc (n); |
2369 | + if (p == 0) |
2370 | + p = fixup_null_alloc (n); |
2371 | + return p; |
2372 | +} |
2373 | + |
2374 | +/* Allocate memory for N elements of S bytes, with error checking. */ |
2375 | + |
2376 | +VOID * |
2377 | +xcalloc (n, s) |
2378 | + size_t n, s; |
2379 | +{ |
2380 | + VOID *p; |
2381 | + |
2382 | + p = calloc (n, s); |
2383 | + if (p == 0) |
2384 | + p = fixup_null_alloc (n); |
2385 | + return p; |
2386 | +} |
2387 | + |
2388 | +/* Change the size of an allocated block of memory P to N bytes, |
2389 | + with error checking. |
2390 | + If P is NULL, run xmalloc. */ |
2391 | + |
2392 | +VOID * |
2393 | +xrealloc (p, n) |
2394 | + VOID *p; |
2395 | + size_t n; |
2396 | +{ |
2397 | + if (p == 0) |
2398 | + return xmalloc (n); |
2399 | + p = realloc (p, n); |
2400 | + if (p == 0) |
2401 | + p = fixup_null_alloc (n); |
2402 | + return p; |
2403 | +} |
2404 | + |
2405 | +/* Make a copy of a string in a newly allocated block of memory. */ |
2406 | + |
2407 | +char * |
2408 | +xstrdup (str) |
2409 | + const char *str; |
2410 | +{ |
2411 | + VOID *p; |
2412 | + |
2413 | + p = xmalloc (strlen (str) + 1); |
2414 | + strcpy (p, str); |
2415 | + return p; |
2416 | +} |
2417 | +#endif |
2418 | |
2419 | === added file 'couchdb-glib/xmalloc.h' |
2420 | --- couchdb-glib/xmalloc.h 1970-01-01 00:00:00 +0000 |
2421 | +++ couchdb-glib/xmalloc.h 2009-09-04 09:28:53 +0000 |
2422 | @@ -0,0 +1,12 @@ |
2423 | +/* Prototypes for functions defined in xmalloc.c */ |
2424 | + |
2425 | +void *xmalloc (size_t n); |
2426 | +void *xcalloc (size_t n, size_t s); |
2427 | +void *xrealloc (void *p, size_t n); |
2428 | +char *xstrdup (const char *p); |
2429 | + |
2430 | +/* POSIX prototypes - avoid compiler warnings with '-posix' */ |
2431 | +int strncasecmp(const char *s1, const char *s2, size_t n); |
2432 | +int snprintf(char *str, size_t size, const char *format, ...); |
2433 | +FILE *popen(const char *command, const char *type); |
2434 | +int pclose(FILE *stream); |
2435 | |
2436 | === modified file 'tests/Makefile.am' |
2437 | --- tests/Makefile.am 2009-08-05 14:32:15 +0000 |
2438 | +++ tests/Makefile.am 2009-09-04 09:28:53 +0000 |
2439 | @@ -9,12 +9,14 @@ |
2440 | test_list_databases_SOURCES = test-list-databases.c |
2441 | test_list_databases_LDADD = \ |
2442 | $(COUCHDB_GLIB_LIBS) \ |
2443 | + $(OAUTH_LIBS) \ |
2444 | -luuid \ |
2445 | $(top_builddir)/couchdb-glib/libcouchdb-glib-1.0.la |
2446 | |
2447 | test_couchdb_glib_SOURCES = test-couchdb-glib.c |
2448 | test_couchdb_glib_LDADD = \ |
2449 | $(COUCHDB_GLIB_LIBS) \ |
2450 | + $(OAUTH_LIBS) \ |
2451 | -luuid \ |
2452 | $(top_builddir)/couchdb-glib/libcouchdb-glib-1.0.la |
2453 |
Added OAuth signing support