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 |          Tjerk Meesters <datibbaw@php.net>                           |
9 +----------------------------------------------------------------------+
10 */
11 
12 #include "php_oauth.h"
13 #include "provider.h"
14 
15 #if PHP_WIN32
16 # include <windows.h>
17 # include <Wincrypt.h>
18 #endif
19 
20 #include "fcntl.h"
21 
22 static zend_object_handlers oauth_provider_obj_hndlrs;
23 static zend_class_entry *oauthprovider;
24 
oauth_provider_set_param_member(zval * provider_obj,char * prop_name,zval * prop)25 static inline void oauth_provider_set_param_member(zval *provider_obj, char *prop_name, zval *prop) /* {{{ */
26 {
27 	zend_update_property(Z_OBJCE_P(provider_obj), OBJ_FOR_PROP(provider_obj), prop_name, strlen(prop_name), prop);
28 }
29 /* }}} */
30 
fetch_sop_object(zval * obj)31 static inline php_oauth_provider *fetch_sop_object(zval *obj) /* {{{ */
32 {
33 	php_oauth_provider *sop = Z_SOP_P(obj);
34 	sop->this_ptr = obj;
35 	return sop;
36 }
37 /* }}} */
38 
oauth_provider_set_default_required_params(HashTable * ht)39 static int oauth_provider_set_default_required_params(HashTable *ht) /* {{{ */
40 {
41 	char *required_params[] = {"oauth_consumer_key", "oauth_signature", "oauth_signature_method", "oauth_nonce", "oauth_timestamp", "oauth_token", NULL};
42 	unsigned int idx = 0;
43 
44 	do {
45 		zval tmp;
46 		ZVAL_NULL(&tmp);
47 		if(zend_hash_str_add(ht, required_params[idx], strlen(required_params[idx]), &tmp) == NULL) {
48 			return FAILURE;
49 		}
50 		++idx;
51 	} while(required_params[idx]);
52 
53 	return SUCCESS;
54 }
55 /* }}} */
56 
oauth_provider_remove_required_param(HashTable * ht,char * required_param)57 static int oauth_provider_remove_required_param(HashTable *ht, char *required_param) /* {{{ */
58 {
59 	zval *dest_entry;
60 	zend_string *key;
61 	zend_ulong num_key;
62 	HashPosition hpos;
63 
64 	if((dest_entry = zend_hash_str_find(ht, required_param, strlen(required_param))) == NULL) {
65 		return FAILURE;
66 	} else {
67 		zend_hash_internal_pointer_reset_ex(ht, &hpos);
68 		do {
69 			if(zend_hash_get_current_key_ex(ht, &key, &num_key, &hpos)!=FAILURE) {
70 				if(!strcmp(ZSTR_VAL(key), required_param)) {
71 					zend_hash_del(ht, key);
72 					return SUCCESS;
73 				}
74 			}
75 		} while(zend_hash_move_forward_ex(ht, &hpos)==SUCCESS);
76 	}
77 	return FAILURE;
78 }
79 /* }}} */
80 
oauth_provider_add_required_param(HashTable * ht,char * required_param)81 static int oauth_provider_add_required_param(HashTable *ht, char *required_param) /* {{{ */
82 {
83 	zval zparam, *dest_entry;
84 
85 	if((dest_entry = zend_hash_str_find(ht, required_param, strlen(required_param))) == NULL) {
86 		ZVAL_NULL(&zparam);
87 		if(zend_hash_str_add(ht, required_param, strlen(required_param), &zparam) == NULL) {
88 			return FAILURE;
89 		}
90 	}
91 	return SUCCESS;
92 }
93 /* }}} */
94 
oauth_provider_apply_custom_param(HashTable * ht,HashTable * custom)95 static void oauth_provider_apply_custom_param(HashTable *ht, HashTable *custom) /* {{{ */
96 {
97 	HashPosition custompos;
98 	zval *entry;
99 	zend_string *key;
100 	zend_ulong num_key;
101 
102 	zend_hash_internal_pointer_reset_ex(custom, &custompos);
103 	do {
104 		if ((entry = zend_hash_get_current_data_ex(custom, &custompos)) != NULL && HASH_KEY_IS_STRING == zend_hash_get_current_key_ex(custom, &key, &num_key, &custompos)) {
105 			if (IS_NULL == Z_TYPE_P(entry)) {
106 				zend_hash_del(ht, key);
107 			} else {
108 				Z_TRY_ADDREF_P(entry);
109 				zend_hash_update(ht, key, entry);
110 			}
111 		}
112 	} while (SUCCESS==zend_hash_move_forward_ex(custom, &custompos));
113 }
114 /* }}} */
115 
oauth_provider_token_required(zval * provider_obj,char * uri)116 static int oauth_provider_token_required(zval *provider_obj, char* uri)
117 {
118 	zval *is_req_token_api, rv;
119 
120 	is_req_token_api = zend_read_property(Z_OBJCE_P(provider_obj), OBJ_FOR_PROP(provider_obj), "request_token_endpoint", sizeof("request_token_endpoint") - 1, 1, &rv);
121 
122 	if (Z_TYPE_P(is_req_token_api) == IS_FALSE) {
123 		php_oauth_provider *sop;
124 
125 		sop = fetch_sop_object(provider_obj);
126 		/* do uri matching on the relative path */
127 		if (sop->endpoint_paths[OAUTH_PROVIDER_PATH_REQUEST]) {
128 			const char *reqtoken_path = sop->endpoint_paths[OAUTH_PROVIDER_PATH_REQUEST];
129 			int uri_matched = 0;
130 
131 			if (reqtoken_path[0]=='/') {
132 				/* match against relative url */
133 				php_url *urlparts = php_url_parse_ex(uri, strlen(uri));
134 				uri_matched = urlparts && 0==strncmp(OAUTH_URL_STR(urlparts->path), reqtoken_path, strlen(reqtoken_path));
135 				php_url_free(urlparts);
136 			} else {
137 				/* match against full uri */
138 				uri_matched = 0==strncmp(uri, reqtoken_path, strlen(reqtoken_path));
139 			}
140 
141 			/* token required if no match was found */
142 			if (uri_matched) {
143 				ZVAL_BOOL(is_req_token_api, 1);
144 				return 0;
145 			}
146 		}
147 
148 		/* no matches, token required */
149 		return 1;
150 	}
151 	return 0;
152 }
153 
oauth_provider_check_required_params(HashTable * required_params,HashTable * params,HashTable * missing_params)154 static void oauth_provider_check_required_params(HashTable *required_params, HashTable *params, HashTable *missing_params) /* {{{ */
155 {
156 	HashPosition hpos, reqhpos, paramhpos;
157 	zval *dest_entry, param;
158 	zend_string *key;
159 	zend_ulong num_key;
160 
161 	zend_hash_internal_pointer_reset_ex(required_params, &hpos);
162 	zend_hash_internal_pointer_reset_ex(params, &reqhpos);
163 	zend_hash_internal_pointer_reset_ex(missing_params, &paramhpos);
164 	do {
165 		if(zend_hash_get_current_key_ex(required_params, &key, &num_key, &hpos) == HASH_KEY_IS_STRING) {
166 			if((dest_entry = zend_hash_find(params, key)) == NULL) {
167 				ZVAL_STRING(&param, ZSTR_VAL(key));
168 				zend_hash_next_index_insert(missing_params, &param);
169 			}
170 		}
171 	} while(zend_hash_move_forward_ex(required_params, &hpos)==SUCCESS);
172 }
173 /* }}} */
174 
oauth_provider_set_std_params(zval * provider_obj,HashTable * sbs_vars)175 static void oauth_provider_set_std_params(zval *provider_obj, HashTable *sbs_vars) /* {{{ */
176 {
177 	zval *dest_entry;
178 
179 	if(!provider_obj || !sbs_vars) {
180 		return;
181 	}
182 
183 	OAUTH_PROVIDER_SET_STD_PARAM(sbs_vars, OAUTH_PARAM_CONSUMER_KEY, OAUTH_PROVIDER_CONSUMER_KEY);
184 	OAUTH_PROVIDER_SET_STD_PARAM(sbs_vars, OAUTH_PARAM_TOKEN, OAUTH_PROVIDER_TOKEN);
185 	OAUTH_PROVIDER_SET_STD_PARAM(sbs_vars, OAUTH_PARAM_SIGNATURE, OAUTH_PROVIDER_SIGNATURE);
186 	OAUTH_PROVIDER_SET_STD_PARAM(sbs_vars, OAUTH_PARAM_NONCE, OAUTH_PROVIDER_NONCE);
187 	OAUTH_PROVIDER_SET_STD_PARAM(sbs_vars, OAUTH_PARAM_TIMESTAMP, OAUTH_PROVIDER_TIMESTAMP);
188 	OAUTH_PROVIDER_SET_STD_PARAM(sbs_vars, OAUTH_PARAM_VERSION, OAUTH_PROVIDER_VERSION);
189 	OAUTH_PROVIDER_SET_STD_PARAM(sbs_vars, OAUTH_PARAM_SIGNATURE_METHOD, OAUTH_PROVIDER_SIGNATURE_METHOD);
190 	OAUTH_PROVIDER_SET_STD_PARAM(sbs_vars, OAUTH_PARAM_CALLBACK, OAUTH_PROVIDER_CALLBACK);
191 	OAUTH_PROVIDER_SET_STD_PARAM(sbs_vars, OAUTH_PARAM_VERIFIER, OAUTH_PROVIDER_VERIFIER);
192 }
193 /* }}} */
194 
oauth_provider_set_param_value(HashTable * ht,char * key,zval * val)195 static inline int oauth_provider_set_param_value(HashTable *ht, char *key, zval *val) /* {{{ */
196 {
197 	Z_TRY_ADDREF_P(val);
198 	return zend_hash_str_update(ht, key, strlen(key), val) != NULL;
199 }
200 /* }}} */
201 
oauth_provider_parse_auth_header(php_oauth_provider * sop,char * auth_header)202 static int oauth_provider_parse_auth_header(php_oauth_provider *sop, char *auth_header) /* {{{ */
203 {
204 	pcre_cache_entry *pce;
205 	zval subpats, return_value, *item_param, *current_param, *current_val;
206 	HashPosition hpos;
207 	zend_string *regex = zend_string_init(OAUTH_REGEX, sizeof(OAUTH_REGEX) - 1, 0);
208 #if PHP_VERSION_ID >= 70400
209 	zend_string *s_auth_header = zend_string_init(auth_header, strlen(auth_header), 0);
210 #endif
211 	size_t decoded_len;
212 
213 	if(!auth_header || strncasecmp(auth_header, "oauth", 4) || !sop) {
214 		return FAILURE;
215 	}
216 	/* pass "OAuth " */
217 	auth_header += 5;
218 
219 	if ((pce = pcre_get_compiled_regex_cache(regex)) == NULL) {
220 		zend_string_release(regex);
221 		return FAILURE;
222 	}
223 	zend_string_release(regex);
224 
225 	ZVAL_NULL(&subpats);
226 	ZVAL_NULL(&return_value);
227 
228 	php_pcre_match_impl(
229 		pce,
230 #if PHP_VERSION_ID >= 70400
231 		s_auth_header,
232 #else
233 		auth_header,
234 		strlen(auth_header),
235 #endif
236 		&return_value,
237 		&subpats,
238 		1, /* global */
239 		1, /* use flags */
240 		2, /* PREG_SET_ORDER */
241 		0
242 	);
243 
244 	if (0 == Z_LVAL(return_value)) {
245 		return FAILURE;
246 	}
247 
248 	zend_hash_internal_pointer_reset_ex(Z_ARRVAL(subpats), &hpos);
249 	/* walk the oauth param names */
250 	do {
251 		if ((item_param = zend_hash_get_current_data_ex(Z_ARRVAL(subpats), &hpos)) != NULL) {
252 			zval decoded_val;
253 			char *tmp;
254 			/*
255 			 * item = array(
256 			 * 	1 => param name
257 			 *	2 => quoted value
258 			 *	3 => unquoted value (defined if matched)
259 			 * )
260 			 */
261 			current_param = zend_hash_index_find(Z_ARRVAL_P(item_param), 1);
262 
263 			if ((current_val =zend_hash_index_find(Z_ARRVAL_P(item_param), 3)) == NULL) {
264 				current_val = zend_hash_index_find(Z_ARRVAL_P(item_param), 2);
265 			}
266 
267 			tmp = estrndup(Z_STRVAL_P(current_val), Z_STRLEN_P(current_val));
268 			decoded_len = php_url_decode(tmp, Z_STRLEN_P(current_val));
269 			ZVAL_STRINGL(&decoded_val, tmp, decoded_len);
270 
271 			if (oauth_provider_set_param_value(sop->oauth_params, Z_STRVAL_P(current_param), &decoded_val)==FAILURE) {
272 				return FAILURE;
273 			}
274 			Z_DELREF(decoded_val);
275 		}
276 	} while (SUCCESS==zend_hash_move_forward_ex(Z_ARRVAL(subpats), &hpos));
277 
278 	zval_ptr_dtor(&return_value);
279 	zval_ptr_dtor(&subpats);
280 
281 	return SUCCESS;
282 }
283 /* }}} */
284 
oauth_provider_register_cb(INTERNAL_FUNCTION_PARAMETERS,int type)285 static void oauth_provider_register_cb(INTERNAL_FUNCTION_PARAMETERS, int type) /* {{{ */
286 {
287 	zend_fcall_info fci;
288 	zend_fcall_info_cache fci_cache;
289 	php_oauth_provider *sop;
290 	php_oauth_provider_fcall *cb;
291 	php_oauth_provider_fcall **tgt_cb;
292 
293 	if(zend_parse_parameters(ZEND_NUM_ARGS(), "f", &fci, &fci_cache)==FAILURE) {
294 		return;
295 	}
296 
297 	sop = fetch_sop_object(getThis());
298 
299 	cb = emalloc(sizeof(php_oauth_provider_fcall));
300 	cb->fcall_info = emalloc(sizeof(zend_fcall_info));
301 	memcpy(cb->fcall_info, &fci, sizeof(zend_fcall_info));
302 	cb->fcall_info_cache = fci_cache;
303 
304 	Z_TRY_ADDREF(cb->fcall_info->function_name);
305 
306 	switch(type) {
307 		case OAUTH_PROVIDER_CONSUMER_CB:
308 			tgt_cb = &sop->consumer_handler;
309 			break;
310 		case OAUTH_PROVIDER_TOKEN_CB:
311 			tgt_cb = &sop->token_handler;
312 			break;
313 		case OAUTH_PROVIDER_TSNONCE_CB:
314 			tgt_cb = &sop->tsnonce_handler;
315 			break;
316 		default:
317 			php_error_docref(NULL, E_ERROR, "Invalid callback type for OAuthProvider");
318 			return;
319 	}
320 
321 	OAUTH_PROVIDER_FREE_CB((*tgt_cb));
322 	(*tgt_cb) = cb;
323 }
324 /* }}} */
325 
oauth_provider_call_cb(INTERNAL_FUNCTION_PARAMETERS,int type)326 static zval *oauth_provider_call_cb(INTERNAL_FUNCTION_PARAMETERS, int type) /* {{{ */
327 {
328 	php_oauth_provider *sop;
329 	php_oauth_provider_fcall *cb = NULL;
330 	zval args, *pthis;
331 	char *errstr = "";
332 
333 	pthis = getThis();
334 	sop = fetch_sop_object(pthis);
335 
336 	switch(type) {
337 		case OAUTH_PROVIDER_CONSUMER_CB:
338 			cb = sop->consumer_handler;
339 			errstr = "Consumer key/secret handler not specified, did you set a valid callback via OAuthProvider::consumerHandler()?";
340 			break;
341 		case OAUTH_PROVIDER_TOKEN_CB:
342 			cb = sop->token_handler;
343 			errstr = "Token handler not specified, did you set a valid callback via OAuthProvider::tokenHandler()?";
344 			break;
345 		case OAUTH_PROVIDER_TSNONCE_CB:
346 			cb = sop->tsnonce_handler;
347 			errstr = "Timestamp/nonce handler not specified, did you set a valid callback via OAuthProvider::timestampNonceHandler()?";
348 			break;
349 		default:
350 			php_error_docref(NULL, E_ERROR, "Invalid callback type for OAuthProvider");
351 			return NULL;
352 	}
353 
354 	if(!cb) {
355 		php_error_docref(NULL, E_ERROR, "%s", errstr);
356 		return NULL;
357 	}
358 
359 	array_init(&args);
360 	add_next_index_zval(&args, pthis);
361 	Z_ADDREF_P(pthis);
362 
363 	errstr = NULL;
364 	if (!zend_is_callable(&cb->fcall_info->function_name, 0, NULL)) {
365 		if (errstr) {
366 			php_error_docref(NULL, E_WARNING, "Invalid callback: %s, %s", Z_STRVAL(cb->fcall_info->function_name), errstr);
367 			efree(errstr);
368 		} else {
369 			php_error_docref(NULL, E_WARNING, "Invalid callback: %s.", Z_STRVAL(cb->fcall_info->function_name));
370 		}
371 	} else if (errstr) {
372 		php_error_docref(NULL, E_WARNING, "%s", errstr);
373 		efree(errstr);
374 	}
375 
376 	if (zend_fcall_info_call(cb->fcall_info, &cb->fcall_info_cache, return_value, &args)!=SUCCESS) {
377 		php_error_docref(NULL, E_ERROR, "Failed calling callback %s", Z_STRVAL(cb->fcall_info->function_name));
378 	}
379 
380 	zval_ptr_dtor(&args);
381 
382 	return return_value;
383 }
384 /* }}} */
385 
oauth_provider_get_http_verb()386 static char *oauth_provider_get_http_verb() /* {{{ */
387 {
388 	zval *tmp;
389 
390 	zend_is_auto_global_str("_SERVER", sizeof("_SERVER")-1);
391 
392 	if(Z_TYPE(PG(http_globals)[TRACK_VARS_SERVER]) != IS_UNDEF) {
393 		if((tmp = zend_hash_str_find(HASH_OF(&PG(http_globals)[TRACK_VARS_SERVER]), "REQUEST_METHOD", sizeof("REQUEST_METHOD") - 1)) != NULL ||
394 		   (tmp = zend_hash_str_find(HASH_OF(&PG(http_globals)[TRACK_VARS_SERVER]), "HTTP_METHOD", sizeof("HTTP_METHOD") - 1)) != NULL
395 		  ) {
396 			return Z_STRVAL_P(tmp);
397 		}
398 	}
399 	return NULL;
400 }
401 /* }}} */
402 
oauth_provider_get_current_uri()403 static char *oauth_provider_get_current_uri()
404 {
405 	zval *host, *port, *uri, *proto, *https;
406 
407 	zend_is_auto_global_str("_SERVER", sizeof("_SERVER")-1);
408 
409 	host = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "HTTP_HOST", sizeof("HTTP_HOST") - 1);
410 	port = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "SERVER_PORT", sizeof("SERVER_PORT") - 1);
411 	uri = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "REQUEST_URI", sizeof("REQUEST_URI") - 1);
412 	proto = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "HTTP_X_FORWARDED_PROTO", sizeof("HTTP_X_FORWARDED_PROTO") - 1);
413 	https = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "HTTPS", sizeof("HTTPS") - 1);
414 
415 	if (host && port && uri)
416 	{
417 		char *tmp,*hostname,*colon_in_hostname;
418 
419 		spprintf(&hostname, 0, "%s", Z_STRVAL_P(host));
420 		colon_in_hostname=strrchr(hostname,':');
421 		if(colon_in_hostname && ((https && Z_LVAL_P(port)==443) || (!https && Z_LVAL_P(port)==80)))
422 		{
423 			*colon_in_hostname=0;
424 		}
425 		if(proto && Z_STRLEN_P(proto))
426 		{
427 			spprintf(&tmp, 0, "%s://%s%s", Z_STRVAL_P(proto), hostname, Z_STRVAL_P(uri));
428 		}
429 		else if(https && Z_STRLEN_P(https)>0 && strcasecmp(Z_STRVAL_P(https),"off")!=0)
430 		{
431 			spprintf(&tmp, 0, "https://%s%s", hostname, Z_STRVAL_P(uri));
432 		}
433 		else
434 		{
435 			spprintf(&tmp, 0, "http://%s%s", hostname, Z_STRVAL_P(uri));
436 		}
437 		efree(hostname);
438 		return tmp;
439 	}
440 
441 	return NULL;
442 }
443 
444 /* {{{ proto void OAuthProvider::__construct()
445    Instantiate a new OAuthProvider object */
SOP_METHOD(__construct)446 SOP_METHOD(__construct)
447 {
448 	php_oauth_provider *sop;
449 	zval *params = NULL, *pthis = NULL, apache_get_headers, retval, *tmpzval, *item_param;
450 	char *authorization_header = NULL;
451 	zend_string *key;
452 	zend_ulong num_key = 0, param_count = 0;
453 	HashPosition hpos;
454 
455 	pthis = getThis();
456 
457 	sop = fetch_sop_object(pthis);
458 
459 	/* XXX throw E_NOTICE if filter!='unsafe_raw' */
460 	if(zend_parse_parameters(ZEND_NUM_ARGS(), "|z", &params)==FAILURE) {
461 		soo_handle_error(NULL, OAUTH_ERR_INTERNAL_ERROR, "Failed to instantiate OAuthProvider", NULL, NULL);
462 		return;
463 	}
464 
465 	if (params && Z_TYPE_P(params)==IS_ARRAY) {
466 		param_count = zend_hash_num_elements(Z_ARRVAL_P(params));
467 	} else {
468 		param_count = 0;
469 	}
470 	if(!strcasecmp("cli", sapi_module.name) && !param_count) {
471 		php_error_docref(NULL, E_ERROR, "For the CLI sapi parameters must be set first via OAuthProvider::__construct(array(\"oauth_param\" => \"value\", ...))");
472 		return;
473 	}
474 
475 	/* hashes for storing parameter info/checks */
476 	ALLOC_HASHTABLE(sop->oauth_params);
477 	zend_hash_init(sop->oauth_params, 0, NULL, ZVAL_PTR_DTOR, 0);
478 	ALLOC_HASHTABLE(sop->missing_params);
479 	zend_hash_init(sop->missing_params, 0, NULL, ZVAL_PTR_DTOR, 0);
480 	ALLOC_HASHTABLE(sop->required_params);
481 	zend_hash_init(sop->required_params, 0, NULL, ZVAL_PTR_DTOR, 0);
482 	ALLOC_HASHTABLE(sop->custom_params);
483 	zend_hash_init(sop->custom_params, 0, NULL, ZVAL_PTR_DTOR, 0);
484 	memset(sop->endpoint_paths, 0, sizeof(sop->endpoint_paths));
485 
486 	sop->consumer_handler = NULL;
487 	sop->token_handler = NULL;
488 	sop->tsnonce_handler = NULL;
489 	sop->handle_errors = 1;
490 
491 	oauth_provider_set_default_required_params(sop->required_params);
492 
493 	zend_update_property_null(Z_OBJCE_P(pthis), OBJ_FOR_PROP(pthis), OAUTH_PROVIDER_CONSUMER_KEY, sizeof(OAUTH_PROVIDER_CONSUMER_KEY)-1);
494 	zend_update_property_null(Z_OBJCE_P(pthis), OBJ_FOR_PROP(pthis), OAUTH_PROVIDER_CONSUMER_SECRET, sizeof(OAUTH_PROVIDER_CONSUMER_SECRET)-1);
495 	zend_update_property_null(Z_OBJCE_P(pthis), OBJ_FOR_PROP(pthis), OAUTH_PROVIDER_NONCE, sizeof(OAUTH_PROVIDER_NONCE)-1);
496 	zend_update_property_null(Z_OBJCE_P(pthis), OBJ_FOR_PROP(pthis), OAUTH_PROVIDER_TOKEN, sizeof(OAUTH_PROVIDER_TOKEN)-1);
497 	zend_update_property_null(Z_OBJCE_P(pthis), OBJ_FOR_PROP(pthis), OAUTH_PROVIDER_TOKEN_SECRET, sizeof(OAUTH_PROVIDER_TOKEN_SECRET)-1);
498 	zend_update_property_null(Z_OBJCE_P(pthis), OBJ_FOR_PROP(pthis), OAUTH_PROVIDER_TIMESTAMP, sizeof(OAUTH_PROVIDER_TIMESTAMP)-1);
499 	zend_update_property_null(Z_OBJCE_P(pthis), OBJ_FOR_PROP(pthis), OAUTH_PROVIDER_VERSION, sizeof(OAUTH_PROVIDER_VERSION)-1);
500 	zend_update_property_null(Z_OBJCE_P(pthis), OBJ_FOR_PROP(pthis), OAUTH_PROVIDER_SIGNATURE_METHOD, sizeof(OAUTH_PROVIDER_SIGNATURE_METHOD)-1);
501 	zend_update_property_null(Z_OBJCE_P(pthis), OBJ_FOR_PROP(pthis), OAUTH_PROVIDER_CALLBACK, sizeof(OAUTH_PROVIDER_CALLBACK)-1);
502 
503 	zend_update_property_bool(Z_OBJCE_P(pthis), OBJ_FOR_PROP(pthis), "request_token_endpoint", sizeof("request_token_endpoint")-1, 0);
504 
505 	if(!param_count) {
506 		/* TODO: support NSAPI */
507 		/* mod_php */
508 		if(!strncasecmp(sapi_module.name, "apache", sizeof("apache") - 1)) {
509 			ZVAL_STRING(&apache_get_headers, "apache_request_headers");
510 
511 			if(zend_is_callable(&apache_get_headers, 0, NULL)) {
512 				if(call_user_function(EG(function_table), NULL, &apache_get_headers, &retval, 0, NULL)) {
513 					php_error_docref(NULL, E_ERROR, "Failed to get HTTP Request headers");
514 				}
515 				if((tmpzval = zend_hash_str_find(HASH_OF(&retval), "Authorization", sizeof("Authorization") - 1)) != NULL) {
516 					authorization_header = estrdup(Z_STRVAL_P(tmpzval));
517 				} else if ((tmpzval = zend_hash_str_find(HASH_OF(&retval), "authorization", sizeof("authorization") - 1)) != NULL) {
518 					authorization_header = estrdup(Z_STRVAL_P(tmpzval));
519 				} else {
520 					/* search one by one */
521 					zend_hash_internal_pointer_reset_ex(HASH_OF(&retval), &hpos);
522 					do {
523 						if (FAILURE != zend_hash_get_current_key_ex(HASH_OF(&retval), &key, &num_key, &hpos) && ZSTR_LEN(key) == sizeof("authorization") && 0 == strcasecmp(ZSTR_VAL(key), "authorization") && (tmpzval = zend_hash_get_current_data_ex(HASH_OF(&retval), &hpos)) != NULL) {
524 							authorization_header = estrdup(Z_STRVAL_P(tmpzval));
525 							break;
526 						}
527 					} while (SUCCESS==zend_hash_move_forward_ex(HASH_OF(&retval), &hpos));
528 				}
529 			} else {
530 				php_error_docref(NULL, E_ERROR, "Failed to call apache_request_headers while running under the Apache SAPI");
531 			}
532 			zval_ptr_dtor(&apache_get_headers);
533 			zval_ptr_dtor(&retval);
534 		} else { /* not mod_php, look in _SERVER and _ENV for Authorization header */
535 			if(!zend_is_auto_global_str("_SERVER", sizeof("_SERVER") - 1) && !zend_is_auto_global_str("_ENV", sizeof("_ENV") - 1)) {
536 				return;
537 			}
538 
539 			/* first look in _SERVER */
540 			if (Z_TYPE(PG(http_globals)[TRACK_VARS_SERVER]) == IS_UNDEF ||
541 					((tmpzval = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "HTTP_AUTHORIZATION", sizeof("HTTP_AUTHORIZATION") - 1)) == NULL
542 					 && (tmpzval = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "REDIRECT_HTTP_AUTHORIZATION", sizeof("REDIRECT_HTTP_AUTHORIZATION") -1)) == NULL))
543 			{
544 				/* well that didn't work out, so let's check out _ENV */
545 				if (Z_TYPE(PG(http_globals)[TRACK_VARS_ENV]) == IS_UNDEF
546 						|| (tmpzval = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_ENV]), "HTTP_AUTHORIZATION", sizeof("HTTP_AUTHORIZATION"))) == NULL)  {
547 					/* not found, [bf]ail */
548 					return;
549 				}
550 			}
551 			authorization_header = estrdup(Z_STRVAL_P(tmpzval));
552 		}
553 		if (authorization_header) {
554 			int ret = oauth_provider_parse_auth_header(sop, authorization_header);
555 
556 			efree(authorization_header);
557 
558 			if (FAILURE==ret) {
559 				soo_handle_error(NULL, OAUTH_SIGNATURE_METHOD_REJECTED, "Unknown signature method", NULL, NULL);
560 				return;
561 			}
562 		}
563 	}
564 	/* let constructor params override any values that may have been found in auth headers */
565 	if (param_count) {
566 		zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(params), &hpos);
567 		do {
568 			if(zend_hash_get_current_key_ex(Z_ARRVAL_P(params), &key, &num_key, &hpos) == HASH_KEY_IS_STRING) {
569 				if((item_param = zend_hash_get_current_data_ex(Z_ARRVAL_P(params), &hpos)) != NULL) {
570 					if(oauth_provider_set_param_value(sop->oauth_params, ZSTR_VAL(key), item_param) == FAILURE) {
571 						return;
572 					}
573 				}
574 			}
575 		} while(zend_hash_move_forward_ex(Z_ARRVAL_P(params), &hpos)==SUCCESS);
576 	}
577 }
578 /* }}} */
579 
580 /* {{{ proto void OAuthProvider::callConsumerHandler()
581    calls the registered consumer key handler function */
SOP_METHOD(callconsumerHandler)582 SOP_METHOD(callconsumerHandler)
583 {
584 	OAUTH_PROVIDER_CALL_CB(INTERNAL_FUNCTION_PARAM_PASSTHRU, OAUTH_PROVIDER_CONSUMER_CB);
585 }
586 /* }}} */
587 
588 /* {{{ proto void OAuthProvider::callTokenHandler()
589    calls the registered token handler function */
SOP_METHOD(calltokenHandler)590 SOP_METHOD(calltokenHandler)
591 {
592 	OAUTH_PROVIDER_CALL_CB(INTERNAL_FUNCTION_PARAM_PASSTHRU, OAUTH_PROVIDER_TOKEN_CB);
593 }
594 /* }}} */
595 
596 /* {{{ proto void OAuthProvider::callTokenHandler()
597    calls the registered token handler function */
SOP_METHOD(callTimestampNonceHandler)598 SOP_METHOD(callTimestampNonceHandler)
599 {
600 	OAUTH_PROVIDER_CALL_CB(INTERNAL_FUNCTION_PARAM_PASSTHRU, OAUTH_PROVIDER_TSNONCE_CB);
601 }
602 /* }}} */
603 
604 /* {{{ proto void OAuthProvider::consumerHandler(callback cb) */
SOP_METHOD(consumerHandler)605 SOP_METHOD(consumerHandler)
606 {
607 	oauth_provider_register_cb(INTERNAL_FUNCTION_PARAM_PASSTHRU, OAUTH_PROVIDER_CONSUMER_CB);
608 }
609 /* }}} */
610 
611 /* {{{ proto void OAuthProvider::tokenHandler(callback cb) */
SOP_METHOD(tokenHandler)612 SOP_METHOD(tokenHandler)
613 {
614 	oauth_provider_register_cb(INTERNAL_FUNCTION_PARAM_PASSTHRU, OAUTH_PROVIDER_TOKEN_CB);
615 }
616 /* }}} */
617 
618 /* {{{ proto void OAuthProvider::timestampNonceHandler(callback cb) */
SOP_METHOD(timestampNonceHandler)619 SOP_METHOD(timestampNonceHandler)
620 {
621 	oauth_provider_register_cb(INTERNAL_FUNCTION_PARAM_PASSTHRU, OAUTH_PROVIDER_TSNONCE_CB);
622 }
623 /* }}} */
624 
625 /* {{{ proto void OAuthProvider::isRequestTokenEndpoint(bool will_issue_request_token) */
SOP_METHOD(isRequestTokenEndpoint)626 SOP_METHOD(isRequestTokenEndpoint)
627 {
628 	zend_bool req_api = 0;
629 	zval *pthis;
630 
631 	if(zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ob", &pthis, oauthprovider, &req_api)==FAILURE) {
632 		return;
633 	}
634 
635 	zend_update_property_bool(Z_OBJCE_P(pthis), OBJ_FOR_PROP(pthis), "request_token_endpoint", sizeof("request_token_endpoint") - 1, req_api);
636 }
637 /* }}} */
638 
SOP_METHOD(setRequestTokenPath)639 SOP_METHOD(setRequestTokenPath)
640 {
641 	zval *pthis;
642 	php_oauth_provider *sop;
643 	char *path;
644 	size_t path_len;
645 
646 	if (FAILURE==zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &pthis, oauthprovider, &path, &path_len)) {
647 		return;
648 	}
649 
650 	sop = fetch_sop_object(pthis);
651 
652 	OAUTH_PROVIDER_SET_ENDPOINT(sop->endpoint_paths[OAUTH_PROVIDER_PATH_REQUEST], path)
653 
654 	RETURN_TRUE;
655 }
656 
657 /* {{{ proto void OAuthProvider::checkOAuthRequest([string url [, string request_method]]) */
SOP_METHOD(checkOAuthRequest)658 SOP_METHOD(checkOAuthRequest)
659 {
660 	zval *retval = NULL, *param, *pthis, *token_secret = NULL, *consumer_secret, *req_signature, *sig_method = NULL, rv;
661 	oauth_sig_context *sig_ctx = NULL;
662 	php_oauth_provider *sop;
663 	zend_ulong missing_param_count = 0, mp_count = 1;
664 	char additional_info[512] = "", *http_verb = NULL, *uri = NULL, *current_uri = NULL;
665 	zend_string *sbs, *signature = NULL;
666 	HashPosition hpos;
667 	HashTable *sbs_vars = NULL;
668 	size_t http_verb_len = 0, uri_len = 0;
669 	int is_token_required = 0;
670 
671 	if(zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|ss", &pthis, oauthprovider, &uri, &uri_len, &http_verb, &http_verb_len)==FAILURE) {
672 		return;
673 	}
674 
675 	sop = fetch_sop_object(pthis);
676 
677 	if(!http_verb_len) {
678 		http_verb = oauth_provider_get_http_verb();
679 	}
680 
681 
682 	if(!http_verb) {
683 		php_error_docref(NULL, E_ERROR, "Failed to detect HTTP method, set a HTTP method via OAuthProvider::checkOAuthRequest()");
684 		return;
685 	}
686 
687 	ALLOC_HASHTABLE(sbs_vars);
688 	zend_hash_init(sbs_vars, 0, NULL, ZVAL_PTR_DTOR, 0);
689 
690 	if(Z_TYPE(PG(http_globals)[TRACK_VARS_GET]) != IS_UNDEF) {
691 		zend_hash_merge(sbs_vars, HASH_OF(&PG(http_globals)[TRACK_VARS_GET]), (copy_ctor_func_t)zval_add_ref, 0);
692 	}
693 	if(Z_TYPE(PG(http_globals)[TRACK_VARS_POST]) != IS_UNDEF) {
694 		zend_hash_merge(sbs_vars, HASH_OF(&PG(http_globals)[TRACK_VARS_POST]), (copy_ctor_func_t)zval_add_ref, 0);
695 	}
696 	if(zend_hash_num_elements(sop->oauth_params)) {
697 		zend_hash_merge(sbs_vars, sop->oauth_params, (copy_ctor_func_t)zval_add_ref, 0);
698 	}
699 
700 	if (zend_hash_num_elements(sop->custom_params)) {
701 		/* apply custom params */
702 		oauth_provider_apply_custom_param(sbs_vars, sop->custom_params);
703 	}
704 
705 	zend_hash_internal_pointer_reset_ex(sbs_vars, &hpos);
706 
707 	/* set the standard stuff present in every request if its found in sbs_vars, IE if we find oauth_consumer_key, set $oauth->consumer_key */
708 	oauth_provider_set_std_params(pthis, sbs_vars);
709 
710 	if (!uri) {
711 		/* get current uri */
712 		uri = current_uri = oauth_provider_get_current_uri();
713 	}
714 
715 	/* if we are in an API which issues a request token, there are is no token handler called */
716 	if (!(is_token_required=oauth_provider_token_required(pthis, uri))) {
717 		/* by default, oauth_token is required; remove from the required list */
718 		oauth_provider_remove_required_param(sop->required_params, "oauth_token");
719 	}
720 
721 	oauth_provider_check_required_params(sop->required_params, sbs_vars, sop->missing_params);
722 
723 	missing_param_count = zend_hash_num_elements(sop->missing_params);
724 	if(missing_param_count) {
725 		zend_hash_internal_pointer_reset_ex(sop->missing_params, &hpos);
726 		do {
727 			if((param = zend_hash_get_current_data_ex(sop->missing_params, &hpos)) != NULL) {
728 				snprintf(additional_info, 512, "%s%s%s", additional_info, Z_STRVAL_P(param), (missing_param_count > 1 && missing_param_count!=mp_count++) ? "%26" : "");
729 			}
730 		} while(zend_hash_move_forward_ex(sop->missing_params, &hpos)==SUCCESS);
731 		soo_handle_error(NULL, OAUTH_PARAMETER_ABSENT, "Missing required parameters", NULL, additional_info);
732 		FREE_ARGS_HASH(sbs_vars);
733 		OAUTH_PROVIDER_FREE_STRING(current_uri);
734 		return;
735 	}
736 
737 	sig_method = zend_read_property(Z_OBJCE_P(pthis), OBJ_FOR_PROP(pthis), OAUTH_PROVIDER_SIGNATURE_METHOD, sizeof(OAUTH_PROVIDER_SIGNATURE_METHOD) - 1, 1, &rv);
738 	do {
739 		if (sig_method && (Z_TYPE_P(sig_method) == IS_STRING) && Z_STRLEN_P(sig_method)) {
740 			sig_ctx = oauth_create_sig_context(Z_STRVAL_P(sig_method));
741 			if (OAUTH_SIGCTX_TYPE_NONE!=sig_ctx->type) {
742 				break;
743 			}
744 			OAUTH_SIGCTX_FREE(sig_ctx);
745 		}
746 		soo_handle_error(NULL, OAUTH_SIGNATURE_METHOD_REJECTED, "Unknown signature method", NULL, NULL);
747 		FREE_ARGS_HASH(sbs_vars);
748 		OAUTH_PROVIDER_FREE_STRING(current_uri);
749 		return;
750 	} while (0);
751 
752 	do {
753 		long cb_res;
754 
755 		retval = oauth_provider_call_cb(INTERNAL_FUNCTION_PARAM_PASSTHRU, OAUTH_PROVIDER_CONSUMER_CB);
756 		if (retval) {
757 			convert_to_long(retval);
758 			cb_res = Z_LVAL_P(retval);
759 			zval_ptr_dtor(retval);
760 
761 			if (OAUTH_OK!=cb_res) {
762 				soo_handle_error(NULL, cb_res, "Invalid consumer key", NULL, additional_info);
763 				break;
764 			}
765 		} else if (EG(exception)) {
766 			/* pass exceptions */
767 			break;
768 		}
769 
770 		if (is_token_required) {
771 			retval = oauth_provider_call_cb(INTERNAL_FUNCTION_PARAM_PASSTHRU, OAUTH_PROVIDER_TOKEN_CB);
772 			if (retval) {
773 				convert_to_long(retval);
774 				cb_res = Z_LVAL_P(retval);
775 				zval_ptr_dtor(retval);
776 
777 				if (OAUTH_OK!=cb_res) {
778 					soo_handle_error(NULL, cb_res, "Invalid token", NULL, additional_info);
779 					break;
780 				}
781 			} else if (EG(exception)) {
782 				/* pass exceptions */
783 				break;
784 			}
785 		}
786 
787 		retval = oauth_provider_call_cb(INTERNAL_FUNCTION_PARAM_PASSTHRU, OAUTH_PROVIDER_TSNONCE_CB);
788 		if (retval) {
789 			convert_to_long(retval);
790 			cb_res = Z_LVAL_P(retval);
791 			zval_ptr_dtor(retval);
792 
793 			if (OAUTH_OK!=cb_res) {
794 				soo_handle_error(NULL, cb_res, "Invalid nonce/timestamp combination", NULL, additional_info);
795 				break;
796 			}
797 		} else if (EG(exception)) {
798 			/* pass exceptions */
799 			break;
800 		}
801 
802 		/* now for the signature stuff */
803 		sbs = oauth_generate_sig_base(NULL, http_verb, uri, sbs_vars, NULL);
804 
805 		if (sbs) {
806 			consumer_secret = zend_read_property(Z_OBJCE_P(pthis), OBJ_FOR_PROP(pthis), OAUTH_PROVIDER_CONSUMER_SECRET, sizeof(OAUTH_PROVIDER_CONSUMER_SECRET) - 1, 1, &rv);
807 			convert_to_string_ex(consumer_secret);
808 			if (is_token_required) {
809 				token_secret = zend_read_property(Z_OBJCE_P(pthis), OBJ_FOR_PROP(pthis), OAUTH_PROVIDER_TOKEN_SECRET, sizeof(OAUTH_PROVIDER_TOKEN_SECRET) - 1, 1, &rv);
810 				convert_to_string_ex(token_secret);
811 			}
812 			signature = soo_sign(NULL, ZSTR_VAL(sbs), consumer_secret, token_secret, sig_ctx);
813 		}
814 
815 		req_signature = zend_read_property(Z_OBJCE_P(pthis), OBJ_FOR_PROP(pthis), OAUTH_PROVIDER_SIGNATURE, sizeof(OAUTH_PROVIDER_SIGNATURE) - 1, 1, &rv);
816 		if (!signature || !Z_STRLEN_P(req_signature) || strcmp(ZSTR_VAL(signature), Z_STRVAL_P(req_signature))) {
817 			soo_handle_error(NULL, OAUTH_INVALID_SIGNATURE, "Signatures do not match", NULL, sbs ? ZSTR_VAL(sbs) : NULL);
818 		}
819 
820 		if (sbs) {
821 			zend_string_release(sbs);
822 		}
823 		if (signature) {
824 			zend_string_release(signature);
825 		}
826 	} while (0);
827 
828 	OAUTH_SIGCTX_FREE(sig_ctx);
829 	OAUTH_PROVIDER_FREE_STRING(current_uri);
830 	FREE_ARGS_HASH(sbs_vars);
831 }
832 /* }}} */
833 
834 /* {{{ proto void OAuthProvider::addRequiredParameter(string $required_param) */
SOP_METHOD(addRequiredParameter)835 SOP_METHOD(addRequiredParameter)
836 {
837 	zval *pthis;
838 	char *required_param;
839 	php_oauth_provider *sop;
840 	size_t req_param_len;
841 
842 	if(zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &pthis, oauthprovider, &required_param, &req_param_len)==FAILURE) {
843 		return;
844 	}
845 
846 	sop = fetch_sop_object(pthis);
847 
848 	if(oauth_provider_add_required_param(sop->required_params, required_param)==SUCCESS) {
849 		RETURN_TRUE;
850 	}
851 
852 	RETURN_FALSE;
853 }
854 /* }}} */
855 
856 /* {{{ proto void OAuthProvider::setParam(string $key, mixed $val) */
SOP_METHOD(setParam)857 SOP_METHOD(setParam)
858 {
859 	zval *pthis, *param_val = NULL;
860 	char *param_key;
861 	size_t param_key_len;
862 	php_oauth_provider *sop;
863 
864 	if (FAILURE==zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os|z/", &pthis, oauthprovider, &param_key, &param_key_len, &param_val)) {
865 		return;
866 	}
867 
868 	sop = fetch_sop_object(pthis);
869 
870 	if (!param_val) {
871 		RETURN_BOOL(SUCCESS == zend_hash_str_del(sop->custom_params, param_key, param_key_len));
872 	} else {
873 		Z_TRY_ADDREF_P(param_val);
874 
875 		RETURN_BOOL(NULL != zend_hash_str_add(sop->custom_params, param_key, param_key_len, param_val));
876 	}
877 }
878 /* }}} */
879 
880 /* {{{ proto void OAuthProvider::removeRequiredParameter(string $required_param) */
SOP_METHOD(removeRequiredParameter)881 SOP_METHOD(removeRequiredParameter)
882 {
883 	zval *pthis;
884 	char *required_param;
885 	php_oauth_provider *sop;
886 	size_t req_param_len;
887 
888 	if(zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &pthis, oauthprovider, &required_param, &req_param_len)==FAILURE) {
889 		return;
890 	}
891 
892 	sop = fetch_sop_object(pthis);
893 
894 	if(oauth_provider_remove_required_param(sop->required_params, required_param)==SUCCESS) {
895 		RETURN_TRUE;
896 	}
897 
898 	RETURN_FALSE;
899 }
900 /* }}} */
901 
902 /* {{{ proto string OAuthProvider::generateToken(int $size[, bool $string = false]) */
SOP_METHOD(generateToken)903 SOP_METHOD(generateToken)
904 {
905 	long size, reaped = 0;
906 	int strong = 0;
907 	char *iv = NULL;
908 
909 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|b", &size, &strong)==FAILURE) {
910 		return;
911 	}
912 
913 	if (size < 1 || size > INT_MAX) {
914 		php_error_docref(NULL, E_WARNING, "Cannot generate token with a size of less than 1 or greater than %d", INT_MAX);
915 		return;
916 	}
917 
918 	iv = ecalloc(size+1, 1);
919 
920 	do {
921 #if PHP_WIN32
922 /*
923  * The Windows port has been ripped from the mcrypt extension; thanks guys! ;-)
924  */
925 		HCRYPTPROV hCryptProv;
926 		BYTE *iv_b = (BYTE *) iv;
927 
928 		if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
929 			break;
930 		}
931 		if (!CryptGenRandom(hCryptProv, size, iv_b)) {
932 			break;
933 		}
934 		reaped = size;
935 #else
936 		int fd;
937 
938 		fd = open(strong?"/dev/random":"/dev/urandom", O_RDONLY);
939 		if (fd < 0) {
940 			break;
941 		}
942 		while (reaped < size) {
943 			register int n;
944 			n = read(fd, iv + reaped, size - reaped);
945 			if (n < 0) {
946 				break;
947 			}
948 			reaped += n;
949 		}
950 		close(fd);
951 #endif
952 	} while (0);
953 
954 	if (reaped < size) {
955 		if (strong) {
956 			php_error_docref(NULL, E_WARNING, "Could not gather enough random data, falling back on rand()");
957 		}
958 		while (reaped < size) {
959 			iv[reaped++] = (char) (255.0 * php_rand() / RAND_MAX);
960 		}
961 	}
962 
963 	RETURN_STRINGL(iv, size);
964 }
965 /* }}} */
966 
967 /* {{{ proto void OAuthProvider::reportProblem(Exception $e) */
SOP_METHOD(reportProblem)968 SOP_METHOD(reportProblem)
969 {
970 	zval *exception, *code, *sbs, *missing_params, rv;
971 	zend_class_entry *ex_ce;
972 	zend_bool out_malloced = 0;
973 	char *out, *tmp_out, *http_header_line;
974 	size_t pr_len;
975 	zend_ulong lcode;
976 	uint32_t http_code;
977 	sapi_header_line ctr = {0};
978 	zend_bool send_headers = 1;
979 
980 	ex_ce = zend_exception_get_default();
981 
982 	if(zend_parse_parameters(ZEND_NUM_ARGS(), "O|b", &exception, ex_ce, &send_headers)==FAILURE) {
983 		return;
984 	}
985 
986 	/* XXX good candidate for refactoring */
987 	code = zend_read_property(Z_OBJCE_P(exception), OBJ_FOR_PROP(exception), "code", sizeof("code") - 1, 1, &rv);
988 	lcode = Z_LVAL_P(code);
989 
990 	switch(lcode) {
991 		case OAUTH_BAD_TIMESTAMP:
992 			http_code = OAUTH_ERR_BAD_AUTH;
993 			out = "oauth_problem=timestamp_refused"; break;
994 		case OAUTH_BAD_NONCE:
995 			http_code = OAUTH_ERR_BAD_AUTH;
996 			out = "oauth_problem=nonce_used"; break;
997 		case OAUTH_CONSUMER_KEY_UNKNOWN:
998 			http_code = OAUTH_ERR_BAD_AUTH;
999 			out = "oauth_problem=consumer_key_unknown"; break;
1000 		case OAUTH_CONSUMER_KEY_REFUSED:
1001 			http_code = OAUTH_ERR_BAD_AUTH;
1002 			out = "oauth_problem=consumer_key_refused"; break;
1003 		case OAUTH_TOKEN_USED:
1004 			http_code = OAUTH_ERR_BAD_AUTH;
1005 			out = "oauth_problem=token_used"; break;
1006 		case OAUTH_TOKEN_EXPIRED:
1007 			http_code = OAUTH_ERR_BAD_AUTH;
1008 			out = "oauth_problem=token_expired"; break;
1009 		case OAUTH_TOKEN_REVOKED:
1010 			http_code = OAUTH_ERR_BAD_AUTH;
1011 			out = "oauth_problem=token_revoked"; break;
1012 		case OAUTH_TOKEN_REJECTED:
1013 			http_code = OAUTH_ERR_BAD_AUTH;
1014 			out = "oauth_problem=token_rejected"; break;
1015 		case OAUTH_VERIFIER_INVALID:
1016 			http_code = OAUTH_ERR_BAD_AUTH;
1017 			out = "oauth_problem=verifier_invalid"; break;
1018 		case OAUTH_INVALID_SIGNATURE:
1019 			http_code = OAUTH_ERR_BAD_AUTH;
1020 			out = "oauth_problem=signature_invalid";
1021 			sbs = zend_read_property(Z_OBJCE_P(exception), OBJ_FOR_PROP(exception), "additionalInfo", sizeof("additionalInfo") - 1, 1, &rv);
1022 			if (sbs && IS_NULL!=Z_TYPE_P(sbs)) {
1023 				convert_to_string_ex(sbs);
1024 				if(Z_STRLEN_P(sbs)) {
1025 					pr_len = Z_STRLEN_P(sbs) + strlen(out) + sizeof("&debug_sbs=");
1026 					tmp_out = emalloc(pr_len);
1027 					/* sbs url encoded so XSS shouldn't be an issue here */
1028 					snprintf(tmp_out, pr_len, "%s&debug_sbs=%s", out, Z_STRVAL_P(sbs));
1029 					out = tmp_out;
1030 					out_malloced = 1;
1031 				}
1032 			}
1033 			break;
1034 		case OAUTH_SIGNATURE_METHOD_REJECTED:
1035 			http_code = OAUTH_ERR_BAD_REQUEST;
1036 			out = "oauth_problem=signature_method_rejected"; break;
1037 		case OAUTH_PARAMETER_ABSENT:
1038 			http_code = OAUTH_ERR_BAD_REQUEST;
1039 			out = "oauth_problem=parameter_absent";
1040 			missing_params = zend_read_property(Z_OBJCE_P(exception), OBJ_FOR_PROP(exception), "additionalInfo", sizeof("additionalInfo") - 1, 1, &rv);
1041 			if(missing_params) {
1042 				convert_to_string_ex(missing_params);
1043 				if(Z_STRLEN_P(missing_params)) {
1044 					pr_len = Z_STRLEN_P(missing_params) + strlen(out) + sizeof("&oauth_parameters_absent=");
1045 					tmp_out = emalloc(pr_len);
1046 					snprintf(tmp_out, pr_len, "%s&oauth_parameters_absent=%s", out, Z_STRVAL_P(missing_params));
1047 					out = tmp_out;
1048 					out_malloced = 1;
1049 				}
1050 			}
1051 			break;
1052 		default:
1053 			http_code = OAUTH_ERR_INTERNAL_ERROR;
1054 			out = emalloc(48);
1055 			snprintf(out, 48, "oauth_problem=unknown_problem&code=%lu", lcode);
1056 			out_malloced = 1;
1057 	}
1058 
1059 	ZVAL_STRINGL(return_value, out, strlen(out));
1060 
1061 	if(send_headers) {
1062 		if(http_code==OAUTH_ERR_BAD_REQUEST) {
1063 			http_header_line = "HTTP/1.1 400 Bad Request";
1064 		} else {
1065 			http_header_line = "HTTP/1.1 401 Unauthorized";
1066 		}
1067 
1068 		ctr.line = http_header_line;
1069 		ctr.line_len = strlen(http_header_line);
1070 		ctr.response_code = http_code;
1071 
1072 		sapi_header_op(SAPI_HEADER_REPLACE, &ctr);
1073 	}
1074 
1075 	if(out_malloced) {
1076 		efree(out);
1077 	}
1078 }
1079 /* }}} */
1080 
oauth_provider_free_storage(zend_object * obj)1081 static void oauth_provider_free_storage(zend_object *obj) /* {{{ */
1082 {
1083 	php_oauth_provider *sop;
1084 
1085 	sop = sop_object_from_obj(obj);
1086 
1087 	zend_object_std_dtor(&sop->zo);
1088 
1089 	OAUTH_PROVIDER_FREE_FCALL_INFO(sop->consumer_handler);
1090 	OAUTH_PROVIDER_FREE_FCALL_INFO(sop->token_handler);
1091 	OAUTH_PROVIDER_FREE_FCALL_INFO(sop->tsnonce_handler);
1092 	FREE_ARGS_HASH(sop->missing_params);
1093 	FREE_ARGS_HASH(sop->oauth_params);
1094 	FREE_ARGS_HASH(sop->required_params);
1095 	FREE_ARGS_HASH(sop->custom_params);
1096 
1097 	OAUTH_PROVIDER_FREE_STRING(sop->endpoint_paths[OAUTH_PROVIDER_PATH_REQUEST]);
1098 	OAUTH_PROVIDER_FREE_STRING(sop->endpoint_paths[OAUTH_PROVIDER_PATH_ACCESS]);
1099 	OAUTH_PROVIDER_FREE_STRING(sop->endpoint_paths[OAUTH_PROVIDER_PATH_AUTH]);
1100 }
1101 /* }}} */
1102 
oauth_provider_new(zend_class_entry * ce)1103 static zend_object* oauth_provider_new(zend_class_entry *ce) /* {{{ */
1104 {
1105 	php_oauth_provider *nos;
1106 	nos = ecalloc(1, sizeof(php_oauth_provider) + zend_object_properties_size(ce));
1107 
1108 	zend_object_std_init(&nos->zo, ce);
1109 	object_properties_init(&nos->zo, ce);
1110 
1111 	nos->zo.handlers = &oauth_provider_obj_hndlrs;
1112 
1113 	return &nos->zo;
1114 }
1115 /* }}} */
1116 
1117 ZEND_BEGIN_ARG_INFO_EX(arginfo_oauth_provider__construct, 0, 0, 0)
1118 ZEND_ARG_INFO(0, params_array)
1119 ZEND_END_ARG_INFO()
1120 
1121 ZEND_BEGIN_ARG_INFO_EX(arginfo_oauth_provider_noparams, 0, 0, 0)
1122 ZEND_END_ARG_INFO()
1123 
1124 ZEND_BEGIN_ARG_INFO_EX(arginfo_oauth_provider_check, 0, 0, 0)
1125 ZEND_ARG_INFO(0, uri)
1126 ZEND_ARG_INFO(0, method)
1127 ZEND_END_ARG_INFO()
1128 
1129 ZEND_BEGIN_ARG_INFO_EX(arginfo_oauth_provider_handler, 0, 0, 1)
1130 ZEND_ARG_INFO(0, function_name)
1131 ZEND_END_ARG_INFO()
1132 
1133 ZEND_BEGIN_ARG_INFO_EX(arginfo_oauth_provider_reportproblem, 0, 0, 1)
1134 ZEND_ARG_INFO(0, oauthexception)
1135 ZEND_END_ARG_INFO()
1136 
1137 ZEND_BEGIN_ARG_INFO_EX(arginfo_oauth_provider_req_token, 0, 0, 1)
1138 ZEND_ARG_INFO(0, params_array)
1139 ZEND_END_ARG_INFO()
1140 
1141 ZEND_BEGIN_ARG_INFO_EX(arginfo_oauth_provider_set_req_param, 0, 0, 1)
1142 ZEND_ARG_INFO(0, req_params)
1143 ZEND_END_ARG_INFO()
1144 
1145 ZEND_BEGIN_ARG_INFO_EX(arginfo_oauth_provider_set_param, 0, 0, 1)
1146 ZEND_ARG_INFO(0, param_key)
1147 ZEND_ARG_INFO(0, param_val)
1148 ZEND_END_ARG_INFO()
1149 
1150 ZEND_BEGIN_ARG_INFO_EX(arginfo_oauth_provider_set_path, 0, 0, 1)
1151 ZEND_ARG_INFO(0, path)
1152 ZEND_END_ARG_INFO()
1153 
1154 ZEND_BEGIN_ARG_INFO_EX(arginfo_oauth_provider_generate_token, 0, 0, 1)
1155 ZEND_ARG_INFO(0, size)
1156 ZEND_ARG_INFO(0, strong)
1157 ZEND_END_ARG_INFO()
1158 
1159 static zend_function_entry oauth_provider_methods[] = { /* {{{ */
1160 		SOP_ME(__construct,			arginfo_oauth_provider__construct,		ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
1161 		SOP_ME(consumerHandler,	arginfo_oauth_provider_handler,		ZEND_ACC_PUBLIC)
1162 		SOP_ME(tokenHandler,	arginfo_oauth_provider_handler,		ZEND_ACC_PUBLIC)
1163 		SOP_ME(timestampNonceHandler,	arginfo_oauth_provider_handler,		ZEND_ACC_PUBLIC)
1164 		SOP_ME(callconsumerHandler,	arginfo_oauth_provider_noparams,		ZEND_ACC_PUBLIC)
1165 		SOP_ME(calltokenHandler,	arginfo_oauth_provider_noparams,		ZEND_ACC_PUBLIC)
1166 		SOP_ME(callTimestampNonceHandler,	arginfo_oauth_provider_noparams,		ZEND_ACC_PUBLIC)
1167 		SOP_ME(checkOAuthRequest,	arginfo_oauth_provider_check,		ZEND_ACC_PUBLIC)
1168 		SOP_ME(isRequestTokenEndpoint,	arginfo_oauth_provider_req_token,		ZEND_ACC_PUBLIC)
1169 		SOP_ME(setRequestTokenPath,	arginfo_oauth_provider_set_path,	ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
1170 		SOP_ME(addRequiredParameter,	arginfo_oauth_provider_set_req_param,		ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
1171 		SOP_ME(reportProblem,	arginfo_oauth_provider_reportproblem,		ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
1172 		SOP_ME(setParam, 		arginfo_oauth_provider_set_param,		ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
1173 		SOP_ME(removeRequiredParameter,	arginfo_oauth_provider_set_req_param,		ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
1174 		SOP_ME(generateToken,		arginfo_oauth_provider_generate_token,		ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
1175 		PHP_MALIAS(oauthprovider,	is2LeggedEndpoint, isRequestTokenEndpoint, arginfo_oauth_provider_req_token, ZEND_ACC_PUBLIC)
1176 		{NULL, NULL, NULL}
1177 };
1178 
oauth_provider_register_class(void)1179 extern int oauth_provider_register_class(void) /* {{{ */
1180 {
1181 	zend_class_entry osce;
1182 
1183 	INIT_CLASS_ENTRY(osce, "OAuthProvider", oauth_provider_methods);
1184 	osce.create_object = oauth_provider_new;
1185 	oauthprovider = zend_register_internal_class(&osce);
1186 
1187 	memcpy(&oauth_provider_obj_hndlrs, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1188 	oauth_provider_obj_hndlrs.offset = XtOffsetOf(php_oauth_provider, zo);
1189 	oauth_provider_obj_hndlrs.free_obj = oauth_provider_free_storage;
1190 
1191 	return SUCCESS;
1192 }
1193 /* }}} */
1194 
1195 /**
1196  * Local Variables:
1197  * c-basic-offset: 4
1198  * tab-width: 4
1199  * indent-tabs-mode: t
1200  * End:
1201  * vim600: fdm=marker
1202  * vim: noet sw=4 ts=4 noexpandtab
1203  */
1204