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