- flush
[m6w6/ext-http] / http_auth_api.c
1 /*
2 +----------------------------------------------------------------------+
3 | PECL :: http |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.0 of the PHP license, that |
6 | is bundled with this package in the file LICENSE, and is available |
7 | through the world-wide-web at http://www.php.net/license/3_0.txt. |
8 | If you did not receive a copy of the PHP license and are unable to |
9 | obtain it through the world-wide-web, please send a note to |
10 | license@php.net so we can mail you a copy immediately. |
11 +----------------------------------------------------------------------+
12 | Copyright (c) 2004-2005 Michael Wallner <mike@php.net> |
13 +----------------------------------------------------------------------+
14 */
15
16 /* $Id$ */
17
18 #ifdef HAVE_CONFIG_H
19 # include "config.h"
20 #endif
21 #include "php.h"
22
23 #include "SAPI.h"
24 #include "ext/standard/base64.h"
25
26 #include "php_http.h"
27 #include "php_http_api.h"
28 #include "php_http_std_defs.h"
29 #include "php_http_send_api.h"
30
31 /*
32 * TODO:
33 * - Digest Auth
34 */
35
36 /* {{{ STATUS http_auth_basic_header(char*) */
37 PHP_HTTP_API STATUS _http_auth_basic_header(const char *realm TSRMLS_DC)
38 {
39 char realm_header[1024] = {0};
40 snprintf(realm_header, 1023, "WWW-Authenticate: Basic realm=\"%s\"", realm);
41 return http_send_status_header(401, realm_header);
42 }
43 /* }}} */
44
45 /* {{{ STATUS http_auth_credentials(char **, char **) */
46 PHP_HTTP_API STATUS _http_auth_basic_credentials(char **user, char **pass TSRMLS_DC)
47 {
48 if (strncmp(sapi_module.name, "isapi", 5)) {
49 zval *zuser, *zpass;
50
51 HTTP_GSC(zuser, "PHP_AUTH_USER", FAILURE);
52 HTTP_GSC(zpass, "PHP_AUTH_PW", FAILURE);
53
54 *user = estrndup(Z_STRVAL_P(zuser), Z_STRLEN_P(zuser));
55 *pass = estrndup(Z_STRVAL_P(zpass), Z_STRLEN_P(zpass));
56
57 return SUCCESS;
58 } else {
59 zval *zauth = NULL;
60 HTTP_GSC(zauth, "HTTP_AUTHORIZATION", FAILURE);
61 {
62 int decoded_len;
63 char *colon, *decoded = (char *) php_base64_decode((const unsigned char *) Z_STRVAL_P(zauth), Z_STRLEN_P(zauth), &decoded_len);
64
65 if (colon = strchr(decoded + 6, ':')) {
66 *user = estrndup(decoded + 6, colon - decoded - 6);
67 *pass = estrndup(colon + 1, decoded + decoded_len - colon - 6 - 1);
68
69 return SUCCESS;
70 } else {
71 return FAILURE;
72 }
73 }
74 }
75 }
76 /* }}} */
77
78
79 /* {{{ Digest * /
80
81 #include "ext/standard/php_rand.h"
82 #include "ext/standard/md5.h"
83
84 #define DIGEST_ALGORITHM "MD5"
85 #define DIGEST_SECRETLEN 20
86 static unsigned char digest_secret[DIGEST_SECRETLEN];
87
88 #define DIGEST_BIN_LEN 16
89 typedef char http_digest_bin_t[DIGEST_BIN_LEN];
90 #define DIGEST_HEX_LEN 32
91 typedef char http_digest_hex_t[DIGEST_HEX_LEN+1];
92
93 void _http_auth_global_init(TSRMLS_D)
94 {
95 int i;
96 // XX this is pretty loose
97 for (i = 0; i < DIGEST_SECRETLEN; ++i) {
98 digest_secret[i] = (unsigned char) ((php_rand(TSRMLS_C) % 254) + 1);
99 }
100 }
101
102 static void http_digest_line_decoder(const char *encoded, size_t encoded_len, char **decoded, size_t *decoded_len TSRMLS_DC)
103 {
104 char l = '\0';
105 size_t i;
106 phpstr s;
107
108 phpstr_init_ex(&s, encoded_len, 1);
109
110 for (i = 0; i < encoded_len; ++i) {
111 if ((encoded[i] != '\\') && (encoded[i] != '"')) {
112 phpstr_append(&s, encoded+i, 1);
113 }
114 }
115
116 phpstr_fix(&s);
117
118 *decoded = PHPSTR_VAL(&s);
119 *decoded_len = PHPSTR_LEN(&s);
120 }
121
122 static void http_digest_tohex(http_digest_bin_t bin, http_digest_hex_t hex)
123 {
124 unsigned short i;
125 unsigned char j;
126
127 for (i = 0; i < DIGEST_BIN_LEN; i++) {
128 j = (bin[i] >> 4) & 0xf;
129 if (j <= 9) {
130 hex[i*2] = (j + '0');
131 } else {
132 hex[i*2] = (j + 'a' - 10);
133 }
134 j = bin[i] & 0xf;
135 if (j <= 9) {
136 hex[i*2+1] = (j + '0');
137 } else {
138 hex[i*2+1] = (j + 'a' - 10);
139 }
140 }
141 hex[DIGEST_HEX_LEN] = '\0';
142 }
143
144 static void http_digest_calc_HA1(
145 const char *alg, const char *user,
146 const char *realm, const char *pass,
147 const char *nonce, const char *cnonce,
148 http_digest_hex_t HA1)
149 {
150 PHP_MD5_CTX md5;
151 http_digest_bin_t HA1_bin;
152
153 PHP_MD5Init(&md5);
154 PHP_MD5Update(&md5, user, strlen(user));
155 PHP_MD5Update(&md5, ":", 1);
156 PHP_MD5Update(&md5, realm, strlen(realm));
157 PHP_MD5Update(&md5, ":", 1);
158 PHP_MD5Update(&md5, pass, strlen(pass));
159 PHP_MD5Final(HA1_bin, &md5);
160
161 if (strcasecmp(alg, "md5-sess") == 0) {
162 PHP_MD5Init(&md5);
163 PHP_MD5Update(&md5, HA1_bin, DIGEST_BIN_LEN);
164 PHP_MD5Update(&md5, ":", 1);
165 PHP_MD5Update(&md5, nonce, strlen(nonce));
166 PHP_MD5Update(&md5, ":", 1);
167 PHP_MD5Update(&md5, cnonce, strlen(cnonce));
168 PHP_MD5Final(HA1_bin, &md5);
169 }
170 http_digest_tohex(HA1_bin, HA1);
171 }
172
173 static void http_digest_calc_response(
174 const http_digest_hex_t HA1,
175 const char *nonce, const char *noncecount,
176 const char *cnonce, const char *qop,
177 const char *method, const char *uri,
178 http_digest_hex_t ent,
179 http_digest_hex_t response)
180 {
181 PHP_MD5_CTX md5;
182 http_digest_bin_t HA2;
183 http_digest_bin_t bin;
184 http_digest_hex_t HA2_hex;
185
186 // calculate H(A2)
187 PHP_MD5Init(&md5);
188 PHP_MD5Update(&md5, method, strlen(method));
189 PHP_MD5Update(&md5, ":", 1);
190 PHP_MD5Update(&md5, uri, strlen(uri));
191 if (strcasecmp(qop, "auth-int") == 0) {
192 PHP_MD5Update(&md5, ":", 1);
193 PHP_MD5Update(&md5, HEntity, DIGEST_HEX_LEN);
194 }
195 PHP_MD5Final(HA2, &md5);
196 http_digest_tohex(HA2, HA2_hex);
197
198 // calculate response
199 PHP_MD5Init(&md5);
200 PHP_MD5Update(&md5, HA1, DIGEST_HEX_LEN);
201 PHP_MD5Update(&md5, ":", 1);
202 PHP_MD5Update(&md5, nonce, strlen(nonce));
203 PHP_MD5Update(&md5, ":", 1);
204 if (*qop) {
205 PHP_MD5Update(&md5, noncecount, strlen(noncecount));
206 PHP_MD5Update(&md5, ":", 1);
207 PHP_MD5Update(&md5, cnonce, strlen(cnonce));
208 PHP_MD5Update(&md5, ":", 1);
209 PHP_MD5Update(&md5, qop, strlen(qop));
210 PHP_MD5Update(&md5, ":", 1);
211 }
212 PHP_MD5Update(&md5, HA2_hex, DIGEST_HEX_LEN);
213 PHP_MD5Final(bin, &md5);
214 http_digest_tohex(bin, response);
215 }
216
217 PHP_HTTP_API STATUS _http_auth_digest_credentials(HashTable *items TSRMLS_DC)
218 {
219 char *auth;
220 zval array, *zauth = NULL;
221
222 HTTP_GSC(zauth, "HTTP_AUTHORIZATION", FAILURE);
223 auth = Z_STRVAL_P(zauth);
224
225 if (strncasecmp(auth, "Digest ", sizeof("Digest")) || (!(auth += sizeof("Digest")))) {
226 return FAILURE;
227 }
228 if (SUCCESS != http_parse_key_list(auth, items, ',', http_digest_line_decoder, 0)) {
229 return FAILURE;
230 }
231 if ( !zend_hash_exists(items, "uri", sizeof("uri")) ||
232 !zend_hash_exists(items, "realm", sizeof("realm")) ||
233 !zend_hash_exists(items, "nonce", sizeof("nonce")) ||
234 !zend_hash_exists(items, "username", sizeof("username")) ||
235 !zend_hash_exists(items, "response", sizeof("response"))) {
236 zend_hash_clean(items);
237 return FAILURE;
238 }
239 return SUCCESS;
240 }
241
242 PHP_HTTP_API STATUS _http_auth_digest_header(const char *realm TSRMLS_DC)
243 {
244 return FAILURE;
245 }
246 /* }}} */
247
248
249 /*
250 * Local variables:
251 * tab-width: 4
252 * c-basic-offset: 4
253 * End:
254 * vim600: sw=4 ts=4 fdm=marker
255 * vim<600: sw=4 ts=4
256 */
257