1 /*
2   +----------------------------------------------------------------------+
3   | See LICENSE file for further copyright information                   |
4   +----------------------------------------------------------------------+
5   | Authors: John Jawed <jawed@php.net>                                  |
6   |          Felipe Pena <felipe@php.net>                                |
7   |          Rasmus Lerdorf <rasmus@php.net>                             |
8   +----------------------------------------------------------------------+
9 */
10 
11 #ifndef PHP_OAUTH_H
12 #define PHP_OAUTH_H
13 
14 #ifdef HAVE_CONFIG_H
15 #include "config.h"
16 #endif
17 
18 #include "php.h"
19 
20 #ifdef PHP_WIN32
21 #include "win32/time.h"
22 #endif
23 
24 #include "SAPI.h"
25 #include "zend_API.h"
26 #include "zend_variables.h"
27 #include "ext/standard/head.h"
28 #include "php_globals.h"
29 #include "php_main.h"
30 #include "php_ini.h"
31 #include "ext/standard/php_string.h"
32 #include "ext/standard/php_rand.h"
33 #include "ext/standard/php_smart_string.h"
34 #include "ext/standard/info.h"
35 #include "ext/standard/php_string.h"
36 #include "ext/standard/php_versioning.h"
37 #include "ext/standard/url.h"
38 #include "php_variables.h"
39 #include "zend_exceptions.h"
40 #include "zend_interfaces.h"
41 #include "php_globals.h"
42 #include "ext/standard/file.h"
43 #include "ext/standard/base64.h"
44 #include "ext/standard/php_lcg.h"
45 #include "ext/pcre/php_pcre.h"
46 #include "php_network.h"
47 
48 #if OAUTH_USE_CURL
49 #include <curl/curl.h>
50 #define CLEANUP_CURL_AND_FORM(f,h)	 \
51 	curl_easy_cleanup(h);	 \
52 	curl_formfree(f);
53 #endif
54 
55 #define PHP_OAUTH_VERSION 2.0.7
56 
57 #define __stringify_1(x)    #x
58 #define __stringify(x)      __stringify_1(x)
59 #define __OAUTH_EXT_VER PHP_OAUTH_VERSION
60 #define OAUTH_EXT_VER __stringify(__OAUTH_EXT_VER)
61 #define OAUTH_USER_AGENT "PECL-OAuth/" __stringify(__OAUTH_EXT_VER)
62 #define OAUTH_HTTP_PORT 80
63 #define OAUTH_HTTPS_PORT 443
64 #define OAUTH_MAX_REDIRS 4L
65 #define OAUTH_MAX_HEADER_LEN 512L
66 #define OAUTH_AUTH_TYPE_URI 0x01
67 #define OAUTH_AUTH_TYPE_FORM 0x02
68 #define OAUTH_AUTH_TYPE_AUTHORIZATION 0x03
69 #define OAUTH_AUTH_TYPE_NONE 0x04
70 
71 #define OAUTH_SIG_METHOD_HMACSHA1 "HMAC-SHA1"
72 #define OAUTH_SIG_METHOD_HMACSHA256 "HMAC-SHA256"
73 #define OAUTH_SIG_METHOD_RSASHA1 "RSA-SHA1"
74 #define OAUTH_SIG_METHOD_PLAINTEXT "PLAINTEXT"
75 
76 extern zend_module_entry oauth_module_entry;
77 
78 #define phpext_oauth_ptr &oauth_module_entry
79 
80 #define PHP_OAUTH_API
81 
82 #define OAUTH_ATTR_CONSUMER_KEY "oauth_consumer_key"
83 #define OAUTH_ATTR_CONSUMER_SECRET "oauth_consumer_secret"
84 #define OAUTH_ATTR_ACCESS_TOKEN "oauth_access_token"
85 #define OAUTH_RAW_LAST_RES "oauth_last_response_raw"
86 #define OAUTH_ATTR_LAST_RES_INFO "oauth_last_response_info"
87 #define OAUTH_ATTR_SIGMETHOD "oauth_sig_method"
88 #define OAUTH_ATTR_TOKEN "oauth_token"
89 #define OAUTH_ATTR_TOKEN_SECRET "oauth_token_secret"
90 #define OAUTH_ATTR_AUTHMETHOD "oauth_auth_method"
91 #define OAUTH_ATTR_OAUTH_VERSION "oauth_version"
92 #define OAUTH_ATTR_OAUTH_NONCE "oauth_nonce"
93 #define OAUTH_ATTR_OAUTH_USER_NONCE "oauth_user_nonce"
94 #define OAUTH_ATTR_CA_PATH "oauth_ssl_ca_path"
95 #define OAUTH_ATTR_CA_INFO "oauth_ssl_ca_info"
96 
97 #define OAUTH_HTTP_METHOD_GET "GET"
98 #define OAUTH_HTTP_METHOD_POST "POST"
99 #define OAUTH_HTTP_METHOD_PUT "PUT"
100 #define OAUTH_HTTP_METHOD_HEAD "HEAD"
101 #define OAUTH_HTTP_METHOD_DELETE "DELETE"
102 
103 #define OAUTH_REQENGINE_STREAMS 1
104 #define OAUTH_REQENGINE_CURL 2
105 
106 #define OAUTH_FETCH_USETOKEN 1
107 #define OAUTH_FETCH_SIGONLY 2
108 #define OAUTH_FETCH_HEADONLY 4
109 #define OAUTH_OVERRIDE_HTTP_METHOD 8
110 
111 #define OAUTH_SSLCHECK_NONE 0
112 #define OAUTH_SSLCHECK_HOST 1
113 #define OAUTH_SSLCHECK_PEER 2
114 #define OAUTH_SSLCHECK_BOTH (OAUTH_SSLCHECK_HOST | OAUTH_SSLCHECK_PEER)
115 
116 #define OAUTH_DEFAULT_VERSION "1.0"
117 
118 /* errors */
119 #define OAUTH_ERR_CONTENT_TYPE "invalidcontentttype"
120 #define OAUTH_ERR_BAD_REQUEST 400
121 #define OAUTH_ERR_BAD_AUTH 401
122 #define OAUTH_ERR_INTERNAL_ERROR 503
123 
124 /* params */
125 #define OAUTH_PARAM_CONSUMER_KEY "oauth_consumer_key"
126 #define OAUTH_PARAM_SIGNATURE "oauth_signature"
127 #define OAUTH_PARAM_SIGNATURE_METHOD "oauth_signature_method"
128 #define OAUTH_PARAM_TIMESTAMP "oauth_timestamp"
129 #define OAUTH_PARAM_NONCE "oauth_nonce"
130 #define OAUTH_PARAM_VERSION "oauth_version"
131 #define OAUTH_PARAM_TOKEN "oauth_token"
132 #define OAUTH_PARAM_ASH "oauth_session_handle"
133 #define OAUTH_PARAM_VERIFIER "oauth_verifier"
134 #define OAUTH_PARAM_CALLBACK "oauth_callback"
135 
136 /* values */
137 #define OAUTH_CALLBACK_OOB "oob"
138 
139 #define OAUTH_PARAM_PREFIX "oauth_"
140 #define OAUTH_PARAM_PREFIX_LEN 6
141 
142 #ifdef ZTS
143 #include "TSRM.h"
144 #endif
145 
146 PHP_MINIT_FUNCTION(oauth);
147 PHP_MSHUTDOWN_FUNCTION(oauth);
148 PHP_MINFO_FUNCTION(oauth);
149 
150 #ifdef ZTS
151 #define OAUTH(v) TSRMG(oauth_globals_id, zend_oauth_globals *, v)
152 #else
153 #define OAUTH(v) (oauth_globals.v)
154 #endif
155 
156 typedef enum { OAUTH_SIGCTX_TYPE_NONE, OAUTH_SIGCTX_TYPE_HMAC, OAUTH_SIGCTX_TYPE_RSA, OAUTH_SIGCTX_TYPE_PLAIN } oauth_sigctx_type;
157 
158 typedef struct {
159 	oauth_sigctx_type	type;
160 	char				*hash_algo;
161 	zval				privatekey;
162 } oauth_sig_context;
163 
164 #define OAUTH_SIGCTX_INIT(ctx) { \
165 		(ctx) = emalloc(sizeof(*(ctx))); \
166 		(ctx)->type = OAUTH_SIGCTX_TYPE_NONE; \
167 		(ctx)->hash_algo = NULL; \
168 		ZVAL_UNDEF(&ctx->privatekey); \
169 	}
170 
171 #define OAUTH_SIGCTX_HMAC(ctx, algo) { \
172 		(ctx)->type = OAUTH_SIGCTX_TYPE_HMAC; \
173 		(ctx)->hash_algo = algo; \
174 	}
175 
176 #define OAUTH_SIGCTX_PLAIN(ctx) { \
177 		(ctx)->type = OAUTH_SIGCTX_TYPE_PLAIN; \
178 	}
179 
180 #define OAUTH_SIGCTX_FREE_PRIVATEKEY(ctx) { \
181 		if (Z_TYPE(ctx->privatekey) != IS_UNDEF) { \
182 			oauth_free_privatekey(&ctx->privatekey); \
183 			ZVAL_UNDEF(&ctx->privatekey); \
184 		} \
185 	}
186 
187 #define OAUTH_SIGCTX_SET_PRIVATEKEY(ctx, privkey) { \
188 		OAUTH_SIGCTX_FREE_PRIVATEKEY(ctx) \
189 		ZVAL_DUP(&ctx->privatekey, &privkey); \
190 	}
191 
192 #define OAUTH_SIGCTX_RSA(ctx, algo) { \
193 		(ctx)->type = OAUTH_SIGCTX_TYPE_RSA; \
194 		(ctx)->hash_algo = algo; \
195 	}
196 
197 #define OAUTH_SIGCTX_FREE(ctx) { \
198 		if (ctx) { \
199 			OAUTH_SIGCTX_FREE_PRIVATEKEY(ctx) \
200 			efree((ctx)); \
201 		} \
202 	}
203 
204 typedef struct {
205 	zend_string		*sbs;
206 	smart_string	headers_in;
207 	smart_string	headers_out;
208 	smart_string	body_in;
209 	smart_string	body_out;
210 	smart_string	curl_info;
211 } php_so_debug;
212 
213 typedef struct {
214 	HashTable *properties;
215 	smart_string lastresponse;
216 	smart_string headers_in;
217 	smart_string headers_out;
218 	char last_location_header[OAUTH_MAX_HEADER_LEN];
219 	uint32_t redirects;
220 	uint32_t multipart_files_num;
221 	uint32_t sslcheck; /* whether we check for SSL verification or not */
222 	uint32_t debug; /* verbose output */
223 	uint32_t follow_redirects; /* follow and sign redirects? */
224 	uint32_t reqengine; /* streams or curl */
225 	long timeout; /* timeout in milliseconds */
226 	char *nonce;
227 	char *timestamp;
228 	zend_string *signature;
229 	zval *this_ptr;
230 	zval debugArr;
231 	oauth_sig_context *sig_ctx;
232 	php_so_debug *debug_info;
233 	char **multipart_files;
234 	char **multipart_params;
235 	uint32_t is_multipart;
236 	void ***thread_ctx;
237 	zend_object zo;
238 } php_so_object;
239 
so_object_from_obj(zend_object * obj)240 static inline php_so_object *so_object_from_obj(zend_object *obj) /* {{{ */ {
241     return (php_so_object*)((char*)(obj) - XtOffsetOf(php_so_object, zo));
242 }
243 /* }}} */
244 
Z_SOO_P(zval * zv)245 static inline php_so_object *Z_SOO_P(zval *zv) /* {{{ */ {
246 	php_so_object *soo = so_object_from_obj(Z_OBJ_P((zv)));
247 	soo->this_ptr = zv;
248 	return soo;
249 }
250 /* }}} */
251 
252 #ifndef zend_parse_parameters_none
253 #define zend_parse_parameters_none()    \
254 	zend_parse_parameters(ZEND_NUM_ARGS(), "")
255 #endif
256 
257 void soo_handle_error(php_so_object *soo, long errorCode, char *msg, char *response, char *additional_info);
258 zend_string *oauth_generate_sig_base(php_so_object *soo, const char *http_method, const char *uri, HashTable *post_args, HashTable *extra_args);
259 
260 #ifndef zend_hash_quick_del
261 #define HASH_DEL_KEY_QUICK 2
262 #define zend_hash_quick_del(ht, arKey, nKeyLength, h) \
263        zend_hash_del_key_or_index(ht, arKey, nKeyLength, h, HASH_DEL_KEY_QUICK)
264 #endif
265 
266 #define SO_ME(func, arg_info, flags) PHP_ME(oauth, func, arg_info, flags)
267 #define SO_MALIAS(func, alias, arg_info, flags) PHP_MALIAS(oauth, func, alias, arg_info, flags)
268 #define SO_METHOD(func) PHP_METHOD(oauth, func)
269 #define FREE_ARGS_HASH(a)	\
270 	if (a) { \
271 		zend_hash_destroy(a);	\
272 		FREE_HASHTABLE(a); \
273 	}
274 
275 #define INIT_smart_string(a) \
276 	(a).len = 0; \
277 	(a).c = NULL;
278 
279 #define HTTP_IS_REDIRECT(http_response_code) \
280 	(http_response_code > 300 && http_response_code < 304)
281 
282 #define INIT_DEBUG_INFO(a) \
283 	INIT_smart_string((a)->headers_out); \
284 	INIT_smart_string((a)->body_in); \
285 	INIT_smart_string((a)->body_out); \
286 	INIT_smart_string((a)->curl_info);
287 
288 #define FREE_DEBUG_INFO(a) \
289 	smart_string_free(&(a)->headers_out); \
290 	smart_string_free(&(a)->body_in); \
291 	smart_string_free(&(a)->body_out); \
292 	smart_string_free(&(a)->curl_info);
293 
294 /* this and code that uses it is from ext/curl/interface.c */
295 #define CAAL(s, v) add_assoc_long_ex(&info, s, sizeof(s) - 1, (long) v);
296 #define CAAD(s, v) add_assoc_double_ex(&info, s, sizeof(s) - 1, (double) v);
297 #define CAAS(s, v) add_assoc_string_ex(&info, s, sizeof(s) - 1, (char *) (v ? v : ""));
298 
299 #define ADD_DEBUG_INFO(a, k, s, t) \
300 	if(s.len) { \
301 		smart_string_0(&(s)); \
302 		if(t) { \
303 			zend_string *tmp, *s_zstr = zend_string_init((s).c, (s).len, 0); \
304 			tmp = php_trim(s_zstr, NULL, 0, 3); \
305 			add_assoc_string((a), k, ZSTR_VAL(tmp)); \
306 			zend_string_release(tmp); \
307 			zend_string_release(s_zstr); \
308 		} else { \
309 			add_assoc_string((a), k, (s).c); \
310 		} \
311 	}
312 
313 #ifndef TRUE
314 #define TRUE 1
315 #define FALSE 0
316 #endif
317 
318 #define OAUTH_OK SUCCESS
319 
320 #if OAUTH_USE_CURL
321 long make_req_curl(php_so_object *soo, const char *url, const smart_string *payload, const char *http_method, HashTable *request_headers);
322 #if LIBCURL_VERSION_NUM >= 0x071304
323 #define OAUTH_PROTOCOLS_ALLOWED CURLPROTO_HTTP | CURLPROTO_HTTPS
324 #endif
325 #endif
326 
327 
328 void oauth_free_privatekey(zval *privatekey);
329 zend_string *soo_sign(php_so_object *soo, char *message, zval *cs, zval *ts, const oauth_sig_context *ctx);
330 oauth_sig_context *oauth_create_sig_context(const char *sigmethod);
331 zend_string *oauth_url_encode(char *url, int url_len);
332 
333 
334 // Compatibility macros
335 #if PHP_VERSION_ID < 70300
336 #define OAUTH_URL_STR(a) (a)
337 #define OAUTH_URL_LEN(a) strlen(a)
338 #else
339 #define OAUTH_URL_STR(a) ZSTR_VAL(a)
340 #define OAUTH_URL_LEN(a) ZSTR_LEN(a)
341 #endif
342 
343 #if PHP_VERSION_ID < 80000
344 #define OBJ_FOR_PROP(zv) (zv)
345 #else
346 #define OBJ_FOR_PROP(zv) Z_OBJ_P(zv)
347 #endif
348 
349 #endif
350 
351 /**
352  * Local Variables:
353  * c-basic-offset: 4
354  * tab-width: 4
355  * indent-tabs-mode: t
356  * End:
357  * vim600: fdm=marker
358  * vim: noet sw=4 ts=4 noexpandtab
359  */
360