From e32f6fed32939bba9839c0e4f7cdaec02d8828dd Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Thu, 9 Jun 2005 15:23:33 +0000 Subject: [PATCH] - move http_parse_cookie() code to an odd http_parse_key_list() function - name basic auth function basic - start auth digest implementation # if anyone wants to get his hands dirty... I've already lost my head --- http_api.c | 93 +++++++++++++++++++++ http_auth_api.c | 178 ++++++++++++++++++++++++++++++++++++++++- http_functions.c | 14 ++-- http_headers_api.c | 72 ----------------- http_methods.c | 19 ++--- http_request_object.c | 4 +- php_http_api.h | 8 ++ php_http_auth_api.h | 16 +++- php_http_headers_api.h | 3 - 9 files changed, 306 insertions(+), 101 deletions(-) diff --git a/http_api.c b/http_api.c index 18b14e2..9c587c8 100644 --- a/http_api.c +++ b/http_api.c @@ -60,6 +60,99 @@ char *_http_pretty_key(char *key, size_t key_len, zend_bool uctitle, zend_bool x } /* }}} */ +/* {{{ */ +void _http_key_list_default_decoder(const char *encoded, size_t encoded_len, char **decoded, size_t *decoded_len TSRMLS_DC) +{ + *decoded = estrndup(encoded, encoded_len); + *decoded_len = (size_t) php_url_decode(*decoded, encoded_len); +} +/* }}} */ + +/* {{{ */ +STATUS _http_parse_key_list(const char *list, HashTable *items, char separator, http_key_list_decode_t decode, zend_bool first_entry_is_name_value_pair TSRMLS_DC) +{ + const char *key = list, *val = NULL; + int vallen = 0, keylen = 0, done = 0; + zval array; + + Z_ARRVAL(array) = items; + + if (!(val = strchr(list, '='))) { + return FAILURE; + } + +#define HTTP_KEYLIST_VAL(array, k, str, len) \ + { \ + char *decoded; \ + size_t decoded_len; \ + if (decode) { \ + decode(str, len, &decoded, &decoded_len TSRMLS_CC); \ + } else { \ + decoded = estrdup(str); \ + decoded_len = len; \ + } \ + add_assoc_stringl(array, k, decoded, decoded_len, 0); \ + } +#define HTTP_KEYLIST_FIXKEY() \ + { \ + while (isspace(*key)) ++key; \ + keylen = val - key; \ + while (isspace(key[keylen - 1])) --keylen; \ + } +#define HTTP_KEYLIST_FIXVAL() \ + { \ + ++val; \ + while (isspace(*val)) ++val; \ + vallen = key - val; \ + while (isspace(val[vallen - 1])) --vallen; \ + } + + HTTP_KEYLIST_FIXKEY(); + + if (first_entry_is_name_value_pair) { + HTTP_KEYLIST_VAL(&array, "name", key, keylen); + + /* just one name=value */ + if (!(key = strchr(val, separator))) { + key = val + strlen(val); + HTTP_KEYLIST_FIXVAL(); + HTTP_KEYLIST_VAL(&array, "value", val, vallen); + goto list_done; + } + /* additional info appended */ + else { + HTTP_KEYLIST_FIXVAL(); + HTTP_KEYLIST_VAL(&array, "value", val, vallen); + } + } + + do { + char *keydup = NULL; + + if (!(val = strchr(key, '='))) { + break; + } + + /* start at 0 if first_entry_is_name_value_pair==0 */ + if (zend_hash_num_elements(items)) { + ++key; + } + + HTTP_KEYLIST_FIXKEY(); + keydup = estrndup(key, keylen); + if (!(key = strchr(val, separator))) { + done = 1; + key = val + strlen(val); + } + HTTP_KEYLIST_FIXVAL(); + HTTP_KEYLIST_VAL(&array, keydup, val, vallen); + efree(keydup); + } while (!done); + +list_done: + return SUCCESS; +} + /* {{{ void http_error(long, long, char*) */ void _http_error_ex(long type, long code, const char *format, ...) { diff --git a/http_auth_api.c b/http_auth_api.c index be2f744..a2c54ae 100644 --- a/http_auth_api.c +++ b/http_auth_api.c @@ -34,17 +34,17 @@ * - Digest Auth */ -/* {{{ STATUS http_auth_header(char *, char*) */ -PHP_HTTP_API STATUS _http_auth_header(const char *type, const char *realm TSRMLS_DC) +/* {{{ STATUS http_auth_basic_header(char*) */ +PHP_HTTP_API STATUS _http_auth_basic_header(const char *realm TSRMLS_DC) { char realm_header[1024] = {0}; - snprintf(realm_header, 1023, "WWW-Authenticate: %s realm=\"%s\"", type, realm); + snprintf(realm_header, 1023, "WWW-Authenticate: Basic realm=\"%s\"", realm); return http_send_status_header(401, realm_header); } /* }}} */ /* {{{ STATUS http_auth_credentials(char **, char **) */ -PHP_HTTP_API STATUS _http_auth_credentials(char **user, char **pass TSRMLS_DC) +PHP_HTTP_API STATUS _http_auth_basic_credentials(char **user, char **pass TSRMLS_DC) { if (strncmp(sapi_module.name, "isapi", 5)) { zval *zuser, *zpass; @@ -77,6 +77,176 @@ PHP_HTTP_API STATUS _http_auth_credentials(char **user, char **pass TSRMLS_DC) /* }}} */ +/* {{{ Digest * / + +#include "ext/standard/php_rand.h" +#include "ext/standard/md5.h" + +#define DIGEST_ALGORITHM "MD5" +#define DIGEST_SECRETLEN 20 +static unsigned char digest_secret[DIGEST_SECRETLEN]; + +#define DIGEST_BIN_LEN 16 +typedef char http_digest_bin_t[DIGEST_BIN_LEN]; +#define DIGEST_HEX_LEN 32 +typedef char http_digest_hex_t[DIGEST_HEX_LEN+1]; + +void _http_auth_global_init(TSRMLS_D) +{ + int i; + // XX this is pretty loose + for (i = 0; i < DIGEST_SECRETLEN; ++i) { + digest_secret[i] = (unsigned char) ((php_rand(TSRMLS_C) % 254) + 1); + } +} + +static void http_digest_line_decoder(const char *encoded, size_t encoded_len, char **decoded, size_t *decoded_len TSRMLS_DC) +{ + char l = '\0'; + size_t i; + phpstr s; + + phpstr_init_ex(&s, encoded_len, 1); + + for (i = 0; i < encoded_len; ++i) { + if ((encoded[i] != '\\') && (encoded[i] != '"')) { + phpstr_append(&s, encoded+i, 1); + } + } + + phpstr_fix(&s); + + *decoded = PHPSTR_VAL(&s); + *decoded_len = PHPSTR_LEN(&s); +} + +static void http_digest_tohex(http_digest_bin_t bin, http_digest_hex_t hex) +{ + unsigned short i; + unsigned char j; + + for (i = 0; i < DIGEST_BIN_LEN; i++) { + j = (bin[i] >> 4) & 0xf; + if (j <= 9) { + hex[i*2] = (j + '0'); + } else { + hex[i*2] = (j + 'a' - 10); + } + j = bin[i] & 0xf; + if (j <= 9) { + hex[i*2+1] = (j + '0'); + } else { + hex[i*2+1] = (j + 'a' - 10); + } + } + hex[DIGEST_HEX_LEN] = '\0'; +} + +static void http_digest_calc_HA1( + const char *alg, const char *user, + const char *realm, const char *pass, + const char *nonce, const char *cnonce, + http_digest_hex_t HA1) +{ + PHP_MD5_CTX md5; + http_digest_bin_t HA1_bin; + + PHP_MD5Init(&md5); + PHP_MD5Update(&md5, user, strlen(user)); + PHP_MD5Update(&md5, ":", 1); + PHP_MD5Update(&md5, realm, strlen(realm)); + PHP_MD5Update(&md5, ":", 1); + PHP_MD5Update(&md5, pass, strlen(pass)); + PHP_MD5Final(HA1_bin, &md5); + + if (strcasecmp(alg, "md5-sess") == 0) { + PHP_MD5Init(&md5); + PHP_MD5Update(&md5, HA1_bin, DIGEST_BIN_LEN); + PHP_MD5Update(&md5, ":", 1); + PHP_MD5Update(&md5, nonce, strlen(nonce)); + PHP_MD5Update(&md5, ":", 1); + PHP_MD5Update(&md5, cnonce, strlen(cnonce)); + PHP_MD5Final(HA1_bin, &md5); + } + http_digest_tohex(HA1_bin, HA1); +} + +static void http_digest_calc_response( + const http_digest_hex_t HA1, + const char *nonce, const char *noncecount, + const char *cnonce, const char *qop, + const char *method, const char *uri, + http_digest_hex_t ent, + http_digest_hex_t response) +{ + PHP_MD5_CTX md5; + http_digest_bin_t HA2; + http_digest_bin_t bin; + http_digest_hex_t HA2_hex; + + // calculate H(A2) + PHP_MD5Init(&md5); + PHP_MD5Update(&md5, method, strlen(method)); + PHP_MD5Update(&md5, ":", 1); + PHP_MD5Update(&md5, uri, strlen(uri)); + if (strcasecmp(qop, "auth-int") == 0) { + PHP_MD5Update(&md5, ":", 1); + PHP_MD5Update(&md5, HEntity, DIGEST_HEX_LEN); + } + PHP_MD5Final(HA2, &md5); + http_digest_tohex(HA2, HA2_hex); + + // calculate response + PHP_MD5Init(&md5); + PHP_MD5Update(&md5, HA1, DIGEST_HEX_LEN); + PHP_MD5Update(&md5, ":", 1); + PHP_MD5Update(&md5, nonce, strlen(nonce)); + PHP_MD5Update(&md5, ":", 1); + if (*qop) { + PHP_MD5Update(&md5, noncecount, strlen(noncecount)); + PHP_MD5Update(&md5, ":", 1); + PHP_MD5Update(&md5, cnonce, strlen(cnonce)); + PHP_MD5Update(&md5, ":", 1); + PHP_MD5Update(&md5, qop, strlen(qop)); + PHP_MD5Update(&md5, ":", 1); + } + PHP_MD5Update(&md5, HA2_hex, DIGEST_HEX_LEN); + PHP_MD5Final(bin, &md5); + http_digest_tohex(bin, response); +} + +PHP_HTTP_API STATUS _http_auth_digest_credentials(HashTable *items TSRMLS_DC) +{ + char *auth; + zval array, *zauth = NULL; + + HTTP_GSC(zauth, "HTTP_AUTHORIZATION", FAILURE); + auth = Z_STRVAL_P(zauth); + + if (strncasecmp(auth, "Digest ", sizeof("Digest")) || (!(auth += sizeof("Digest")))) { + return FAILURE; + } + if (SUCCESS != http_parse_key_list(auth, items, ',', http_digest_line_decoder, 0)) { + return FAILURE; + } + if ( !zend_hash_exists(items, "uri", sizeof("uri")) || + !zend_hash_exists(items, "realm", sizeof("realm")) || + !zend_hash_exists(items, "nonce", sizeof("nonce")) || + !zend_hash_exists(items, "username", sizeof("username")) || + !zend_hash_exists(items, "response", sizeof("response"))) { + zend_hash_clean(items); + return FAILURE; + } + return SUCCESS; +} + +PHP_HTTP_API STATUS _http_auth_digest_header(const char *realm TSRMLS_DC) +{ + return FAILURE; +} +/* }}} */ + + /* * Local variables: * tab-width: 4 diff --git a/http_functions.c b/http_functions.c index fa9cf9c..9f76881 100644 --- a/http_functions.c +++ b/http_functions.c @@ -1108,18 +1108,18 @@ PHP_FUNCTION(http_auth_basic) realm = "Restricted"; } - if (SUCCESS != http_auth_credentials(&suser, &spass)) { - http_auth_header("Basic", realm); + if (SUCCESS != http_auth_basic_credentials(&suser, &spass)) { + http_auth_basic_header(realm); RETURN_FALSE; } if (strcasecmp(suser, user)) { - http_auth_header("Basic", realm); + http_auth_basic_header(realm); RETURN_FALSE; } if (strcmp(spass, pass)) { - http_auth_header("Basic", realm); + http_auth_basic_header(realm); RETURN_FALSE; } @@ -1161,8 +1161,8 @@ PHP_FUNCTION(http_auth_basic_cb) realm = "Restricted"; } - if (SUCCESS != http_auth_credentials(&user, &pass)) { - http_auth_header("Basic", realm); + if (SUCCESS != http_auth_basic_credentials(&user, &pass)) { + http_auth_basic_header(realm); RETURN_FALSE; } { @@ -1185,7 +1185,7 @@ PHP_FUNCTION(http_auth_basic_cb) efree(zparams[1]); if (!result) { - http_auth_header("Basic", realm); + http_auth_basic_header(realm); } RETURN_BOOL(result); diff --git a/http_headers_api.c b/http_headers_api.c index 81181e5..96a8b66 100644 --- a/http_headers_api.c +++ b/http_headers_api.c @@ -366,78 +366,6 @@ PHP_HTTP_API void _http_parse_headers_default_callback(const char *http_line, Ha } } -/* {{{ */ -PHP_HTTP_API STATUS _http_parse_cookie(const char *cookie, HashTable *values TSRMLS_DC) -{ - const char *key = cookie, *val = NULL; - int vallen = 0, keylen = 0, done = 0; - zval array; - - Z_ARRVAL(array) = values; - - if (!(val = strchr(cookie, '='))) { - return FAILURE; - } - -#define HTTP_COOKIE_VAL(array, k, str, len) \ - { \ - const char *encoded = str; \ - char *decoded = NULL; \ - int decoded_len = 0, encoded_len = len; \ - decoded = estrndup(encoded, encoded_len); \ - decoded_len = php_url_decode(decoded, encoded_len); \ - add_assoc_stringl(array, k, decoded, decoded_len, 0); \ - } -#define HTTP_COOKIE_FIXKEY() \ - { \ - while (isspace(*key)) ++key; \ - keylen = val - key; \ - while (isspace(key[keylen - 1])) --keylen; \ - } -#define HTTP_COOKIE_FIXVAL() \ - { \ - ++val; \ - while (isspace(*val)) ++val; \ - vallen = key - val; \ - while (isspace(val[vallen - 1])) --vallen; \ - } - - HTTP_COOKIE_FIXKEY(); - HTTP_COOKIE_VAL(&array, "name", key, keylen); - - /* just a name=value cookie */ - if (!(key = strchr(val, ';'))) { - key = val + strlen(val); - HTTP_COOKIE_FIXVAL(); - HTTP_COOKIE_VAL(&array, "value", val, vallen); - } - /* additional info appended */ - else { - char *keydup = NULL; - - HTTP_COOKIE_FIXVAL(); - HTTP_COOKIE_VAL(&array, "value", val, vallen); - - do { - if (!(val = strchr(key, '='))) { - break; - } - ++key; - HTTP_COOKIE_FIXKEY(); - keydup = estrndup(key, keylen); - if (!(key = strchr(val, ';'))) { - done = 1; - key = val + strlen(val); - } - HTTP_COOKIE_FIXVAL(); - HTTP_COOKIE_VAL(&array, keydup, val, vallen); - efree(keydup); - } while (!done); - } - return SUCCESS; -} -/* }}} */ - /* {{{ void http_get_request_headers_ex(HashTable *, zend_bool) */ PHP_HTTP_API void _http_get_request_headers_ex(HashTable *headers, zend_bool prettify TSRMLS_DC) { diff --git a/http_methods.c b/http_methods.c index a8f5d94..ebb892a 100644 --- a/http_methods.c +++ b/http_methods.c @@ -2237,15 +2237,15 @@ PHP_METHOD(HttpRequestPool, send) * * Usage: *
- *	socketSend()) {
- *			do_something_else();
- *			if (!$pool->socketSelect()) {
- *				die('Socket error');
- *			}
- *		}
- *		$pool->socketRead();
- *	?>
+ * socketSend()) {
+ *         do_something_else();
+ *         if (!$pool->socketSelect()) {
+ *             die('Socket error');
+ *         }
+ *     }
+ *     $pool->socketRead();
+ * ?>
  * 
