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