1 /* $Id: fpm_php.c,v 1.22.2.4 2008/12/13 03:21:18 anight Exp $ */
2 /* (c) 2007,2008 Andrei Nigmatulin */
3
4 #include "fpm_config.h"
5
6 #include <stdlib.h>
7 #include <string.h>
8 #include <stdio.h>
9
10 #include "php.h"
11 #include "php_main.h"
12 #include "php_ini.h"
13 #include "ext/standard/dl.h"
14
15 #include "fastcgi.h"
16
17 #include "fpm.h"
18 #include "fpm_php.h"
19 #include "fpm_cleanup.h"
20 #include "fpm_worker_pool.h"
21 #include "zlog.h"
22
23 static char **limit_extensions = NULL;
24
fpm_php_zend_ini_alter_master(char * name,int name_length,char * new_value,int new_value_length,int mode,int stage)25 static int fpm_php_zend_ini_alter_master(char *name, int name_length, char *new_value, int new_value_length, int mode, int stage) /* {{{ */
26 {
27 zend_ini_entry *ini_entry;
28 zend_string *duplicate;
29
30 if ((ini_entry = zend_hash_str_find_ptr(EG(ini_directives), name, name_length)) == NULL) {
31 return FAILURE;
32 }
33
34 duplicate = zend_string_init(new_value, new_value_length, 1);
35
36 if (!ini_entry->on_modify
37 || ini_entry->on_modify(ini_entry, duplicate,
38 ini_entry->mh_arg1, ini_entry->mh_arg2, ini_entry->mh_arg3, stage) == SUCCESS) {
39 ini_entry->value = duplicate;
40 ini_entry->modifiable = mode;
41 } else {
42 zend_string_release(duplicate);
43 }
44
45 return SUCCESS;
46 }
47 /* }}} */
48
fpm_php_disable(char * value,int (* zend_disable)(char *,size_t))49 static void fpm_php_disable(char *value, int (*zend_disable)(char *, size_t)) /* {{{ */
50 {
51 char *s = 0, *e = value;
52
53 while (*e) {
54 switch (*e) {
55 case ' ':
56 case ',':
57 if (s) {
58 *e = '\0';
59 zend_disable(s, e - s);
60 s = 0;
61 }
62 break;
63 default:
64 if (!s) {
65 s = e;
66 }
67 break;
68 }
69 e++;
70 }
71
72 if (s) {
73 zend_disable(s, e - s);
74 }
75 }
76 /* }}} */
77
fpm_php_apply_defines_ex(struct key_value_s * kv,int mode)78 int fpm_php_apply_defines_ex(struct key_value_s *kv, int mode) /* {{{ */
79 {
80
81 char *name = kv->key;
82 char *value = kv->value;
83 int name_len = strlen(name);
84 int value_len = strlen(value);
85
86 if (!strcmp(name, "extension") && *value) {
87 zval zv;
88 php_dl(value, MODULE_PERSISTENT, &zv, 1);
89 return Z_TYPE(zv) == IS_TRUE;
90 }
91
92 if (fpm_php_zend_ini_alter_master(name, name_len, value, value_len, mode, PHP_INI_STAGE_ACTIVATE) == FAILURE) {
93 return -1;
94 }
95
96 if (!strcmp(name, "disable_functions") && *value) {
97 char *v = strdup(value);
98 PG(disable_functions) = v;
99 fpm_php_disable(v, zend_disable_function);
100 return 1;
101 }
102
103 if (!strcmp(name, "disable_classes") && *value) {
104 char *v = strdup(value);
105 PG(disable_classes) = v;
106 fpm_php_disable(v, zend_disable_class);
107 return 1;
108 }
109
110 return 1;
111 }
112 /* }}} */
113
fpm_php_apply_defines(struct fpm_worker_pool_s * wp)114 static int fpm_php_apply_defines(struct fpm_worker_pool_s *wp) /* {{{ */
115 {
116 struct key_value_s *kv;
117
118 for (kv = wp->config->php_values; kv; kv = kv->next) {
119 if (fpm_php_apply_defines_ex(kv, ZEND_INI_USER) == -1) {
120 zlog(ZLOG_ERROR, "Unable to set php_value '%s'", kv->key);
121 }
122 }
123
124 for (kv = wp->config->php_admin_values; kv; kv = kv->next) {
125 if (fpm_php_apply_defines_ex(kv, ZEND_INI_SYSTEM) == -1) {
126 zlog(ZLOG_ERROR, "Unable to set php_admin_value '%s'", kv->key);
127 }
128 }
129
130 return 0;
131 }
132 /* }}} */
133
fpm_php_set_allowed_clients(struct fpm_worker_pool_s * wp)134 static int fpm_php_set_allowed_clients(struct fpm_worker_pool_s *wp) /* {{{ */
135 {
136 if (wp->listen_address_domain == FPM_AF_INET) {
137 fcgi_set_allowed_clients(wp->config->listen_allowed_clients);
138 }
139 return 0;
140 }
141 /* }}} */
142
143 #if 0 /* Comment out this non used function. It could be used later. */
144 static int fpm_php_set_fcgi_mgmt_vars(struct fpm_worker_pool_s *wp) /* {{{ */
145 {
146 char max_workers[10 + 1]; /* 4294967295 */
147 int len;
148
149 len = sprintf(max_workers, "%u", (unsigned int) wp->config->pm_max_children);
150
151 fcgi_set_mgmt_var("FCGI_MAX_CONNS", sizeof("FCGI_MAX_CONNS")-1, max_workers, len);
152 fcgi_set_mgmt_var("FCGI_MAX_REQS", sizeof("FCGI_MAX_REQS")-1, max_workers, len);
153 return 0;
154 }
155 /* }}} */
156 #endif
157
fpm_php_script_filename(void)158 char *fpm_php_script_filename(void) /* {{{ */
159 {
160 return SG(request_info).path_translated;
161 }
162 /* }}} */
163
fpm_php_request_uri(void)164 char *fpm_php_request_uri(void) /* {{{ */
165 {
166 return (char *) SG(request_info).request_uri;
167 }
168 /* }}} */
169
fpm_php_request_method(void)170 char *fpm_php_request_method(void) /* {{{ */
171 {
172 return (char *) SG(request_info).request_method;
173 }
174 /* }}} */
175
fpm_php_query_string(void)176 char *fpm_php_query_string(void) /* {{{ */
177 {
178 return SG(request_info).query_string;
179 }
180 /* }}} */
181
fpm_php_auth_user(void)182 char *fpm_php_auth_user(void) /* {{{ */
183 {
184 return SG(request_info).auth_user;
185 }
186 /* }}} */
187
fpm_php_content_length(void)188 size_t fpm_php_content_length(void) /* {{{ */
189 {
190 return SG(request_info).content_length;
191 }
192 /* }}} */
193
fpm_php_cleanup(int which,void * arg)194 static void fpm_php_cleanup(int which, void *arg) /* {{{ */
195 {
196 php_module_shutdown();
197 sapi_shutdown();
198 }
199 /* }}} */
200
fpm_php_soft_quit()201 void fpm_php_soft_quit() /* {{{ */
202 {
203 fcgi_terminate();
204 }
205 /* }}} */
206
fpm_php_init_main()207 int fpm_php_init_main() /* {{{ */
208 {
209 if (0 > fpm_cleanup_add(FPM_CLEANUP_PARENT, fpm_php_cleanup, 0)) {
210 return -1;
211 }
212 return 0;
213 }
214 /* }}} */
215
fpm_php_init_child(struct fpm_worker_pool_s * wp)216 int fpm_php_init_child(struct fpm_worker_pool_s *wp) /* {{{ */
217 {
218 if (0 > fpm_php_apply_defines(wp) ||
219 0 > fpm_php_set_allowed_clients(wp)) {
220 return -1;
221 }
222
223 if (wp->limit_extensions) {
224 limit_extensions = wp->limit_extensions;
225 }
226 return 0;
227 }
228 /* }}} */
229
fpm_php_limit_extensions(char * path)230 int fpm_php_limit_extensions(char *path) /* {{{ */
231 {
232 char **p;
233 size_t path_len;
234
235 if (!path || !limit_extensions) {
236 return 0; /* allowed by default */
237 }
238
239 p = limit_extensions;
240 path_len = strlen(path);
241 while (p && *p) {
242 size_t ext_len = strlen(*p);
243 if (path_len > ext_len) {
244 char *path_ext = path + path_len - ext_len;
245 if (strcmp(*p, path_ext) == 0) {
246 return 0; /* allow as the extension has been found */
247 }
248 }
249 p++;
250 }
251
252
253 zlog(ZLOG_NOTICE, "Access to the script '%s' has been denied (see security.limit_extensions)", path);
254 return 1; /* extension not found: not allowed */
255 }
256 /* }}} */
257
fpm_php_get_string_from_table(zend_string * table,char * key)258 char* fpm_php_get_string_from_table(zend_string *table, char *key) /* {{{ */
259 {
260 zval *data, *tmp;
261 zend_string *str;
262 if (!table || !key) {
263 return NULL;
264 }
265
266 /* inspired from ext/standard/info.c */
267
268 zend_is_auto_global(table);
269
270 /* find the table and ensure it's an array */
271 data = zend_hash_find(&EG(symbol_table), table);
272 if (!data || Z_TYPE_P(data) != IS_ARRAY) {
273 return NULL;
274 }
275
276 ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(data), str, tmp) {
277 if (str && !strncmp(ZSTR_VAL(str), key, ZSTR_LEN(str))) {
278 return Z_STRVAL_P(tmp);
279 }
280 } ZEND_HASH_FOREACH_END();
281
282 return NULL;
283 }
284 /* }}} */
285