*/ PHP_METHOD(HttpRequestPool, socketSend) @@ -2284,6 +2284,7 @@ PHP_METHOD(HttpRequestPool, socketRead) zend_llist_apply(&obj->pool.handles, (llist_apply_func_t) http_request_pool_responsehandler TSRMLS_CC); } +/* }}} */ /* }}} */ diff --git a/http_request_object.c b/http_request_object.c index 055a43e..1c99c8c 100644 --- a/http_request_object.c +++ b/http_request_object.c @@ -208,7 +208,7 @@ void _http_request_object_free(zend_object *object TSRMLS_DC) STATUS _http_request_object_requesthandler(http_request_object *obj, zval *this_ptr, http_request_body *body TSRMLS_DC) { zval *meth, *URL, *qdata, *opts; - char *request_uri, *uri; + char *request_uri; STATUS status; if (!body) { @@ -283,7 +283,7 @@ STATUS _http_request_object_requesthandler(http_request_object *obj, zval *this_ body->data = Z_STRVAL_P(post); body->size = Z_STRLEN_P(post); - status = http_request_init(obj->ch, Z_LVAL_P(meth), uri, body, Z_ARRVAL_P(opts), &obj->response); + status = http_request_init(obj->ch, Z_LVAL_P(meth), request_uri, body, Z_ARRVAL_P(opts), &obj->response); } break; } diff --git a/php_http_api.h b/php_http_api.h index 44d8ac6..a68b5b7 100644 --- a/php_http_api.h +++ b/php_http_api.h @@ -23,6 +23,14 @@ #define pretty_key(key, key_len, uctitle, xhyphen) _http_pretty_key(key, key_len, uctitle, xhyphen) extern char *_http_pretty_key(char *key, size_t key_len, zend_bool uctitle, zend_bool xhyphen); +typedef void (*http_key_list_decode_t)(const char *encoded, size_t encoded_len, char **decoded, size_t *decoded_len TSRMLS_DC); +#define http_key_list_default_decoder _http_key_list_default_decoder +extern void _http_key_list_default_decoder(const char *encoded, size_t encoded_len, char **decoded, size_t *decoded_len TSRMLS_DC); + +#define http_parse_cookie(l, i) _http_parse_key_list((l), (i), ';', http_key_list_default_decoder, 1 TSRMLS_CC) +#define http_parse_key_list(l, i, s, d, f) _http_parse_key_list((l), (i), (s), (d), (f) TSRMLS_CC) +extern STATUS _http_parse_key_list(const char *list, HashTable *items, char separator, http_key_list_decode_t decode, zend_bool first_entry_is_name_value_pair TSRMLS_DC); + #define http_error(type, code, string) _http_error_ex(type, code, "%s", string) #define http_error_ex _http_error_ex extern void _http_error_ex(long type, long code, const char *format, ...); diff --git a/php_http_auth_api.h b/php_http_auth_api.h index 7c06980..62ffd3e 100644 --- a/php_http_auth_api.h +++ b/php_http_auth_api.h @@ -20,11 +20,19 @@ #include "php_http_std_defs.h" -#define http_auth_credentials(u, p) _http_auth_credentials((u), (p) TSRMLS_CC) -PHP_HTTP_API STATUS _http_auth_credentials(char **user, char **pass TSRMLS_DC); +#define http_auth_basic_credentials(u, p) _http_auth_basic_credentials((u), (p) TSRMLS_CC) +PHP_HTTP_API STATUS _http_auth_basic_credentials(char **user, char **pass TSRMLS_DC); -#define http_auth_header(t, r) _http_auth_header((t), (r) TSRMLS_CC) -PHP_HTTP_API STATUS _http_auth_header(const char *type, const char *realm TSRMLS_DC); +#define http_auth_basic_header(r) _http_auth_basic_header((r) TSRMLS_CC) +PHP_HTTP_API STATUS _http_auth_basic_header(const char *realm TSRMLS_DC); + +/* +#define http_auth_digest_credentials(i) _http_auth_digest_credentials((i) TSRMLS_CC) +PHP_HTTP_API STATUS _http_auth_digest_credentials(HashTable *items TSRMLS_DC); + +#define http_auth_digest_header(r) _http_auth_digest_header((r) TSRMLS_CC) +PHP_HTTP_API STATUS _http_auth_digest_header(const char *realm TSRMLS_DC); +*/ #endif diff --git a/php_http_headers_api.h b/php_http_headers_api.h index 6d6319a..d3221f5 100644 --- a/php_http_headers_api.h +++ b/php_http_headers_api.h @@ -36,9 +36,6 @@ PHP_HTTP_API void _http_parse_headers_default_callback(const char *http_line, Ha #define http_parse_headers_cb(h, ht, p, f, d) _http_parse_headers_ex((h), (ht), (p), (f), (d) TSRMLS_CC) PHP_HTTP_API STATUS _http_parse_headers_ex(const char *header, HashTable *headers, zend_bool prettify, http_parse_headers_callback_t func, void **callback_data TSRMLS_DC); -#define http_parse_cookie(c, ht) _http_parse_cookie((c), (ht) TSRMLS_CC) -PHP_HTTP_API STATUS _http_parse_cookie(const char *cookie, HashTable *values TSRMLS_DC); - #define http_get_request_headers(h) _http_get_request_headers_ex(Z_ARRVAL_P(h), 1 TSRMLS_CC) #define http_get_request_headers_ex(h, p) _http_get_request_headers_ex((h), (p) TSRMLS_CC) PHP_HTTP_API void _http_get_request_headers_ex(HashTable *headers, zend_bool prettify TSRMLS_DC); -- 2.30.2