Merge lp:~rodrigo-moya/couchdb-glib/oauth-signing into lp:couchdb-glib

Proposed by Rodrigo Moya
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
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.

To post a comment you must log in.
Revision history for this message
Rodrigo Moya (rodrigo-moya) wrote :

Added OAuth signing support

90. By Rodrigo Moya

Added missing 'return TRUE' in couchdb_enable_oauth

91. By Rodrigo Moya

Remove extra ;

Revision history for this message
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.

review: Needs Fixing
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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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

Subscribers

People subscribed via source and target branches