X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-http;a=blobdiff_plain;f=http_auth_api.c;h=5e5bafc07ef3e6387800b494cd341961bc715a15;hp=386faffcf3eb9fe537569ff4a8e829dbd7111b60;hb=020d5b055921392c0dfb25043962a40867d8b033;hpb=0ac32c9b8590e88a5f110cc8b3154001d5c0c089 diff --git a/http_auth_api.c b/http_auth_api.c index 386faff..5e5bafc 100644 --- a/http_auth_api.c +++ b/http_auth_api.c @@ -18,11 +18,10 @@ #ifdef HAVE_CONFIG_H # include "config.h" #endif - #include "php.h" -#include "ext/standard/base64.h" #include "SAPI.h" +#include "ext/standard/base64.h" #include "php_http.h" #include "php_http_api.h" @@ -34,17 +33,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; @@ -60,10 +59,8 @@ PHP_HTTP_API STATUS _http_auth_credentials(char **user, char **pass TSRMLS_DC) zval *zauth = NULL; HTTP_GSC(zauth, "HTTP_AUTHORIZATION", FAILURE); { - char *decoded, *colon; int decoded_len; - decoded = php_base64_decode(Z_STRVAL_P(zauth), Z_STRLEN_P(zauth), - &decoded_len); + char *colon, *decoded = (char *) php_base64_decode((const unsigned char *) Z_STRVAL_P(zauth), Z_STRLEN_P(zauth), &decoded_len); if (colon = strchr(decoded + 6, ':')) { *user = estrndup(decoded + 6, colon - decoded - 6); @@ -79,6 +76,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