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, ¶mhpos);
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(¶m, ZSTR_VAL(key));
168 zend_hash_next_index_insert(missing_params, ¶m);
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", ¶ms)==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, ¶m_key, ¶m_key_len, ¶m_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